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 kIOPMRootDomainWakeTypeMaintenance "Maintenance"
194 #define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer"
195 #define kIOPMrootDomainWakeTypeLowBattery "LowBattery"
196 #define kIOPMRootDomainWakeTypeUser "User"
197 #define kIOPMRootDomainWakeTypeAlarm "Alarm"
198 #define kIOPMRootDomainWakeTypeNetwork "Network"
200 // Special interest that entitles the interested client from receiving
201 // all system messages. Only used by powerd.
203 #define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest"
208 #define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
209 #define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
211 #define kAggressivesMinValue 1
214 kAggressivesStateBusy
= 0x01,
215 kAggressivesStateQuickSpindown
= 0x02
218 struct AggressivesRecord
{
224 struct AggressivesRequest
{
230 AggressivesRecord record
;
235 kAggressivesRequestTypeService
= 1,
236 kAggressivesRequestTypeRecord
240 kAggressivesOptionSynchronous
= 0x00000001,
241 kAggressivesOptionQuickSpindownEnable
= 0x00000100,
242 kAggressivesOptionQuickSpindownDisable
= 0x00000200,
243 kAggressivesOptionQuickSpindownMask
= 0x00000300
247 kAggressivesRecordFlagModified
= 0x00000001,
248 kAggressivesRecordFlagMinValue
= 0x00000002
253 kDarkWakeFlagHIDTickleEarly
= 0x01, // hid tickle before gfx suppression
254 kDarkWakeFlagHIDTickleLate
= 0x02, // hid tickle after gfx suppression
255 kDarkWakeFlagHIDTickleNone
= 0x03, // hid tickle is not posted
256 kDarkWakeFlagHIDTickleMask
= 0x03,
257 kDarkWakeFlagIgnoreDiskIOInDark
= 0x04, // ignore disk idle in DW
258 kDarkWakeFlagIgnoreDiskIOAlways
= 0x08, // always ignore disk idle
259 kDarkWakeFlagIgnoreDiskIOMask
= 0x0C,
260 kDarkWakeFlagAlarmIsDark
= 0x0100
263 static IOPMrootDomain
* gRootDomain
;
264 static IONotifier
* gSysPowerDownNotifier
= 0;
265 static UInt32 gSleepOrShutdownPending
= 0;
266 static UInt32 gWillShutdown
= 0;
267 static UInt32 gPagingOff
= 0;
268 static UInt32 gSleepWakeUUIDIsSet
= false;
269 static uint32_t gAggressivesState
= 0;
270 static uint32_t gDarkWakeFlags
= kDarkWakeFlagHIDTickleNone
;
271 static bool gRAMDiskImageBoot
= false;
273 struct timeval gIOLastSleepTime
;
274 struct timeval gIOLastWakeTime
;
276 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
277 #define kCPUUnknownIndex 9999999
284 const OSSymbol
*gIOPMStatsApplicationResponseTimedOut
;
285 const OSSymbol
*gIOPMStatsApplicationResponseCancel
;
286 const OSSymbol
*gIOPMStatsApplicationResponseSlow
;
290 * Opaque handle passed to clients of registerPMSettingController()
292 class PMSettingHandle
: public OSObject
294 OSDeclareFinalStructors( PMSettingHandle
)
295 friend class PMSettingObject
;
298 PMSettingObject
*pmso
;
304 * Internal object to track each PM setting controller
306 class PMSettingObject
: public OSObject
308 OSDeclareFinalStructors( PMSettingObject
)
309 friend class IOPMrootDomain
;
312 queue_head_t calloutQueue
;
314 IOPMrootDomain
*parent
;
315 PMSettingHandle
*pmsh
;
316 IOPMSettingControllerCallback func
;
319 uint32_t *publishedFeatureID
;
320 uint32_t settingCount
;
326 static PMSettingObject
*pmSettingObject(
327 IOPMrootDomain
*parent_arg
,
328 IOPMSettingControllerCallback handler_arg
,
329 OSObject
*target_arg
,
330 uintptr_t refcon_arg
,
331 uint32_t supportedPowerSources
,
332 const OSSymbol
*settings
[],
333 OSObject
**handle_obj
);
335 void dispatchPMSetting(const OSSymbol
*type
, OSObject
*object
);
336 void clientHandleFreed(void);
339 struct PMSettingCallEntry
{
344 #define PMSETTING_LOCK() IOLockLock(settingsCtrlLock)
345 #define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock)
346 #define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
347 #define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
349 //*********************************************************************************
350 //*********************************************************************************
351 //*********************************************************************************
353 /* @class IOPMTimeline
354 * @astract Tracks & records PM activity.
355 * @discussion Intended for use only as a helper-class to IOPMrootDomain.
356 * Do not subclass or directly invoke iOPMTimeline
358 class IOPMTimeline
: public OSObject
360 OSDeclareDefaultStructors( IOPMTimeline
);
363 static IOPMTimeline
* timeline(IOPMrootDomain
*root_domain
);
365 bool setProperties(OSDictionary
*d
);
366 OSDictionary
*copyInfoDictionary(void);
368 IOReturn
recordSystemPowerEvent( PMEventDetails
*details
);
370 IOReturn
recordDetailedPowerEvent( PMEventDetails
*details
);
372 IOMemoryDescriptor
*getPMTraceMemoryDescriptor();
374 uint32_t getNumEventsLoggedThisPeriod();
375 void setNumEventsLoggedThisPeriod(uint32_t newCount
);
376 bool isSleepCycleInProgress();
377 void setSleepCycleInProgressFlag(bool flag
);
382 void setEventsTrackedCount(uint32_t newTracked
);
383 void setEventsRecordingLevel(uint32_t eventsTrackedBits
);
384 static uint32_t _atomicIndexIncrement(uint32_t *index
, uint32_t limit
);
387 kPMTimelineRecordTardyDrivers
= 1 << 0,
388 kPMTmielineRecordSystemEvents
= 1 << 1,
389 kPMTimelineRecordAllDrivers
= 1 << 2,
390 kPMTimelineRecordOff
= 0,
391 kPMTimelineRecordDefault
= 3,
392 kPMTimelineRecordDebug
= 7
395 // eventsRecordingLevel is a bitfield defining which PM driver events will get logged
396 // into the PM buffer.
397 uint32_t eventsRecordingLevel
;
399 // pmTraceMemoryDescriptor represents the memory block that IOPMTimeLine records PM trace points into.
400 IOBufferMemoryDescriptor
*pmTraceMemoryDescriptor
;
402 // Pointer to starting address in pmTraceMemoryDescriptor
403 IOPMSystemEventRecord
*traceBuffer
;
404 IOPMTraceBufferHeader
*hdr
;
406 uint16_t systemState
;
409 IOPMrootDomain
*owner
;
411 uint32_t numEventsLoggedThisPeriod
;
412 bool sleepCycleInProgress
;
415 OSDefineMetaClassAndStructors( IOPMTimeline
, OSObject
)
419 * Internal helper object for logging trace points to RTC
420 * IOPMrootDomain and only IOPMrootDomain should instantiate
421 * exactly one of these.
424 typedef void (*IOPMTracePointHandler
)(
425 void * target
, uint32_t code
, uint32_t data
);
427 class PMTraceWorker
: public OSObject
429 OSDeclareDefaultStructors(PMTraceWorker
)
431 typedef enum { kPowerChangeStart
, kPowerChangeCompleted
} change_t
;
433 static PMTraceWorker
*tracer( IOPMrootDomain
* );
434 void tracePCIPowerChange(change_t
, IOService
*, uint32_t, uint32_t);
435 void tracePoint(uint8_t phase
);
436 void tracePoint(uint8_t phase
, uint8_t data8
);
437 void traceDetail(uint32_t detail
);
438 void traceLoginWindowPhase(uint8_t phase
);
439 int recordTopLevelPCIDevice(IOService
*);
440 void RTC_TRACE(void);
441 virtual bool serialize(OSSerialize
*s
) const;
443 IOPMTracePointHandler tracePointHandler
;
444 void * tracePointTarget
;
446 IOPMrootDomain
*owner
;
447 IOLock
*pciMappingLock
;
448 OSArray
*pciDeviceBitMappings
;
450 uint8_t addedToRegistry
;
452 uint8_t loginWindowPhase
;
454 uint32_t traceData32
;
458 * PMAssertionsTracker
459 * Tracks kernel and user space PM assertions
461 class PMAssertionsTracker
: public OSObject
463 OSDeclareFinalStructors(PMAssertionsTracker
)
465 static PMAssertionsTracker
*pmAssertionsTracker( IOPMrootDomain
* );
467 IOReturn
createAssertion(IOPMDriverAssertionType
, IOPMDriverAssertionLevel
, IOService
*, const char *, IOPMDriverAssertionID
*);
468 IOReturn
releaseAssertion(IOPMDriverAssertionID
);
469 IOReturn
setAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
470 IOReturn
setUserAssertionLevels(IOPMDriverAssertionType
);
472 OSArray
*copyAssertionsArray(void);
473 IOPMDriverAssertionType
getActivatedAssertions(void);
474 IOPMDriverAssertionLevel
getAssertionLevel(IOPMDriverAssertionType
);
476 IOReturn
handleCreateAssertion(OSData
*);
477 IOReturn
handleReleaseAssertion(IOPMDriverAssertionID
);
478 IOReturn
handleSetAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
479 IOReturn
handleSetUserAssertionLevels(void * arg0
);
480 void publishProperties(void);
484 IOPMDriverAssertionID id
;
485 IOPMDriverAssertionType assertionBits
;
486 uint64_t createdTime
;
487 uint64_t modifiedTime
;
488 const OSSymbol
*ownerString
;
489 IOService
*ownerService
;
490 IOPMDriverAssertionLevel level
;
493 uint32_t tabulateProducerCount
;
494 uint32_t tabulateConsumerCount
;
496 PMAssertStruct
*detailsForID(IOPMDriverAssertionID
, int *);
499 IOPMrootDomain
*owner
;
500 OSArray
*assertionsArray
;
501 IOLock
*assertionsArrayLock
;
502 IOPMDriverAssertionID issuingUniqueID
__attribute__((aligned(8))); /* aligned for atomic access */
503 IOPMDriverAssertionType assertionsKernel
;
504 IOPMDriverAssertionType assertionsUser
;
505 IOPMDriverAssertionType assertionsCombined
;
508 OSDefineMetaClassAndFinalStructors(PMAssertionsTracker
, OSObject
);
512 * Internal helper object for Shutdown/Restart notifications.
514 #define kPMHaltMaxWorkers 8
515 #define kPMHaltTimeoutMS 100
517 class PMHaltWorker
: public OSObject
519 OSDeclareFinalStructors( PMHaltWorker
)
522 IOService
* service
; // service being worked on
523 AbsoluteTime startTime
; // time when work started
524 int depth
; // work on nubs at this PM-tree depth
525 int visits
; // number of nodes visited (debug)
527 bool timeout
; // service took too long
529 static PMHaltWorker
* worker( void );
530 static void main( void * arg
, wait_result_t waitResult
);
531 static void work( PMHaltWorker
* me
);
532 static void checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
);
533 virtual void free( void );
536 OSDefineMetaClassAndFinalStructors( PMHaltWorker
, OSObject
)
539 #define super IOService
540 OSDefineMetaClassAndFinalStructors(IOPMrootDomain
, IOService
)
542 static void IOPMRootDomainWillShutdown(void)
544 if (OSCompareAndSwap(0, 1, &gWillShutdown
))
546 OSKext::willShutdown();
547 for (int i
= 0; i
< 100; i
++)
549 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending
)) break;
557 IONotifier
* registerSleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
559 return gRootDomain
->registerInterest( gIOGeneralInterest
, handler
, self
, ref
);
562 IONotifier
* registerPrioritySleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
564 return gRootDomain
->registerInterest( gIOPriorityPowerStateInterest
, handler
, self
, ref
);
567 IOReturn
acknowledgeSleepWakeNotification(void * PMrefcon
)
569 return gRootDomain
->allowPowerChange ( (unsigned long)PMrefcon
);
572 IOReturn
vetoSleepWakeNotification(void * PMrefcon
)
574 return gRootDomain
->cancelPowerChange ( (unsigned long)PMrefcon
);
577 IOReturn
rootDomainRestart ( void )
579 return gRootDomain
->restartSystem();
582 IOReturn
rootDomainShutdown ( void )
584 return gRootDomain
->shutdownSystem();
587 void IOSystemShutdownNotification(void)
589 IOPMRootDomainWillShutdown();
590 if (OSCompareAndSwap(0, 1, &gPagingOff
))
593 gRootDomain
->handlePlatformHaltRestart(kPEPagingOff
);
598 int sync_internal(void);
602 A device is always in the highest power state which satisfies its driver,
603 its policy-maker, and any power children it has, but within the constraint
604 of the power state provided by its parent. The driver expresses its desire by
605 calling changePowerStateTo(), the policy-maker expresses its desire by calling
606 changePowerStateToPriv(), and the children express their desires by calling
607 requestPowerDomainState().
609 The Root Power Domain owns the policy for idle and demand sleep for the system.
610 It is a power-managed IOService just like the others in the system.
611 It implements several power states which map to what we see as Sleep and On.
613 The sleep policy is as follows:
614 1. Sleep is prevented if the case is open so that nobody will think the machine
615 is off and plug/unplug cards.
616 2. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
617 3. System cannot Sleep if some object in the tree is in a power state marked
618 kIOPMPreventSystemSleep.
620 These three conditions are enforced using the "driver clamp" by calling
621 changePowerStateTo(). For example, if the case is opened,
622 changePowerStateTo(ON_STATE) is called to hold the system on regardless
623 of the desires of the children of the root or the state of the other clamp.
625 Demand Sleep is initiated by pressing the front panel power button, closing
626 the clamshell, or selecting the menu item. In this case the root's parent
627 actually initiates the power state change so that the root domain has no
628 choice and does not give applications the opportunity to veto the change.
630 Idle Sleep occurs if no objects in the tree are in a state marked
631 kIOPMPreventIdleSleep. When this is true, the root's children are not holding
632 the root on, so it sets the "policy-maker clamp" by calling
633 changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
634 This timer is set for the difference between the sleep timeout slider and the
635 display dim timeout slider. When the timer expires, it releases its clamp and
636 now nothing is holding it awake, so it falls asleep.
638 Demand sleep is prevented when the system is booting. When preferences are
639 transmitted by the loginwindow at the end of boot, a flag is cleared,
640 and this allows subsequent Demand Sleep.
643 //******************************************************************************
645 IOPMrootDomain
* IOPMrootDomain::construct( void )
647 IOPMrootDomain
*root
;
649 root
= new IOPMrootDomain
;
656 //******************************************************************************
658 static void disk_sync_callout( thread_call_param_t p0
, thread_call_param_t p1
)
660 IOService
* rootDomain
= (IOService
*) p0
;
661 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
662 uint32_t powerState
= rootDomain
->getPowerState();
664 DLOG("disk_sync_callout ps=%u\n", powerState
);
666 if (ON_STATE
== powerState
)
669 IOHibernateSystemSleep();
676 IOHibernateSystemPostWake();
680 rootDomain
->allowPowerChange(notifyRef
);
681 DLOG("disk_sync_callout finish\n");
684 //******************************************************************************
686 static UInt32
computeDeltaTimeMS( const AbsoluteTime
* startTime
)
688 AbsoluteTime endTime
;
691 clock_get_uptime(&endTime
);
692 if (CMP_ABSOLUTETIME(&endTime
, startTime
) > 0)
694 SUB_ABSOLUTETIME(&endTime
, startTime
);
695 absolutetime_to_nanoseconds(endTime
, &nano
);
698 return (UInt32
)(nano
/ 1000000ULL);
701 //******************************************************************************
704 sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
706 struct timeval
*swt
= (struct timeval
*)arg1
;
707 struct proc
*p
= req
->p
;
710 return sysctl_io_opaque(req
, swt
, sizeof(*swt
), NULL
);
711 } else if(proc_is64bit(p
)) {
712 struct user64_timeval t
;
713 t
.tv_sec
= swt
->tv_sec
;
714 t
.tv_usec
= swt
->tv_usec
;
715 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
717 struct user32_timeval t
;
718 t
.tv_sec
= swt
->tv_sec
;
719 t
.tv_usec
= swt
->tv_usec
;
720 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
724 static SYSCTL_PROC(_kern
, OID_AUTO
, sleeptime
,
725 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
726 &gIOLastSleepTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
728 static SYSCTL_PROC(_kern
, OID_AUTO
, waketime
,
729 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
730 &gIOLastWakeTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
735 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
737 int new_value
, changed
;
738 int error
= sysctl_io_number(req
, gWillShutdown
, sizeof(int), &new_value
, &changed
);
740 if (!gWillShutdown
&& (new_value
== 1)) {
741 IOPMRootDomainWillShutdown();
748 static SYSCTL_PROC(_kern
, OID_AUTO
, willshutdown
,
749 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
750 0, 0, sysctl_willshutdown
, "I", "");
755 sysctl_progressmeterenable
756 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
759 int new_value
, changed
;
761 error
= sysctl_io_number(req
, vc_progress_meter_enable
, sizeof(int), &new_value
, &changed
);
764 vc_enable_progressmeter(new_value
);
771 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
774 int new_value
, changed
;
776 error
= sysctl_io_number(req
, vc_progress_meter_value
, sizeof(int), &new_value
, &changed
);
779 vc_set_progressmeter(new_value
);
784 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeterenable
,
785 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
786 0, 0, sysctl_progressmeterenable
, "I", "");
788 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeter
,
789 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
790 0, 0, sysctl_progressmeter
, "I", "");
794 static SYSCTL_INT(_debug
, OID_AUTO
, darkwake
, CTLFLAG_RW
, &gDarkWakeFlags
, 0, "");
796 static const OSSymbol
* gIOPMSettingAutoWakeSecondsKey
;
797 static const OSSymbol
* gIOPMSettingDebugWakeRelativeKey
;
798 static const OSSymbol
* gIOPMSettingMaintenanceWakeCalendarKey
;
800 //******************************************************************************
803 //******************************************************************************
805 #define kRootDomainSettingsCount 16
807 bool IOPMrootDomain::start( IOService
* nub
)
809 OSIterator
*psIterator
;
810 OSDictionary
*tmpDict
;
811 IORootParent
* patriarch
;
816 gIOPMSettingAutoWakeSecondsKey
= OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey
);
817 gIOPMSettingDebugWakeRelativeKey
= OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey
);
818 gIOPMSettingMaintenanceWakeCalendarKey
=
819 OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey
);
821 gIOPMStatsApplicationResponseTimedOut
= OSSymbol::withCString(kIOPMStatsResponseTimedOut
);
822 gIOPMStatsApplicationResponseCancel
= OSSymbol::withCString(kIOPMStatsResponseCancel
);
823 gIOPMStatsApplicationResponseSlow
= OSSymbol::withCString(kIOPMStatsResponseSlow
);
825 sleepSupportedPEFunction
= OSSymbol::withCString("IOPMSetSleepSupported");
826 sleepMessagePEFunction
= OSSymbol::withCString("IOPMSystemSleepMessage");
828 const OSSymbol
*settingsArr
[kRootDomainSettingsCount
] =
830 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey
),
831 gIOPMSettingAutoWakeSecondsKey
,
832 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey
),
833 OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey
),
834 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey
),
835 gIOPMSettingDebugWakeRelativeKey
,
836 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey
),
837 OSSymbol::withCString(kIOPMSettingWakeOnRingKey
),
838 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
),
839 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey
),
840 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey
),
841 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey
),
842 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey
),
843 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey
),
844 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey
),
845 OSSymbol::withCString(kIOPMStateConsoleShutdown
)
848 PE_parse_boot_argn("darkwake", &gDarkWakeFlags
, sizeof(gDarkWakeFlags
));
850 IORegistryEntry
* chosenEntry
= IORegistryEntry::fromPath("/chosen", gIODTPlane
);
853 if (chosenEntry
->getProperty("boot-ramdmg-size") &&
854 chosenEntry
->getProperty("boot-ramdmg-extents"))
856 gRAMDiskImageBoot
= true;
858 chosenEntry
->release();
861 queue_init(&aggressivesQueue
);
862 aggressivesThreadCall
= thread_call_allocate(handleAggressivesFunction
, this);
863 aggressivesData
= OSData::withCapacity(
864 sizeof(AggressivesRecord
) * (kPMLastAggressivenessType
+ 4));
866 featuresDictLock
= IOLockAlloc();
867 settingsCtrlLock
= IOLockAlloc();
868 setPMRootDomain(this);
870 extraSleepTimer
= thread_call_allocate(
871 idleSleepTimerExpired
,
872 (thread_call_param_t
) this);
874 diskSyncCalloutEntry
= thread_call_allocate(
876 (thread_call_param_t
) this);
878 setProperty(kIOSleepSupportedKey
, true);
880 bzero(&pmStats
, sizeof(pmStats
));
882 pmTracer
= PMTraceWorker::tracer(this);
884 pmAssertions
= PMAssertionsTracker::pmAssertionsTracker(this);
886 userDisabledAllSleep
= false;
887 systemBooting
= true;
889 idleSleepTimerPending
= false;
891 clamshellClosed
= false;
892 clamshellExists
= false;
893 clamshellDisabled
= true;
894 acAdaptorConnected
= true;
896 // Set the default system capabilities at boot.
897 _currentCapability
= kIOPMSystemCapabilityCPU
|
898 kIOPMSystemCapabilityGraphics
|
899 kIOPMSystemCapabilityAudio
|
900 kIOPMSystemCapabilityNetwork
;
902 _pendingCapability
= _currentCapability
;
903 _desiredCapability
= _currentCapability
;
904 _highestCapability
= _currentCapability
;
905 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
907 queuedSleepWakeUUIDString
= NULL
;
908 pmStatsAppResponses
= OSArray::withCapacity(5);
909 _statsNameKey
= OSSymbol::withCString(kIOPMStatsNameKey
);
910 _statsPIDKey
= OSSymbol::withCString(kIOPMStatsPIDKey
);
911 _statsTimeMSKey
= OSSymbol::withCString(kIOPMStatsTimeMSKey
);
912 _statsResponseTypeKey
= OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey
);
913 _statsMessageTypeKey
= OSSymbol::withCString(kIOPMStatsMessageTypeKey
);
915 idxPMCPUClamshell
= kCPUUnknownIndex
;
916 idxPMCPULimitedPower
= kCPUUnknownIndex
;
918 tmpDict
= OSDictionary::withCapacity(1);
919 setProperty(kRootDomainSupportedFeatures
, tmpDict
);
922 settingsCallbacks
= OSDictionary::withCapacity(1);
924 // Create a list of the valid PM settings that we'll relay to
925 // interested clients in setProperties() => setPMSetting()
926 allowedPMSettings
= OSArray::withObjects(
927 (const OSObject
**)settingsArr
,
928 kRootDomainSettingsCount
,
931 fPMSettingsDict
= OSDictionary::withCapacity(5);
933 PMinit(); // creates gIOPMWorkLoop
935 // Create IOPMPowerStateQueue used to queue external power
936 // events, and to handle those events on the PM work loop.
937 pmPowerStateQueue
= IOPMPowerStateQueue::PMPowerStateQueue(
938 this, OSMemberFunctionCast(IOEventSource::Action
, this,
939 &IOPMrootDomain::dispatchPowerEvent
));
940 getPMworkloop()->addEventSource(pmPowerStateQueue
);
941 #ifdef CHECK_THREAD_CONTEXT
942 gIOPMWorkLoop
= getPMworkloop();
945 // create our power parent
946 patriarch
= new IORootParent
;
948 patriarch
->attach(this);
949 patriarch
->start(this);
950 patriarch
->addPowerChild(this);
952 registerPowerDriver(this, ourPowerStates
, NUM_POWER_STATES
);
953 changePowerStateToPriv(ON_STATE
);
955 if (gIOKitDebug
& (kIOLogDriverPower1
| kIOLogDriverPower2
))
957 // Setup our PM logging & recording code
958 timeline
= IOPMTimeline::timeline(this);
960 OSDictionary
*tlInfo
= timeline
->copyInfoDictionary();
964 setProperty(kIOPMTimelineDictionaryKey
, tlInfo
);
970 // install power change handler
971 gSysPowerDownNotifier
= registerPrioritySleepWakeInterest( &sysPowerDownHandler
, this, 0);
974 // Register for a notification when IODisplayWrangler is published
975 if ((tmpDict
= serviceMatching("IODisplayWrangler")))
977 _displayWranglerNotifier
= addMatchingNotification(
978 gIOPublishNotification
, tmpDict
,
979 (IOServiceMatchingNotificationHandler
) &displayWranglerMatchPublished
,
985 const OSSymbol
*ucClassName
= OSSymbol::withCStringNoCopy("RootDomainUserClient");
986 setProperty(gIOUserClientClassKey
, (OSObject
*) ucClassName
);
987 ucClassName
->release();
989 // IOBacklightDisplay can take a long time to load at boot, or it may
990 // not load at all if you're booting with clamshell closed. We publish
991 // 'DisplayDims' here redundantly to get it published early and at all.
992 psIterator
= getMatchingServices( serviceMatching("IOPMPowerSource") );
993 if( psIterator
&& psIterator
->getNextObject() )
995 // There's at least one battery on the system, so we publish
996 // 'DisplayDims' support for the LCD.
997 publishFeature("DisplayDims");
1000 psIterator
->release();
1003 sysctl_register_oid(&sysctl__kern_sleeptime
);
1004 sysctl_register_oid(&sysctl__kern_waketime
);
1005 sysctl_register_oid(&sysctl__kern_willshutdown
);
1006 #if !CONFIG_EMBEDDED
1007 sysctl_register_oid(&sysctl__kern_progressmeterenable
);
1008 sysctl_register_oid(&sysctl__kern_progressmeter
);
1009 #endif /* !CONFIG_EMBEDDED */
1012 IOHibernateSystemInit(this);
1015 registerService(); // let clients find us
1020 //******************************************************************************
1023 // Receive a setProperty call
1024 // The "System Boot" property means the system is completely booted.
1025 //******************************************************************************
1027 IOReturn
IOPMrootDomain::setProperties( OSObject
* props_obj
)
1029 IOReturn return_value
= kIOReturnSuccess
;
1030 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, props_obj
);
1038 const OSSymbol
*publish_simulated_battery_string
= OSSymbol::withCString("SoftwareSimulatedBatteries");
1039 const OSSymbol
*boot_complete_string
= OSSymbol::withCString("System Boot Complete");
1040 const OSSymbol
*sys_shutdown_string
= OSSymbol::withCString("System Shutdown");
1041 const OSSymbol
*stall_halt_string
= OSSymbol::withCString("StallSystemAtHalt");
1042 const OSSymbol
*battery_warning_disabled_string
= OSSymbol::withCString("BatteryWarningsDisabled");
1043 const OSSymbol
*idle_seconds_string
= OSSymbol::withCString("System Idle Seconds");
1044 const OSSymbol
*sleepdisabled_string
= OSSymbol::withCString("SleepDisabled");
1045 const OSSymbol
*ondeck_sleepwake_uuid_string
= OSSymbol::withCString(kIOPMSleepWakeUUIDKey
);
1046 const OSSymbol
*loginwindow_tracepoint_string
= OSSymbol::withCString(kIOPMLoginWindowSecurityDebugKey
);
1047 const OSSymbol
*pmTimelineLogging_string
= OSSymbol::withCString(kIOPMTimelineDictionaryKey
);
1049 const OSSymbol
*hibernatemode_string
= OSSymbol::withCString(kIOHibernateModeKey
);
1050 const OSSymbol
*hibernatefile_string
= OSSymbol::withCString(kIOHibernateFileKey
);
1051 const OSSymbol
*hibernatefreeratio_string
= OSSymbol::withCString(kIOHibernateFreeRatioKey
);
1052 const OSSymbol
*hibernatefreetime_string
= OSSymbol::withCString(kIOHibernateFreeTimeKey
);
1057 return_value
= kIOReturnBadArgument
;
1061 if ((b
= OSDynamicCast(OSBoolean
, dict
->getObject(publish_simulated_battery_string
))))
1063 publishResource(publish_simulated_battery_string
, kOSBooleanTrue
);
1066 if ((n
= OSDynamicCast(OSNumber
, dict
->getObject(idle_seconds_string
))))
1068 setProperty(idle_seconds_string
, n
);
1069 idleSeconds
= n
->unsigned32BitValue();
1072 if (boot_complete_string
&& dict
->getObject(boot_complete_string
))
1074 pmPowerStateQueue
->submitPowerEvent( kPowerEventSystemBootCompleted
);
1077 if( battery_warning_disabled_string
&& dict
->getObject(battery_warning_disabled_string
))
1079 setProperty( battery_warning_disabled_string
, dict
->getObject(battery_warning_disabled_string
));
1082 if (pmTimelineLogging_string
&& (d
= OSDynamicCast(OSDictionary
, dict
->getObject(pmTimelineLogging_string
))))
1084 if (timeline
&& timeline
->setProperties(d
))
1086 OSDictionary
*tlInfo
= timeline
->copyInfoDictionary();
1088 setProperty(kIOPMTimelineDictionaryKey
, tlInfo
);
1094 if( sys_shutdown_string
&& (b
= OSDynamicCast(OSBoolean
, dict
->getObject(sys_shutdown_string
))))
1096 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemShutdown
, (void *) b
);
1099 if( stall_halt_string
&& (b
= OSDynamicCast(OSBoolean
, dict
->getObject(stall_halt_string
))) )
1101 setProperty(stall_halt_string
, b
);
1105 if ( hibernatemode_string
1106 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(hibernatemode_string
))))
1108 setProperty(hibernatemode_string
, n
);
1110 if ( hibernatefreeratio_string
1111 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(hibernatefreeratio_string
))))
1113 setProperty(hibernatefreeratio_string
, n
);
1115 if ( hibernatefreetime_string
1116 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(hibernatefreetime_string
))))
1118 setProperty(hibernatefreetime_string
, n
);
1121 if ( hibernatefile_string
1122 && (str
= OSDynamicCast(OSString
, dict
->getObject(hibernatefile_string
))))
1124 setProperty(hibernatefile_string
, str
);
1128 if( sleepdisabled_string
1129 && (b
= OSDynamicCast(OSBoolean
, dict
->getObject(sleepdisabled_string
))) )
1131 setProperty(sleepdisabled_string
, b
);
1132 pmPowerStateQueue
->submitPowerEvent(kPowerEventUserDisabledSleep
, (void *) b
);
1134 if (ondeck_sleepwake_uuid_string
1135 && (obj
= dict
->getObject(ondeck_sleepwake_uuid_string
)))
1137 if(pmPowerStateQueue
) {
1139 pmPowerStateQueue
->submitPowerEvent(kPowerEventQueueSleepWakeUUID
, (void *)obj
);
1144 if (loginwindow_tracepoint_string
1145 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(loginwindow_tracepoint_string
)))
1148 pmTracer
->traceLoginWindowPhase( n
->unsigned8BitValue() );
1151 if ((b
= OSDynamicCast(OSBoolean
, dict
->getObject(kIOPMDeepSleepEnabledKey
))))
1153 setProperty(kIOPMDeepSleepEnabledKey
, b
);
1155 if ((n
= OSDynamicCast(OSNumber
, dict
->getObject(kIOPMDeepSleepDelayKey
))))
1157 setProperty(kIOPMDeepSleepDelayKey
, n
);
1159 if ((b
= OSDynamicCast(OSBoolean
, dict
->getObject(kIOPMDestroyFVKeyOnStandbyKey
))))
1161 setProperty(kIOPMDestroyFVKeyOnStandbyKey
, b
);
1164 // Relay our allowed PM settings onto our registered PM clients
1165 for(i
= 0; i
< allowedPMSettings
->getCount(); i
++) {
1167 type
= (OSSymbol
*)allowedPMSettings
->getObject(i
);
1170 obj
= dict
->getObject(type
);
1173 if ((gIOPMSettingAutoWakeSecondsKey
== type
) && ((n
= OSDynamicCast(OSNumber
, obj
))))
1175 UInt32 rsecs
= n
->unsigned32BitValue();
1177 autoWakeStart
= autoWakeEnd
= 0;
1180 AbsoluteTime deadline
;
1181 clock_interval_to_deadline(rsecs
+ kAutoWakePostWindow
, kSecondScale
, &deadline
);
1182 autoWakeEnd
= AbsoluteTime_to_scalar(&deadline
);
1183 if (rsecs
> kAutoWakePreWindow
)
1184 rsecs
-= kAutoWakePreWindow
;
1187 clock_interval_to_deadline(rsecs
, kSecondScale
, &deadline
);
1188 autoWakeStart
= AbsoluteTime_to_scalar(&deadline
);
1191 if (gIOPMSettingDebugWakeRelativeKey
== type
)
1193 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1194 _debugWakeSeconds
= n
->unsigned32BitValue();
1196 _debugWakeSeconds
= 0;
1199 return_value
= setPMSetting(type
, obj
);
1201 if(kIOReturnSuccess
!= return_value
) goto exit
;
1205 if(publish_simulated_battery_string
) publish_simulated_battery_string
->release();
1206 if(boot_complete_string
) boot_complete_string
->release();
1207 if(sys_shutdown_string
) sys_shutdown_string
->release();
1208 if(stall_halt_string
) stall_halt_string
->release();
1209 if(battery_warning_disabled_string
) battery_warning_disabled_string
->release();
1210 if(idle_seconds_string
) idle_seconds_string
->release();
1211 if(sleepdisabled_string
) sleepdisabled_string
->release();
1212 if(ondeck_sleepwake_uuid_string
) ondeck_sleepwake_uuid_string
->release();
1213 if(loginwindow_tracepoint_string
) loginwindow_tracepoint_string
->release();
1214 if(pmTimelineLogging_string
) pmTimelineLogging_string
->release();
1216 if(hibernatemode_string
) hibernatemode_string
->release();
1217 if(hibernatefile_string
) hibernatefile_string
->release();
1218 if(hibernatefreeratio_string
) hibernatefreeratio_string
->release();
1219 if(hibernatefreetime_string
) hibernatefreetime_string
->release();
1221 return return_value
;
1225 // MARK: Aggressiveness
1227 //******************************************************************************
1228 // setAggressiveness
1230 // Override IOService::setAggressiveness()
1231 //******************************************************************************
1233 IOReturn
IOPMrootDomain::setAggressiveness(
1235 unsigned long value
)
1237 return setAggressiveness( type
, value
, 0 );
1241 * Private setAggressiveness() with an internal options argument.
1243 IOReturn
IOPMrootDomain::setAggressiveness(
1245 unsigned long value
,
1246 IOOptionBits options
)
1248 AggressivesRequest
* entry
;
1249 AggressivesRequest
* request
;
1252 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1253 (uint32_t) options
, (uint32_t) type
, (uint32_t) value
);
1255 request
= IONew(AggressivesRequest
, 1);
1257 return kIOReturnNoMemory
;
1259 memset(request
, 0, sizeof(*request
));
1260 request
->options
= options
;
1261 request
->dataType
= kAggressivesRequestTypeRecord
;
1262 request
->data
.record
.type
= (uint32_t) type
;
1263 request
->data
.record
.value
= (uint32_t) value
;
1267 // Update disk quick spindown flag used by getAggressiveness().
1268 // Never merge requests with quick spindown flags set.
1270 if (options
& kAggressivesOptionQuickSpindownEnable
)
1271 gAggressivesState
|= kAggressivesStateQuickSpindown
;
1272 else if (options
& kAggressivesOptionQuickSpindownDisable
)
1273 gAggressivesState
&= ~kAggressivesStateQuickSpindown
;
1276 // Coalesce requests with identical aggressives types.
1277 // Deal with callers that calls us too "aggressively".
1279 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1281 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1282 (entry
->data
.record
.type
== type
) &&
1283 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1285 entry
->data
.record
.value
= value
;
1294 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1297 AGGRESSIVES_UNLOCK();
1300 IODelete(request
, AggressivesRequest
, 1);
1302 if (options
& kAggressivesOptionSynchronous
)
1303 handleAggressivesRequests(); // not truly synchronous
1305 thread_call_enter(aggressivesThreadCall
);
1307 return kIOReturnSuccess
;
1310 //******************************************************************************
1311 // getAggressiveness
1313 // Override IOService::setAggressiveness()
1314 // Fetch the aggressiveness factor with the given type.
1315 //******************************************************************************
1317 IOReturn
IOPMrootDomain::getAggressiveness (
1319 unsigned long * outLevel
)
1325 return kIOReturnBadArgument
;
1329 // Disk quick spindown in effect, report value = 1
1331 if ((gAggressivesState
& kAggressivesStateQuickSpindown
) &&
1332 (type
== kPMMinutesToSpinDown
))
1334 value
= kAggressivesMinValue
;
1338 // Consult the pending request queue.
1342 AggressivesRequest
* entry
;
1344 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1346 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1347 (entry
->data
.record
.type
== type
) &&
1348 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1350 value
= entry
->data
.record
.value
;
1357 // Consult the backend records.
1359 if (!source
&& aggressivesData
)
1361 AggressivesRecord
* record
;
1364 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1365 record
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1367 for (i
= 0; i
< count
; i
++, record
++)
1369 if (record
->type
== type
)
1371 value
= record
->value
;
1378 AGGRESSIVES_UNLOCK();
1382 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1383 source
, (uint32_t) type
, value
);
1384 *outLevel
= (unsigned long) value
;
1385 return kIOReturnSuccess
;
1389 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type
);
1390 *outLevel
= 0; // default return = 0, driver may not check for error
1391 return kIOReturnInvalid
;
1395 //******************************************************************************
1396 // joinAggressiveness
1398 // Request from IOService to join future aggressiveness broadcasts.
1399 //******************************************************************************
1401 IOReturn
IOPMrootDomain::joinAggressiveness(
1402 IOService
* service
)
1404 AggressivesRequest
* request
;
1406 if (!service
|| (service
== this))
1407 return kIOReturnBadArgument
;
1409 DLOG("joinAggressiveness %s %p\n", service
->getName(), service
);
1411 request
= IONew(AggressivesRequest
, 1);
1413 return kIOReturnNoMemory
;
1415 service
->retain(); // released by synchronizeAggressives()
1417 memset(request
, 0, sizeof(*request
));
1418 request
->dataType
= kAggressivesRequestTypeService
;
1419 request
->data
.service
= service
;
1422 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1423 AGGRESSIVES_UNLOCK();
1425 thread_call_enter(aggressivesThreadCall
);
1427 return kIOReturnSuccess
;
1430 //******************************************************************************
1431 // handleAggressivesRequests
1433 // Backend thread processes all incoming aggressiveness requests in the queue.
1434 //******************************************************************************
1437 handleAggressivesFunction(
1438 thread_call_param_t param1
,
1439 thread_call_param_t param2
)
1443 ((IOPMrootDomain
*) param1
)->handleAggressivesRequests();
1447 void IOPMrootDomain::handleAggressivesRequests( void )
1449 AggressivesRecord
* start
;
1450 AggressivesRecord
* record
;
1451 AggressivesRequest
* request
;
1452 queue_head_t joinedQueue
;
1456 bool pingSelf
= false;
1460 if ((gAggressivesState
& kAggressivesStateBusy
) || !aggressivesData
||
1461 queue_empty(&aggressivesQueue
))
1464 gAggressivesState
|= kAggressivesStateBusy
;
1465 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1466 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1471 queue_init(&joinedQueue
);
1475 // Remove request from the incoming queue in FIFO order.
1476 queue_remove_first(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1477 switch (request
->dataType
)
1479 case kAggressivesRequestTypeRecord
:
1480 // Update existing record if found.
1482 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1484 if (record
->type
== request
->data
.record
.type
)
1488 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1490 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1493 record
->flags
|= (kAggressivesRecordFlagMinValue
|
1494 kAggressivesRecordFlagModified
);
1495 DLOG("disk spindown accelerated, was %u min\n",
1499 else if (request
->options
& kAggressivesOptionQuickSpindownDisable
)
1501 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1504 record
->flags
|= kAggressivesRecordFlagModified
;
1505 record
->flags
&= ~kAggressivesRecordFlagMinValue
;
1506 DLOG("disk spindown restored to %u min\n",
1510 else if (record
->value
!= request
->data
.record
.value
)
1512 record
->value
= request
->data
.record
.value
;
1513 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1516 record
->flags
|= kAggressivesRecordFlagModified
;
1523 // No matching record, append a new record.
1525 ((request
->options
& kAggressivesOptionQuickSpindownDisable
) == 0))
1527 AggressivesRecord newRecord
;
1529 newRecord
.flags
= kAggressivesRecordFlagModified
;
1530 newRecord
.type
= request
->data
.record
.type
;
1531 newRecord
.value
= request
->data
.record
.value
;
1532 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1534 newRecord
.flags
|= kAggressivesRecordFlagMinValue
;
1535 DLOG("disk spindown accelerated\n");
1538 aggressivesData
->appendBytes(&newRecord
, sizeof(newRecord
));
1540 // OSData may have switched to another (larger) buffer.
1541 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1542 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1546 // Finished processing the request, release it.
1547 IODelete(request
, AggressivesRequest
, 1);
1550 case kAggressivesRequestTypeService
:
1551 // synchronizeAggressives() will free request.
1552 queue_enter(&joinedQueue
, request
, AggressivesRequest
*, chain
);
1556 panic("bad aggressives request type %x\n", request
->dataType
);
1559 } while (!queue_empty(&aggressivesQueue
));
1561 // Release the lock to perform work, with busy flag set.
1562 if (!queue_empty(&joinedQueue
) || broadcast
)
1564 AGGRESSIVES_UNLOCK();
1565 if (!queue_empty(&joinedQueue
))
1566 synchronizeAggressives(&joinedQueue
, start
, count
);
1568 broadcastAggressives(start
, count
);
1572 // Remove the modified flag from all records.
1573 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1575 if ((record
->flags
& kAggressivesRecordFlagModified
) &&
1576 ((record
->type
== kPMMinutesToDim
) ||
1577 (record
->type
== kPMMinutesToSleep
)))
1580 record
->flags
&= ~kAggressivesRecordFlagModified
;
1583 // Check the incoming queue again since new entries may have been
1584 // added while lock was released above.
1586 } while (!queue_empty(&aggressivesQueue
));
1588 gAggressivesState
&= ~kAggressivesStateBusy
;
1591 AGGRESSIVES_UNLOCK();
1593 // Root domain is interested in system and display sleep slider changes.
1594 // Submit a power event to handle those changes on the PM work loop.
1596 if (pingSelf
&& pmPowerStateQueue
) {
1597 pmPowerStateQueue
->submitPowerEvent(
1598 kPowerEventPolicyStimulus
,
1599 (void *) kStimulusAggressivenessChanged
);
1603 //******************************************************************************
1604 // synchronizeAggressives
1606 // Push all known aggressiveness records to one or more IOService.
1607 //******************************************************************************
1609 void IOPMrootDomain::synchronizeAggressives(
1610 queue_head_t
* joinedQueue
,
1611 const AggressivesRecord
* array
,
1614 IOService
* service
;
1615 AggressivesRequest
* request
;
1616 const AggressivesRecord
* record
;
1617 IOPMDriverCallEntry callEntry
;
1621 while (!queue_empty(joinedQueue
))
1623 queue_remove_first(joinedQueue
, request
, AggressivesRequest
*, chain
);
1624 if (request
->dataType
== kAggressivesRequestTypeService
)
1625 service
= request
->data
.service
;
1629 IODelete(request
, AggressivesRequest
, 1);
1634 if (service
->assertPMDriverCall(&callEntry
))
1636 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1638 value
= record
->value
;
1639 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1640 value
= kAggressivesMinValue
;
1642 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
1643 record
->type
, value
, service
->getName());
1644 service
->setAggressiveness(record
->type
, value
);
1646 service
->deassertPMDriverCall(&callEntry
);
1648 service
->release(); // retained by joinAggressiveness()
1653 //******************************************************************************
1654 // broadcastAggressives
1656 // Traverse PM tree and call setAggressiveness() for records that have changed.
1657 //******************************************************************************
1659 void IOPMrootDomain::broadcastAggressives(
1660 const AggressivesRecord
* array
,
1663 IORegistryIterator
* iter
;
1664 IORegistryEntry
* entry
;
1665 IOPowerConnection
* connect
;
1666 IOService
* service
;
1667 const AggressivesRecord
* record
;
1668 IOPMDriverCallEntry callEntry
;
1672 iter
= IORegistryIterator::iterateOver(
1673 this, gIOPowerPlane
, kIORegistryIterateRecursively
);
1679 while ((entry
= iter
->getNextObject()))
1681 connect
= OSDynamicCast(IOPowerConnection
, entry
);
1682 if (!connect
|| !connect
->getReadyFlag())
1685 if ((service
= (IOService
*) connect
->copyChildEntry(gIOPowerPlane
)))
1687 if (service
->assertPMDriverCall(&callEntry
))
1689 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1691 if (record
->flags
& kAggressivesRecordFlagModified
)
1693 value
= record
->value
;
1694 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1695 value
= kAggressivesMinValue
;
1696 _LOG("broadcastAggressives %x = %u to %s\n",
1697 record
->type
, value
, service
->getName());
1698 service
->setAggressiveness(record
->type
, value
);
1701 service
->deassertPMDriverCall(&callEntry
);
1707 while (!entry
&& !iter
->isValid());
1713 // MARK: System Sleep
1715 //******************************************************************************
1716 // startIdleSleepTimer
1718 //******************************************************************************
1720 void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds
)
1722 AbsoluteTime deadline
;
1727 clock_interval_to_deadline(inSeconds
, kSecondScale
, &deadline
);
1728 thread_call_enter_delayed(extraSleepTimer
, deadline
);
1729 idleSleepTimerPending
= true;
1730 DLOG("idle timer set for %u seconds\n", inSeconds
);
1734 //******************************************************************************
1735 // cancelIdleSleepTimer
1737 //******************************************************************************
1739 void IOPMrootDomain::cancelIdleSleepTimer( void )
1742 if (idleSleepTimerPending
)
1744 DLOG("idle timer cancelled\n");
1745 thread_call_cancel(extraSleepTimer
);
1746 idleSleepTimerPending
= false;
1750 //******************************************************************************
1751 // idleSleepTimerExpired
1753 //******************************************************************************
1755 static void idleSleepTimerExpired(
1756 thread_call_param_t us
, thread_call_param_t
)
1758 ((IOPMrootDomain
*)us
)->handleSleepTimerExpiration();
1761 //******************************************************************************
1762 // handleSleepTimerExpiration
1764 // The time between the sleep idle timeout and the next longest one has elapsed.
1765 // It's time to sleep. Start that by removing the clamp that's holding us awake.
1766 //******************************************************************************
1768 void IOPMrootDomain::handleSleepTimerExpiration( void )
1770 if (!getPMworkloop()->inGate())
1772 getPMworkloop()->runAction(
1773 OSMemberFunctionCast(IOWorkLoop::Action
, this,
1774 &IOPMrootDomain::handleSleepTimerExpiration
),
1781 DLOG("sleep timer expired\n");
1784 idleSleepTimerPending
= false;
1786 clock_get_uptime(&time
);
1787 if ((AbsoluteTime_to_scalar(&time
) > autoWakeStart
) &&
1788 (AbsoluteTime_to_scalar(&time
) < autoWakeEnd
))
1790 thread_call_enter_delayed(extraSleepTimer
, *((AbsoluteTime
*) &autoWakeEnd
));
1794 setQuickSpinDownTimeout();
1795 adjustPowerState(true);
1798 //******************************************************************************
1799 // setQuickSpinDownTimeout
1801 //******************************************************************************
1803 void IOPMrootDomain::setQuickSpinDownTimeout( void )
1807 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownEnable
);
1810 //******************************************************************************
1811 // restoreUserSpinDownTimeout
1813 //******************************************************************************
1815 void IOPMrootDomain::restoreUserSpinDownTimeout( void )
1819 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownDisable
);
1822 //******************************************************************************
1825 //******************************************************************************
1828 IOReturn
IOPMrootDomain::sleepSystem( void )
1830 return sleepSystemOptions(NULL
);
1834 IOReturn
IOPMrootDomain::sleepSystemOptions( OSDictionary
*options
)
1836 /* sleepSystem is a public function, and may be called by any kernel driver.
1837 * And that's bad - drivers should sleep the system by calling
1838 * receivePowerNotification() instead. Drivers should not use sleepSystem.
1840 * Note that user space app calls to IOPMSleepSystem() will also travel
1841 * this code path and thus be correctly identified as software sleeps.
1844 if (options
&& options
->getObject("OSSwitch"))
1846 // Log specific sleep cause for OS Switch hibernation
1847 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate
);
1849 return privateSleepSystem( kIOPMSleepReasonSoftware
);
1854 IOReturn
IOPMrootDomain::privateSleepSystem( uint32_t sleepReason
)
1856 static const char * IOPMSleepReasons
[] = {
1858 kIOPMClamshellSleepKey
,
1859 kIOPMPowerButtonSleepKey
,
1860 kIOPMSoftwareSleepKey
,
1861 kIOPMOSSwitchHibernationKey
,
1863 kIOPMLowPowerSleepKey
,
1864 kIOPMClamshellSleepKey
,
1865 kIOPMThermalEmergencySleepKey
,
1866 kIOPMMaintenanceSleepKey
1869 PMEventDetails
*details
;
1871 if (!checkSystemCanSleep())
1873 // Record why the system couldn't sleep
1874 details
= PMEventDetails::eventDetails(kIOPMEventTypeSleep
, NULL
,
1875 sleepReason
, kIOReturnNotPermitted
);
1877 recordAndReleasePMEvent( details
);
1878 return kIOReturnNotPermitted
;
1882 timeline
->setSleepCycleInProgressFlag(true);
1884 // Time to publish a UUID for the Sleep --> Wake cycle
1885 if(pmPowerStateQueue
) {
1886 pmPowerStateQueue
->submitPowerEvent(kPowerEventPublishSleepWakeUUID
, (void *)true);
1890 // Log the beginning of system sleep.
1891 details
= PMEventDetails::eventDetails(kIOPMEventTypeSleep
, NULL
,
1892 sleepReason
, kIOReturnSuccess
);
1894 recordAndReleasePMEvent( details
);
1896 // Record sleep cause in IORegistry
1897 lastSleepReason
= sleepReason
;
1898 sleepReason
-= (kIOPMSleepReasonClamshell
- 1);
1899 if (sleepReason
&& (sleepReason
< sizeof(IOPMSleepReasons
)/sizeof(IOPMSleepReasons
[0]))) {
1900 setProperty(kRootDomainSleepReasonKey
, IOPMSleepReasons
[sleepReason
]);
1903 if (pmPowerStateQueue
)
1904 pmPowerStateQueue
->submitPowerEvent(
1905 kPowerEventPolicyStimulus
,
1906 (void *) kStimulusDemandSystemSleep
);
1908 return kIOReturnSuccess
;
1911 IOReturn
IOPMrootDomain::recordPMEventGated(PMEventDetails
*record
)
1913 // If we don't have a place to log to, we can't actually
1914 // log anything. Chances are, the person who is asking us to do
1915 // the PM logging has forgotten to set the right bootflags
1917 return kIOReturnSuccess
;
1919 if(gIOPMWorkLoop
->inGate() == false) {
1921 IOReturn ret
= gIOPMWorkLoop
->runAction(
1922 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::recordPMEventGated
),
1929 // Now that we're guaranteed to be running in gate ...
1931 // Check the validity of the argument we are given
1933 return kIOReturnBadArgument
;
1935 // Record a driver event, or a system event
1936 if(record
->eventClassifier
== kIOPMEventClassDriverEvent
1937 || record
->eventClassifier
== kIOPMEventClassSystemEvent
)
1938 return this->recordPMEvent(record
);
1941 return kIOReturnBadArgument
;
1945 IOReturn
IOPMrootDomain::recordAndReleasePMEventGated(PMEventDetails
*record
)
1947 IOReturn ret
= kIOReturnBadArgument
;
1951 ret
= recordPMEventGated(record
);
1958 //******************************************************************************
1961 // This overrides powerChangeDone in IOService.
1962 //******************************************************************************
1964 void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState
)
1966 PMEventDetails
*details
;
1969 DLOG("PowerChangeDone: %u->%u\n",
1970 (uint32_t) previousPowerState
, (uint32_t) getPowerState());
1972 switch ( getPowerState() )
1975 if (previousPowerState
!= ON_STATE
)
1978 details
= PMEventDetails::eventDetails(
1979 kIOPMEventTypeSleepDone
,
1984 recordAndReleasePMEvent( details
);
1986 // re-enable this timer for next sleep
1987 cancelIdleSleepTimer();
1990 clock_usec_t microsecs
;
1991 clock_get_calendar_microtime(&secs
, µsecs
);
1993 gIOLastSleepTime
.tv_sec
= secs
;
1994 gIOLastSleepTime
.tv_usec
= microsecs
;
1995 gIOLastWakeTime
.tv_sec
= 0;
1996 gIOLastWakeTime
.tv_usec
= 0;
1999 LOG("System %sSleep\n", gIOHibernateState
? "Safe" : "");
2001 IOHibernateSystemHasSlept();
2003 evaluateSystemSleepPolicyFinal();
2005 LOG("System Sleep\n");
2008 getPlatform()->sleepKernel();
2010 // The CPU(s) are off at this point,
2011 // Code will resume execution here upon wake.
2013 clock_get_uptime(&systemWakeTime
);
2016 IOHibernateSystemWake();
2019 // sleep transition complete
2020 gSleepOrShutdownPending
= 0;
2022 // trip the reset of the calendar clock
2023 clock_wakeup_calendar();
2026 LOG("System %sWake\n", gIOHibernateState
? "SafeSleep " : "");
2030 getPlatform()->PMLog(kIOPMrootDomainClass
, kPMLogSystemWake
, 0, 0);
2031 lowBatteryCondition
= false;
2032 lastSleepReason
= 0;
2034 // And start logging the wake event here
2035 // TODO: Publish the wakeReason string as an integer
2036 details
= PMEventDetails::eventDetails(
2042 recordAndReleasePMEvent( details
);
2049 #if defined(__i386__) || defined(__x86_64__)
2050 wranglerTickled
= false;
2051 graphicsSuppressed
= false;
2052 darkWakePostTickle
= false;
2053 logGraphicsClamp
= true;
2054 logWranglerTickle
= true;
2055 sleepTimerMaintenance
= false;
2057 OSString
* wakeType
= OSDynamicCast(
2058 OSString
, getProperty(kIOPMRootDomainWakeTypeKey
));
2059 OSString
* wakeReason
= OSDynamicCast(
2060 OSString
, getProperty(kIOPMRootDomainWakeReasonKey
));
2062 if (wakeType
&& wakeType
->isEqualTo(kIOPMrootDomainWakeTypeLowBattery
))
2064 lowBatteryCondition
= true;
2065 darkWakeMaintenance
= true;
2066 darkWakeToSleepASAP
= true;
2068 else if ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0)
2070 OSNumber
* hibOptions
= OSDynamicCast(
2071 OSNumber
, getProperty(kIOHibernateOptionsKey
));
2073 if (hibernateAborted
||
2075 !(hibOptions
->unsigned32BitValue() & kIOHibernateOptionDarkWake
))) ||
2076 ((_debugWakeSeconds
!= 0) &&
2077 ((gDarkWakeFlags
& kDarkWakeFlagAlarmIsDark
) == 0)) ||
2079 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeUser
) ||
2080 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeAlarm
))))
2082 wranglerTickled
= true;
2086 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
))
2088 darkWakeMaintenance
= true;
2089 darkWakeToSleepASAP
= true;
2093 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2095 darkWakeMaintenance
= true;
2096 darkWakeToSleepASAP
= true;
2097 sleepTimerMaintenance
= true;
2101 // Unidentified wake source, resume to full wake if debug
2102 // alarm is pending.
2104 if (_debugWakeSeconds
&& (!wakeReason
|| wakeReason
->isEqualTo("")))
2105 wranglerTickled
= true;
2107 darkWakeToSleepASAP
= true;
2112 // Post a HID tickle immediately - except for maintenance wake.
2114 if (hibernateAborted
|| !wakeType
||
2115 !wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
))
2117 wranglerTickled
= true;
2121 darkWakeMaintenance
= true;
2122 darkWakeToSleepASAP
= true;
2126 if (wranglerTickled
)
2128 else if (!darkWakeMaintenance
)
2130 // Early/late tickle for non-maintenance wake.
2131 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2132 kDarkWakeFlagHIDTickleEarly
) ||
2133 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2134 kDarkWakeFlagHIDTickleLate
))
2136 darkWakePostTickle
= true;
2139 #else /* !__i386__ && !__x86_64__ */
2140 // stay awake for at least 30 seconds
2141 wranglerTickled
= true;
2142 startIdleSleepTimer(30);
2145 changePowerStateToPriv(ON_STATE
);
2149 bool wasPrevented
= childPreventSystemSleep
;
2151 details
= PMEventDetails::eventDetails(
2152 kIOPMEventTypeWakeDone
,
2157 recordAndReleasePMEvent( details
);
2159 if (previousPowerState
!= ON_STATE
)
2160 _debugWakeSeconds
= 0;
2162 // Update childPreventSystemSleep flag using the capability computed
2163 // by IOSevice::rebuildChildClampBits().
2165 childPreventSystemSleep
=
2166 ((currentCapability() & kIOPMChildClamp2
) != 0);
2168 if (wasPrevented
&& !childPreventSystemSleep
)
2170 evaluatePolicy( kStimulusDarkWakeEvaluate
);
2176 //******************************************************************************
2177 // requestPowerDomainState
2179 // Extend implementation in IOService. Running on PM work loop thread.
2181 // Examine children desires and initiate idle-sleep if all children are idle,
2182 // prevent idle and system sleep flags are not set.
2183 //******************************************************************************
2185 IOReturn
IOPMrootDomain::requestPowerDomainState (
2186 IOPMPowerFlags childDesire
,
2187 IOPowerConnection
* childConnection
,
2188 unsigned long specification
)
2192 IOPowerConnection
*connection
;
2193 IOPMPowerFlags mergedChildDesire
= 0;
2194 IOPMPowerFlags editedChildDesire
;
2195 IOPMPowerFlags thisDesire
;
2196 bool sleepASAP
= false;
2200 // Disregard disk I/O (anything besides the display wrangler) as a
2201 // factor in preventing idle sleep - based on a runtime setting.
2203 if ((gDarkWakeFlags
& kDarkWakeFlagIgnoreDiskIOAlways
) &&
2204 (kIOPMPreventIdleSleep
& childDesire
) &&
2205 (childConnection
!= wranglerConnection
))
2207 childDesire
&= ~kIOPMPreventIdleSleep
;
2210 // Force the child's input power requirement to 0 unless the prevent
2211 // idle-sleep flag is set. Nil input power flags maps to our state 0.
2212 // Our power clamp (deviceDesire) clamps the lowest power state at 2.
2214 editedChildDesire
= 0;
2215 if (childDesire
& kIOPMPreventIdleSleep
)
2216 editedChildDesire
|= (kIOPMPowerOn
| kIOPMPreventIdleSleep
);
2217 if (childDesire
& kIOPMPreventSystemSleep
)
2218 editedChildDesire
|= (kIOPMPowerOn
| kIOPMPreventSystemSleep
);
2220 iter
= getChildIterator(gIOPowerPlane
);
2223 while ( (next
= iter
->getNextObject()) )
2225 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
2227 // Ignore child that are in the process of joining.
2228 if (connection
->getReadyFlag() == false)
2231 // OR in the child's input power requirements.
2232 // Is this connection attached to the child that called
2233 // requestPowerDomainState()?
2235 if (connection
== childConnection
)
2237 thisDesire
= editedChildDesire
;
2242 if (connection
->getPreventIdleSleepFlag())
2243 thisDesire
|= (kIOPMPowerOn
| kIOPMPreventIdleSleep
);
2244 if (connection
->getPreventSystemSleepFlag())
2245 thisDesire
|= (kIOPMPowerOn
| kIOPMPreventSystemSleep
);
2248 mergedChildDesire
|= thisDesire
;
2249 if (thisDesire
&& (kIOLogPMRootDomain
& gIOKitDebug
))
2252 (IOService
*) connection
->getChildEntry(gIOPowerPlane
);
2253 LOG("child %p, noIdle %d, noSleep %d - %s\n",
2255 ((thisDesire
& kIOPMPreventIdleSleep
) != 0),
2256 ((thisDesire
& kIOPMPreventSystemSleep
) != 0),
2257 child
? child
->getName() : "?");
2264 DLOG("mergedChildDesire 0x%lx, extraSleepDelay %ld\n",
2265 mergedChildDesire
, extraSleepDelay
);
2267 if ( !mergedChildDesire
&& !systemBooting
)
2271 changePowerStateToPriv(ON_STATE
);
2274 // stay awake for at least idleSeconds
2275 startIdleSleepTimer(idleSeconds
);
2278 else if (!extraSleepDelay
&& !idleSleepTimerPending
&& !systemDarkWake
)
2284 // Drop our power clamp to SLEEP_STATE when all children became idle,
2285 // and system sleep and display sleep slider values are equal.
2287 adjustPowerState(sleepASAP
);
2289 // If our power clamp has already dropped to SLEEP_STATE, and no child
2290 // is keeping us at ON_STATE, then the following will trigger idle sleep.
2292 return super::requestPowerDomainState(
2293 editedChildDesire
, childConnection
, specification
);
2296 //******************************************************************************
2299 // Override the superclass implementation to send a different message type.
2300 //******************************************************************************
2302 bool IOPMrootDomain::tellChangeDown( unsigned long stateNum
)
2304 DLOG("tellChangeDown %u->%u\n",
2305 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2307 if (SLEEP_STATE
== stateNum
)
2309 if (!ignoreTellChangeDown
)
2310 tracePoint( kIOPMTracePointSleepApplications
);
2312 tracePoint( kIOPMTracePointSleepPriorityClients
);
2315 if ((SLEEP_STATE
== stateNum
) && !ignoreTellChangeDown
)
2317 userActivityAtSleep
= userActivityCount
;
2318 hibernateAborted
= false;
2319 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep
);
2321 // Direct callout into OSKext so it can disable kext unloads
2322 // during sleep/wake to prevent deadlocks.
2323 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep
);
2325 IOService::updateConsoleUsers(NULL
, kIOMessageSystemWillSleep
);
2327 // Notify platform that sleep has begun
2328 getPlatform()->callPlatformFunction(
2329 sleepMessagePEFunction
, false,
2330 (void *)(uintptr_t) kIOMessageSystemWillSleep
,
2333 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2334 // But tellClientsWithResponse() must be called for both.
2335 ignoreTellChangeDown
= true;
2338 return super::tellClientsWithResponse( kIOMessageSystemWillSleep
);
2341 //******************************************************************************
2344 // Override the superclass implementation to send a different message type.
2345 // This must be idle sleep since we don't ask during any other power change.
2346 //******************************************************************************
2348 bool IOPMrootDomain::askChangeDown( unsigned long stateNum
)
2350 DLOG("askChangeDown %u->%u\n",
2351 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2353 // Don't log for dark wake entry
2354 if (kSystemTransitionSleep
== _systemTransitionType
)
2355 tracePoint( kIOPMTracePointSleepApplications
);
2357 return super::tellClientsWithResponse( kIOMessageCanSystemSleep
);
2360 //******************************************************************************
2361 // askChangeDownDone
2363 // Called by PM after all apps have responded to kIOMessageCanSystemSleep.
2364 // pmconfigd may create a deny sleep assertion before ack'ing.
2365 //******************************************************************************
2367 void IOPMrootDomain::askChangeDownDone(
2368 IOPMPowerChangeFlags
* inOutChangeFlags
, bool * cancel
)
2370 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2371 *inOutChangeFlags
, *cancel
,
2372 _systemTransitionType
,
2373 _currentCapability
, _pendingCapability
);
2375 if ((false == *cancel
) && (kSystemTransitionSleep
== _systemTransitionType
))
2377 // Dark->Sleep transition.
2378 // Check if there are any deny sleep assertions.
2379 // Full->Dark transition is never cancelled.
2381 if (!checkSystemCanSleep(true))
2383 // Cancel dark wake to sleep transition.
2384 // Must re-scan assertions upon entering dark wake.
2387 DLOG("cancel dark->sleep\n");
2392 //******************************************************************************
2395 // Notify registered applications and kernel clients that we are not dropping
2398 // We override the superclass implementation so we can send a different message
2399 // type to the client or application being notified.
2401 // This must be a vetoed idle sleep, since no other power change can be vetoed.
2402 //******************************************************************************
2404 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum
)
2406 DLOG("tellNoChangeDown %u->%u\n",
2407 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2409 if (idleSeconds
&& !wrangler
)
2411 // stay awake for at least idleSeconds
2412 startIdleSleepTimer(idleSeconds
);
2414 return tellClients( kIOMessageSystemWillNotSleep
);
2417 //******************************************************************************
2420 // Notify registered applications and kernel clients that we are raising power.
2422 // We override the superclass implementation so we can send a different message
2423 // type to the client or application being notified.
2424 //******************************************************************************
2426 void IOPMrootDomain::tellChangeUp( unsigned long stateNum
)
2428 OSData
*publishPMStats
= NULL
;
2430 DLOG("tellChangeUp %u->%u\n",
2431 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2433 ignoreTellChangeDown
= false;
2435 if ( stateNum
== ON_STATE
)
2437 // Direct callout into OSKext so it can disable kext unloads
2438 // during sleep/wake to prevent deadlocks.
2439 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
2441 // Notify platform that sleep was cancelled or resumed.
2442 getPlatform()->callPlatformFunction(
2443 sleepMessagePEFunction
, false,
2444 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn
,
2447 if (getPowerState() == ON_STATE
)
2449 // this is a quick wake from aborted sleep
2450 if (idleSeconds
&& !wrangler
)
2452 // stay awake for at least idleSeconds
2453 startIdleSleepTimer(idleSeconds
);
2455 tellClients( kIOMessageSystemWillPowerOn
);
2458 tracePoint( kIOPMTracePointWakeApplications
);
2459 publishPMStats
= OSData::withBytes(&pmStats
, sizeof(pmStats
));
2460 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
);
2461 publishPMStats
->release();
2462 bzero(&pmStats
, sizeof(pmStats
));
2464 if (pmStatsAppResponses
)
2466 setProperty(kIOPMSleepStatisticsAppsKey
, pmStatsAppResponses
);
2467 pmStatsAppResponses
->release();
2468 pmStatsAppResponses
= OSArray::withCapacity(5);
2471 tellClients( kIOMessageSystemHasPoweredOn
);
2475 //******************************************************************************
2476 // sysPowerDownHandler
2478 // Perform a vfs sync before system sleep.
2479 //******************************************************************************
2481 IOReturn
IOPMrootDomain::sysPowerDownHandler(
2482 void * target
, void * refCon
,
2483 UInt32 messageType
, IOService
* service
,
2484 void * messageArgs
, vm_size_t argSize
)
2488 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType
));
2491 return kIOReturnUnsupported
;
2493 if (messageType
== kIOMessageSystemCapabilityChange
)
2495 IOPMSystemCapabilityChangeParameters
* params
=
2496 (IOPMSystemCapabilityChangeParameters
*) messageArgs
;
2498 // Interested applications have been notified of an impending power
2499 // change and have acked (when applicable).
2500 // This is our chance to save whatever state we can before powering
2502 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
2505 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
2506 params
->fromCapabilities
, params
->toCapabilities
,
2507 params
->changeFlags
);
2509 if ((params
->changeFlags
& kIOPMSystemCapabilityWillChange
) &&
2510 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) &&
2511 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
) == 0)
2513 // We will ack within 20 seconds
2514 params
->maxWaitForReply
= 20 * 1000 * 1000;
2516 gRootDomain
->evaluateSystemSleepPolicyEarly();
2518 // add in time we could spend freeing pages
2519 if (gRootDomain
->hibernateMode
&& !gRootDomain
->hibernateDisabled
)
2521 params
->maxWaitForReply
= kCapabilityClientMaxWait
;
2523 DLOG("sysPowerDownHandler timeout %d s\n", (int) (params
->maxWaitForReply
/ 1000 / 1000));
2526 if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) )
2528 // Purposely delay the ack and hope that shutdown occurs quickly.
2529 // Another option is not to schedule the thread and wait for
2531 AbsoluteTime deadline
;
2532 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
2533 thread_call_enter1_delayed(
2534 gRootDomain
->diskSyncCalloutEntry
,
2535 (thread_call_param_t
) params
->notifyRef
,
2540 gRootDomain
->diskSyncCalloutEntry
,
2541 (thread_call_param_t
) params
->notifyRef
);
2545 if ((params
->changeFlags
& kIOPMSystemCapabilityDidChange
) &&
2546 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
) &&
2547 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) == 0)
2549 // We will ack within 110 seconds
2550 params
->maxWaitForReply
= 110 * 1000 * 1000;
2553 gRootDomain
->diskSyncCalloutEntry
,
2554 (thread_call_param_t
) params
->notifyRef
);
2557 ret
= kIOReturnSuccess
;
2563 //******************************************************************************
2564 // handleQueueSleepWakeUUID
2566 // Called from IOPMrootDomain when we're initiating a sleep,
2567 // or indirectly from PM configd when PM decides to clear the UUID.
2568 // PM clears the UUID several minutes after successful wake from sleep,
2569 // so that we might associate App spindumps with the immediately previous
2572 // @param obj has a retain on it. We're responsible for releasing that retain.
2573 //******************************************************************************
2575 void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject
*obj
)
2577 OSString
*str
= NULL
;
2579 if (kOSBooleanFalse
== obj
)
2581 handlePublishSleepWakeUUID(NULL
);
2583 else if ((str
= OSDynamicCast(OSString
, obj
)))
2585 // This branch caches the UUID for an upcoming sleep/wake
2586 if (queuedSleepWakeUUIDString
) {
2587 queuedSleepWakeUUIDString
->release();
2588 queuedSleepWakeUUIDString
= NULL
;
2590 queuedSleepWakeUUIDString
= str
;
2591 queuedSleepWakeUUIDString
->retain();
2593 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString
->getCStringNoCopy());
2602 //******************************************************************************
2603 // handlePublishSleepWakeUUID
2605 // Called from IOPMrootDomain when we're initiating a sleep,
2606 // or indirectly from PM configd when PM decides to clear the UUID.
2607 // PM clears the UUID several minutes after successful wake from sleep,
2608 // so that we might associate App spindumps with the immediately previous
2610 //******************************************************************************
2612 void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish
)
2617 * Clear the current UUID
2619 if (gSleepWakeUUIDIsSet
)
2621 DLOG("SleepWake UUID cleared\n");
2623 OSString
*UUIDstring
= NULL
;
2626 (UUIDstring
= OSDynamicCast(OSString
, getProperty(kIOPMSleepWakeUUIDKey
))))
2628 PMEventDetails
*details
= PMEventDetails::eventDetails(kIOPMEventTypeUUIDClear
,
2629 UUIDstring
->getCStringNoCopy(), NULL
, 0);
2631 timeline
->recordSystemPowerEvent( details
);
2634 timeline
->setNumEventsLoggedThisPeriod(0);
2637 gSleepWakeUUIDIsSet
= false;
2639 removeProperty(kIOPMSleepWakeUUIDKey
);
2640 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDCleared
);
2644 * Optionally, publish a new UUID
2646 if (queuedSleepWakeUUIDString
&& shouldPublish
) {
2648 OSString
*publishThisUUID
= NULL
;
2650 publishThisUUID
= queuedSleepWakeUUIDString
;
2651 publishThisUUID
->retain();
2654 PMEventDetails
*details
;
2655 details
= PMEventDetails::eventDetails(kIOPMEventTypeUUIDSet
,
2656 publishThisUUID
->getCStringNoCopy(), NULL
, 0);
2658 timeline
->recordSystemPowerEvent( details
);
2663 if (publishThisUUID
)
2665 setProperty(kIOPMSleepWakeUUIDKey
, publishThisUUID
);
2666 publishThisUUID
->release();
2669 gSleepWakeUUIDIsSet
= true;
2670 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDSet
);
2672 queuedSleepWakeUUIDString
->release();
2673 queuedSleepWakeUUIDString
= NULL
;
2677 //******************************************************************************
2678 // changePowerStateTo & changePowerStateToPriv
2680 // Override of these methods for logging purposes.
2681 //******************************************************************************
2683 IOReturn
IOPMrootDomain::changePowerStateTo( unsigned long ordinal
)
2685 return kIOReturnUnsupported
; // ignored
2688 IOReturn
IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal
)
2690 DLOG("changePowerStateToPriv(%lu)\n", ordinal
);
2692 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
2693 return kIOReturnUnsupported
;
2695 return super::changePowerStateToPriv(ordinal
);
2698 //******************************************************************************
2701 //******************************************************************************
2703 bool IOPMrootDomain::activitySinceSleep(void)
2705 return (userActivityCount
!= userActivityAtSleep
);
2708 bool IOPMrootDomain::abortHibernation(void)
2710 bool ret
= activitySinceSleep();
2712 if (ret
&& !hibernateAborted
)
2714 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount
, userActivityAtSleep
);
2715 hibernateAborted
= true;
2721 hibernate_should_abort(void)
2724 return (gRootDomain
->abortHibernation());
2729 //******************************************************************************
2730 // sleepOnClamshellClosed
2732 // contains the logic to determine if the system should sleep when the clamshell
2734 //******************************************************************************
2736 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
2738 if (!clamshellExists
)
2741 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d\n",
2742 clamshellClosed
, clamshellDisabled
, desktopMode
, acAdaptorConnected
);
2744 return ( !clamshellDisabled
&& !(desktopMode
&& acAdaptorConnected
) );
2747 void IOPMrootDomain::sendClientClamshellNotification( void )
2749 /* Only broadcast clamshell alert if clamshell exists. */
2750 if (!clamshellExists
)
2753 setProperty(kAppleClamshellStateKey
,
2754 clamshellClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
2756 setProperty(kAppleClamshellCausesSleepKey
,
2757 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
2759 /* Argument to message is a bitfiel of
2760 * ( kClamshellStateBit | kClamshellSleepBit )
2762 messageClients(kIOPMMessageClamshellStateChange
,
2763 (void *) ( (clamshellClosed
? kClamshellStateBit
: 0)
2764 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)) );
2767 //******************************************************************************
2768 // getSleepSupported
2771 //******************************************************************************
2773 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
2775 return( platformSleepSupport
);
2778 //******************************************************************************
2779 // setSleepSupported
2782 //******************************************************************************
2784 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
2786 DLOG("setSleepSupported(%x)\n", (uint32_t) flags
);
2787 OSBitOrAtomic(flags
, &platformSleepSupport
);
2790 //******************************************************************************
2794 //******************************************************************************
2796 void IOPMrootDomain::wakeFromDoze( void )
2798 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
2804 //******************************************************************************
2807 // Adds a new feature to the supported features dictionary
2808 //******************************************************************************
2810 void IOPMrootDomain::publishFeature( const char * feature
)
2812 publishFeature(feature
, kRD_AllPowerSources
, NULL
);
2815 //******************************************************************************
2816 // publishFeature (with supported power source specified)
2818 // Adds a new feature to the supported features dictionary
2819 //******************************************************************************
2821 void IOPMrootDomain::publishFeature(
2822 const char *feature
,
2823 uint32_t supportedWhere
,
2824 uint32_t *uniqueFeatureID
)
2826 static uint16_t next_feature_id
= 500;
2828 OSNumber
*new_feature_data
= NULL
;
2829 OSNumber
*existing_feature
= NULL
;
2830 OSArray
*existing_feature_arr
= NULL
;
2831 OSObject
*osObj
= NULL
;
2832 uint32_t feature_value
= 0;
2834 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
2836 if(!supportedWhere
) {
2837 // Feature isn't supported anywhere!
2841 if(next_feature_id
> 5000) {
2842 // Far, far too many features!
2846 if(featuresDictLock
) IOLockLock(featuresDictLock
);
2848 OSDictionary
*features
=
2849 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
2851 // Create new features dict if necessary
2852 if ( features
&& OSDynamicCast(OSDictionary
, features
)) {
2853 features
= OSDictionary::withDictionary(features
);
2855 features
= OSDictionary::withCapacity(1);
2858 // Create OSNumber to track new feature
2860 next_feature_id
+= 1;
2861 if( uniqueFeatureID
) {
2862 // We don't really mind if the calling kext didn't give us a place
2863 // to stash their unique id. Many kexts don't plan to unload, and thus
2864 // have no need to remove themselves later.
2865 *uniqueFeatureID
= next_feature_id
;
2868 feature_value
= (uint32_t)next_feature_id
;
2869 feature_value
<<= 16;
2870 feature_value
+= supportedWhere
;
2872 new_feature_data
= OSNumber::withNumber(
2873 (unsigned long long)feature_value
, 32);
2875 // Does features object already exist?
2876 if( (osObj
= features
->getObject(feature
)) )
2878 if(( existing_feature
= OSDynamicCast(OSNumber
, osObj
) ))
2880 // We need to create an OSArray to hold the now 2 elements.
2881 existing_feature_arr
= OSArray::withObjects(
2882 (const OSObject
**)&existing_feature
, 1, 2);
2883 } else if(( existing_feature_arr
= OSDynamicCast(OSArray
, osObj
) ))
2885 // Add object to existing array
2886 existing_feature_arr
= OSArray::withArray(
2887 existing_feature_arr
,
2888 existing_feature_arr
->getCount() + 1);
2891 if (existing_feature_arr
)
2893 existing_feature_arr
->setObject(new_feature_data
);
2894 features
->setObject(feature
, existing_feature_arr
);
2895 existing_feature_arr
->release();
2896 existing_feature_arr
= 0;
2899 // The easy case: no previously existing features listed. We simply
2900 // set the OSNumber at key 'feature' and we're on our way.
2901 features
->setObject(feature
, new_feature_data
);
2904 new_feature_data
->release();
2906 setProperty(kRootDomainSupportedFeatures
, features
);
2908 features
->release();
2910 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
2912 // Notify EnergySaver and all those in user space so they might
2913 // re-populate their feature specific UI
2914 if(pmPowerStateQueue
) {
2915 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
2919 //******************************************************************************
2920 // removePublishedFeature
2922 // Removes previously published feature
2923 //******************************************************************************
2925 IOReturn
IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
2927 IOReturn ret
= kIOReturnError
;
2928 uint32_t feature_value
= 0;
2929 uint16_t feature_id
= 0;
2930 bool madeAChange
= false;
2932 OSSymbol
*dictKey
= NULL
;
2933 OSCollectionIterator
*dictIterator
= NULL
;
2934 OSArray
*arrayMember
= NULL
;
2935 OSNumber
*numberMember
= NULL
;
2936 OSObject
*osObj
= NULL
;
2937 OSNumber
*osNum
= NULL
;
2938 OSArray
*arrayMemberCopy
;
2940 if(featuresDictLock
) IOLockLock(featuresDictLock
);
2942 OSDictionary
*features
=
2943 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
2945 if ( features
&& OSDynamicCast(OSDictionary
, features
) )
2947 // Any modifications to the dictionary are made to the copy to prevent
2948 // races & crashes with userland clients. Dictionary updated
2949 // automically later.
2950 features
= OSDictionary::withDictionary(features
);
2953 ret
= kIOReturnNotFound
;
2957 // We iterate 'features' dictionary looking for an entry tagged
2958 // with 'removeFeatureID'. If found, we remove it from our tracking
2959 // structures and notify the OS via a general interest message.
2961 dictIterator
= OSCollectionIterator::withCollection(features
);
2966 while( (dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject())) )
2968 osObj
= features
->getObject(dictKey
);
2970 // Each Feature is either tracked by an OSNumber
2971 if( osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
)) )
2973 feature_value
= numberMember
->unsigned32BitValue();
2974 feature_id
= (uint16_t)(feature_value
>> 16);
2976 if( feature_id
== (uint16_t)removeFeatureID
)
2979 features
->removeObject(dictKey
);
2984 // Or tracked by an OSArray of OSNumbers
2985 } else if( osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
)) )
2987 unsigned int arrayCount
= arrayMember
->getCount();
2989 for(unsigned int i
=0; i
<arrayCount
; i
++)
2991 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
2996 feature_value
= osNum
->unsigned32BitValue();
2997 feature_id
= (uint16_t)(feature_value
>> 16);
2999 if( feature_id
== (uint16_t)removeFeatureID
)
3002 if( 1 == arrayCount
) {
3003 // If the array only contains one element, remove
3005 features
->removeObject(dictKey
);
3007 // Otherwise remove the element from a copy of the array.
3008 arrayMemberCopy
= OSArray::withArray(arrayMember
);
3009 if (arrayMemberCopy
)
3011 arrayMemberCopy
->removeObject(i
);
3012 features
->setObject(dictKey
, arrayMemberCopy
);
3013 arrayMemberCopy
->release();
3024 dictIterator
->release();
3028 ret
= kIOReturnSuccess
;
3030 setProperty(kRootDomainSupportedFeatures
, features
);
3032 // Notify EnergySaver and all those in user space so they might
3033 // re-populate their feature specific UI
3034 if(pmPowerStateQueue
) {
3035 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3038 ret
= kIOReturnNotFound
;
3042 if(features
) features
->release();
3043 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3047 //******************************************************************************
3048 // setPMSetting (private)
3050 // Internal helper to relay PM settings changes from user space to individual
3051 // drivers. Should be called only by IOPMrootDomain::setProperties.
3052 //******************************************************************************
3054 IOReturn
IOPMrootDomain::setPMSetting(
3055 const OSSymbol
*type
,
3058 PMSettingCallEntry
*entries
= 0;
3059 OSArray
*chosen
= 0;
3060 const OSArray
*array
;
3061 PMSettingObject
*pmso
;
3062 thread_t thisThread
;
3063 int i
, j
, count
, capacity
;
3066 return kIOReturnBadArgument
;
3070 // Update settings dict so changes are visible from copyPMSetting().
3071 fPMSettingsDict
->setObject(type
, object
);
3073 // Prep all PMSetting objects with the given 'type' for callout.
3074 array
= (const OSArray
*) settingsCallbacks
->getObject(type
);
3075 if (!array
|| ((capacity
= array
->getCount()) == 0))
3078 // Array to retain PMSetting objects targeted for callout.
3079 chosen
= OSArray::withCapacity(capacity
);
3081 goto unlock_exit
; // error
3083 entries
= IONew(PMSettingCallEntry
, capacity
);
3085 goto unlock_exit
; // error
3086 memset(entries
, 0, sizeof(PMSettingCallEntry
) * capacity
);
3088 thisThread
= current_thread();
3090 for (i
= 0, j
= 0; i
<capacity
; i
++)
3092 pmso
= (PMSettingObject
*) array
->getObject(i
);
3095 entries
[j
].thread
= thisThread
;
3096 queue_enter(&pmso
->calloutQueue
, &entries
[j
], PMSettingCallEntry
*, link
);
3097 chosen
->setObject(pmso
);
3106 // Call each pmso in the chosen array.
3107 for (i
=0; i
<count
; i
++)
3109 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3110 pmso
->dispatchPMSetting(type
, object
);
3114 for (i
=0; i
<count
; i
++)
3116 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3117 queue_remove(&pmso
->calloutQueue
, &entries
[i
], PMSettingCallEntry
*, link
);
3118 if (pmso
->waitThread
)
3120 PMSETTING_WAKEUP(pmso
);
3126 if (chosen
) chosen
->release();
3127 if (entries
) IODelete(entries
, PMSettingCallEntry
, capacity
);
3129 return kIOReturnSuccess
;
3132 //******************************************************************************
3133 // copyPMSetting (public)
3135 // Allows kexts to safely read setting values, without being subscribed to
3137 //******************************************************************************
3139 OSObject
* IOPMrootDomain::copyPMSetting(
3140 OSSymbol
*whichSetting
)
3142 OSObject
*obj
= NULL
;
3144 if(!whichSetting
) return NULL
;
3147 obj
= fPMSettingsDict
->getObject(whichSetting
);
3156 //******************************************************************************
3157 // registerPMSettingController (public)
3159 // direct wrapper to registerPMSettingController with uint32_t power source arg
3160 //******************************************************************************
3162 IOReturn
IOPMrootDomain::registerPMSettingController(
3163 const OSSymbol
* settings
[],
3164 IOPMSettingControllerCallback func
,
3169 return registerPMSettingController(
3171 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
3172 func
, target
, refcon
, handle
);
3175 //******************************************************************************
3176 // registerPMSettingController (public)
3178 // Kexts may register for notifications when a particular setting is changed.
3179 // A list of settings is available in IOPM.h.
3181 // * settings - An OSArray containing OSSymbols. Caller should populate this
3182 // array with a list of settings caller wants notifications from.
3183 // * func - A C function callback of the type IOPMSettingControllerCallback
3184 // * target - caller may provide an OSObject *, which PM will pass as an
3185 // target to calls to "func"
3186 // * refcon - caller may provide an void *, which PM will pass as an
3187 // argument to calls to "func"
3188 // * handle - This is a return argument. We will populate this pointer upon
3189 // call success. Hold onto this and pass this argument to
3190 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3192 // kIOReturnSuccess on success
3193 //******************************************************************************
3195 IOReturn
IOPMrootDomain::registerPMSettingController(
3196 const OSSymbol
* settings
[],
3197 uint32_t supportedPowerSources
,
3198 IOPMSettingControllerCallback func
,
3203 PMSettingObject
*pmso
= NULL
;
3204 OSObject
*pmsh
= NULL
;
3205 OSArray
*list
= NULL
;
3208 if (NULL
== settings
||
3212 return kIOReturnBadArgument
;
3215 pmso
= PMSettingObject::pmSettingObject(
3216 (IOPMrootDomain
*) this, func
, target
,
3217 refcon
, supportedPowerSources
, settings
, &pmsh
);
3221 return kIOReturnInternalError
;
3225 for (i
=0; settings
[i
]; i
++)
3227 list
= (OSArray
*) settingsCallbacks
->getObject(settings
[i
]);
3229 // New array of callbacks for this setting
3230 list
= OSArray::withCapacity(1);
3231 settingsCallbacks
->setObject(settings
[i
], list
);
3235 // Add caller to the callback list
3236 list
->setObject(pmso
);
3240 // Return handle to the caller, the setting object is private.
3243 return kIOReturnSuccess
;
3246 //******************************************************************************
3247 // deregisterPMSettingObject (private)
3249 // Only called from PMSettingObject.
3250 //******************************************************************************
3252 void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject
* pmso
)
3254 thread_t thisThread
= current_thread();
3255 PMSettingCallEntry
*callEntry
;
3256 OSCollectionIterator
*iter
;
3264 pmso
->disabled
= true;
3266 // Wait for all callout threads to finish.
3269 queue_iterate(&pmso
->calloutQueue
, callEntry
, PMSettingCallEntry
*, link
)
3271 if (callEntry
->thread
!= thisThread
)
3279 assert(0 == pmso
->waitThread
);
3280 pmso
->waitThread
= thisThread
;
3281 PMSETTING_WAIT(pmso
);
3282 pmso
->waitThread
= 0;
3286 // Search each PM settings array in the kernel.
3287 iter
= OSCollectionIterator::withCollection(settingsCallbacks
);
3290 while ((sym
= OSDynamicCast(OSSymbol
, iter
->getNextObject())))
3292 array
= (OSArray
*) settingsCallbacks
->getObject(sym
);
3293 index
= array
->getNextIndexOfObject(pmso
, 0);
3295 array
->removeObject(index
);
3306 //******************************************************************************
3307 // informCPUStateChange
3309 // Call into PM CPU code so that CPU power savings may dynamically adjust for
3310 // running on battery, with the lid closed, etc.
3312 // informCPUStateChange is a no-op on non x86 systems
3313 // only x86 has explicit support in the IntelCPUPowerManagement kext
3314 //******************************************************************************
3316 void IOPMrootDomain::informCPUStateChange(
3320 #if defined(__i386__) || defined(__x86_64__)
3322 pmioctlVariableInfo_t varInfoStruct
;
3324 const char *varNameStr
= NULL
;
3325 int32_t *varIndex
= NULL
;
3327 if (kInformAC
== type
) {
3328 varNameStr
= kIOPMRootDomainBatPowerCString
;
3329 varIndex
= &idxPMCPULimitedPower
;
3330 } else if (kInformLid
== type
) {
3331 varNameStr
= kIOPMRootDomainLidCloseCString
;
3332 varIndex
= &idxPMCPUClamshell
;
3337 // Set the new value!
3338 // pmCPUControl will assign us a new ID if one doesn't exist yet
3339 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
3340 varInfoStruct
.varID
= *varIndex
;
3341 varInfoStruct
.varType
= vBool
;
3342 varInfoStruct
.varInitValue
= value
;
3343 varInfoStruct
.varCurValue
= value
;
3344 strncpy( (char *)varInfoStruct
.varName
,
3345 (const char *)varNameStr
,
3346 strlen(varNameStr
) + 1 );
3349 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
3351 // pmCPU only assigns numerical id's when a new varName is specified
3353 && (*varIndex
== kCPUUnknownIndex
))
3355 // pmCPUControl has assigned us a new variable ID.
3356 // Let's re-read the structure we just SET to learn that ID.
3357 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
3361 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
3362 *varIndex
= varInfoStruct
.varID
;
3368 #endif /* __i386__ || __x86_64__ */
3372 // MARK: Deep Sleep Policy
3376 //******************************************************************************
3377 // evaluateSystemSleepPolicy
3378 //******************************************************************************
3380 struct IOPMSystemSleepPolicyEntry
3382 uint32_t factorMask
;
3383 uint32_t factorBits
;
3384 uint32_t sleepFlags
;
3385 uint32_t wakeEvents
;
3388 struct IOPMSystemSleepPolicyTable
3390 uint8_t signature
[4];
3392 uint16_t entryCount
;
3393 IOPMSystemSleepPolicyEntry entries
[];
3397 kIOPMSleepFactorSleepTimerWake
= 0x00000001,
3398 kIOPMSleepFactorLidOpen
= 0x00000002,
3399 kIOPMSleepFactorACPower
= 0x00000004,
3400 kIOPMSleepFactorLowBattery
= 0x00000008,
3401 kIOPMSleepFactorDeepSleepNoDelay
= 0x00000010,
3402 kIOPMSleepFactorDeepSleepDemand
= 0x00000020,
3403 kIOPMSleepFactorDeepSleepDisable
= 0x00000040,
3404 kIOPMSleepFactorUSBExternalDevice
= 0x00000080,
3405 kIOPMSleepFactorBluetoothHIDDevice
= 0x00000100,
3406 kIOPMSleepFactorExternalMediaMounted
= 0x00000200,
3407 kIOPMSleepFactorDriverAssertBit5
= 0x00000400, /* Reserved for ThunderBolt */
3408 kIOPMSleepFactorDriverAssertBit6
= 0x00000800,
3409 kIOPMSleepFactorDriverAssertBit7
= 0x00001000
3412 bool IOPMrootDomain::evaluateSystemSleepPolicy( IOPMSystemSleepParameters
* p
)
3414 const IOPMSystemSleepPolicyTable
* pt
;
3415 OSObject
* prop
= 0;
3416 OSData
* policyData
;
3417 uint32_t currentFactors
;
3418 uint32_t deepSleepDelay
= 0;
3419 bool success
= false;
3421 if (getProperty(kIOPMDeepSleepEnabledKey
) != kOSBooleanTrue
)
3424 getSleepOption(kIOPMDeepSleepDelayKey
, &deepSleepDelay
);
3426 prop
= getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey
);
3430 policyData
= OSDynamicCast(OSData
, prop
);
3432 (policyData
->getLength() < sizeof(IOPMSystemSleepPolicyTable
)))
3437 pt
= (const IOPMSystemSleepPolicyTable
*) policyData
->getBytesNoCopy();
3438 if ((pt
->signature
[0] != 'S') ||
3439 (pt
->signature
[1] != 'L') ||
3440 (pt
->signature
[2] != 'P') ||
3441 (pt
->signature
[3] != 'T') ||
3442 (pt
->version
!= 1) ||
3443 (pt
->entryCount
== 0))
3448 if ((policyData
->getLength() - sizeof(IOPMSystemSleepPolicyTable
)) !=
3449 (sizeof(IOPMSystemSleepPolicyEntry
) * pt
->entryCount
))
3455 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit
) !=
3456 kIOPMDriverAssertionLevelOff
)
3457 currentFactors
|= kIOPMSleepFactorUSBExternalDevice
;
3458 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit
) !=
3459 kIOPMDriverAssertionLevelOff
)
3460 currentFactors
|= kIOPMSleepFactorBluetoothHIDDevice
;
3461 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit
) !=
3462 kIOPMDriverAssertionLevelOff
)
3463 currentFactors
|= kIOPMSleepFactorExternalMediaMounted
;
3464 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5
) != /* AssertionBit5 = Thunderbolt */
3465 kIOPMDriverAssertionLevelOff
)
3466 currentFactors
|= kIOPMSleepFactorDriverAssertBit5
;
3467 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit7
) !=
3468 kIOPMDriverAssertionLevelOff
)
3469 currentFactors
|= kIOPMSleepFactorDriverAssertBit7
;
3470 if (0 == deepSleepDelay
)
3471 currentFactors
|= kIOPMSleepFactorDeepSleepNoDelay
;
3472 if (!clamshellClosed
)
3473 currentFactors
|= kIOPMSleepFactorLidOpen
;
3474 if (acAdaptorConnected
)
3475 currentFactors
|= kIOPMSleepFactorACPower
;
3476 if (lowBatteryCondition
)
3477 currentFactors
|= kIOPMSleepFactorLowBattery
;
3478 if (sleepTimerMaintenance
)
3479 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
3482 if ((hibernateMode
& kIOHibernateModeOn
) == 0)
3483 currentFactors
|= kIOPMSleepFactorDeepSleepDisable
;
3484 else if ((hibernateMode
& kIOHibernateModeSleep
) == 0)
3485 currentFactors
|= kIOPMSleepFactorDeepSleepDemand
;
3487 DLOG("Sleep policy %u entries, current factors 0x%x\n",
3488 pt
->entryCount
, currentFactors
);
3490 for (uint32_t i
= 0; i
< pt
->entryCount
; i
++)
3492 const IOPMSystemSleepPolicyEntry
* policyEntry
= &pt
->entries
[i
];
3494 DLOG("factor mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x\n",
3495 policyEntry
->factorMask
, policyEntry
->factorBits
,
3496 policyEntry
->sleepFlags
, policyEntry
->wakeEvents
);
3498 if ((currentFactors
^ policyEntry
->factorBits
) & policyEntry
->factorMask
)
3499 continue; // mismatch, try next
3504 p
->sleepFlags
= policyEntry
->sleepFlags
;
3506 p
->wakeEvents
= policyEntry
->wakeEvents
;
3507 if (p
->sleepFlags
& kIOPMSleepFlagSleepTimerEnable
)
3509 p
->sleepTimer
= deepSleepDelay
;
3513 DLOG("matched policy entry %u\n", i
);
3525 void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
3527 IOPMSystemSleepParameters params
;
3529 // Evaluate sleep policy before driver sleep phase.
3531 DLOG("%s\n", __FUNCTION__
);
3532 removeProperty(kIOPMSystemSleepParametersKey
);
3534 hibernateDisabled
= false;
3536 getSleepOption(kIOHibernateModeKey
, &hibernateMode
);
3538 if (!hibernateNoDefeat
&&
3539 evaluateSystemSleepPolicy(¶ms
) &&
3540 ((params
.sleepFlags
& kIOPMSleepFlagHibernate
) == 0))
3542 hibernateDisabled
= true;
3546 void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
3548 IOPMSystemSleepParameters params
;
3549 OSData
* paramsData
;
3551 // Evaluate sleep policy after drivers but before platform sleep.
3553 DLOG("%s\n", __FUNCTION__
);
3555 if (evaluateSystemSleepPolicy(¶ms
))
3557 if ((hibernateDisabled
|| hibernateAborted
) &&
3558 (params
.sleepFlags
& kIOPMSleepFlagHibernate
))
3560 // Should hibernate but unable to or aborted.
3561 // Arm timer for a short sleep and retry or wake fully.
3563 params
.sleepFlags
&= ~kIOPMSleepFlagHibernate
;
3564 params
.sleepFlags
|= kIOPMSleepFlagSleepTimerEnable
;
3565 params
.sleepTimer
= 1;
3566 hibernateNoDefeat
= true;
3567 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d\n",
3568 params
.sleepTimer
, hibernateDisabled
, hibernateAborted
);
3571 hibernateNoDefeat
= false;
3573 paramsData
= OSData::withBytes(¶ms
, sizeof(params
));
3576 setProperty(kIOPMSystemSleepParametersKey
, paramsData
);
3577 paramsData
->release();
3580 if (params
.sleepFlags
& kIOPMSleepFlagHibernate
)
3583 gIOHibernateMode
&= ~kIOHibernateModeSleep
;
3588 bool IOPMrootDomain::getHibernateSettings(
3589 uint32_t * hibernateMode
,
3590 uint32_t * hibernateFreeRatio
,
3591 uint32_t * hibernateFreeTime
)
3593 bool ok
= getSleepOption(kIOHibernateModeKey
, hibernateMode
);
3594 getSleepOption(kIOHibernateFreeRatioKey
, hibernateFreeRatio
);
3595 getSleepOption(kIOHibernateFreeTimeKey
, hibernateFreeTime
);
3596 if (hibernateDisabled
)
3598 DLOG("hibernateMode 0x%x\n", *hibernateMode
);
3602 bool IOPMrootDomain::getSleepOption( const char * key
, uint32_t * option
)
3604 OSObject
* optionsProp
;
3605 OSDictionary
* optionsDict
;
3610 optionsProp
= copyProperty(kRootDomainSleepOptionsKey
);
3611 optionsDict
= OSDynamicCast(OSDictionary
, optionsProp
);
3615 obj
= optionsDict
->getObject(key
);
3616 if (obj
) obj
->retain();
3620 obj
= copyProperty(key
);
3622 if (obj
&& (num
= OSDynamicCast(OSNumber
, obj
)))
3624 *option
= num
->unsigned32BitValue();
3631 optionsProp
->release();
3635 #endif /* HIBERNATION */
3638 // MARK: Shutdown and Restart
3640 //******************************************************************************
3641 // handlePlatformHaltRestart
3643 //******************************************************************************
3645 struct HaltRestartApplierContext
{
3646 IOPMrootDomain
* RootDomain
;
3647 unsigned long PowerState
;
3648 IOPMPowerFlags PowerFlags
;
3654 platformHaltRestartApplier( OSObject
* object
, void * context
)
3656 IOPowerStateChangeNotification notify
;
3657 HaltRestartApplierContext
* ctx
;
3658 AbsoluteTime startTime
;
3661 ctx
= (HaltRestartApplierContext
*) context
;
3663 memset(¬ify
, 0, sizeof(notify
));
3664 notify
.powerRef
= (void *)ctx
->Counter
;
3665 notify
.returnValue
= 0;
3666 notify
.stateNumber
= ctx
->PowerState
;
3667 notify
.stateFlags
= ctx
->PowerFlags
;
3669 clock_get_uptime(&startTime
);
3670 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
3671 deltaTime
= computeDeltaTimeMS(&startTime
);
3673 if ((deltaTime
> kPMHaltTimeoutMS
) ||
3674 (gIOKitDebug
& kIOLogPMRootDomain
))
3676 _IOServiceInterestNotifier
* notifier
;
3677 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
3679 // IOService children of IOPMrootDomain are not instrumented.
3680 // Only IORootParent currently falls under that group.
3684 LOG("%s handler %p took %u ms\n",
3685 (ctx
->MessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" :
3686 (ctx
->MessageType
== kIOMessageSystemPagingOff
) ? "PagingOff" : "Restart",
3687 notifier
->handler
, (uint32_t) deltaTime
);
3694 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
3696 HaltRestartApplierContext ctx
;
3697 AbsoluteTime startTime
;
3700 memset(&ctx
, 0, sizeof(ctx
));
3701 ctx
.RootDomain
= this;
3703 clock_get_uptime(&startTime
);
3707 case kPEUPSDelayHaltCPU
:
3708 ctx
.PowerState
= OFF_STATE
;
3709 ctx
.MessageType
= kIOMessageSystemWillPowerOff
;
3713 ctx
.PowerState
= RESTART_STATE
;
3714 ctx
.MessageType
= kIOMessageSystemWillRestart
;
3718 ctx
.PowerState
= ON_STATE
;
3719 ctx
.MessageType
= kIOMessageSystemPagingOff
;
3720 IOService::updateConsoleUsers(NULL
, kIOMessageSystemPagingOff
);
3727 // Notify legacy clients
3728 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &ctx
);
3730 // For normal shutdown, turn off File Server Mode.
3731 if (kPEHaltCPU
== pe_type
)
3733 const OSSymbol
* setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
3734 OSNumber
* num
= OSNumber::withNumber((unsigned long long) 0, 32);
3737 setPMSetting(setting
, num
);
3743 if (kPEPagingOff
!= pe_type
)
3745 // Notify in power tree order
3746 notifySystemShutdown(this, ctx
.MessageType
);
3749 deltaTime
= computeDeltaTimeMS(&startTime
);
3750 LOG("%s all drivers took %u ms\n",
3751 (ctx
.MessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" :
3752 (ctx
.MessageType
== kIOMessageSystemPagingOff
) ? "PagingOff" : "Restart",
3753 (uint32_t) deltaTime
);
3756 //******************************************************************************
3759 //******************************************************************************
3761 IOReturn
IOPMrootDomain::shutdownSystem( void )
3763 return kIOReturnUnsupported
;
3766 //******************************************************************************
3769 //******************************************************************************
3771 IOReturn
IOPMrootDomain::restartSystem( void )
3773 return kIOReturnUnsupported
;
3777 // MARK: System Capability
3779 //******************************************************************************
3780 // tagPowerPlaneService
3782 // Running on PM work loop thread.
3783 //******************************************************************************
3785 void IOPMrootDomain::tagPowerPlaneService(
3786 IOService
* service
,
3787 IOPMActions
* actions
)
3790 bool isDisplayWrangler
;
3792 memset(actions
, 0, sizeof(*actions
));
3793 actions
->target
= this;
3795 if (service
== this)
3797 actions
->actionPowerChangeStart
=
3798 OSMemberFunctionCast(
3799 IOPMActionPowerChangeStart
, this,
3800 &IOPMrootDomain::handleOurPowerChangeStart
);
3802 actions
->actionPowerChangeDone
=
3803 OSMemberFunctionCast(
3804 IOPMActionPowerChangeDone
, this,
3805 &IOPMrootDomain::handleOurPowerChangeDone
);
3807 actions
->actionPowerChangeOverride
=
3808 OSMemberFunctionCast(
3809 IOPMActionPowerChangeOverride
, this,
3810 &IOPMrootDomain::overrideOurPowerChange
);
3815 isDisplayWrangler
= (0 != service
->metaCast("IODisplayWrangler"));
3816 if (isDisplayWrangler
)
3819 wranglerConnection
= (IOService
*) service
->getParentEntry(gIOPowerPlane
);
3822 isDisplayWrangler
= false;
3825 #if defined(__i386__) || defined(__x86_64__)
3826 if (isDisplayWrangler
)
3827 flags
|= kPMActionsFlagIsDisplayWrangler
;
3828 if (service
->getProperty("IOPMStrictTreeOrder"))
3829 flags
|= kPMActionsFlagIsGraphicsDevice
;
3830 if (service
->getProperty("IOPMUnattendedWakePowerState"))
3831 flags
|= kPMActionsFlagIsAudioDevice
;
3834 // Find the power connection object that is a child of the PCI host
3835 // bridge, and has a graphics/audio device attached below. Mark the
3836 // power branch for delayed child notifications.
3840 IORegistryEntry
* child
= service
;
3841 IORegistryEntry
* parent
= child
->getParentEntry(gIOPowerPlane
);
3843 while (child
!= this)
3845 if ((parent
== pciHostBridgeDriver
) ||
3848 if (OSDynamicCast(IOPowerConnection
, child
))
3850 IOPowerConnection
* conn
= (IOPowerConnection
*) child
;
3851 conn
->delayChildNotification
= true;
3856 parent
= child
->getParentEntry(gIOPowerPlane
);
3862 DLOG("%s tag flags %x\n", service
->getName(), flags
);
3863 actions
->parameter
|= flags
;
3864 actions
->actionPowerChangeOverride
=
3865 OSMemberFunctionCast(
3866 IOPMActionPowerChangeOverride
, this,
3867 &IOPMrootDomain::overridePowerChangeForUIService
);
3869 if (flags
& kPMActionsFlagIsDisplayWrangler
)
3871 actions
->actionActivityTickle
=
3872 OSMemberFunctionCast(
3873 IOPMActionActivityTickle
, this,
3874 &IOPMrootDomain::handleActivityTickleForDisplayWrangler
);
3879 // Locate the first PCI host bridge for PMTrace.
3880 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge"))
3882 IOService
* provider
= service
->getProvider();
3883 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
3884 provider
->inPlane(gIODTPlane
))
3886 pciHostBridgeDevice
= provider
;
3887 pciHostBridgeDriver
= service
;
3888 DLOG("PMTrace found PCI host bridge %s->%s\n",
3889 provider
->getName(), service
->getName());
3893 // Tag top-level PCI devices. The order of PMinit() call does not
3894 // change across boots and is used as the PCI bit number.
3895 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice"))
3897 // Would prefer to check built-in property, but tagPowerPlaneService()
3898 // is called before pciDevice->registerService().
3899 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
3900 if ((parent
== pciHostBridgeDevice
) && service
->getProperty("acpi-device"))
3902 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
3905 // Save the assigned bit for fast lookup.
3906 actions
->parameter
|= (bit
& kPMActionsPCIBitNumberMask
);
3908 actions
->actionPowerChangeStart
=
3909 OSMemberFunctionCast(
3910 IOPMActionPowerChangeStart
, this,
3911 &IOPMrootDomain::handlePowerChangeStartForPCIDevice
);
3913 actions
->actionPowerChangeDone
=
3914 OSMemberFunctionCast(
3915 IOPMActionPowerChangeDone
, this,
3916 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice
);
3922 //******************************************************************************
3923 // PM actions for root domain
3924 //******************************************************************************
3926 void IOPMrootDomain::overrideOurPowerChange(
3927 IOService
* service
,
3928 IOPMActions
* actions
,
3929 unsigned long * inOutPowerState
,
3930 uint32_t * inOutChangeFlags
)
3932 uint32_t powerState
= (uint32_t) *inOutPowerState
;
3933 uint32_t changeFlags
= *inOutChangeFlags
;
3934 uint32_t currentPowerState
= (uint32_t) getPowerState();
3936 if ((currentPowerState
== powerState
) ||
3937 (changeFlags
& kIOPMParentInitiated
))
3939 // FIXME: cancel any parent change (unexpected)
3940 // Root parent is permanently pegged at max power,
3941 // kIOPMParentInitiated is unexpected.
3945 if (powerState
< currentPowerState
)
3947 if ((changeFlags
& kIOPMSkipAskPowerDown
) == 0)
3949 /* Convenient place to run any code at idle sleep time
3950 * IOPMrootDomain initiates an idle sleep here
3952 * Set last sleep cause accordingly.
3954 pmPowerStateQueue
->submitPowerEvent(kPowerEventPublishSleepWakeUUID
, (void *)true);
3956 lastSleepReason
= kIOPMSleepReasonIdle
;
3957 setProperty(kRootDomainSleepReasonKey
, kIOPMIdleSleepKey
);
3959 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
3961 // Root domain is dropping power state ON->SLEEP.
3962 // If system is in full wake, first drop to dark wake.
3964 darkWakeToSleepASAP
= true;
3966 // Drop graphics capability.
3967 // No transition if system is already in dark wake.
3969 _desiredCapability
&= ~(
3970 kIOPMSystemCapabilityGraphics
|
3971 kIOPMSystemCapabilityAudio
);
3973 *inOutPowerState
= ON_STATE
;
3974 *inOutChangeFlags
|= kIOPMSynchronize
;
3976 // Revert device desire from SLEEP->ON.
3977 changePowerStateToPriv(ON_STATE
);
3982 void IOPMrootDomain::handleOurPowerChangeStart(
3983 IOService
* service
,
3984 IOPMActions
* actions
,
3985 uint32_t powerState
,
3986 uint32_t * inOutChangeFlags
)
3988 uint32_t changeFlags
= *inOutChangeFlags
;
3989 uint32_t currentPowerState
= (uint32_t) getPowerState();
3991 _systemTransitionType
= kSystemTransitionNone
;
3992 _systemMessageClientMask
= 0;
3993 capabilityLoss
= false;
3995 // 1. Explicit capability change.
3997 if (changeFlags
& kIOPMSynchronize
)
3999 if (powerState
== ON_STATE
)
4001 if (changeFlags
& kIOPMSyncNoChildNotify
)
4002 _systemTransitionType
= kSystemTransitionNewCapClient
;
4004 _systemTransitionType
= kSystemTransitionCapability
;
4008 // 2. Going to sleep (cancellation still possible).
4010 else if (powerState
< currentPowerState
)
4011 _systemTransitionType
= kSystemTransitionSleep
;
4013 // 3. Woke from (idle or demand) sleep.
4015 else if (!systemBooting
&&
4016 (changeFlags
& kIOPMSelfInitiated
) &&
4017 (powerState
> currentPowerState
))
4019 _systemTransitionType
= kSystemTransitionWake
;
4020 _desiredCapability
= kIOPMSystemCapabilityCPU
|
4021 kIOPMSystemCapabilityNetwork
;
4023 // Check for early HID events (e.g. LID open)
4024 if (wranglerTickled
)
4026 _desiredCapability
|= (
4027 kIOPMSystemCapabilityGraphics
|
4028 kIOPMSystemCapabilityAudio
);
4032 // Update pending wake capability at the beginning of every
4033 // state transition (including synchronize). This will become
4034 // the current capability at the end of the transition.
4036 if (kSystemTransitionSleep
== _systemTransitionType
)
4038 _pendingCapability
= 0;
4039 capabilityLoss
= true;
4041 else if (kSystemTransitionNewCapClient
!= _systemTransitionType
)
4043 _pendingCapability
= _desiredCapability
|
4044 kIOPMSystemCapabilityCPU
|
4045 kIOPMSystemCapabilityNetwork
;
4047 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4048 _pendingCapability
|= kIOPMSystemCapabilityAudio
;
4050 if ((kSystemTransitionCapability
== _systemTransitionType
) &&
4051 (_pendingCapability
== _currentCapability
))
4053 // Cancel the PM state change.
4054 _systemTransitionType
= kSystemTransitionNone
;
4055 *inOutChangeFlags
|= kIOPMNotDone
;
4057 if (__builtin_popcount(_pendingCapability
) <
4058 __builtin_popcount(_currentCapability
))
4059 capabilityLoss
= true;
4060 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4061 rejectWranglerTickle
= true;
4064 // 1. Capability change.
4066 if (kSystemTransitionCapability
== _systemTransitionType
)
4068 // Dark to Full transition.
4069 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4071 tracePoint( kIOPMTracePointDarkWakeExit
);
4072 wranglerSleepIgnored
= false;
4073 sleepTimerMaintenance
= false;
4074 hibernateNoDefeat
= false;
4075 _systemMessageClientMask
= kSystemMessageClientUser
;
4076 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4077 _systemMessageClientMask
|= kSystemMessageClientKernel
;
4079 tellClients(kIOMessageSystemWillPowerOn
);
4082 // Full to Dark transition.
4083 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4085 tracePoint( kIOPMTracePointDarkWakeEntry
);
4086 *inOutChangeFlags
|= kIOPMSyncTellPowerDown
;
4087 _systemMessageClientMask
= kSystemMessageClientUser
;
4093 else if (kSystemTransitionSleep
== _systemTransitionType
)
4095 // Beginning of a system sleep transition.
4096 // Cancellation is still possible.
4097 tracePoint( kIOPMTracePointSleepStarted
, lastSleepReason
);
4099 _systemMessageClientMask
= kSystemMessageClientAll
;
4100 if ((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4101 _systemMessageClientMask
&= ~kSystemMessageClientApp
;
4102 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4103 _systemMessageClientMask
&= ~kSystemMessageClientKernel
;
4105 // Optimization to ignore wrangler power down thus skipping
4106 // the disk spindown and arming the idle timer for demand sleep.
4108 if (changeFlags
& kIOPMIgnoreChildren
)
4110 wranglerSleepIgnored
= true;
4113 logWranglerTickle
= false;
4118 else if (kSystemTransitionWake
== _systemTransitionType
)
4120 wranglerSleepIgnored
= false;
4122 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4124 _systemMessageClientMask
= kSystemMessageClientAll
;
4128 _systemMessageClientMask
= kSystemMessageClientConfigd
;
4131 tracePoint( kIOPMTracePointWakeWillPowerOnClients
);
4132 tellClients(kIOMessageSystemWillPowerOn
);
4135 if ((kSystemTransitionNone
!= _systemTransitionType
) &&
4136 (kSystemTransitionNewCapClient
!= _systemTransitionType
))
4138 _systemStateGeneration
++;
4139 systemDarkWake
= false;
4141 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4143 currentPowerState
, powerState
, *inOutChangeFlags
,
4144 _systemTransitionType
, _systemStateGeneration
,
4145 _systemMessageClientMask
,
4146 _desiredCapability
, _currentCapability
, _pendingCapability
);
4150 void IOPMrootDomain::handleOurPowerChangeDone(
4151 IOService
* service
,
4152 IOPMActions
* actions
,
4153 uint32_t powerState
,
4154 uint32_t changeFlags
)
4156 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
4158 _systemTransitionType
= kSystemTransitionNone
;
4162 if (_systemTransitionType
!= kSystemTransitionNone
)
4164 uint32_t currentPowerState
= (uint32_t) getPowerState();
4166 if (changeFlags
& kIOPMNotDone
)
4168 // Power down was cancelled or vetoed.
4169 _pendingCapability
= _currentCapability
;
4170 lastSleepReason
= 0;
4172 if (((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
4173 (_currentCapability
& kIOPMSystemCapabilityCPU
))
4175 pmPowerStateQueue
->submitPowerEvent(
4176 kPowerEventPolicyStimulus
,
4177 (void *) kStimulusDarkWakeReentry
,
4178 _systemStateGeneration
);
4181 // Revert device desire to max.
4182 changePowerStateToPriv(ON_STATE
);
4186 // Send message on dark wake to full wake promotion.
4187 // tellChangeUp() handles the normal SLEEP->ON case.
4189 if (kSystemTransitionCapability
== _systemTransitionType
)
4191 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4193 tellClients(kIOMessageSystemHasPoweredOn
);
4194 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
4195 // Re-evaluate clamshell state ourselves when graphics
4196 // will not get kIOMessageSystemHasPoweredOn.
4198 if (clamshellClosed
&&
4199 ((_systemMessageClientMask
& kSystemMessageClientKernel
) == 0))
4201 receivePowerNotification( kLocalEvalClamshellCommand
);
4205 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4206 wranglerTickled
= false;
4209 // Reset state after exiting from dark wake.
4211 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
4212 CAP_LOSS(kIOPMSystemCapabilityCPU
))
4214 darkWakeMaintenance
= false;
4215 darkWakeToSleepASAP
= false;
4216 pciCantSleepValid
= false;
4217 rejectWranglerTickle
= false;
4220 // Entered dark mode.
4222 if (((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
4223 (_pendingCapability
& kIOPMSystemCapabilityCPU
))
4225 if (((gDarkWakeFlags
& kDarkWakeFlagIgnoreDiskIOInDark
) == 0) &&
4226 (kSystemTransitionWake
== _systemTransitionType
) &&
4227 (_debugWakeSeconds
== 0))
4229 OSObject
* prop
= copyProperty(kIOPMRootDomainWakeTypeKey
);
4232 OSString
* wakeType
= OSDynamicCast(OSString
, prop
);
4234 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeNetwork
))
4236 // Woke from network and entered dark wake.
4237 if (darkWakeToSleepASAP
)
4239 DLOG("cleared darkWakeToSleepASAP\n");
4240 darkWakeToSleepASAP
= false;
4247 // Queue an evaluation of whether to remain in dark wake,
4248 // and for how long. This serves the purpose of draining
4249 // any assertions from the queue.
4251 pmPowerStateQueue
->submitPowerEvent(
4252 kPowerEventPolicyStimulus
,
4253 (void *) kStimulusDarkWakeEntry
,
4254 _systemStateGeneration
);
4258 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4259 "dcp %x:%x:%x, dbgtimer %u\n",
4260 currentPowerState
, powerState
, changeFlags
,
4261 _systemTransitionType
, _systemStateGeneration
,
4262 _systemMessageClientMask
,
4263 _desiredCapability
, _currentCapability
, _pendingCapability
,
4266 // Update current system capability.
4268 if (_currentCapability
!= _pendingCapability
)
4269 _currentCapability
= _pendingCapability
;
4271 // Update highest system capability.
4273 if (!CAP_CURRENT(kIOPMSystemCapabilityCPU
))
4274 _highestCapability
= 0; // reset at sleep state
4276 _highestCapability
|= _currentCapability
;
4278 if (darkWakePostTickle
&&
4279 (kSystemTransitionWake
== _systemTransitionType
) &&
4280 (gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
4281 kDarkWakeFlagHIDTickleLate
)
4283 darkWakePostTickle
= false;
4287 // Reset tracepoint at completion of capability change,
4288 // completion of wake transition, and aborted sleep transition.
4290 if ((_systemTransitionType
== kSystemTransitionCapability
) ||
4291 (_systemTransitionType
== kSystemTransitionWake
) ||
4292 ((_systemTransitionType
== kSystemTransitionSleep
) &&
4293 (changeFlags
& kIOPMNotDone
)))
4295 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
4296 tracePoint( kIOPMTracePointSystemUp
, 0 );
4299 _systemTransitionType
= kSystemTransitionNone
;
4300 _systemMessageClientMask
= 0;
4302 logGraphicsClamp
= false;
4306 //******************************************************************************
4307 // PM actions for graphics and audio.
4308 //******************************************************************************
4310 void IOPMrootDomain::overridePowerChangeForUIService(
4311 IOService
* service
,
4312 IOPMActions
* actions
,
4313 unsigned long * inOutPowerState
,
4314 uint32_t * inOutChangeFlags
)
4316 uint32_t powerState
= (uint32_t) *inOutPowerState
;
4317 uint32_t changeFlags
= (uint32_t) *inOutChangeFlags
;
4319 if (kSystemTransitionNone
== _systemTransitionType
)
4321 // Not in midst of a system transition.
4322 // Do not modify power limit enable state.
4324 else if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
4326 // Activate power limiter.
4328 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
4329 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0))
4331 actions
->parameter
|= kPMActionsFlagLimitPower
;
4333 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
4334 ((_pendingCapability
& kIOPMSystemCapabilityAudio
) == 0))
4336 actions
->parameter
|= kPMActionsFlagLimitPower
;
4338 else if ((actions
->parameter
& kPMActionsFlagIsGraphicsDevice
) &&
4339 (_systemTransitionType
== kSystemTransitionSleep
))
4341 // For graphics devices, arm the limiter when entering
4342 // system sleep. Not when dropping to dark wake.
4343 actions
->parameter
|= kPMActionsFlagLimitPower
;
4346 if (actions
->parameter
& kPMActionsFlagLimitPower
)
4348 DLOG("+ plimit %s %p\n",
4349 service
->getName(), service
);
4354 // Remove power limit.
4356 if ((actions
->parameter
& (
4357 kPMActionsFlagIsDisplayWrangler
|
4358 kPMActionsFlagIsGraphicsDevice
)) &&
4359 (_pendingCapability
& kIOPMSystemCapabilityGraphics
))
4361 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
4363 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
4364 (_pendingCapability
& kIOPMSystemCapabilityAudio
))
4366 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
4369 if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
4371 DLOG("- plimit %s %p\n",
4372 service
->getName(), service
);
4376 if (gRAMDiskImageBoot
&&
4377 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
))
4379 // Tag devices subject to power suppression.
4380 *inOutChangeFlags
|= kIOPMPowerSuppressed
;
4383 if (actions
->parameter
& kPMActionsFlagLimitPower
)
4385 uint32_t maxPowerState
= (uint32_t)(-1);
4387 if (changeFlags
& (kIOPMDomainDidChange
| kIOPMDomainWillChange
))
4389 // Enforce limit for system power/cap transitions.
4392 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
4393 (!gRAMDiskImageBoot
|| (service
->getPowerState() > 0)))
4395 // Forces a 3->1 transition sequence
4396 if (changeFlags
& kIOPMDomainWillChange
)
4404 // Deny all self-initiated changes when power is limited.
4405 // Wrangler tickle should never defeat the limiter.
4407 maxPowerState
= service
->getPowerState();
4410 if (powerState
> maxPowerState
)
4412 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
4413 service
->getName(), service
, powerState
, maxPowerState
,
4415 *inOutPowerState
= maxPowerState
;
4417 if (darkWakePostTickle
&&
4418 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
4419 (changeFlags
& kIOPMDomainWillChange
) &&
4420 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
4421 kDarkWakeFlagHIDTickleEarly
))
4423 darkWakePostTickle
= false;
4428 if (!graphicsSuppressed
&& (changeFlags
& kIOPMDomainDidChange
))
4430 if (logGraphicsClamp
)
4435 clock_get_uptime(&now
);
4436 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
4437 absolutetime_to_nanoseconds(now
, &nsec
);
4438 MSG("Graphics suppressed %u ms\n",
4439 ((int)((nsec
) / 1000000ULL)));
4441 graphicsSuppressed
= true;
4446 void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
4447 IOService
* service
,
4448 IOPMActions
* actions
)
4450 // Warning: Not running in PM work loop context - don't modify state !!!
4451 // Trap tickle directed to IODisplayWrangler while running with graphics
4452 // capability suppressed.
4454 assert(service
== wrangler
);
4456 if (service
== wrangler
)
4458 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonIdle
)
4459 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
4461 userActivityCount
++;
4462 DLOG("display wrangler tickled1 %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
4466 if (!wranglerTickled
&& !lowBatteryCondition
&&
4467 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0))
4469 DLOG("display wrangler tickled\n");
4470 if (kIOLogPMRootDomain
& gIOKitDebug
)
4471 OSReportWithBacktrace("Dark wake display tickle");
4472 if (pmPowerStateQueue
)
4474 pmPowerStateQueue
->submitPowerEvent(
4475 kPowerEventPolicyStimulus
,
4476 (void *) kStimulusDarkWakeActivityTickle
);
4481 //******************************************************************************
4482 // Approve usage of delayed child notification by PM.
4483 //******************************************************************************
4485 bool IOPMrootDomain::shouldDelayChildNotification(
4486 IOService
* service
)
4488 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0) &&
4490 (kSystemTransitionWake
== _systemTransitionType
))
4492 DLOG("%s: delay child notify\n", service
->getName());
4498 //******************************************************************************
4499 // PM actions for PCI device.
4500 //******************************************************************************
4502 void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
4503 IOService
* service
,
4504 IOPMActions
* actions
,
4505 uint32_t powerState
,
4506 uint32_t * inOutChangeFlags
)
4508 pmTracer
->tracePCIPowerChange(
4509 PMTraceWorker::kPowerChangeStart
,
4510 service
, *inOutChangeFlags
,
4511 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
4514 void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
4515 IOService
* service
,
4516 IOPMActions
* actions
,
4517 uint32_t powerState
,
4518 uint32_t changeFlags
)
4520 pmTracer
->tracePCIPowerChange(
4521 PMTraceWorker::kPowerChangeCompleted
,
4522 service
, changeFlags
,
4523 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
4526 //******************************************************************************
4529 // Override IOService::registerInterest() to intercept special clients.
4530 //******************************************************************************
4532 IONotifier
* IOPMrootDomain::registerInterest(
4533 const OSSymbol
* typeOfInterest
,
4534 IOServiceInterestHandler handler
,
4535 void * target
, void * ref
)
4537 IONotifier
* notifier
;
4538 bool isSystemCapabilityClient
;
4539 bool isKernelCapabilityClient
;
4541 isSystemCapabilityClient
=
4543 typeOfInterest
->isEqualTo(kIOPMSystemCapabilityInterest
);
4545 isKernelCapabilityClient
=
4547 typeOfInterest
->isEqualTo(gIOPriorityPowerStateInterest
);
4549 if (isSystemCapabilityClient
)
4550 typeOfInterest
= gIOAppPowerStateInterest
;
4552 notifier
= super::registerInterest(typeOfInterest
, handler
, target
, ref
);
4553 if (notifier
&& pmPowerStateQueue
)
4555 if (isSystemCapabilityClient
)
4558 if (pmPowerStateQueue
->submitPowerEvent(
4559 kPowerEventRegisterSystemCapabilityClient
, notifier
) == false)
4560 notifier
->release();
4563 if (isKernelCapabilityClient
)
4566 if (pmPowerStateQueue
->submitPowerEvent(
4567 kPowerEventRegisterKernelCapabilityClient
, notifier
) == false)
4568 notifier
->release();
4575 //******************************************************************************
4576 // systemMessageFilter
4578 //******************************************************************************
4580 bool IOPMrootDomain::systemMessageFilter(
4581 void * object
, void * arg1
, void * arg2
, void * arg3
)
4583 const IOPMInterestContext
* context
= (const IOPMInterestContext
*) arg1
;
4584 bool isCapMsg
= (context
->messageType
== kIOMessageSystemCapabilityChange
);
4585 bool isCapClient
= false;
4589 if ((kSystemTransitionNewCapClient
== _systemTransitionType
) &&
4590 (!isCapMsg
|| !_joinedCapabilityClients
||
4591 !_joinedCapabilityClients
->containsObject((OSObject
*) object
)))
4594 // Capability change message for app and kernel clients.
4598 if ((context
->notifyType
== kNotifyPriority
) ||
4599 (context
->notifyType
== kNotifyCapabilityChangePriority
))
4602 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) &&
4603 (object
== (void *) systemCapabilityNotifier
))
4609 IOPMSystemCapabilityChangeParameters
* capArgs
=
4610 (IOPMSystemCapabilityChangeParameters
*) arg2
;
4612 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
4614 capArgs
->fromCapabilities
= 0;
4615 capArgs
->toCapabilities
= _currentCapability
;
4616 capArgs
->changeFlags
= 0;
4620 capArgs
->fromCapabilities
= _currentCapability
;
4621 capArgs
->toCapabilities
= _pendingCapability
;
4623 if (context
->isPreChange
)
4624 capArgs
->changeFlags
= kIOPMSystemCapabilityWillChange
;
4626 capArgs
->changeFlags
= kIOPMSystemCapabilityDidChange
;
4629 // Capability change messages only go to the PM configd plugin.
4630 // Wait for response post-change if capabilitiy is increasing.
4631 // Wait for response pre-change if capability is decreasing.
4633 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) && arg3
&&
4634 ( (capabilityLoss
&& context
->isPreChange
) ||
4635 (!capabilityLoss
&& !context
->isPreChange
) ) )
4637 // app has not replied yet, wait for it
4638 *((OSObject
**) arg3
) = kOSBooleanFalse
;
4645 // Capability client will always see kIOMessageCanSystemSleep,
4646 // even for demand sleep.
4648 if ((kIOMessageCanSystemSleep
== context
->messageType
) ||
4649 (kIOMessageSystemWillNotSleep
== context
->messageType
))
4651 if (object
== (OSObject
*) systemCapabilityNotifier
)
4657 // Not idle sleep, don't ask apps.
4658 if (context
->changeFlags
& kIOPMSkipAskPowerDown
)
4664 // Reject capability change messages for legacy clients.
4665 // Reject legacy system sleep messages for capability client.
4667 if (isCapMsg
|| (object
== (OSObject
*) systemCapabilityNotifier
))
4672 // Filter system sleep messages.
4674 if ((context
->notifyType
== kNotifyApps
) &&
4675 (_systemMessageClientMask
& kSystemMessageClientApp
))
4679 else if ((context
->notifyType
== kNotifyPriority
) &&
4680 (_systemMessageClientMask
& kSystemMessageClientKernel
))
4687 if (allow
&& isCapMsg
&& _joinedCapabilityClients
)
4689 _joinedCapabilityClients
->removeObject((OSObject
*) object
);
4690 if (_joinedCapabilityClients
->getCount() == 0)
4692 DLOG("destroyed capability client set %p\n",
4693 _joinedCapabilityClients
);
4694 _joinedCapabilityClients
->release();
4695 _joinedCapabilityClients
= 0;
4702 //******************************************************************************
4703 // setMaintenanceWakeCalendar
4705 //******************************************************************************
4707 IOReturn
IOPMrootDomain::setMaintenanceWakeCalendar(
4708 const IOPMCalendarStruct
* calendar
)
4714 return kIOReturnBadArgument
;
4716 data
= OSData::withBytesNoCopy((void *) calendar
, sizeof(*calendar
));
4718 return kIOReturnNoMemory
;
4720 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
, data
);
4727 // MARK: Display Wrangler
4729 //******************************************************************************
4730 // displayWranglerNotification
4732 // Handle the notification when the IODisplayWrangler changes power state.
4733 //******************************************************************************
4735 IOReturn
IOPMrootDomain::displayWranglerNotification(
4736 void * target
, void * refCon
,
4737 UInt32 messageType
, IOService
* service
,
4738 void * messageArgument
, vm_size_t argSize
)
4741 int displayPowerState
;
4742 IOPowerStateChangeNotification
* params
=
4743 (IOPowerStateChangeNotification
*) messageArgument
;
4745 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
4746 (messageType
!= kIOMessageDeviceHasPoweredOn
))
4747 return kIOReturnUnsupported
;
4751 return kIOReturnUnsupported
;
4753 displayPowerState
= params
->stateNumber
;
4754 DLOG("DisplayWrangler message 0x%x, power state %d\n",
4755 (uint32_t) messageType
, displayPowerState
);
4757 switch (messageType
) {
4758 case kIOMessageDeviceWillPowerOff
:
4760 // Display wrangler has dropped power due to display idle
4761 // or force system sleep.
4766 // 1 Not visible to user
4767 // 0 Not visible to user
4769 if (displayPowerState
> 2)
4772 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerSleep
);
4775 case kIOMessageDeviceHasPoweredOn
:
4777 // Display wrangler has powered on due to user activity
4778 // or wake from sleep.
4780 if ( 4 != displayPowerState
)
4783 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerWake
);
4787 return kIOReturnUnsupported
;
4790 //*********************************************************************************
4791 // displayWranglerMatchPublished
4793 // Receives a notification when the IODisplayWrangler is published.
4794 // When it's published we install a power state change handler.
4795 //******************************************************************************
4797 bool IOPMrootDomain::displayWranglerMatchPublished(
4800 IOService
* newService
,
4801 IONotifier
* notifier __unused
)
4804 // found the display wrangler, now install a handler
4805 if( !newService
->registerInterest( gIOGeneralInterest
,
4806 &displayWranglerNotification
, target
, 0) )
4814 //******************************************************************************
4817 //******************************************************************************
4819 void IOPMrootDomain::reportUserInput( void )
4826 iter
= getMatchingServices(serviceMatching("IODisplayWrangler"));
4829 wrangler
= (IOService
*) iter
->getNextObject();
4835 wrangler
->activityTickle(0,0);
4842 //******************************************************************************
4845 // Notification on battery class IOPowerSource appearance
4846 //******************************************************************************
4848 bool IOPMrootDomain::batteryPublished(
4851 IOService
* resourceService
,
4852 IONotifier
* notifier __unused
)
4854 // rdar://2936060&4435589
4855 // All laptops have dimmable LCD displays
4856 // All laptops have batteries
4857 // So if this machine has a battery, publish the fact that the backlight
4858 // supports dimming.
4859 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
4865 // MARK: System PM Policy
4867 //******************************************************************************
4868 // checkSystemCanSleep
4870 //******************************************************************************
4872 bool IOPMrootDomain::checkSystemCanSleep( IOOptionBits options
)
4876 // Conditions that prevent idle and demand system sleep.
4879 if (userDisabledAllSleep
)
4881 err
= 1; // 1. user-space sleep kill switch
4885 if (systemBooting
|| systemShutdown
)
4887 err
= 2; // 2. restart or shutdown in progress
4894 // Conditions above pegs the system at full wake.
4895 // Conditions below prevent system sleep but does not prevent
4896 // dark wake, and must be called from gated context.
4899 err
= 3; // 3. config does not support sleep
4903 if (lowBatteryCondition
)
4905 break; // always sleep on low battery
4908 if (childPreventSystemSleep
)
4910 err
= 4; // 4. child prevent system sleep clamp
4914 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit
) ==
4915 kIOPMDriverAssertionLevelOn
)
4917 err
= 5; // 5. CPU assertion
4921 if (pciCantSleepValid
)
4923 if (pciCantSleepFlag
)
4924 err
= 6; // 6. PCI card does not support PM (cached)
4927 else if (sleepSupportedPEFunction
&&
4928 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
4931 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
4932 ret
= getPlatform()->callPlatformFunction(
4933 sleepSupportedPEFunction
, false,
4934 NULL
, NULL
, NULL
, NULL
);
4935 pciCantSleepValid
= true;
4936 pciCantSleepFlag
= false;
4937 if ((platformSleepSupport
& kPCICantSleep
) ||
4938 ((ret
!= kIOReturnSuccess
) && (ret
!= kIOReturnUnsupported
)))
4940 err
= 6; // 6. PCI card does not support PM
4941 pciCantSleepFlag
= true;
4950 DLOG("System sleep prevented by %d\n", err
);
4956 //******************************************************************************
4959 // Conditions that affect our wake/sleep decision has changed.
4960 // If conditions dictate that the system must remain awake, clamp power
4961 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
4962 // is TRUE, then remove the power clamp and allow the power state to drop
4964 //******************************************************************************
4966 void IOPMrootDomain::adjustPowerState( bool sleepASAP
)
4968 DLOG("adjustPowerState ps %u, asap %d, slider %ld\n",
4969 (uint32_t) getPowerState(), sleepASAP
, sleepSlider
);
4973 if ((sleepSlider
== 0) || !checkSystemCanSleep())
4975 changePowerStateToPriv(ON_STATE
);
4977 else if ( sleepASAP
)
4979 changePowerStateToPriv(SLEEP_STATE
);
4983 //******************************************************************************
4984 // dispatchPowerEvent
4986 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
4987 //******************************************************************************
4989 void IOPMrootDomain::dispatchPowerEvent(
4990 uint32_t event
, void * arg0
, uint64_t arg1
)
4992 DLOG("power event %u args %p 0x%llx\n", event
, arg0
, arg1
);
4997 case kPowerEventFeatureChanged
:
4998 messageClients(kIOPMMessageFeatureChange
, this);
5001 case kPowerEventReceivedPowerNotification
:
5002 handlePowerNotification( (UInt32
)(uintptr_t) arg0
);
5005 case kPowerEventSystemBootCompleted
:
5008 systemBooting
= false;
5010 // If lid is closed, re-send lid closed notification
5011 // now that booting is complete.
5012 if ( clamshellClosed
)
5014 handlePowerNotification(kLocalEvalClamshellCommand
);
5016 evaluatePolicy( kStimulusAllowSystemSleepChanged
);
5020 case kPowerEventSystemShutdown
:
5021 if (kOSBooleanTrue
== (OSBoolean
*) arg0
)
5023 /* We set systemShutdown = true during shutdown
5024 to prevent sleep at unexpected times while loginwindow is trying
5025 to shutdown apps and while the OS is trying to transition to
5028 Set to true during shutdown, as soon as loginwindow shows
5029 the "shutdown countdown dialog", through individual app
5030 termination, and through black screen kernel shutdown.
5032 systemShutdown
= true;
5035 A shutdown was initiated, but then the shutdown
5036 was cancelled, clearing systemShutdown to false here.
5038 systemShutdown
= false;
5042 case kPowerEventUserDisabledSleep
:
5043 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
5046 case kPowerEventRegisterSystemCapabilityClient
:
5047 if (systemCapabilityNotifier
)
5049 systemCapabilityNotifier
->release();
5050 systemCapabilityNotifier
= 0;
5054 systemCapabilityNotifier
= (IONotifier
*) arg0
;
5055 systemCapabilityNotifier
->retain();
5057 /* intentional fall-through */
5059 case kPowerEventRegisterKernelCapabilityClient
:
5060 if (!_joinedCapabilityClients
)
5061 _joinedCapabilityClients
= OSSet::withCapacity(8);
5064 IONotifier
* notify
= (IONotifier
*) arg0
;
5065 if (_joinedCapabilityClients
)
5067 _joinedCapabilityClients
->setObject(notify
);
5068 synchronizePowerTree( kIOPMSyncNoChildNotify
);
5074 case kPowerEventPolicyStimulus
:
5077 int stimulus
= (uintptr_t) arg0
;
5078 evaluatePolicy( stimulus
, (uint32_t) arg1
);
5082 case kPowerEventAssertionCreate
:
5084 pmAssertions
->handleCreateAssertion((OSData
*)arg0
);
5089 case kPowerEventAssertionRelease
:
5091 pmAssertions
->handleReleaseAssertion(arg1
);
5095 case kPowerEventAssertionSetLevel
:
5097 pmAssertions
->handleSetAssertionLevel(arg1
, (IOPMDriverAssertionLevel
)(uintptr_t)arg0
);
5101 case kPowerEventQueueSleepWakeUUID
:
5102 handleQueueSleepWakeUUID((OSObject
*)arg0
);
5104 case kPowerEventPublishSleepWakeUUID
:
5105 handlePublishSleepWakeUUID((bool)arg0
);
5110 //******************************************************************************
5111 // systemPowerEventOccurred
5113 // The power controller is notifying us of a hardware-related power management
5114 // event that we must handle.
5116 // systemPowerEventOccurred covers the same functionality that
5117 // receivePowerNotification does; it simply provides a richer API for conveying
5118 // more information.
5119 //******************************************************************************
5121 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
5122 const OSSymbol
*event
,
5125 IOReturn attempt
= kIOReturnSuccess
;
5126 OSNumber
*newNumber
= NULL
;
5129 return kIOReturnBadArgument
;
5131 newNumber
= OSNumber::withNumber(intValue
, 8*sizeof(intValue
));
5133 return kIOReturnInternalError
;
5135 attempt
= systemPowerEventOccurred(event
, (OSObject
*)newNumber
);
5137 newNumber
->release();
5142 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
5143 const OSSymbol
*event
,
5146 OSDictionary
*thermalsDict
= NULL
;
5147 bool shouldUpdate
= true;
5149 if (!event
|| !value
)
5150 return kIOReturnBadArgument
;
5153 // We reuse featuresDict Lock because it already exists and guards
5154 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
5155 // of stepping on that lock.
5156 if (featuresDictLock
) IOLockLock(featuresDictLock
);
5158 thermalsDict
= (OSDictionary
*)getProperty(kIOPMRootDomainPowerStatusKey
);
5160 if (thermalsDict
&& OSDynamicCast(OSDictionary
, thermalsDict
)) {
5161 thermalsDict
= OSDictionary::withDictionary(thermalsDict
);
5163 thermalsDict
= OSDictionary::withCapacity(1);
5166 if (!thermalsDict
) {
5167 shouldUpdate
= false;
5171 thermalsDict
->setObject (event
, value
);
5173 setProperty (kIOPMRootDomainPowerStatusKey
, thermalsDict
);
5175 thermalsDict
->release();
5179 if (featuresDictLock
) IOLockUnlock(featuresDictLock
);
5182 messageClients (kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
5184 return kIOReturnSuccess
;
5187 //******************************************************************************
5188 // receivePowerNotification
5190 // The power controller is notifying us of a hardware-related power management
5191 // event that we must handle. This may be a result of an 'environment' interrupt
5192 // from the power mgt micro.
5193 //******************************************************************************
5195 IOReturn
IOPMrootDomain::receivePowerNotification( UInt32 msg
)
5197 pmPowerStateQueue
->submitPowerEvent(
5198 kPowerEventReceivedPowerNotification
, (void *) msg
);
5199 return kIOReturnSuccess
;
5202 void IOPMrootDomain::handlePowerNotification( UInt32 msg
)
5204 bool eval_clamshell
= false;
5209 * Local (IOPMrootDomain only) eval clamshell command
5211 if (msg
& kLocalEvalClamshellCommand
)
5213 eval_clamshell
= true;
5219 if (msg
& kIOPMOverTemp
)
5221 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
5222 privateSleepSystem (kIOPMSleepReasonThermalEmergency
);
5228 if (msg
& kIOPMSleepNow
)
5230 privateSleepSystem (kIOPMSleepReasonSoftware
);
5236 if (msg
& kIOPMPowerEmergency
)
5238 lowBatteryCondition
= true;
5239 privateSleepSystem (kIOPMSleepReasonLowPower
);
5245 if (msg
& kIOPMClamshellOpened
)
5247 // Received clamshel open message from clamshell controlling driver
5248 // Update our internal state and tell general interest clients
5249 clamshellClosed
= false;
5250 clamshellExists
= true;
5252 if (msg
& kIOPMSetValue
)
5258 informCPUStateChange(kInformLid
, 0);
5260 // Tell general interest clients
5261 sendClientClamshellNotification();
5263 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonClamshell
)
5264 || (lastSleepReason
== kIOPMSleepReasonIdle
)
5265 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
5266 if (aborting
) userActivityCount
++;
5267 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
5272 * Send the clamshell interest notification since the lid is closing.
5274 if (msg
& kIOPMClamshellClosed
)
5276 // Received clamshel open message from clamshell controlling driver
5277 // Update our internal state and tell general interest clients
5278 clamshellClosed
= true;
5279 clamshellExists
= true;
5282 informCPUStateChange(kInformLid
, 1);
5284 // Tell general interest clients
5285 sendClientClamshellNotification();
5287 // And set eval_clamshell = so we can attempt
5288 eval_clamshell
= true;
5292 * Set Desktop mode (sent from graphics)
5294 * -> reevaluate lid state
5296 if (msg
& kIOPMSetDesktopMode
)
5298 desktopMode
= (0 != (msg
& kIOPMSetValue
));
5299 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
5301 sendClientClamshellNotification();
5303 // Re-evaluate the lid state
5304 if( clamshellClosed
)
5306 eval_clamshell
= true;
5311 * AC Adaptor connected
5313 * -> reevaluate lid state
5315 if (msg
& kIOPMSetACAdaptorConnected
)
5317 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
5318 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
5321 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
5323 // Tell BSD if AC is connected
5324 // 0 == external power source; 1 == on battery
5325 post_sys_powersource(acAdaptorConnected
? 0:1);
5327 sendClientClamshellNotification();
5329 // Re-evaluate the lid state
5330 if( clamshellClosed
)
5332 eval_clamshell
= true;
5337 * Enable Clamshell (external display disappear)
5339 * -> reevaluate lid state
5341 if (msg
& kIOPMEnableClamshell
)
5343 // Re-evaluate the lid state
5344 // System should sleep on external display disappearance
5345 // in lid closed operation.
5346 if( clamshellClosed
&& (true == clamshellDisabled
) )
5348 eval_clamshell
= true;
5351 clamshellDisabled
= false;
5353 sendClientClamshellNotification();
5357 * Disable Clamshell (external display appeared)
5358 * We don't bother re-evaluating clamshell state. If the system is awake,
5359 * the lid is probably open.
5361 if (msg
& kIOPMDisableClamshell
)
5363 clamshellDisabled
= true;
5365 sendClientClamshellNotification();
5369 * Evaluate clamshell and SLEEP if appropiate
5371 if ( eval_clamshell
&& shouldSleepOnClamshellClosed() )
5376 privateSleepSystem (kIOPMSleepReasonClamshell
);
5378 else if ( eval_clamshell
)
5380 evaluatePolicy(kStimulusDarkWakeEvaluate
);
5386 if (msg
& kIOPMPowerButton
)
5388 if (!wranglerAsleep
)
5390 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
5391 // Check that power button sleep is enabled
5393 if( kOSBooleanTrue
!= getProperty(pbs
))
5394 privateSleepSystem (kIOPMSleepReasonPowerButton
);
5402 //******************************************************************************
5405 // Evaluate root-domain policy in response to external changes.
5406 //******************************************************************************
5408 void IOPMrootDomain::evaluatePolicy( int stimulus
, uint32_t arg
)
5412 int idleSleepEnabled
: 1;
5413 int idleSleepDisabled
: 1;
5414 int displaySleep
: 1;
5415 int sleepDelayChanged
: 1;
5416 int evaluateDarkWake
: 1;
5421 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
5428 case kStimulusDisplayWranglerSleep
:
5429 if (!wranglerAsleep
)
5431 wranglerAsleep
= true;
5432 clock_get_uptime(&wranglerSleepTime
);
5433 flags
.bit
.displaySleep
= true;
5437 case kStimulusDisplayWranglerWake
:
5438 wranglerAsleep
= false;
5439 flags
.bit
.idleSleepDisabled
= true;
5442 case kStimulusAggressivenessChanged
:
5444 unsigned long minutesToIdleSleep
= 0;
5445 unsigned long minutesToDisplayDim
= 0;
5446 unsigned long minutesDelta
= 0;
5448 // Fetch latest display and system sleep slider values.
5449 getAggressiveness(kPMMinutesToSleep
, &minutesToIdleSleep
);
5450 getAggressiveness(kPMMinutesToDim
, &minutesToDisplayDim
);
5451 DLOG("aggressiveness changed: system %u->%u, display %u\n",
5452 (uint32_t) sleepSlider
,
5453 (uint32_t) minutesToIdleSleep
,
5454 (uint32_t) minutesToDisplayDim
);
5456 DLOG("idle time -> %ld secs (ena %d)\n",
5457 idleSeconds
, (minutesToIdleSleep
!= 0));
5459 if (0x7fffffff == minutesToIdleSleep
)
5460 minutesToIdleSleep
= idleSeconds
;
5462 // How long to wait before sleeping the system once
5463 // the displays turns off is indicated by 'extraSleepDelay'.
5465 if ( minutesToIdleSleep
> minutesToDisplayDim
)
5466 minutesDelta
= minutesToIdleSleep
- minutesToDisplayDim
;
5468 if ((sleepSlider
== 0) && (minutesToIdleSleep
!= 0))
5469 flags
.bit
.idleSleepEnabled
= true;
5471 if ((sleepSlider
!= 0) && (minutesToIdleSleep
== 0))
5472 flags
.bit
.idleSleepDisabled
= true;
5474 if ((minutesDelta
!= extraSleepDelay
) &&
5475 !flags
.bit
.idleSleepEnabled
&& !flags
.bit
.idleSleepDisabled
)
5476 flags
.bit
.sleepDelayChanged
= true;
5478 if (systemDarkWake
&& !darkWakeToSleepASAP
&&
5479 (flags
.bit
.idleSleepEnabled
|| flags
.bit
.idleSleepDisabled
))
5481 // Reconsider decision to remain in dark wake
5482 flags
.bit
.evaluateDarkWake
= true;
5485 sleepSlider
= minutesToIdleSleep
;
5486 extraSleepDelay
= minutesDelta
;
5489 case kStimulusDemandSystemSleep
:
5490 changePowerStateWithOverrideTo( SLEEP_STATE
);
5493 case kStimulusAllowSystemSleepChanged
:
5494 // FIXME: de-compose to change flags.
5498 case kStimulusDarkWakeActivityTickle
:
5499 if (false == wranglerTickled
)
5501 uint32_t options
= 0;
5502 IOService
* pciRoot
= 0;
5504 if (rejectWranglerTickle
)
5506 DLOG("rejected tickle, type %u capability %x:%x\n",
5507 _systemTransitionType
,
5508 _currentCapability
, _pendingCapability
);
5512 _desiredCapability
|=
5513 (kIOPMSystemCapabilityGraphics
|
5514 kIOPMSystemCapabilityAudio
);
5516 if ((kSystemTransitionWake
== _systemTransitionType
) &&
5517 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
5518 !graphicsSuppressed
)
5520 DLOG("Promoting to full wake\n");
5522 // Elevate to full wake while waking up to dark wake.
5523 // PM will hold off notifying the graphics subsystem about
5524 // system wake as late as possible, so if a HID event does
5525 // arrive, we can turn on graphics on this wake cycle, and
5526 // not have to wait till the following cycle. That latency
5527 // can be huge on some systems. However, once any graphics
5528 // suppression has taken effect, it is too late. All other
5529 // graphics devices must be similarly suppressed. But the
5530 // delay till the following cycle should be very short.
5532 _pendingCapability
|=
5533 (kIOPMSystemCapabilityGraphics
|
5534 kIOPMSystemCapabilityAudio
);
5536 // Immediately bring up audio and graphics.
5537 pciRoot
= pciHostBridgeDriver
;
5539 // Notify clients about full wake.
5540 _systemMessageClientMask
= kSystemMessageClientAll
;
5541 tellClients(kIOMessageSystemWillPowerOn
);
5544 // Unsafe to cancel once graphics was powered.
5545 // If system woke from dark wake, the return to sleep can
5546 // be cancelled. But "awake -> dark -> sleep" transition
5547 // cannot be cancelled.
5549 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
)) {
5550 options
|= kIOPMSyncCancelPowerDown
;
5553 synchronizePowerTree( options
, pciRoot
);
5554 wranglerTickled
= true;
5555 // IOGraphics doesn't lit the display even though graphics
5556 // is enanbled in kIOMessageSystemCapabilityChange message(radar 9502104)
5557 // So, do an explicit activity tickle
5559 wrangler
->activityTickle(0,0);
5561 if (logWranglerTickle
)
5566 clock_get_uptime(&now
);
5567 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
5568 absolutetime_to_nanoseconds(now
, &nsec
);
5569 MSG("HID tickle %u ms\n",
5570 ((int)((nsec
) / 1000000ULL)));
5571 logWranglerTickle
= false;
5576 case kStimulusDarkWakeEntry
:
5577 case kStimulusDarkWakeReentry
:
5578 // Any system transitions since the last dark wake transition
5579 // will invalid the stimulus.
5581 if (arg
== _systemStateGeneration
)
5583 DLOG("dark wake entry\n");
5584 systemDarkWake
= true;
5585 wranglerAsleep
= true;
5586 clock_get_uptime(&wranglerSleepTime
);
5588 // Always accelerate disk spindown while in dark wake,
5589 // even if system does not support/allow sleep.
5591 cancelIdleSleepTimer();
5592 setQuickSpinDownTimeout();
5593 flags
.bit
.evaluateDarkWake
= true;
5597 case kStimulusDarkWakeEvaluate
:
5600 flags
.bit
.evaluateDarkWake
= true;
5602 #if !DARK_TO_FULL_EVALUATE_CLAMSHELL
5605 // Not through kLocalEvalClamshellCommand to avoid loop.
5606 if (clamshellClosed
&& shouldSleepOnClamshellClosed() &&
5607 checkSystemCanSleep(true))
5609 privateSleepSystem( kIOPMSleepReasonClamshell
);
5615 } /* switch(stimulus) */
5617 if (flags
.bit
.evaluateDarkWake
&& !wranglerTickled
)
5619 if (darkWakeToSleepASAP
||
5620 (clamshellClosed
&& !(desktopMode
&& acAdaptorConnected
)))
5622 // System currently in dark wake, and no children and
5623 // assertion prevent system sleep.
5625 if (checkSystemCanSleep(true))
5627 if (lowBatteryCondition
)
5629 lastSleepReason
= kIOPMSleepReasonLowPower
;
5630 setProperty(kRootDomainSleepReasonKey
, kIOPMLowPowerSleepKey
);
5632 else if (darkWakeMaintenance
)
5634 lastSleepReason
= kIOPMSleepReasonMaintenance
;
5635 setProperty(kRootDomainSleepReasonKey
, kIOPMMaintenanceSleepKey
);
5637 changePowerStateWithOverrideTo( SLEEP_STATE
);
5641 // Parked in dark wake, a tickle will return to full wake
5642 rejectWranglerTickle
= false;
5644 } else // non-maintenance (network) dark wake
5646 if (checkSystemCanSleep(true))
5648 // Release power clamp, and wait for children idle.
5649 adjustPowerState(true);
5653 changePowerStateToPriv(ON_STATE
);
5655 rejectWranglerTickle
= false;
5661 // The rest are irrelevant while system is in dark wake.
5665 if (flags
.bit
.displaySleep
|| flags
.bit
.sleepDelayChanged
)
5667 bool cancelQuickSpindown
= false;
5669 if (flags
.bit
.sleepDelayChanged
)
5671 DLOG("extra sleep timer changed\n");
5672 cancelIdleSleepTimer();
5673 cancelQuickSpindown
= true;
5677 DLOG("display sleep\n");
5680 if (wranglerAsleep
&& !wranglerSleepIgnored
)
5682 if ( extraSleepDelay
)
5684 // Start a timer here if the System Sleep timer is greater
5685 // than the Display Sleep timer.
5687 startIdleSleepTimer(gRootDomain
->extraSleepDelay
* 60);
5689 else if ( sleepSlider
)
5691 // Accelerate disk spindown if system sleep and display sleep
5692 // sliders are set to the same value (e.g. both set to 5 min),
5693 // and display is about to go dark. Check the system sleep is
5694 // not set to never sleep. Disk sleep setting is ignored.
5696 setQuickSpinDownTimeout();
5697 cancelQuickSpindown
= false;
5701 if (cancelQuickSpindown
)
5702 restoreUserSpinDownTimeout();
5705 if (flags
.bit
.idleSleepEnabled
)
5707 DLOG("idle sleep timer enabled\n");
5710 changePowerStateToPriv(ON_STATE
);
5713 startIdleSleepTimer( idleSeconds
);
5718 // Start idle sleep timer if wrangler went to sleep
5719 // while system sleep was disabled. Disk spindown is
5720 // accelerated upon timer expiration.
5726 uint32_t minutesSinceDisplaySleep
= 0;
5727 uint32_t sleepDelay
;
5729 clock_get_uptime(&now
);
5730 if (CMP_ABSOLUTETIME(&now
, &wranglerSleepTime
) > 0)
5732 SUB_ABSOLUTETIME(&now
, &wranglerSleepTime
);
5733 absolutetime_to_nanoseconds(now
, &nanos
);
5734 minutesSinceDisplaySleep
= nanos
/ (60000000000ULL);
5737 if (extraSleepDelay
> minutesSinceDisplaySleep
)
5739 sleepDelay
= extraSleepDelay
- minutesSinceDisplaySleep
;
5743 sleepDelay
= 1; // 1 min
5746 startIdleSleepTimer(sleepDelay
* 60);
5747 DLOG("display slept %u min, set idle timer to %u min\n",
5748 minutesSinceDisplaySleep
, sleepDelay
);
5753 if (flags
.bit
.idleSleepDisabled
)
5755 DLOG("idle sleep timer disabled\n");
5756 cancelIdleSleepTimer();
5757 restoreUserSpinDownTimeout();
5765 //******************************************************************************
5768 //******************************************************************************
5770 void IOPMrootDomain::pmStatsRecordEvent(
5772 AbsoluteTime timestamp
)
5774 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
5775 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
5779 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
5781 absolutetime_to_nanoseconds(timestamp
, &nsec
);
5783 switch (eventIndex
) {
5784 case kIOPMStatsHibernateImageWrite
:
5786 pmStats
.hibWrite
.start
= nsec
;
5788 pmStats
.hibWrite
.stop
= nsec
;
5791 delta
= pmStats
.hibWrite
.stop
- pmStats
.hibWrite
.start
;
5792 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/1000000ULL);
5795 case kIOPMStatsHibernateImageRead
:
5797 pmStats
.hibRead
.start
= nsec
;
5799 pmStats
.hibRead
.stop
= nsec
;
5802 delta
= pmStats
.hibRead
.stop
- pmStats
.hibRead
.start
;
5803 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/1000000ULL);
5810 * Appends a record of the application response to
5811 * IOPMrootDomain::pmStatsAppResponses
5813 void IOPMrootDomain::pmStatsRecordApplicationResponse(
5814 const OSSymbol
*response
,
5820 OSDictionary
*responseDescription
= NULL
;
5821 OSNumber
*delayNum
= NULL
;
5822 OSNumber
*pidNum
= NULL
;
5823 OSNumber
*msgNum
= NULL
;
5824 const OSSymbol
*appname
;
5825 const OSSymbol
*entryName
;
5826 OSObject
*entryType
;
5829 if (!pmStatsAppResponses
|| pmStatsAppResponses
->getCount() > 50)
5833 while ((responseDescription
= (OSDictionary
*) pmStatsAppResponses
->getObject(i
++)))
5835 entryType
= responseDescription
->getObject(_statsResponseTypeKey
);
5836 entryName
= (OSSymbol
*) responseDescription
->getObject(_statsNameKey
);
5837 if (entryName
&& (entryType
== response
) && entryName
->isEqualTo(name
))
5839 OSNumber
* entryValue
;
5840 entryValue
= (OSNumber
*) responseDescription
->getObject(_statsTimeMSKey
);
5841 if (entryValue
&& (entryValue
->unsigned32BitValue() < delay_ms
))
5842 entryValue
->setValue(delay_ms
);
5847 responseDescription
= OSDictionary::withCapacity(5);
5848 if (responseDescription
)
5851 responseDescription
->setObject(_statsResponseTypeKey
, response
);
5854 if (messageType
!= 0) {
5855 msgNum
= OSNumber::withNumber(messageType
, 32);
5857 responseDescription
->setObject(_statsMessageTypeKey
, msgNum
);
5862 if (name
&& (strlen(name
) > 0))
5864 appname
= OSSymbol::withCString(name
);
5866 responseDescription
->setObject(_statsNameKey
, appname
);
5871 if (app_pid
!= -1) {
5872 pidNum
= OSNumber::withNumber(app_pid
, 32);
5874 responseDescription
->setObject(_statsPIDKey
, pidNum
);
5879 delayNum
= OSNumber::withNumber(delay_ms
, 32);
5881 responseDescription
->setObject(_statsTimeMSKey
, delayNum
);
5882 delayNum
->release();
5885 if (pmStatsAppResponses
) {
5886 pmStatsAppResponses
->setObject(responseDescription
);
5889 responseDescription
->release();
5895 // MARK: PMTraceWorker
5897 //******************************************************************************
5898 // TracePoint support
5900 //******************************************************************************
5902 #define kIOPMRegisterNVRAMTracePointHandlerKey \
5903 "IOPMRegisterNVRAMTracePointHandler"
5905 IOReturn
IOPMrootDomain::callPlatformFunction(
5906 const OSSymbol
* functionName
,
5907 bool waitForFunction
,
5908 void * param1
, void * param2
,
5909 void * param3
, void * param4
)
5911 if (pmTracer
&& functionName
&&
5912 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
5913 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
)
5915 uint32_t tracePointPhases
, tracePointPCI
;
5916 uint64_t statusCode
;
5918 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
5919 pmTracer
->tracePointTarget
= (void *) param2
;
5920 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
5921 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
5922 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
5923 if ((tracePointPhases
>> 24) != kIOPMTracePointSystemUp
)
5925 MSG("Sleep failure code 0x%08x 0x%08x\n",
5926 tracePointPCI
, tracePointPhases
);
5928 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
5929 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
5931 return kIOReturnSuccess
;
5934 return super::callPlatformFunction(
5935 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
5938 void IOPMrootDomain::tracePoint( uint8_t point
)
5941 pmTracer
->tracePoint(point
);
5944 void IOPMrootDomain::tracePoint( uint8_t point
, uint8_t data
)
5947 pmTracer
->tracePoint(point
, data
);
5950 void IOPMrootDomain::traceDetail( uint32_t detail
)
5953 pmTracer
->traceDetail( detail
);
5956 //******************************************************************************
5957 // PMTraceWorker Class
5959 //******************************************************************************
5962 #define super OSObject
5963 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
5965 #define kPMBestGuessPCIDevicesCount 25
5966 #define kPMMaxRTCBitfieldSize 32
5968 PMTraceWorker
*PMTraceWorker::tracer(IOPMrootDomain
*owner
)
5972 me
= OSTypeAlloc( PMTraceWorker
);
5973 if (!me
|| !me
->init())
5978 DLOG("PMTraceWorker %p\n", me
);
5980 // Note that we cannot instantiate the PCI device -> bit mappings here, since
5981 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
5982 // this dictionary lazily.
5984 me
->pciDeviceBitMappings
= NULL
;
5985 me
->pciMappingLock
= IOLockAlloc();
5986 me
->tracePhase
= kIOPMTracePointSystemUp
;
5987 me
->loginWindowPhase
= 0;
5988 me
->traceData32
= 0;
5992 void PMTraceWorker::RTC_TRACE(void)
5994 if (tracePointHandler
&& tracePointTarget
)
5998 wordA
= (tracePhase
<< 24) | (loginWindowPhase
<< 16) |
6001 tracePointHandler( tracePointTarget
, traceData32
, wordA
);
6002 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32
, wordA
);
6006 int PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
6008 const OSSymbol
* deviceName
;
6011 IOLockLock(pciMappingLock
);
6013 if (!pciDeviceBitMappings
)
6015 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
6016 if (!pciDeviceBitMappings
)
6020 // Check for bitmask overflow.
6021 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
)
6024 if ((deviceName
= pciDevice
->copyName()) &&
6025 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
, 0) == (unsigned int)-1) &&
6026 pciDeviceBitMappings
->setObject(deviceName
))
6028 index
= pciDeviceBitMappings
->getCount() - 1;
6029 _LOG("PMTrace PCI array: set object %s => %d\n",
6030 deviceName
->getCStringNoCopy(), index
);
6033 deviceName
->release();
6034 if (!addedToRegistry
&& (index
>= 0))
6035 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
6038 IOLockUnlock(pciMappingLock
);
6042 bool PMTraceWorker::serialize(OSSerialize
*s
) const
6045 if (pciDeviceBitMappings
)
6047 IOLockLock(pciMappingLock
);
6048 ok
= pciDeviceBitMappings
->serialize(s
);
6049 IOLockUnlock(pciMappingLock
);
6054 void PMTraceWorker::tracePoint(uint8_t phase
)
6056 // clear trace detail when phase begins
6057 if (tracePhase
!= phase
)
6062 DLOG("trace point 0x%02x\n", tracePhase
);
6066 void PMTraceWorker::tracePoint(uint8_t phase
, uint8_t data8
)
6068 // clear trace detail when phase begins
6069 if (tracePhase
!= phase
)
6075 DLOG("trace point 0x%02x 0x%02x\n", tracePhase
, traceData8
);
6079 void PMTraceWorker::traceDetail(uint32_t detail
)
6081 if (kIOPMTracePointSleepPriorityClients
!= tracePhase
)
6084 traceData32
= detail
;
6085 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
6090 void PMTraceWorker::traceLoginWindowPhase(uint8_t phase
)
6092 loginWindowPhase
= phase
;
6094 DLOG("loginwindow tracepoint 0x%02x\n", loginWindowPhase
);
6098 void PMTraceWorker::tracePCIPowerChange(
6099 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
6102 uint32_t expectedFlag
;
6104 // Ignore PCI changes outside of system sleep/wake.
6105 if ((kIOPMTracePointSleepPowerPlaneDrivers
!= tracePhase
) &&
6106 (kIOPMTracePointWakePowerPlaneDrivers
!= tracePhase
))
6109 // Only record the WillChange transition when going to sleep,
6110 // and the DidChange on the way up.
6111 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
6112 expectedFlag
= (kIOPMTracePointSleepPowerPlaneDrivers
== tracePhase
) ?
6113 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
6114 if (changeFlags
!= expectedFlag
)
6117 // Mark this device off in our bitfield
6118 if (bitNum
< kPMMaxRTCBitfieldSize
)
6120 bitMask
= (1 << bitNum
);
6122 if (kPowerChangeStart
== type
)
6124 traceData32
|= bitMask
;
6125 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
6126 service
->getName(), bitNum
, bitMask
, traceData32
);
6130 traceData32
&= ~bitMask
;
6131 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
6132 service
->getName(), bitNum
, bitMask
, traceData32
);
6140 // MARK: PMHaltWorker
6142 //******************************************************************************
6143 // PMHaltWorker Class
6145 //******************************************************************************
6147 static unsigned int gPMHaltBusyCount
;
6148 static unsigned int gPMHaltIdleCount
;
6149 static int gPMHaltDepth
;
6150 static unsigned long gPMHaltEvent
;
6151 static IOLock
* gPMHaltLock
= 0;
6152 static OSArray
* gPMHaltArray
= 0;
6153 static const OSSymbol
* gPMHaltClientAcknowledgeKey
= 0;
6155 PMHaltWorker
* PMHaltWorker::worker( void )
6161 me
= OSTypeAlloc( PMHaltWorker
);
6162 if (!me
|| !me
->init())
6165 me
->lock
= IOLockAlloc();
6169 DLOG("PMHaltWorker %p\n", me
);
6170 me
->retain(); // thread holds extra retain
6171 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
))
6176 thread_deallocate(thread
);
6181 if (me
) me
->release();
6185 void PMHaltWorker::free( void )
6187 DLOG("PMHaltWorker free %p\n", this);
6193 return OSObject::free();
6196 void PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
6198 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
6200 IOLockLock( gPMHaltLock
);
6202 me
->depth
= gPMHaltDepth
;
6203 IOLockUnlock( gPMHaltLock
);
6205 while (me
->depth
>= 0)
6207 PMHaltWorker::work( me
);
6209 IOLockLock( gPMHaltLock
);
6210 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
)
6212 // This is the last thread to finish work on this level,
6213 // inform everyone to start working on next lower level.
6215 me
->depth
= gPMHaltDepth
;
6216 gPMHaltIdleCount
= 0;
6217 thread_wakeup((event_t
) &gPMHaltIdleCount
);
6221 // One or more threads are still working on this level,
6222 // this thread must wait.
6223 me
->depth
= gPMHaltDepth
- 1;
6225 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
6226 } while (me
->depth
!= gPMHaltDepth
);
6228 IOLockUnlock( gPMHaltLock
);
6231 // No more work to do, terminate thread
6232 DLOG("All done for worker: %p (visits = %u)\n", me
, me
->visits
);
6233 thread_wakeup( &gPMHaltDepth
);
6237 void PMHaltWorker::work( PMHaltWorker
* me
)
6239 IOService
* service
;
6241 AbsoluteTime startTime
;
6250 // Claim an unit of work from the shared pool
6251 IOLockLock( gPMHaltLock
);
6252 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
6255 service
= (IOService
*)inner
->getAnyObject();
6259 inner
->removeObject(service
);
6262 IOLockUnlock( gPMHaltLock
);
6264 break; // no more work at this depth
6266 clock_get_uptime(&startTime
);
6268 if (!service
->isInactive() &&
6269 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
))
6271 IOLockLock(me
->lock
);
6272 me
->startTime
= startTime
;
6273 me
->service
= service
;
6274 me
->timeout
= false;
6275 IOLockUnlock(me
->lock
);
6277 service
->systemWillShutdown( gPMHaltEvent
);
6279 // Wait for driver acknowledgement
6280 IOLockLock(me
->lock
);
6281 while (service
->getProperty(gPMHaltClientAcknowledgeKey
))
6283 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
6286 timeout
= me
->timeout
;
6287 IOLockUnlock(me
->lock
);
6290 deltaTime
= computeDeltaTimeMS(&startTime
);
6291 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
||
6292 (gIOKitDebug
& kIOLogPMRootDomain
))
6294 LOG("%s driver %s (%p) took %u ms\n",
6295 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
6296 "PowerOff" : "Restart",
6297 service
->getName(), service
,
6298 (uint32_t) deltaTime
);
6306 void PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
6309 AbsoluteTime startTime
;
6310 AbsoluteTime endTime
;
6314 IOLockLock(me
->lock
);
6315 if (me
->service
&& !me
->timeout
)
6317 startTime
= me
->startTime
;
6319 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
6321 SUB_ABSOLUTETIME(&endTime
, &startTime
);
6322 absolutetime_to_nanoseconds(endTime
, &nano
);
6324 if (nano
> 3000000000ULL)
6327 MSG("%s still waiting on %s\n",
6328 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
6329 "PowerOff" : "Restart",
6330 me
->service
->getName());
6333 IOLockUnlock(me
->lock
);
6337 //******************************************************************************
6338 // acknowledgeSystemWillShutdown
6340 // Acknowledgement from drivers that they have prepared for shutdown/restart.
6341 //******************************************************************************
6343 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
6345 PMHaltWorker
* worker
;
6351 //DLOG("%s acknowledged\n", from->getName());
6352 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
6355 worker
= (PMHaltWorker
*) prop
;
6356 IOLockLock(worker
->lock
);
6357 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
6358 thread_wakeup((event_t
) worker
);
6359 IOLockUnlock(worker
->lock
);
6364 DLOG("%s acknowledged without worker property\n",
6370 //******************************************************************************
6371 // notifySystemShutdown
6373 // Notify all objects in PM tree that system will shutdown or restart
6374 //******************************************************************************
6377 notifySystemShutdown( IOService
* root
, unsigned long event
)
6379 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
6380 IORegistryIterator
* iter
;
6381 IORegistryEntry
* entry
;
6384 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
6385 AbsoluteTime deadline
;
6386 unsigned int totalNodes
= 0;
6388 unsigned int rootDepth
;
6389 unsigned int numWorkers
;
6395 DLOG("%s event = %lx\n", __FUNCTION__
, event
);
6397 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
6399 // Iterate the entire PM tree starting from root
6401 rootDepth
= root
->getDepth( gIOPowerPlane
);
6402 if (!rootDepth
) goto done
;
6404 // debug - for repeated test runs
6405 while (PMHaltWorker::metaClass
->getInstanceCount())
6410 gPMHaltArray
= OSArray::withCapacity(40);
6411 if (!gPMHaltArray
) goto done
;
6414 gPMHaltArray
->flushCollection();
6418 gPMHaltLock
= IOLockAlloc();
6419 if (!gPMHaltLock
) goto done
;
6422 if (!gPMHaltClientAcknowledgeKey
)
6424 gPMHaltClientAcknowledgeKey
=
6425 OSSymbol::withCStringNoCopy("PMShutdown");
6426 if (!gPMHaltClientAcknowledgeKey
) goto done
;
6429 gPMHaltEvent
= event
;
6431 // Depth-first walk of PM plane
6433 iter
= IORegistryIterator::iterateOver(
6434 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
6438 while ((entry
= iter
->getNextObject()))
6440 node
= OSDynamicCast(IOService
, entry
);
6445 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
))
6448 depth
= node
->getDepth( gIOPowerPlane
);
6449 if (depth
<= rootDepth
)
6454 // adjust to zero based depth
6455 depth
-= (rootDepth
+ 1);
6457 // gPMHaltArray is an array of containers, each container
6458 // refers to nodes with the same depth.
6460 count
= gPMHaltArray
->getCount();
6461 while (depth
>= count
)
6463 // expand array and insert placeholders
6464 gPMHaltArray
->setObject(PLACEHOLDER
);
6467 count
= gPMHaltArray
->getCount();
6470 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
6471 if (inner
== PLACEHOLDER
)
6473 inner
= OSSet::withCapacity(40);
6476 gPMHaltArray
->replaceObject(depth
, inner
);
6481 // PM nodes that appear more than once in the tree will have
6482 // the same depth, OSSet will refuse to add the node twice.
6484 ok
= inner
->setObject(node
);
6487 DLOG("Skipped PM node %s\n", node
->getName());
6493 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++)
6496 if (inner
!= PLACEHOLDER
)
6497 count
= inner
->getCount();
6498 DLOG("Nodes at depth %u = %u\n", i
, count
);
6501 // strip placeholders (not all depths are populated)
6503 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); )
6505 if (inner
== PLACEHOLDER
)
6507 gPMHaltArray
->removeObject(i
);
6510 count
= inner
->getCount();
6511 if (count
> numWorkers
)
6513 totalNodes
+= count
;
6517 if (gPMHaltArray
->getCount() == 0 || !numWorkers
)
6520 gPMHaltBusyCount
= 0;
6521 gPMHaltIdleCount
= 0;
6522 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
6524 // Create multiple workers (and threads)
6526 if (numWorkers
> kPMHaltMaxWorkers
)
6527 numWorkers
= kPMHaltMaxWorkers
;
6529 DLOG("PM nodes = %u, maxDepth = %u, workers = %u\n",
6530 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
6532 for (unsigned int i
= 0; i
< numWorkers
; i
++)
6533 workers
[i
] = PMHaltWorker::worker();
6535 // Wait for workers to exhaust all available work
6537 IOLockLock(gPMHaltLock
);
6538 while (gPMHaltDepth
>= 0)
6540 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
6542 waitResult
= IOLockSleepDeadline(
6543 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
6544 if (THREAD_TIMED_OUT
== waitResult
)
6547 clock_get_uptime(&now
);
6549 IOLockUnlock(gPMHaltLock
);
6550 for (unsigned int i
= 0 ; i
< numWorkers
; i
++)
6553 PMHaltWorker::checkTimeout(workers
[i
], &now
);
6555 IOLockLock(gPMHaltLock
);
6558 IOLockUnlock(gPMHaltLock
);
6560 // Release all workers
6562 for (unsigned int i
= 0; i
< numWorkers
; i
++)
6565 workers
[i
]->release();
6566 // worker also retained by it's own thread
6570 DLOG("%s done\n", __FUNCTION__
);
6574 //*********************************************************************************
6575 // Sleep/Wake logging
6577 //*********************************************************************************
6579 IOMemoryDescriptor
*IOPMrootDomain::getPMTraceMemoryDescriptor(void)
6582 return timeline
->getPMTraceMemoryDescriptor();
6587 // Forwards external reports of detailed events to IOPMTimeline
6588 IOReturn
IOPMrootDomain::recordPMEvent(PMEventDetails
*details
)
6590 if (timeline
&& details
) {
6594 // Record a detailed driver power change event, or...
6595 if(details
->eventClassifier
== kIOPMEventClassDriverEvent
) {
6596 rc
= timeline
->recordDetailedPowerEvent( details
);
6599 // Record a system power management event
6600 else if(details
->eventClassifier
== kIOPMEventClassSystemEvent
) {
6601 rc
= timeline
->recordSystemPowerEvent( details
);
6604 return kIOReturnBadArgument
;
6607 // If we get to record this message, then we've reached the
6608 // end of another successful Sleep --> Wake cycle
6609 // At this point, we pat ourselves in the back and allow
6610 // our Sleep --> Wake UUID to be published
6611 if(details
->eventType
== kIOPMEventTypeWakeDone
) {
6612 timeline
->setSleepCycleInProgressFlag(false);
6616 // Check if its time to clear the timeline buffer
6617 if(getProperty(kIOPMSleepWakeUUIDKey)
6618 && timeline->isSleepCycleInProgress() == false
6619 && timeline->getNumEventsLoggedThisPeriod() > 500) {
6621 // Clear the old UUID
6622 if(pmPowerStateQueue) {
6623 pmPowerStateQueue->submitPowerEvent(kPowerEventPublishSleepWakeUUID, (void *)false );
6630 return kIOReturnNotReady
;
6633 IOReturn
IOPMrootDomain::recordAndReleasePMEvent(PMEventDetails
*details
)
6635 IOReturn ret
= kIOReturnBadArgument
;
6639 ret
= recordPMEvent(details
);
6646 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6648 IOPMDriverAssertionID
IOPMrootDomain::createPMAssertion(
6649 IOPMDriverAssertionType whichAssertionBits
,
6650 IOPMDriverAssertionLevel assertionLevel
,
6651 IOService
*ownerService
,
6652 const char *ownerDescription
)
6655 IOPMDriverAssertionID newAssertion
;
6660 ret
= pmAssertions
->createAssertion(whichAssertionBits
, assertionLevel
, ownerService
, ownerDescription
, &newAssertion
);
6662 if (kIOReturnSuccess
== ret
)
6663 return newAssertion
;
6668 IOReturn
IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion
)
6671 return kIOReturnInternalError
;
6673 return pmAssertions
->releaseAssertion(releaseAssertion
);
6676 IOReturn
IOPMrootDomain::setPMAssertionLevel(
6677 IOPMDriverAssertionID assertionID
,
6678 IOPMDriverAssertionLevel assertionLevel
)
6680 return pmAssertions
->setAssertionLevel(assertionID
, assertionLevel
);
6683 IOPMDriverAssertionLevel
IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion
)
6685 IOPMDriverAssertionType sysLevels
;
6687 if (!pmAssertions
|| whichAssertion
== 0)
6688 return kIOPMDriverAssertionLevelOff
;
6690 sysLevels
= pmAssertions
->getActivatedAssertions();
6692 // Check that every bit set in argument 'whichAssertion' is asserted
6693 // in the aggregate bits.
6694 if ((sysLevels
& whichAssertion
) == whichAssertion
)
6695 return kIOPMDriverAssertionLevelOn
;
6697 return kIOPMDriverAssertionLevelOff
;
6700 IOReturn
IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels
)
6703 return kIOReturnNotFound
;
6705 return pmAssertions
->setUserAssertionLevels(inLevels
);
6708 bool IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
6712 pmAssertions
->publishProperties();
6714 return( IOService::serializeProperties(s
) );
6717 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6720 // MARK: PMSettingHandle
6722 OSDefineMetaClassAndStructors( PMSettingHandle
, OSObject
)
6724 void PMSettingHandle::free( void )
6728 pmso
->clientHandleFreed();
6737 // MARK: PMSettingObject
6740 #define super OSObject
6741 OSDefineMetaClassAndFinalStructors( PMSettingObject
, OSObject
)
6744 * Static constructor/initializer for PMSettingObject
6746 PMSettingObject
*PMSettingObject::pmSettingObject(
6747 IOPMrootDomain
*parent_arg
,
6748 IOPMSettingControllerCallback handler_arg
,
6749 OSObject
*target_arg
,
6750 uintptr_t refcon_arg
,
6751 uint32_t supportedPowerSources
,
6752 const OSSymbol
* settings
[],
6753 OSObject
**handle_obj
)
6755 uint32_t settingCount
= 0;
6756 PMSettingObject
*pmso
= 0;
6757 PMSettingHandle
*pmsh
= 0;
6759 if ( !parent_arg
|| !handler_arg
|| !settings
|| !handle_obj
)
6762 // count OSSymbol entries in NULL terminated settings array
6763 while (settings
[settingCount
]) {
6766 if (0 == settingCount
)
6769 pmso
= new PMSettingObject
;
6770 if (!pmso
|| !pmso
->init())
6773 pmsh
= new PMSettingHandle
;
6774 if (!pmsh
|| !pmsh
->init())
6777 queue_init(&pmso
->calloutQueue
);
6778 pmso
->parent
= parent_arg
;
6779 pmso
->func
= handler_arg
;
6780 pmso
->target
= target_arg
;
6781 pmso
->refcon
= refcon_arg
;
6782 pmso
->settingCount
= settingCount
;
6784 pmso
->retain(); // handle holds a retain on pmso
6788 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount
);
6789 if (pmso
->publishedFeatureID
) {
6790 for (unsigned int i
=0; i
<settingCount
; i
++) {
6791 // Since there is now at least one listener to this setting, publish
6792 // PM root domain support for it.
6793 parent_arg
->publishFeature( settings
[i
]->getCStringNoCopy(),
6794 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
6802 if (pmso
) pmso
->release();
6803 if (pmsh
) pmsh
->release();
6807 void PMSettingObject::free( void )
6809 if (publishedFeatureID
) {
6810 for (uint32_t i
=0; i
<settingCount
; i
++) {
6811 if (publishedFeatureID
[i
]) {
6812 parent
->removePublishedFeature( publishedFeatureID
[i
] );
6816 IOFree(publishedFeatureID
, sizeof(uint32_t) * settingCount
);
6822 void PMSettingObject::dispatchPMSetting( const OSSymbol
* type
, OSObject
* object
)
6824 (*func
)(target
, type
, object
, refcon
);
6827 void PMSettingObject::clientHandleFreed( void )
6829 parent
->deregisterPMSettingObject(this);
6833 // MARK: IOPMTimeline
6836 #define super OSObject
6838 //*********************************************************************************
6839 //*********************************************************************************
6840 //*********************************************************************************
6842 IOPMTimeline
*IOPMTimeline::timeline(IOPMrootDomain
*root_domain
)
6844 IOPMTimeline
*myself
;
6849 myself
= new IOPMTimeline
;
6852 myself
->owner
= root_domain
;
6859 bool IOPMTimeline::init(void)
6861 if (!super::init()) {
6865 logLock
= IOLockAlloc();
6867 // Fresh timeline, no events logged yet
6868 this->numEventsLoggedThisPeriod
= 0;
6869 this->sleepCycleInProgress
= false;
6871 //this->setEventsRecordingLevel(1); // TODO
6872 this->setEventsTrackedCount(kIOPMDefaultSystemEventsTracked
);
6877 void IOPMTimeline::free(void)
6879 if (pmTraceMemoryDescriptor
) {
6880 pmTraceMemoryDescriptor
->release();
6881 pmTraceMemoryDescriptor
= NULL
;
6884 IOLockFree(logLock
);
6889 IOMemoryDescriptor
*IOPMTimeline::getPMTraceMemoryDescriptor()
6891 return pmTraceMemoryDescriptor
;
6894 //*********************************************************************************
6895 //*********************************************************************************
6896 //*********************************************************************************
6898 bool IOPMTimeline::setProperties(OSDictionary
*d
)
6901 OSBoolean
*b
= NULL
;
6902 bool changed
= false;
6904 /* Changes size of detailed events buffer */
6905 n
= (OSNumber
*)d
->getObject(kIOPMTimelineSystemNumberTrackedKey
);
6906 if (OSDynamicCast(OSNumber
, n
))
6909 this->setEventsTrackedCount(n
->unsigned32BitValue());
6913 /* enables or disables system events */
6914 b
= (OSBoolean
*)d
->getObject(kIOPMTimelineEnabledKey
);
6918 this->setEventsRecordingLevel((int)(kOSBooleanTrue
== b
));
6924 //*********************************************************************************
6925 //*********************************************************************************
6926 //*********************************************************************************
6928 OSDictionary
*IOPMTimeline::copyInfoDictionary(void)
6930 OSDictionary
*out
= OSDictionary::withCapacity(3);
6936 n
= OSNumber::withNumber(hdr
->sizeEntries
, 32);
6937 out
->setObject(kIOPMTimelineSystemNumberTrackedKey
, n
);
6940 n
= OSNumber::withNumber(hdr
->sizeBytes
, 32);
6941 out
->setObject(kIOPMTimelineSystemBufferSizeKey
, n
);
6945 out
->setObject(kIOPMTimelineEnabledKey
, eventsRecordingLevel
? kOSBooleanTrue
: kOSBooleanFalse
);
6950 //*********************************************************************************
6951 //*********************************************************************************
6952 //*********************************************************************************
6954 /* IOPMTimeline::recordSystemPowerEvent()
6956 * Expected "type" arguments are listed in IOPMPrivate.h under enum "SystemEventTypes"
6957 * Type arguments include "system events", and "Intermediate events"
6959 * - System Events have paired "start" and "stop" events.
6960 * - A start event shall be followed by a stop event.
6961 * - Any number of Intermediate Events may fall between the
6962 * start and stop events.
6963 * - Intermediate events are meaningless outside the bounds of a system event's
6964 * start & stoup routines.
6965 * - It's invalid to record a Start event without a following Stop event; e.g. two
6966 * Start events without an intervenining Stop event is invalid.
6969 * - The first recorded system event shall be preceded by an entry with type == 0
6970 * - IOPMTimeline may choose not to record intermediate events while there's not
6971 * a system event in process.
6973 IOReturn
IOPMTimeline::recordSystemPowerEvent( PMEventDetails
*details
)
6975 static bool wakeDonePending
= true;
6976 IOPMSystemEventRecord
*record_to
= NULL
;
6977 OSString
*swUUIDKey
= NULL
;
6978 uint32_t useIndex
= 0;
6981 return kIOReturnBadArgument
;
6984 return kIOReturnNotReady
;
6986 if (details
->eventType
== kIOPMEventTypeWakeDone
)
6988 if(!wakeDonePending
)
6989 return kIOReturnBadArgument
;
6992 IOLockLock(logLock
);
6994 if (details
->eventType
== kIOPMEventTypeWake
) {
6995 wakeDonePending
= true;
6996 } else if (details
->eventType
== kIOPMEventTypeWakeDone
) {
6997 wakeDonePending
= false;
7000 systemState
= details
->eventType
;
7002 useIndex
= _atomicIndexIncrement(&hdr
->index
, hdr
->sizeEntries
);
7004 // The entry immediately after the latest entry (and thus
7005 // immediately before the first entry) shall have a type 0.
7006 if (useIndex
+ 1 >= hdr
->sizeEntries
) {
7007 traceBuffer
[useIndex
+ 1].eventType
= 0;
7009 traceBuffer
[0].eventType
= 0;
7012 record_to
= &traceBuffer
[useIndex
];
7013 bzero(record_to
, sizeof(IOPMSystemEventRecord
));
7016 record_to
->eventType
= details
->eventType
;
7017 record_to
->eventReason
= details
->reason
;
7018 record_to
->eventResult
= details
->result
;
7019 pmEventTimeStamp(&record_to
->timestamp
);
7021 // If caller doesn't provide a UUID, we'll use the UUID that's posted
7022 // on IOPMrootDomain under key kIOPMSleepWakeUUIDKey
7023 if (!details
->uuid
) {
7024 swUUIDKey
= OSDynamicCast(OSString
, owner
->copyProperty(kIOPMSleepWakeUUIDKey
));
7027 details
->uuid
= swUUIDKey
->getCStringNoCopy();
7031 strncpy(record_to
->uuid
, details
->uuid
, kMaxPMStringLength
);
7034 swUUIDKey
->release();
7036 numEventsLoggedThisPeriod
++;
7039 IOLockUnlock(logLock
);
7041 return kIOReturnSuccess
;
7045 //*********************************************************************************
7046 //*********************************************************************************
7047 //*********************************************************************************
7049 IOReturn
IOPMTimeline::recordDetailedPowerEvent( PMEventDetails
*details
)
7051 IOPMSystemEventRecord
*record_to
= NULL
;
7054 if (!details
->eventType
|| !details
->ownerName
)
7055 return kIOReturnBadArgument
;
7057 IOLockLock(logLock
);
7059 useIndex
= _atomicIndexIncrement(&hdr
->index
, hdr
->sizeEntries
);
7061 record_to
= (IOPMSystemEventRecord
*)&traceBuffer
[useIndex
];
7062 bzero(record_to
, sizeof(IOPMSystemEventRecord
));
7065 record_to
->eventType
= details
->eventType
;
7066 if (details
->ownerName
&& (strlen(details
->ownerName
) > 1)) {
7067 strlcpy( record_to
->ownerName
,
7069 sizeof(record_to
->ownerName
));
7072 record_to
->ownerDisambiguateID
= details
->ownerUnique
;
7074 if (details
->interestName
&& (strlen(details
->interestName
) > 1)) {
7075 strlcpy(record_to
->interestName
,
7076 details
->interestName
,
7077 sizeof(record_to
->interestName
));
7080 record_to
->oldState
= details
->oldState
;
7081 record_to
->newState
= details
->newState
;
7082 record_to
->eventResult
= details
->result
;
7083 record_to
->elapsedTimeUS
= details
->elapsedTimeUS
;
7084 pmEventTimeStamp(&record_to
->timestamp
);
7086 numEventsLoggedThisPeriod
++;
7089 IOLockUnlock(logLock
);
7090 return kIOReturnSuccess
;
7093 uint32_t IOPMTimeline::getNumEventsLoggedThisPeriod() {
7094 return this->numEventsLoggedThisPeriod
;
7097 void IOPMTimeline::setNumEventsLoggedThisPeriod(uint32_t newCount
) {
7098 this->numEventsLoggedThisPeriod
= newCount
;
7101 bool IOPMTimeline::isSleepCycleInProgress() {
7102 return this->sleepCycleInProgress
;
7105 void IOPMTimeline::setSleepCycleInProgressFlag(bool flag
) {
7106 this->sleepCycleInProgress
= flag
;
7108 //*********************************************************************************
7109 //*********************************************************************************
7110 //*********************************************************************************
7112 void IOPMTimeline::setEventsTrackedCount(uint32_t newTracked
)
7114 size_t make_buf_size
= 0;
7116 make_buf_size
= sizeof(IOPMTraceBufferHeader
) + (newTracked
* sizeof(IOPMSystemEventRecord
));
7118 IOLockLock(logLock
);
7120 if (pmTraceMemoryDescriptor
) {
7121 pmTraceMemoryDescriptor
->release();
7122 pmTraceMemoryDescriptor
= NULL
;
7128 if (0 == newTracked
)
7130 IOLog("IOPMrootDomain -> erased buffer.\n");
7134 pmTraceMemoryDescriptor
= IOBufferMemoryDescriptor::withOptions(
7135 kIOMemoryKernelUserShared
| kIODirectionIn
, make_buf_size
);
7137 if (!pmTraceMemoryDescriptor
)
7139 IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns NULL\n", (int)make_buf_size
);
7143 pmTraceMemoryDescriptor
->prepare(kIODirectionIn
);
7145 // Header occupies the first sizeof(IOPMTraceBufferHeader) bytes
7146 hdr
= (IOPMTraceBufferHeader
*)pmTraceMemoryDescriptor
->getBytesNoCopy();
7148 // Recorded events occupy the remaining bulk of the buffer
7149 traceBuffer
= (IOPMSystemEventRecord
*)((uint8_t *)hdr
+ sizeof(IOPMTraceBufferHeader
));
7151 bzero(hdr
, make_buf_size
);
7153 hdr
->sizeBytes
= make_buf_size
;
7154 hdr
->sizeEntries
= newTracked
;
7156 IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns bufferMB with address 0x%08x\n", (int)make_buf_size
, (unsigned int)(uintptr_t)traceBuffer
);
7159 IOLockUnlock(logLock
);
7162 //*********************************************************************************
7163 //*********************************************************************************
7164 //*********************************************************************************
7166 void IOPMTimeline::setEventsRecordingLevel(uint32_t eventsTrackedBits
)
7175 /* static helper to IOPMTimeline
7177 uint32_t IOPMTimeline::_atomicIndexIncrement(uint32_t *index
, uint32_t limit
)
7187 inc_index
= (was_index
+1)%limit
;
7188 } while (!OSCompareAndSwap(was_index
, inc_index
, index
));
7194 // MARK: PMAssertionsTracker
7196 //*********************************************************************************
7197 //*********************************************************************************
7198 //*********************************************************************************
7199 // class PMAssertionsTracker Implementation
7201 #define kAssertUniqueIDStart 500
7203 PMAssertionsTracker
*PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain
*rootDomain
)
7205 PMAssertionsTracker
*myself
;
7207 myself
= new PMAssertionsTracker
;
7211 myself
->owner
= rootDomain
;
7212 myself
->issuingUniqueID
= kAssertUniqueIDStart
;
7213 myself
->assertionsArray
= OSArray::withCapacity(5);
7214 myself
->assertionsKernel
= 0;
7215 myself
->assertionsUser
= 0;
7216 myself
->assertionsCombined
= 0;
7217 myself
->assertionsArrayLock
= IOLockAlloc();
7218 myself
->tabulateProducerCount
= myself
->tabulateConsumerCount
= 0;
7220 if (!myself
->assertionsArray
|| !myself
->assertionsArrayLock
)
7228 * - Update assertionsKernel to reflect the state of all
7229 * assertions in the kernel.
7230 * - Update assertionsCombined to reflect both kernel & user space.
7232 void PMAssertionsTracker::tabulate(void)
7236 PMAssertStruct
*_a
= NULL
;
7239 IOPMDriverAssertionType oldKernel
= assertionsKernel
;
7240 IOPMDriverAssertionType oldCombined
= assertionsCombined
;
7244 assertionsKernel
= 0;
7245 assertionsCombined
= 0;
7247 if (!assertionsArray
)
7250 if ((count
= assertionsArray
->getCount()))
7252 for (i
=0; i
<count
; i
++)
7254 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
7257 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
7258 if (_a
&& (kIOPMDriverAssertionLevelOn
== _a
->level
))
7259 assertionsKernel
|= _a
->assertionBits
;
7264 tabulateProducerCount
++;
7265 assertionsCombined
= assertionsKernel
| assertionsUser
;
7267 if ((assertionsKernel
!= oldKernel
) ||
7268 (assertionsCombined
!= oldCombined
))
7270 owner
->messageClients(kIOPMMessageDriverAssertionsChanged
);
7272 if (((assertionsCombined
& kIOPMDriverAssertionPreventDisplaySleepBit
) != 0)
7273 && ((oldCombined
& kIOPMDriverAssertionPreventDisplaySleepBit
) == 0))
7275 /* We react to a new PreventDisplaySleep assertion by waking the display
7276 * with an activityTickle
7278 owner
->evaluatePolicy(kStimulusDarkWakeActivityTickle
);
7280 owner
->evaluatePolicy(kStimulusDarkWakeEvaluate
);
7285 void PMAssertionsTracker::publishProperties( void )
7287 OSArray
*assertionsSummary
= NULL
;
7289 if (tabulateConsumerCount
!= tabulateProducerCount
)
7291 IOLockLock(assertionsArrayLock
);
7293 tabulateConsumerCount
= tabulateProducerCount
;
7295 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
7297 assertionsSummary
= copyAssertionsArray();
7298 if (assertionsSummary
)
7300 owner
->setProperty(kIOPMAssertionsDriverDetailedKey
, assertionsSummary
);
7301 assertionsSummary
->release();
7305 owner
->removeProperty(kIOPMAssertionsDriverDetailedKey
);
7308 /* Publish the IOPMrootDomain property "DriverPMAssertions"
7310 owner
->setProperty(kIOPMAssertionsDriverKey
, assertionsKernel
, 64);
7312 IOLockUnlock(assertionsArrayLock
);
7316 PMAssertionsTracker::PMAssertStruct
*PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id
, int *index
)
7318 PMAssertStruct
*_a
= NULL
;
7325 && (count
= assertionsArray
->getCount()))
7327 for (i
=0; i
<count
; i
++)
7329 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
7332 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
7333 if (_a
&& (_id
== _a
->id
)) {
7350 /* PMAssertionsTracker::handleCreateAssertion
7351 * Perform assertion work on the PM workloop. Do not call directly.
7353 IOReturn
PMAssertionsTracker::handleCreateAssertion(OSData
*newAssertion
)
7359 IOLockLock(assertionsArrayLock
);
7360 assertionsArray
->setObject(newAssertion
);
7361 IOLockUnlock(assertionsArrayLock
);
7362 newAssertion
->release();
7366 return kIOReturnSuccess
;
7369 /* PMAssertionsTracker::createAssertion
7370 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
7373 IOReturn
PMAssertionsTracker::createAssertion(
7374 IOPMDriverAssertionType which
,
7375 IOPMDriverAssertionLevel level
,
7376 IOService
*serviceID
,
7377 const char *whoItIs
,
7378 IOPMDriverAssertionID
*outID
)
7380 OSData
*dataStore
= NULL
;
7381 PMAssertStruct track
;
7383 // Warning: trillions and trillions of created assertions may overflow the unique ID.
7384 track
.id
= OSIncrementAtomic64((SInt64
*) &issuingUniqueID
);
7385 track
.level
= level
;
7386 track
.assertionBits
= which
;
7387 track
.ownerString
= whoItIs
? OSSymbol::withCString(whoItIs
) : 0;
7388 track
.ownerService
= serviceID
;
7389 track
.modifiedTime
= 0;
7390 pmEventTimeStamp(&track
.createdTime
);
7392 dataStore
= OSData::withBytes(&track
, sizeof(PMAssertStruct
));
7395 if (track
.ownerString
)
7396 track
.ownerString
->release();
7397 return kIOReturnNoMemory
;
7402 if (owner
&& owner
->pmPowerStateQueue
) {
7403 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionCreate
, (void *)dataStore
);
7406 return kIOReturnSuccess
;
7409 /* PMAssertionsTracker::handleReleaseAssertion
7410 * Runs in PM workloop. Do not call directly.
7412 IOReturn
PMAssertionsTracker::handleReleaseAssertion(
7413 IOPMDriverAssertionID _id
)
7418 PMAssertStruct
*assertStruct
= detailsForID(_id
, &index
);
7421 return kIOReturnNotFound
;
7423 IOLockLock(assertionsArrayLock
);
7424 if (assertStruct
->ownerString
)
7425 assertStruct
->ownerString
->release();
7427 assertionsArray
->removeObject(index
);
7428 IOLockUnlock(assertionsArrayLock
);
7431 return kIOReturnSuccess
;
7434 /* PMAssertionsTracker::releaseAssertion
7435 * Releases an assertion and affects system behavior if appropiate.
7436 * Actual work happens on PM workloop.
7438 IOReturn
PMAssertionsTracker::releaseAssertion(
7439 IOPMDriverAssertionID _id
)
7441 if (owner
&& owner
->pmPowerStateQueue
) {
7442 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionRelease
, 0, _id
);
7444 return kIOReturnSuccess
;
7447 /* PMAssertionsTracker::handleSetAssertionLevel
7448 * Runs in PM workloop. Do not call directly.
7450 IOReturn
PMAssertionsTracker::handleSetAssertionLevel(
7451 IOPMDriverAssertionID _id
,
7452 IOPMDriverAssertionLevel _level
)
7454 PMAssertStruct
*assertStruct
= detailsForID(_id
, NULL
);
7458 if (!assertStruct
) {
7459 return kIOReturnNotFound
;
7462 IOLockLock(assertionsArrayLock
);
7463 pmEventTimeStamp(&assertStruct
->modifiedTime
);
7464 assertStruct
->level
= _level
;
7465 IOLockUnlock(assertionsArrayLock
);
7468 return kIOReturnSuccess
;
7471 /* PMAssertionsTracker::setAssertionLevel
7473 IOReturn
PMAssertionsTracker::setAssertionLevel(
7474 IOPMDriverAssertionID _id
,
7475 IOPMDriverAssertionLevel _level
)
7477 if (owner
&& owner
->pmPowerStateQueue
) {
7478 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionSetLevel
,
7479 (void *)_level
, _id
);
7482 return kIOReturnSuccess
;
7485 IOReturn
PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0
)
7487 IOPMDriverAssertionType new_user_levels
= *(IOPMDriverAssertionType
*) arg0
;
7491 if (new_user_levels
!= assertionsUser
)
7493 assertionsUser
= new_user_levels
;
7494 DLOG("assertionsUser 0x%llx\n", assertionsUser
);
7498 return kIOReturnSuccess
;
7501 IOReturn
PMAssertionsTracker::setUserAssertionLevels(
7502 IOPMDriverAssertionType new_user_levels
)
7504 if (gIOPMWorkLoop
) {
7505 gIOPMWorkLoop
->runAction(
7506 OSMemberFunctionCast(
7509 &PMAssertionsTracker::handleSetUserAssertionLevels
),
7511 (void *) &new_user_levels
, 0, 0, 0);
7514 return kIOReturnSuccess
;
7518 OSArray
*PMAssertionsTracker::copyAssertionsArray(void)
7522 OSArray
*outArray
= NULL
;
7524 if (!assertionsArray
||
7525 (0 == (count
= assertionsArray
->getCount())) ||
7526 (NULL
== (outArray
= OSArray::withCapacity(count
))))
7531 for (i
=0; i
<count
; i
++)
7533 PMAssertStruct
*_a
= NULL
;
7535 OSDictionary
*details
= NULL
;
7537 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
7538 if (_d
&& (_a
= (PMAssertStruct
*)_d
->getBytesNoCopy()))
7540 OSNumber
*_n
= NULL
;
7542 details
= OSDictionary::withCapacity(7);
7546 outArray
->setObject(details
);
7549 _n
= OSNumber::withNumber(_a
->id
, 64);
7551 details
->setObject(kIOPMDriverAssertionIDKey
, _n
);
7554 _n
= OSNumber::withNumber(_a
->createdTime
, 64);
7556 details
->setObject(kIOPMDriverAssertionCreatedTimeKey
, _n
);
7559 _n
= OSNumber::withNumber(_a
->modifiedTime
, 64);
7561 details
->setObject(kIOPMDriverAssertionModifiedTimeKey
, _n
);
7564 _n
= OSNumber::withNumber((uintptr_t)_a
->ownerService
, 64);
7566 details
->setObject(kIOPMDriverAssertionOwnerServiceKey
, _n
);
7569 _n
= OSNumber::withNumber(_a
->level
, 64);
7571 details
->setObject(kIOPMDriverAssertionLevelKey
, _n
);
7574 _n
= OSNumber::withNumber(_a
->assertionBits
, 64);
7576 details
->setObject(kIOPMDriverAssertionAssertedKey
, _n
);
7580 if (_a
->ownerString
) {
7581 details
->setObject(kIOPMDriverAssertionOwnerStringKey
, _a
->ownerString
);
7590 IOPMDriverAssertionType
PMAssertionsTracker::getActivatedAssertions(void)
7592 return assertionsCombined
;
7595 IOPMDriverAssertionLevel
PMAssertionsTracker::getAssertionLevel(
7596 IOPMDriverAssertionType type
)
7598 if (type
&& ((type
& assertionsKernel
) == assertionsKernel
))
7600 return kIOPMDriverAssertionLevelOn
;
7602 return kIOPMDriverAssertionLevelOff
;
7606 //*********************************************************************************
7607 //*********************************************************************************
7608 //*********************************************************************************
7611 static void pmEventTimeStamp(uint64_t *recordTS
)
7619 // We assume tsec fits into 32 bits; 32 bits holds enough
7620 // seconds for 136 years since the epoch in 1970.
7621 clock_get_calendar_microtime(&tsec
, &tusec
);
7624 // Pack the sec & microsec calendar time into a uint64_t, for fun.
7626 *recordTS
|= (uint32_t)tusec
;
7627 *recordTS
|= ((uint64_t)tsec
<< 32);
7633 // MARK: IORootParent
7635 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7637 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
7639 // The reason that root domain needs a root parent is to facilitate demand
7640 // sleep, since a power change from the root parent cannot be vetoed.
7642 // The above statement is no longer true since root domain now performs
7643 // demand sleep using overrides. But root parent remains to avoid changing
7644 // the power tree stacking. Root parent is parked at the max power state.
7647 static IOPMPowerState patriarchPowerStates
[2] =
7649 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
7650 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
7653 void IORootParent::initialize( void )
7657 bool IORootParent::start( IOService
* nub
)
7659 IOService::start(nub
);
7660 attachToParent( getRegistryRoot(), gIOPowerPlane
);
7662 registerPowerDriver(this, patriarchPowerStates
, 2);
7667 void IORootParent::shutDownSystem( void )
7671 void IORootParent::restartSystem( void )
7675 void IORootParent::sleepSystem( void )
7679 void IORootParent::dozeSystem( void )
7683 void IORootParent::sleepToDoze( void )
7687 void IORootParent::wakeSystem( void )
7691 OSObject
* IORootParent::copyProperty( const char * aKey
) const
7693 return (IOService::copyProperty(aKey
));