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
;
3726 // Notify legacy clients
3727 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &ctx
);
3729 // For normal shutdown, turn off File Server Mode.
3730 if (kPEHaltCPU
== pe_type
)
3732 const OSSymbol
* setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
3733 OSNumber
* num
= OSNumber::withNumber((unsigned long long) 0, 32);
3736 setPMSetting(setting
, num
);
3742 if (kPEPagingOff
!= pe_type
)
3744 // Notify in power tree order
3745 notifySystemShutdown(this, ctx
.MessageType
);
3748 deltaTime
= computeDeltaTimeMS(&startTime
);
3749 LOG("%s all drivers took %u ms\n",
3750 (ctx
.MessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" :
3751 (ctx
.MessageType
== kIOMessageSystemPagingOff
) ? "PagingOff" : "Restart",
3752 (uint32_t) deltaTime
);
3755 //******************************************************************************
3758 //******************************************************************************
3760 IOReturn
IOPMrootDomain::shutdownSystem( void )
3762 return kIOReturnUnsupported
;
3765 //******************************************************************************
3768 //******************************************************************************
3770 IOReturn
IOPMrootDomain::restartSystem( void )
3772 return kIOReturnUnsupported
;
3776 // MARK: System Capability
3778 //******************************************************************************
3779 // tagPowerPlaneService
3781 // Running on PM work loop thread.
3782 //******************************************************************************
3784 void IOPMrootDomain::tagPowerPlaneService(
3785 IOService
* service
,
3786 IOPMActions
* actions
)
3789 bool isDisplayWrangler
;
3791 memset(actions
, 0, sizeof(*actions
));
3792 actions
->target
= this;
3794 if (service
== this)
3796 actions
->actionPowerChangeStart
=
3797 OSMemberFunctionCast(
3798 IOPMActionPowerChangeStart
, this,
3799 &IOPMrootDomain::handleOurPowerChangeStart
);
3801 actions
->actionPowerChangeDone
=
3802 OSMemberFunctionCast(
3803 IOPMActionPowerChangeDone
, this,
3804 &IOPMrootDomain::handleOurPowerChangeDone
);
3806 actions
->actionPowerChangeOverride
=
3807 OSMemberFunctionCast(
3808 IOPMActionPowerChangeOverride
, this,
3809 &IOPMrootDomain::overrideOurPowerChange
);
3814 isDisplayWrangler
= (0 != service
->metaCast("IODisplayWrangler"));
3815 if (isDisplayWrangler
)
3818 wranglerConnection
= (IOService
*) service
->getParentEntry(gIOPowerPlane
);
3821 isDisplayWrangler
= false;
3824 #if defined(__i386__) || defined(__x86_64__)
3825 if (isDisplayWrangler
)
3826 flags
|= kPMActionsFlagIsDisplayWrangler
;
3827 if (service
->getProperty("IOPMStrictTreeOrder"))
3828 flags
|= kPMActionsFlagIsGraphicsDevice
;
3829 if (service
->getProperty("IOPMUnattendedWakePowerState"))
3830 flags
|= kPMActionsFlagIsAudioDevice
;
3833 // Find the power connection object that is a child of the PCI host
3834 // bridge, and has a graphics/audio device attached below. Mark the
3835 // power branch for delayed child notifications.
3839 IORegistryEntry
* child
= service
;
3840 IORegistryEntry
* parent
= child
->getParentEntry(gIOPowerPlane
);
3842 while (child
!= this)
3844 if ((parent
== pciHostBridgeDriver
) ||
3847 if (OSDynamicCast(IOPowerConnection
, child
))
3849 IOPowerConnection
* conn
= (IOPowerConnection
*) child
;
3850 conn
->delayChildNotification
= true;
3855 parent
= child
->getParentEntry(gIOPowerPlane
);
3861 DLOG("%s tag flags %x\n", service
->getName(), flags
);
3862 actions
->parameter
|= flags
;
3863 actions
->actionPowerChangeOverride
=
3864 OSMemberFunctionCast(
3865 IOPMActionPowerChangeOverride
, this,
3866 &IOPMrootDomain::overridePowerChangeForUIService
);
3868 if (flags
& kPMActionsFlagIsDisplayWrangler
)
3870 actions
->actionActivityTickle
=
3871 OSMemberFunctionCast(
3872 IOPMActionActivityTickle
, this,
3873 &IOPMrootDomain::handleActivityTickleForDisplayWrangler
);
3878 // Locate the first PCI host bridge for PMTrace.
3879 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge"))
3881 IOService
* provider
= service
->getProvider();
3882 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
3883 provider
->inPlane(gIODTPlane
))
3885 pciHostBridgeDevice
= provider
;
3886 pciHostBridgeDriver
= service
;
3887 DLOG("PMTrace found PCI host bridge %s->%s\n",
3888 provider
->getName(), service
->getName());
3892 // Tag top-level PCI devices. The order of PMinit() call does not
3893 // change across boots and is used as the PCI bit number.
3894 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice"))
3896 // Would prefer to check built-in property, but tagPowerPlaneService()
3897 // is called before pciDevice->registerService().
3898 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
3899 if ((parent
== pciHostBridgeDevice
) && service
->getProperty("acpi-device"))
3901 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
3904 // Save the assigned bit for fast lookup.
3905 actions
->parameter
|= (bit
& kPMActionsPCIBitNumberMask
);
3907 actions
->actionPowerChangeStart
=
3908 OSMemberFunctionCast(
3909 IOPMActionPowerChangeStart
, this,
3910 &IOPMrootDomain::handlePowerChangeStartForPCIDevice
);
3912 actions
->actionPowerChangeDone
=
3913 OSMemberFunctionCast(
3914 IOPMActionPowerChangeDone
, this,
3915 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice
);
3921 //******************************************************************************
3922 // PM actions for root domain
3923 //******************************************************************************
3925 void IOPMrootDomain::overrideOurPowerChange(
3926 IOService
* service
,
3927 IOPMActions
* actions
,
3928 unsigned long * inOutPowerState
,
3929 uint32_t * inOutChangeFlags
)
3931 uint32_t powerState
= (uint32_t) *inOutPowerState
;
3932 uint32_t changeFlags
= *inOutChangeFlags
;
3933 uint32_t currentPowerState
= (uint32_t) getPowerState();
3935 if ((currentPowerState
== powerState
) ||
3936 (changeFlags
& kIOPMParentInitiated
))
3938 // FIXME: cancel any parent change (unexpected)
3939 // Root parent is permanently pegged at max power,
3940 // kIOPMParentInitiated is unexpected.
3944 if (powerState
< currentPowerState
)
3946 if ((changeFlags
& kIOPMSkipAskPowerDown
) == 0)
3948 /* Convenient place to run any code at idle sleep time
3949 * IOPMrootDomain initiates an idle sleep here
3951 * Set last sleep cause accordingly.
3953 pmPowerStateQueue
->submitPowerEvent(kPowerEventPublishSleepWakeUUID
, (void *)true);
3955 lastSleepReason
= kIOPMSleepReasonIdle
;
3956 setProperty(kRootDomainSleepReasonKey
, kIOPMIdleSleepKey
);
3958 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
3960 // Root domain is dropping power state ON->SLEEP.
3961 // If system is in full wake, first drop to dark wake.
3963 darkWakeToSleepASAP
= true;
3965 // Drop graphics capability.
3966 // No transition if system is already in dark wake.
3968 _desiredCapability
&= ~(
3969 kIOPMSystemCapabilityGraphics
|
3970 kIOPMSystemCapabilityAudio
);
3972 *inOutPowerState
= ON_STATE
;
3973 *inOutChangeFlags
|= kIOPMSynchronize
;
3975 // Revert device desire from SLEEP->ON.
3976 changePowerStateToPriv(ON_STATE
);
3981 void IOPMrootDomain::handleOurPowerChangeStart(
3982 IOService
* service
,
3983 IOPMActions
* actions
,
3984 uint32_t powerState
,
3985 uint32_t * inOutChangeFlags
)
3987 uint32_t changeFlags
= *inOutChangeFlags
;
3988 uint32_t currentPowerState
= (uint32_t) getPowerState();
3990 _systemTransitionType
= kSystemTransitionNone
;
3991 _systemMessageClientMask
= 0;
3992 capabilityLoss
= false;
3994 // 1. Explicit capability change.
3996 if (changeFlags
& kIOPMSynchronize
)
3998 if (powerState
== ON_STATE
)
4000 if (changeFlags
& kIOPMSyncNoChildNotify
)
4001 _systemTransitionType
= kSystemTransitionNewCapClient
;
4003 _systemTransitionType
= kSystemTransitionCapability
;
4007 // 2. Going to sleep (cancellation still possible).
4009 else if (powerState
< currentPowerState
)
4010 _systemTransitionType
= kSystemTransitionSleep
;
4012 // 3. Woke from (idle or demand) sleep.
4014 else if (!systemBooting
&&
4015 (changeFlags
& kIOPMSelfInitiated
) &&
4016 (powerState
> currentPowerState
))
4018 _systemTransitionType
= kSystemTransitionWake
;
4019 _desiredCapability
= kIOPMSystemCapabilityCPU
|
4020 kIOPMSystemCapabilityNetwork
;
4022 // Check for early HID events (e.g. LID open)
4023 if (wranglerTickled
)
4025 _desiredCapability
|= (
4026 kIOPMSystemCapabilityGraphics
|
4027 kIOPMSystemCapabilityAudio
);
4031 // Update pending wake capability at the beginning of every
4032 // state transition (including synchronize). This will become
4033 // the current capability at the end of the transition.
4035 if (kSystemTransitionSleep
== _systemTransitionType
)
4037 _pendingCapability
= 0;
4038 capabilityLoss
= true;
4040 else if (kSystemTransitionNewCapClient
!= _systemTransitionType
)
4042 _pendingCapability
= _desiredCapability
|
4043 kIOPMSystemCapabilityCPU
|
4044 kIOPMSystemCapabilityNetwork
;
4046 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4047 _pendingCapability
|= kIOPMSystemCapabilityAudio
;
4049 if ((kSystemTransitionCapability
== _systemTransitionType
) &&
4050 (_pendingCapability
== _currentCapability
))
4052 // Cancel the PM state change.
4053 _systemTransitionType
= kSystemTransitionNone
;
4054 *inOutChangeFlags
|= kIOPMNotDone
;
4056 if (__builtin_popcount(_pendingCapability
) <
4057 __builtin_popcount(_currentCapability
))
4058 capabilityLoss
= true;
4059 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4060 rejectWranglerTickle
= true;
4063 // 1. Capability change.
4065 if (kSystemTransitionCapability
== _systemTransitionType
)
4067 // Dark to Full transition.
4068 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4070 tracePoint( kIOPMTracePointDarkWakeExit
);
4071 wranglerSleepIgnored
= false;
4072 sleepTimerMaintenance
= false;
4073 hibernateNoDefeat
= false;
4074 _systemMessageClientMask
= kSystemMessageClientUser
;
4075 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4076 _systemMessageClientMask
|= kSystemMessageClientKernel
;
4078 tellClients(kIOMessageSystemWillPowerOn
);
4081 // Full to Dark transition.
4082 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4084 tracePoint( kIOPMTracePointDarkWakeEntry
);
4085 *inOutChangeFlags
|= kIOPMSyncTellPowerDown
;
4086 _systemMessageClientMask
= kSystemMessageClientUser
;
4092 else if (kSystemTransitionSleep
== _systemTransitionType
)
4094 // Beginning of a system sleep transition.
4095 // Cancellation is still possible.
4096 tracePoint( kIOPMTracePointSleepStarted
, lastSleepReason
);
4098 _systemMessageClientMask
= kSystemMessageClientAll
;
4099 if ((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4100 _systemMessageClientMask
&= ~kSystemMessageClientApp
;
4101 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4102 _systemMessageClientMask
&= ~kSystemMessageClientKernel
;
4104 // Optimization to ignore wrangler power down thus skipping
4105 // the disk spindown and arming the idle timer for demand sleep.
4107 if (changeFlags
& kIOPMIgnoreChildren
)
4109 wranglerSleepIgnored
= true;
4112 logWranglerTickle
= false;
4117 else if (kSystemTransitionWake
== _systemTransitionType
)
4119 wranglerSleepIgnored
= false;
4121 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4123 _systemMessageClientMask
= kSystemMessageClientAll
;
4127 _systemMessageClientMask
= kSystemMessageClientConfigd
;
4130 tracePoint( kIOPMTracePointWakeWillPowerOnClients
);
4131 tellClients(kIOMessageSystemWillPowerOn
);
4134 if ((kSystemTransitionNone
!= _systemTransitionType
) &&
4135 (kSystemTransitionNewCapClient
!= _systemTransitionType
))
4137 _systemStateGeneration
++;
4138 systemDarkWake
= false;
4140 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4142 currentPowerState
, powerState
, *inOutChangeFlags
,
4143 _systemTransitionType
, _systemStateGeneration
,
4144 _systemMessageClientMask
,
4145 _desiredCapability
, _currentCapability
, _pendingCapability
);
4149 void IOPMrootDomain::handleOurPowerChangeDone(
4150 IOService
* service
,
4151 IOPMActions
* actions
,
4152 uint32_t powerState
,
4153 uint32_t changeFlags
)
4155 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
4157 _systemTransitionType
= kSystemTransitionNone
;
4161 if (_systemTransitionType
!= kSystemTransitionNone
)
4163 uint32_t currentPowerState
= (uint32_t) getPowerState();
4165 if (changeFlags
& kIOPMNotDone
)
4167 // Power down was cancelled or vetoed.
4168 _pendingCapability
= _currentCapability
;
4169 lastSleepReason
= 0;
4171 if (((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
4172 (_currentCapability
& kIOPMSystemCapabilityCPU
))
4174 pmPowerStateQueue
->submitPowerEvent(
4175 kPowerEventPolicyStimulus
,
4176 (void *) kStimulusDarkWakeReentry
,
4177 _systemStateGeneration
);
4180 // Revert device desire to max.
4181 changePowerStateToPriv(ON_STATE
);
4185 // Send message on dark wake to full wake promotion.
4186 // tellChangeUp() handles the normal SLEEP->ON case.
4188 if (kSystemTransitionCapability
== _systemTransitionType
)
4190 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4192 tellClients(kIOMessageSystemHasPoweredOn
);
4193 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
4194 // Re-evaluate clamshell state ourselves when graphics
4195 // will not get kIOMessageSystemHasPoweredOn.
4197 if (clamshellClosed
&&
4198 ((_systemMessageClientMask
& kSystemMessageClientKernel
) == 0))
4200 receivePowerNotification( kLocalEvalClamshellCommand
);
4204 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4205 wranglerTickled
= false;
4208 // Reset state after exiting from dark wake.
4210 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
4211 CAP_LOSS(kIOPMSystemCapabilityCPU
))
4213 darkWakeMaintenance
= false;
4214 darkWakeToSleepASAP
= false;
4215 pciCantSleepValid
= false;
4216 rejectWranglerTickle
= false;
4219 // Entered dark mode.
4221 if (((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
4222 (_pendingCapability
& kIOPMSystemCapabilityCPU
))
4224 if (((gDarkWakeFlags
& kDarkWakeFlagIgnoreDiskIOInDark
) == 0) &&
4225 (kSystemTransitionWake
== _systemTransitionType
) &&
4226 (_debugWakeSeconds
== 0))
4228 OSObject
* prop
= copyProperty(kIOPMRootDomainWakeTypeKey
);
4231 OSString
* wakeType
= OSDynamicCast(OSString
, prop
);
4233 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeNetwork
))
4235 // Woke from network and entered dark wake.
4236 if (darkWakeToSleepASAP
)
4238 DLOG("cleared darkWakeToSleepASAP\n");
4239 darkWakeToSleepASAP
= false;
4246 // Queue an evaluation of whether to remain in dark wake,
4247 // and for how long. This serves the purpose of draining
4248 // any assertions from the queue.
4250 pmPowerStateQueue
->submitPowerEvent(
4251 kPowerEventPolicyStimulus
,
4252 (void *) kStimulusDarkWakeEntry
,
4253 _systemStateGeneration
);
4257 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4258 "dcp %x:%x:%x, dbgtimer %u\n",
4259 currentPowerState
, powerState
, changeFlags
,
4260 _systemTransitionType
, _systemStateGeneration
,
4261 _systemMessageClientMask
,
4262 _desiredCapability
, _currentCapability
, _pendingCapability
,
4265 // Update current system capability.
4267 if (_currentCapability
!= _pendingCapability
)
4268 _currentCapability
= _pendingCapability
;
4270 // Update highest system capability.
4272 if (!CAP_CURRENT(kIOPMSystemCapabilityCPU
))
4273 _highestCapability
= 0; // reset at sleep state
4275 _highestCapability
|= _currentCapability
;
4277 if (darkWakePostTickle
&&
4278 (kSystemTransitionWake
== _systemTransitionType
) &&
4279 (gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
4280 kDarkWakeFlagHIDTickleLate
)
4282 darkWakePostTickle
= false;
4286 // Reset tracepoint at completion of capability change,
4287 // completion of wake transition, and aborted sleep transition.
4289 if ((_systemTransitionType
== kSystemTransitionCapability
) ||
4290 (_systemTransitionType
== kSystemTransitionWake
) ||
4291 ((_systemTransitionType
== kSystemTransitionSleep
) &&
4292 (changeFlags
& kIOPMNotDone
)))
4294 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
4295 tracePoint( kIOPMTracePointSystemUp
, 0 );
4298 _systemTransitionType
= kSystemTransitionNone
;
4299 _systemMessageClientMask
= 0;
4301 logGraphicsClamp
= false;
4305 //******************************************************************************
4306 // PM actions for graphics and audio.
4307 //******************************************************************************
4309 void IOPMrootDomain::overridePowerChangeForUIService(
4310 IOService
* service
,
4311 IOPMActions
* actions
,
4312 unsigned long * inOutPowerState
,
4313 uint32_t * inOutChangeFlags
)
4315 uint32_t powerState
= (uint32_t) *inOutPowerState
;
4316 uint32_t changeFlags
= (uint32_t) *inOutChangeFlags
;
4318 if (kSystemTransitionNone
== _systemTransitionType
)
4320 // Not in midst of a system transition.
4321 // Do not modify power limit enable state.
4323 else if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
4325 // Activate power limiter.
4327 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
4328 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0))
4330 actions
->parameter
|= kPMActionsFlagLimitPower
;
4332 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
4333 ((_pendingCapability
& kIOPMSystemCapabilityAudio
) == 0))
4335 actions
->parameter
|= kPMActionsFlagLimitPower
;
4337 else if ((actions
->parameter
& kPMActionsFlagIsGraphicsDevice
) &&
4338 (_systemTransitionType
== kSystemTransitionSleep
))
4340 // For graphics devices, arm the limiter when entering
4341 // system sleep. Not when dropping to dark wake.
4342 actions
->parameter
|= kPMActionsFlagLimitPower
;
4345 if (actions
->parameter
& kPMActionsFlagLimitPower
)
4347 DLOG("+ plimit %s %p\n",
4348 service
->getName(), service
);
4353 // Remove power limit.
4355 if ((actions
->parameter
& (
4356 kPMActionsFlagIsDisplayWrangler
|
4357 kPMActionsFlagIsGraphicsDevice
)) &&
4358 (_pendingCapability
& kIOPMSystemCapabilityGraphics
))
4360 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
4362 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
4363 (_pendingCapability
& kIOPMSystemCapabilityAudio
))
4365 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
4368 if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
4370 DLOG("- plimit %s %p\n",
4371 service
->getName(), service
);
4375 if (gRAMDiskImageBoot
&&
4376 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
))
4378 // Tag devices subject to power suppression.
4379 *inOutChangeFlags
|= kIOPMPowerSuppressed
;
4382 if (actions
->parameter
& kPMActionsFlagLimitPower
)
4384 uint32_t maxPowerState
= (uint32_t)(-1);
4386 if (changeFlags
& (kIOPMDomainDidChange
| kIOPMDomainWillChange
))
4388 // Enforce limit for system power/cap transitions.
4391 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
4392 (!gRAMDiskImageBoot
|| (service
->getPowerState() > 0)))
4394 // Forces a 3->1 transition sequence
4395 if (changeFlags
& kIOPMDomainWillChange
)
4403 // Deny all self-initiated changes when power is limited.
4404 // Wrangler tickle should never defeat the limiter.
4406 maxPowerState
= service
->getPowerState();
4409 if (powerState
> maxPowerState
)
4411 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
4412 service
->getName(), service
, powerState
, maxPowerState
,
4414 *inOutPowerState
= maxPowerState
;
4416 if (darkWakePostTickle
&&
4417 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
4418 (changeFlags
& kIOPMDomainWillChange
) &&
4419 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
4420 kDarkWakeFlagHIDTickleEarly
))
4422 darkWakePostTickle
= false;
4427 if (!graphicsSuppressed
&& (changeFlags
& kIOPMDomainDidChange
))
4429 if (logGraphicsClamp
)
4434 clock_get_uptime(&now
);
4435 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
4436 absolutetime_to_nanoseconds(now
, &nsec
);
4437 MSG("Graphics suppressed %u ms\n",
4438 ((int)((nsec
) / 1000000ULL)));
4440 graphicsSuppressed
= true;
4445 void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
4446 IOService
* service
,
4447 IOPMActions
* actions
)
4449 // Warning: Not running in PM work loop context - don't modify state !!!
4450 // Trap tickle directed to IODisplayWrangler while running with graphics
4451 // capability suppressed.
4453 assert(service
== wrangler
);
4455 if (service
== wrangler
)
4457 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonIdle
)
4458 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
4460 userActivityCount
++;
4461 DLOG("display wrangler tickled1 %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
4465 if (!wranglerTickled
&& !lowBatteryCondition
&&
4466 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0))
4468 DLOG("display wrangler tickled\n");
4469 if (kIOLogPMRootDomain
& gIOKitDebug
)
4470 OSReportWithBacktrace("Dark wake display tickle");
4471 if (pmPowerStateQueue
)
4473 pmPowerStateQueue
->submitPowerEvent(
4474 kPowerEventPolicyStimulus
,
4475 (void *) kStimulusDarkWakeActivityTickle
);
4480 //******************************************************************************
4481 // Approve usage of delayed child notification by PM.
4482 //******************************************************************************
4484 bool IOPMrootDomain::shouldDelayChildNotification(
4485 IOService
* service
)
4487 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0) &&
4489 (kSystemTransitionWake
== _systemTransitionType
))
4491 DLOG("%s: delay child notify\n", service
->getName());
4497 //******************************************************************************
4498 // PM actions for PCI device.
4499 //******************************************************************************
4501 void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
4502 IOService
* service
,
4503 IOPMActions
* actions
,
4504 uint32_t powerState
,
4505 uint32_t * inOutChangeFlags
)
4507 pmTracer
->tracePCIPowerChange(
4508 PMTraceWorker::kPowerChangeStart
,
4509 service
, *inOutChangeFlags
,
4510 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
4513 void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
4514 IOService
* service
,
4515 IOPMActions
* actions
,
4516 uint32_t powerState
,
4517 uint32_t changeFlags
)
4519 pmTracer
->tracePCIPowerChange(
4520 PMTraceWorker::kPowerChangeCompleted
,
4521 service
, changeFlags
,
4522 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
4525 //******************************************************************************
4528 // Override IOService::registerInterest() to intercept special clients.
4529 //******************************************************************************
4531 IONotifier
* IOPMrootDomain::registerInterest(
4532 const OSSymbol
* typeOfInterest
,
4533 IOServiceInterestHandler handler
,
4534 void * target
, void * ref
)
4536 IONotifier
* notifier
;
4537 bool isSystemCapabilityClient
;
4538 bool isKernelCapabilityClient
;
4540 isSystemCapabilityClient
=
4542 typeOfInterest
->isEqualTo(kIOPMSystemCapabilityInterest
);
4544 isKernelCapabilityClient
=
4546 typeOfInterest
->isEqualTo(gIOPriorityPowerStateInterest
);
4548 if (isSystemCapabilityClient
)
4549 typeOfInterest
= gIOAppPowerStateInterest
;
4551 notifier
= super::registerInterest(typeOfInterest
, handler
, target
, ref
);
4552 if (notifier
&& pmPowerStateQueue
)
4554 if (isSystemCapabilityClient
)
4557 if (pmPowerStateQueue
->submitPowerEvent(
4558 kPowerEventRegisterSystemCapabilityClient
, notifier
) == false)
4559 notifier
->release();
4562 if (isKernelCapabilityClient
)
4565 if (pmPowerStateQueue
->submitPowerEvent(
4566 kPowerEventRegisterKernelCapabilityClient
, notifier
) == false)
4567 notifier
->release();
4574 //******************************************************************************
4575 // systemMessageFilter
4577 //******************************************************************************
4579 bool IOPMrootDomain::systemMessageFilter(
4580 void * object
, void * arg1
, void * arg2
, void * arg3
)
4582 const IOPMInterestContext
* context
= (const IOPMInterestContext
*) arg1
;
4583 bool isCapMsg
= (context
->messageType
== kIOMessageSystemCapabilityChange
);
4584 bool isCapClient
= false;
4588 if ((kSystemTransitionNewCapClient
== _systemTransitionType
) &&
4589 (!isCapMsg
|| !_joinedCapabilityClients
||
4590 !_joinedCapabilityClients
->containsObject((OSObject
*) object
)))
4593 // Capability change message for app and kernel clients.
4597 if ((context
->notifyType
== kNotifyPriority
) ||
4598 (context
->notifyType
== kNotifyCapabilityChangePriority
))
4601 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) &&
4602 (object
== (void *) systemCapabilityNotifier
))
4608 IOPMSystemCapabilityChangeParameters
* capArgs
=
4609 (IOPMSystemCapabilityChangeParameters
*) arg2
;
4611 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
4613 capArgs
->fromCapabilities
= 0;
4614 capArgs
->toCapabilities
= _currentCapability
;
4615 capArgs
->changeFlags
= 0;
4619 capArgs
->fromCapabilities
= _currentCapability
;
4620 capArgs
->toCapabilities
= _pendingCapability
;
4622 if (context
->isPreChange
)
4623 capArgs
->changeFlags
= kIOPMSystemCapabilityWillChange
;
4625 capArgs
->changeFlags
= kIOPMSystemCapabilityDidChange
;
4628 // Capability change messages only go to the PM configd plugin.
4629 // Wait for response post-change if capabilitiy is increasing.
4630 // Wait for response pre-change if capability is decreasing.
4632 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) && arg3
&&
4633 ( (capabilityLoss
&& context
->isPreChange
) ||
4634 (!capabilityLoss
&& !context
->isPreChange
) ) )
4636 // app has not replied yet, wait for it
4637 *((OSObject
**) arg3
) = kOSBooleanFalse
;
4644 // Capability client will always see kIOMessageCanSystemSleep,
4645 // even for demand sleep.
4647 if ((kIOMessageCanSystemSleep
== context
->messageType
) ||
4648 (kIOMessageSystemWillNotSleep
== context
->messageType
))
4650 if (object
== (OSObject
*) systemCapabilityNotifier
)
4656 // Not idle sleep, don't ask apps.
4657 if (context
->changeFlags
& kIOPMSkipAskPowerDown
)
4663 // Reject capability change messages for legacy clients.
4664 // Reject legacy system sleep messages for capability client.
4666 if (isCapMsg
|| (object
== (OSObject
*) systemCapabilityNotifier
))
4671 // Filter system sleep messages.
4673 if ((context
->notifyType
== kNotifyApps
) &&
4674 (_systemMessageClientMask
& kSystemMessageClientApp
))
4678 else if ((context
->notifyType
== kNotifyPriority
) &&
4679 (_systemMessageClientMask
& kSystemMessageClientKernel
))
4686 if (allow
&& isCapMsg
&& _joinedCapabilityClients
)
4688 _joinedCapabilityClients
->removeObject((OSObject
*) object
);
4689 if (_joinedCapabilityClients
->getCount() == 0)
4691 DLOG("destroyed capability client set %p\n",
4692 _joinedCapabilityClients
);
4693 _joinedCapabilityClients
->release();
4694 _joinedCapabilityClients
= 0;
4701 //******************************************************************************
4702 // setMaintenanceWakeCalendar
4704 //******************************************************************************
4706 IOReturn
IOPMrootDomain::setMaintenanceWakeCalendar(
4707 const IOPMCalendarStruct
* calendar
)
4713 return kIOReturnBadArgument
;
4715 data
= OSData::withBytesNoCopy((void *) calendar
, sizeof(*calendar
));
4717 return kIOReturnNoMemory
;
4719 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
, data
);
4726 // MARK: Display Wrangler
4728 //******************************************************************************
4729 // displayWranglerNotification
4731 // Handle the notification when the IODisplayWrangler changes power state.
4732 //******************************************************************************
4734 IOReturn
IOPMrootDomain::displayWranglerNotification(
4735 void * target
, void * refCon
,
4736 UInt32 messageType
, IOService
* service
,
4737 void * messageArgument
, vm_size_t argSize
)
4740 int displayPowerState
;
4741 IOPowerStateChangeNotification
* params
=
4742 (IOPowerStateChangeNotification
*) messageArgument
;
4744 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
4745 (messageType
!= kIOMessageDeviceHasPoweredOn
))
4746 return kIOReturnUnsupported
;
4750 return kIOReturnUnsupported
;
4752 displayPowerState
= params
->stateNumber
;
4753 DLOG("DisplayWrangler message 0x%x, power state %d\n",
4754 (uint32_t) messageType
, displayPowerState
);
4756 switch (messageType
) {
4757 case kIOMessageDeviceWillPowerOff
:
4759 // Display wrangler has dropped power due to display idle
4760 // or force system sleep.
4765 // 1 Not visible to user
4766 // 0 Not visible to user
4768 if (displayPowerState
> 2)
4771 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerSleep
);
4774 case kIOMessageDeviceHasPoweredOn
:
4776 // Display wrangler has powered on due to user activity
4777 // or wake from sleep.
4779 if ( 4 != displayPowerState
)
4782 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerWake
);
4786 return kIOReturnUnsupported
;
4789 //*********************************************************************************
4790 // displayWranglerMatchPublished
4792 // Receives a notification when the IODisplayWrangler is published.
4793 // When it's published we install a power state change handler.
4794 //******************************************************************************
4796 bool IOPMrootDomain::displayWranglerMatchPublished(
4799 IOService
* newService
,
4800 IONotifier
* notifier __unused
)
4803 // found the display wrangler, now install a handler
4804 if( !newService
->registerInterest( gIOGeneralInterest
,
4805 &displayWranglerNotification
, target
, 0) )
4813 //******************************************************************************
4816 //******************************************************************************
4818 void IOPMrootDomain::reportUserInput( void )
4825 iter
= getMatchingServices(serviceMatching("IODisplayWrangler"));
4828 wrangler
= (IOService
*) iter
->getNextObject();
4834 wrangler
->activityTickle(0,0);
4841 //******************************************************************************
4844 // Notification on battery class IOPowerSource appearance
4845 //******************************************************************************
4847 bool IOPMrootDomain::batteryPublished(
4850 IOService
* resourceService
,
4851 IONotifier
* notifier __unused
)
4853 // rdar://2936060&4435589
4854 // All laptops have dimmable LCD displays
4855 // All laptops have batteries
4856 // So if this machine has a battery, publish the fact that the backlight
4857 // supports dimming.
4858 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
4864 // MARK: System PM Policy
4866 //******************************************************************************
4867 // checkSystemCanSleep
4869 //******************************************************************************
4871 bool IOPMrootDomain::checkSystemCanSleep( IOOptionBits options
)
4875 // Conditions that prevent idle and demand system sleep.
4878 if (userDisabledAllSleep
)
4880 err
= 1; // 1. user-space sleep kill switch
4884 if (systemBooting
|| systemShutdown
)
4886 err
= 2; // 2. restart or shutdown in progress
4893 // Conditions above pegs the system at full wake.
4894 // Conditions below prevent system sleep but does not prevent
4895 // dark wake, and must be called from gated context.
4898 err
= 3; // 3. config does not support sleep
4902 if (lowBatteryCondition
)
4904 break; // always sleep on low battery
4907 if (childPreventSystemSleep
)
4909 err
= 4; // 4. child prevent system sleep clamp
4913 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit
) ==
4914 kIOPMDriverAssertionLevelOn
)
4916 err
= 5; // 5. CPU assertion
4920 if (pciCantSleepValid
)
4922 if (pciCantSleepFlag
)
4923 err
= 6; // 6. PCI card does not support PM (cached)
4926 else if (sleepSupportedPEFunction
&&
4927 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
4930 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
4931 ret
= getPlatform()->callPlatformFunction(
4932 sleepSupportedPEFunction
, false,
4933 NULL
, NULL
, NULL
, NULL
);
4934 pciCantSleepValid
= true;
4935 pciCantSleepFlag
= false;
4936 if ((platformSleepSupport
& kPCICantSleep
) ||
4937 ((ret
!= kIOReturnSuccess
) && (ret
!= kIOReturnUnsupported
)))
4939 err
= 6; // 6. PCI card does not support PM
4940 pciCantSleepFlag
= true;
4949 DLOG("System sleep prevented by %d\n", err
);
4955 //******************************************************************************
4958 // Conditions that affect our wake/sleep decision has changed.
4959 // If conditions dictate that the system must remain awake, clamp power
4960 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
4961 // is TRUE, then remove the power clamp and allow the power state to drop
4963 //******************************************************************************
4965 void IOPMrootDomain::adjustPowerState( bool sleepASAP
)
4967 DLOG("adjustPowerState ps %u, asap %d, slider %ld\n",
4968 (uint32_t) getPowerState(), sleepASAP
, sleepSlider
);
4972 if ((sleepSlider
== 0) || !checkSystemCanSleep())
4974 changePowerStateToPriv(ON_STATE
);
4976 else if ( sleepASAP
)
4978 changePowerStateToPriv(SLEEP_STATE
);
4982 //******************************************************************************
4983 // dispatchPowerEvent
4985 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
4986 //******************************************************************************
4988 void IOPMrootDomain::dispatchPowerEvent(
4989 uint32_t event
, void * arg0
, uint64_t arg1
)
4991 DLOG("power event %u args %p 0x%llx\n", event
, arg0
, arg1
);
4996 case kPowerEventFeatureChanged
:
4997 messageClients(kIOPMMessageFeatureChange
, this);
5000 case kPowerEventReceivedPowerNotification
:
5001 handlePowerNotification( (UInt32
)(uintptr_t) arg0
);
5004 case kPowerEventSystemBootCompleted
:
5007 systemBooting
= false;
5009 // If lid is closed, re-send lid closed notification
5010 // now that booting is complete.
5011 if ( clamshellClosed
)
5013 handlePowerNotification(kLocalEvalClamshellCommand
);
5015 evaluatePolicy( kStimulusAllowSystemSleepChanged
);
5019 case kPowerEventSystemShutdown
:
5020 if (kOSBooleanTrue
== (OSBoolean
*) arg0
)
5022 /* We set systemShutdown = true during shutdown
5023 to prevent sleep at unexpected times while loginwindow is trying
5024 to shutdown apps and while the OS is trying to transition to
5027 Set to true during shutdown, as soon as loginwindow shows
5028 the "shutdown countdown dialog", through individual app
5029 termination, and through black screen kernel shutdown.
5031 systemShutdown
= true;
5034 A shutdown was initiated, but then the shutdown
5035 was cancelled, clearing systemShutdown to false here.
5037 systemShutdown
= false;
5041 case kPowerEventUserDisabledSleep
:
5042 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
5045 case kPowerEventRegisterSystemCapabilityClient
:
5046 if (systemCapabilityNotifier
)
5048 systemCapabilityNotifier
->release();
5049 systemCapabilityNotifier
= 0;
5053 systemCapabilityNotifier
= (IONotifier
*) arg0
;
5054 systemCapabilityNotifier
->retain();
5056 /* intentional fall-through */
5058 case kPowerEventRegisterKernelCapabilityClient
:
5059 if (!_joinedCapabilityClients
)
5060 _joinedCapabilityClients
= OSSet::withCapacity(8);
5063 IONotifier
* notify
= (IONotifier
*) arg0
;
5064 if (_joinedCapabilityClients
)
5066 _joinedCapabilityClients
->setObject(notify
);
5067 synchronizePowerTree( kIOPMSyncNoChildNotify
);
5073 case kPowerEventPolicyStimulus
:
5076 int stimulus
= (uintptr_t) arg0
;
5077 evaluatePolicy( stimulus
, (uint32_t) arg1
);
5081 case kPowerEventAssertionCreate
:
5083 pmAssertions
->handleCreateAssertion((OSData
*)arg0
);
5088 case kPowerEventAssertionRelease
:
5090 pmAssertions
->handleReleaseAssertion(arg1
);
5094 case kPowerEventAssertionSetLevel
:
5096 pmAssertions
->handleSetAssertionLevel(arg1
, (IOPMDriverAssertionLevel
)(uintptr_t)arg0
);
5100 case kPowerEventQueueSleepWakeUUID
:
5101 handleQueueSleepWakeUUID((OSObject
*)arg0
);
5103 case kPowerEventPublishSleepWakeUUID
:
5104 handlePublishSleepWakeUUID((bool)arg0
);
5109 //******************************************************************************
5110 // systemPowerEventOccurred
5112 // The power controller is notifying us of a hardware-related power management
5113 // event that we must handle.
5115 // systemPowerEventOccurred covers the same functionality that
5116 // receivePowerNotification does; it simply provides a richer API for conveying
5117 // more information.
5118 //******************************************************************************
5120 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
5121 const OSSymbol
*event
,
5124 IOReturn attempt
= kIOReturnSuccess
;
5125 OSNumber
*newNumber
= NULL
;
5128 return kIOReturnBadArgument
;
5130 newNumber
= OSNumber::withNumber(intValue
, 8*sizeof(intValue
));
5132 return kIOReturnInternalError
;
5134 attempt
= systemPowerEventOccurred(event
, (OSObject
*)newNumber
);
5136 newNumber
->release();
5141 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
5142 const OSSymbol
*event
,
5145 OSDictionary
*thermalsDict
= NULL
;
5146 bool shouldUpdate
= true;
5148 if (!event
|| !value
)
5149 return kIOReturnBadArgument
;
5152 // We reuse featuresDict Lock because it already exists and guards
5153 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
5154 // of stepping on that lock.
5155 if (featuresDictLock
) IOLockLock(featuresDictLock
);
5157 thermalsDict
= (OSDictionary
*)getProperty(kIOPMRootDomainPowerStatusKey
);
5159 if (thermalsDict
&& OSDynamicCast(OSDictionary
, thermalsDict
)) {
5160 thermalsDict
= OSDictionary::withDictionary(thermalsDict
);
5162 thermalsDict
= OSDictionary::withCapacity(1);
5165 if (!thermalsDict
) {
5166 shouldUpdate
= false;
5170 thermalsDict
->setObject (event
, value
);
5172 setProperty (kIOPMRootDomainPowerStatusKey
, thermalsDict
);
5174 thermalsDict
->release();
5178 if (featuresDictLock
) IOLockUnlock(featuresDictLock
);
5181 messageClients (kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
5183 return kIOReturnSuccess
;
5186 //******************************************************************************
5187 // receivePowerNotification
5189 // The power controller is notifying us of a hardware-related power management
5190 // event that we must handle. This may be a result of an 'environment' interrupt
5191 // from the power mgt micro.
5192 //******************************************************************************
5194 IOReturn
IOPMrootDomain::receivePowerNotification( UInt32 msg
)
5196 pmPowerStateQueue
->submitPowerEvent(
5197 kPowerEventReceivedPowerNotification
, (void *) msg
);
5198 return kIOReturnSuccess
;
5201 void IOPMrootDomain::handlePowerNotification( UInt32 msg
)
5203 bool eval_clamshell
= false;
5208 * Local (IOPMrootDomain only) eval clamshell command
5210 if (msg
& kLocalEvalClamshellCommand
)
5212 eval_clamshell
= true;
5218 if (msg
& kIOPMOverTemp
)
5220 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
5221 privateSleepSystem (kIOPMSleepReasonThermalEmergency
);
5227 if (msg
& kIOPMSleepNow
)
5229 privateSleepSystem (kIOPMSleepReasonSoftware
);
5235 if (msg
& kIOPMPowerEmergency
)
5237 lowBatteryCondition
= true;
5238 privateSleepSystem (kIOPMSleepReasonLowPower
);
5244 if (msg
& kIOPMClamshellOpened
)
5246 // Received clamshel open message from clamshell controlling driver
5247 // Update our internal state and tell general interest clients
5248 clamshellClosed
= false;
5249 clamshellExists
= true;
5251 if (msg
& kIOPMSetValue
)
5257 informCPUStateChange(kInformLid
, 0);
5259 // Tell general interest clients
5260 sendClientClamshellNotification();
5262 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonClamshell
)
5263 || (lastSleepReason
== kIOPMSleepReasonIdle
)
5264 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
5265 if (aborting
) userActivityCount
++;
5266 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
5271 * Send the clamshell interest notification since the lid is closing.
5273 if (msg
& kIOPMClamshellClosed
)
5275 // Received clamshel open message from clamshell controlling driver
5276 // Update our internal state and tell general interest clients
5277 clamshellClosed
= true;
5278 clamshellExists
= true;
5281 informCPUStateChange(kInformLid
, 1);
5283 // Tell general interest clients
5284 sendClientClamshellNotification();
5286 // And set eval_clamshell = so we can attempt
5287 eval_clamshell
= true;
5291 * Set Desktop mode (sent from graphics)
5293 * -> reevaluate lid state
5295 if (msg
& kIOPMSetDesktopMode
)
5297 desktopMode
= (0 != (msg
& kIOPMSetValue
));
5298 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
5300 sendClientClamshellNotification();
5302 // Re-evaluate the lid state
5303 if( clamshellClosed
)
5305 eval_clamshell
= true;
5310 * AC Adaptor connected
5312 * -> reevaluate lid state
5314 if (msg
& kIOPMSetACAdaptorConnected
)
5316 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
5317 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
5320 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
5322 // Tell BSD if AC is connected
5323 // 0 == external power source; 1 == on battery
5324 post_sys_powersource(acAdaptorConnected
? 0:1);
5326 sendClientClamshellNotification();
5328 // Re-evaluate the lid state
5329 if( clamshellClosed
)
5331 eval_clamshell
= true;
5336 * Enable Clamshell (external display disappear)
5338 * -> reevaluate lid state
5340 if (msg
& kIOPMEnableClamshell
)
5342 // Re-evaluate the lid state
5343 // System should sleep on external display disappearance
5344 // in lid closed operation.
5345 if( clamshellClosed
&& (true == clamshellDisabled
) )
5347 eval_clamshell
= true;
5350 clamshellDisabled
= false;
5352 sendClientClamshellNotification();
5356 * Disable Clamshell (external display appeared)
5357 * We don't bother re-evaluating clamshell state. If the system is awake,
5358 * the lid is probably open.
5360 if (msg
& kIOPMDisableClamshell
)
5362 clamshellDisabled
= true;
5364 sendClientClamshellNotification();
5368 * Evaluate clamshell and SLEEP if appropiate
5370 if ( eval_clamshell
&& shouldSleepOnClamshellClosed() )
5375 privateSleepSystem (kIOPMSleepReasonClamshell
);
5377 else if ( eval_clamshell
)
5379 evaluatePolicy(kStimulusDarkWakeEvaluate
);
5385 if (msg
& kIOPMPowerButton
)
5387 if (!wranglerAsleep
)
5389 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
5390 // Check that power button sleep is enabled
5392 if( kOSBooleanTrue
!= getProperty(pbs
))
5393 privateSleepSystem (kIOPMSleepReasonPowerButton
);
5401 //******************************************************************************
5404 // Evaluate root-domain policy in response to external changes.
5405 //******************************************************************************
5407 void IOPMrootDomain::evaluatePolicy( int stimulus
, uint32_t arg
)
5411 int idleSleepEnabled
: 1;
5412 int idleSleepDisabled
: 1;
5413 int displaySleep
: 1;
5414 int sleepDelayChanged
: 1;
5415 int evaluateDarkWake
: 1;
5420 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
5427 case kStimulusDisplayWranglerSleep
:
5428 if (!wranglerAsleep
)
5430 wranglerAsleep
= true;
5431 clock_get_uptime(&wranglerSleepTime
);
5432 flags
.bit
.displaySleep
= true;
5436 case kStimulusDisplayWranglerWake
:
5437 wranglerAsleep
= false;
5438 flags
.bit
.idleSleepDisabled
= true;
5441 case kStimulusAggressivenessChanged
:
5443 unsigned long minutesToIdleSleep
= 0;
5444 unsigned long minutesToDisplayDim
= 0;
5445 unsigned long minutesDelta
= 0;
5447 // Fetch latest display and system sleep slider values.
5448 getAggressiveness(kPMMinutesToSleep
, &minutesToIdleSleep
);
5449 getAggressiveness(kPMMinutesToDim
, &minutesToDisplayDim
);
5450 DLOG("aggressiveness changed: system %u->%u, display %u\n",
5451 (uint32_t) sleepSlider
,
5452 (uint32_t) minutesToIdleSleep
,
5453 (uint32_t) minutesToDisplayDim
);
5455 DLOG("idle time -> %ld secs (ena %d)\n",
5456 idleSeconds
, (minutesToIdleSleep
!= 0));
5458 if (0x7fffffff == minutesToIdleSleep
)
5459 minutesToIdleSleep
= idleSeconds
;
5461 // How long to wait before sleeping the system once
5462 // the displays turns off is indicated by 'extraSleepDelay'.
5464 if ( minutesToIdleSleep
> minutesToDisplayDim
)
5465 minutesDelta
= minutesToIdleSleep
- minutesToDisplayDim
;
5467 if ((sleepSlider
== 0) && (minutesToIdleSleep
!= 0))
5468 flags
.bit
.idleSleepEnabled
= true;
5470 if ((sleepSlider
!= 0) && (minutesToIdleSleep
== 0))
5471 flags
.bit
.idleSleepDisabled
= true;
5473 if ((minutesDelta
!= extraSleepDelay
) &&
5474 !flags
.bit
.idleSleepEnabled
&& !flags
.bit
.idleSleepDisabled
)
5475 flags
.bit
.sleepDelayChanged
= true;
5477 if (systemDarkWake
&& !darkWakeToSleepASAP
&&
5478 (flags
.bit
.idleSleepEnabled
|| flags
.bit
.idleSleepDisabled
))
5480 // Reconsider decision to remain in dark wake
5481 flags
.bit
.evaluateDarkWake
= true;
5484 sleepSlider
= minutesToIdleSleep
;
5485 extraSleepDelay
= minutesDelta
;
5488 case kStimulusDemandSystemSleep
:
5489 changePowerStateWithOverrideTo( SLEEP_STATE
);
5492 case kStimulusAllowSystemSleepChanged
:
5493 // FIXME: de-compose to change flags.
5497 case kStimulusDarkWakeActivityTickle
:
5498 if (false == wranglerTickled
)
5500 uint32_t options
= 0;
5501 IOService
* pciRoot
= 0;
5503 if (rejectWranglerTickle
)
5505 DLOG("rejected tickle, type %u capability %x:%x\n",
5506 _systemTransitionType
,
5507 _currentCapability
, _pendingCapability
);
5511 _desiredCapability
|=
5512 (kIOPMSystemCapabilityGraphics
|
5513 kIOPMSystemCapabilityAudio
);
5515 if ((kSystemTransitionWake
== _systemTransitionType
) &&
5516 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
5517 !graphicsSuppressed
)
5519 DLOG("Promoting to full wake\n");
5521 // Elevate to full wake while waking up to dark wake.
5522 // PM will hold off notifying the graphics subsystem about
5523 // system wake as late as possible, so if a HID event does
5524 // arrive, we can turn on graphics on this wake cycle, and
5525 // not have to wait till the following cycle. That latency
5526 // can be huge on some systems. However, once any graphics
5527 // suppression has taken effect, it is too late. All other
5528 // graphics devices must be similarly suppressed. But the
5529 // delay till the following cycle should be very short.
5531 _pendingCapability
|=
5532 (kIOPMSystemCapabilityGraphics
|
5533 kIOPMSystemCapabilityAudio
);
5535 // Immediately bring up audio and graphics.
5536 pciRoot
= pciHostBridgeDriver
;
5538 // Notify clients about full wake.
5539 _systemMessageClientMask
= kSystemMessageClientAll
;
5540 tellClients(kIOMessageSystemWillPowerOn
);
5543 // Unsafe to cancel once graphics was powered.
5544 // If system woke from dark wake, the return to sleep can
5545 // be cancelled. But "awake -> dark -> sleep" transition
5546 // cannot be cancelled.
5548 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
)) {
5549 options
|= kIOPMSyncCancelPowerDown
;
5552 synchronizePowerTree( options
, pciRoot
);
5553 wranglerTickled
= true;
5554 // IOGraphics doesn't lit the display even though graphics
5555 // is enanbled in kIOMessageSystemCapabilityChange message(radar 9502104)
5556 // So, do an explicit activity tickle
5558 wrangler
->activityTickle(0,0);
5560 if (logWranglerTickle
)
5565 clock_get_uptime(&now
);
5566 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
5567 absolutetime_to_nanoseconds(now
, &nsec
);
5568 MSG("HID tickle %u ms\n",
5569 ((int)((nsec
) / 1000000ULL)));
5570 logWranglerTickle
= false;
5575 case kStimulusDarkWakeEntry
:
5576 case kStimulusDarkWakeReentry
:
5577 // Any system transitions since the last dark wake transition
5578 // will invalid the stimulus.
5580 if (arg
== _systemStateGeneration
)
5582 DLOG("dark wake entry\n");
5583 systemDarkWake
= true;
5584 wranglerAsleep
= true;
5585 clock_get_uptime(&wranglerSleepTime
);
5587 // Always accelerate disk spindown while in dark wake,
5588 // even if system does not support/allow sleep.
5590 cancelIdleSleepTimer();
5591 setQuickSpinDownTimeout();
5592 flags
.bit
.evaluateDarkWake
= true;
5596 case kStimulusDarkWakeEvaluate
:
5599 flags
.bit
.evaluateDarkWake
= true;
5601 #if !DARK_TO_FULL_EVALUATE_CLAMSHELL
5604 // Not through kLocalEvalClamshellCommand to avoid loop.
5605 if (clamshellClosed
&& shouldSleepOnClamshellClosed() &&
5606 checkSystemCanSleep(true))
5608 privateSleepSystem( kIOPMSleepReasonClamshell
);
5614 } /* switch(stimulus) */
5616 if (flags
.bit
.evaluateDarkWake
&& !wranglerTickled
)
5618 if (darkWakeToSleepASAP
||
5619 (clamshellClosed
&& !(desktopMode
&& acAdaptorConnected
)))
5621 // System currently in dark wake, and no children and
5622 // assertion prevent system sleep.
5624 if (checkSystemCanSleep(true))
5626 if (lowBatteryCondition
)
5628 lastSleepReason
= kIOPMSleepReasonLowPower
;
5629 setProperty(kRootDomainSleepReasonKey
, kIOPMLowPowerSleepKey
);
5631 else if (darkWakeMaintenance
)
5633 lastSleepReason
= kIOPMSleepReasonMaintenance
;
5634 setProperty(kRootDomainSleepReasonKey
, kIOPMMaintenanceSleepKey
);
5636 changePowerStateWithOverrideTo( SLEEP_STATE
);
5640 // Parked in dark wake, a tickle will return to full wake
5641 rejectWranglerTickle
= false;
5643 } else // non-maintenance (network) dark wake
5645 if (checkSystemCanSleep(true))
5647 // Release power clamp, and wait for children idle.
5648 adjustPowerState(true);
5652 changePowerStateToPriv(ON_STATE
);
5654 rejectWranglerTickle
= false;
5660 // The rest are irrelevant while system is in dark wake.
5664 if (flags
.bit
.displaySleep
|| flags
.bit
.sleepDelayChanged
)
5666 bool cancelQuickSpindown
= false;
5668 if (flags
.bit
.sleepDelayChanged
)
5670 DLOG("extra sleep timer changed\n");
5671 cancelIdleSleepTimer();
5672 cancelQuickSpindown
= true;
5676 DLOG("display sleep\n");
5679 if (wranglerAsleep
&& !wranglerSleepIgnored
)
5681 if ( extraSleepDelay
)
5683 // Start a timer here if the System Sleep timer is greater
5684 // than the Display Sleep timer.
5686 startIdleSleepTimer(gRootDomain
->extraSleepDelay
* 60);
5688 else if ( sleepSlider
)
5690 // Accelerate disk spindown if system sleep and display sleep
5691 // sliders are set to the same value (e.g. both set to 5 min),
5692 // and display is about to go dark. Check the system sleep is
5693 // not set to never sleep. Disk sleep setting is ignored.
5695 setQuickSpinDownTimeout();
5696 cancelQuickSpindown
= false;
5700 if (cancelQuickSpindown
)
5701 restoreUserSpinDownTimeout();
5704 if (flags
.bit
.idleSleepEnabled
)
5706 DLOG("idle sleep timer enabled\n");
5709 changePowerStateToPriv(ON_STATE
);
5712 startIdleSleepTimer( idleSeconds
);
5717 // Start idle sleep timer if wrangler went to sleep
5718 // while system sleep was disabled. Disk spindown is
5719 // accelerated upon timer expiration.
5725 uint32_t minutesSinceDisplaySleep
= 0;
5726 uint32_t sleepDelay
;
5728 clock_get_uptime(&now
);
5729 if (CMP_ABSOLUTETIME(&now
, &wranglerSleepTime
) > 0)
5731 SUB_ABSOLUTETIME(&now
, &wranglerSleepTime
);
5732 absolutetime_to_nanoseconds(now
, &nanos
);
5733 minutesSinceDisplaySleep
= nanos
/ (60000000000ULL);
5736 if (extraSleepDelay
> minutesSinceDisplaySleep
)
5738 sleepDelay
= extraSleepDelay
- minutesSinceDisplaySleep
;
5742 sleepDelay
= 1; // 1 min
5745 startIdleSleepTimer(sleepDelay
* 60);
5746 DLOG("display slept %u min, set idle timer to %u min\n",
5747 minutesSinceDisplaySleep
, sleepDelay
);
5752 if (flags
.bit
.idleSleepDisabled
)
5754 DLOG("idle sleep timer disabled\n");
5755 cancelIdleSleepTimer();
5756 restoreUserSpinDownTimeout();
5764 //******************************************************************************
5767 //******************************************************************************
5769 void IOPMrootDomain::pmStatsRecordEvent(
5771 AbsoluteTime timestamp
)
5773 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
5774 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
5778 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
5780 absolutetime_to_nanoseconds(timestamp
, &nsec
);
5782 switch (eventIndex
) {
5783 case kIOPMStatsHibernateImageWrite
:
5785 pmStats
.hibWrite
.start
= nsec
;
5787 pmStats
.hibWrite
.stop
= nsec
;
5790 delta
= pmStats
.hibWrite
.stop
- pmStats
.hibWrite
.start
;
5791 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/1000000ULL);
5794 case kIOPMStatsHibernateImageRead
:
5796 pmStats
.hibRead
.start
= nsec
;
5798 pmStats
.hibRead
.stop
= nsec
;
5801 delta
= pmStats
.hibRead
.stop
- pmStats
.hibRead
.start
;
5802 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/1000000ULL);
5809 * Appends a record of the application response to
5810 * IOPMrootDomain::pmStatsAppResponses
5812 void IOPMrootDomain::pmStatsRecordApplicationResponse(
5813 const OSSymbol
*response
,
5819 OSDictionary
*responseDescription
= NULL
;
5820 OSNumber
*delayNum
= NULL
;
5821 OSNumber
*pidNum
= NULL
;
5822 OSNumber
*msgNum
= NULL
;
5823 const OSSymbol
*appname
;
5824 const OSSymbol
*entryName
;
5825 OSObject
*entryType
;
5828 if (!pmStatsAppResponses
|| pmStatsAppResponses
->getCount() > 50)
5832 while ((responseDescription
= (OSDictionary
*) pmStatsAppResponses
->getObject(i
++)))
5834 entryType
= responseDescription
->getObject(_statsResponseTypeKey
);
5835 entryName
= (OSSymbol
*) responseDescription
->getObject(_statsNameKey
);
5836 if (entryName
&& (entryType
== response
) && entryName
->isEqualTo(name
))
5838 OSNumber
* entryValue
;
5839 entryValue
= (OSNumber
*) responseDescription
->getObject(_statsTimeMSKey
);
5840 if (entryValue
&& (entryValue
->unsigned32BitValue() < delay_ms
))
5841 entryValue
->setValue(delay_ms
);
5846 responseDescription
= OSDictionary::withCapacity(5);
5847 if (responseDescription
)
5850 responseDescription
->setObject(_statsResponseTypeKey
, response
);
5853 if (messageType
!= 0) {
5854 msgNum
= OSNumber::withNumber(messageType
, 32);
5856 responseDescription
->setObject(_statsMessageTypeKey
, msgNum
);
5861 if (name
&& (strlen(name
) > 0))
5863 appname
= OSSymbol::withCString(name
);
5865 responseDescription
->setObject(_statsNameKey
, appname
);
5870 if (app_pid
!= -1) {
5871 pidNum
= OSNumber::withNumber(app_pid
, 32);
5873 responseDescription
->setObject(_statsPIDKey
, pidNum
);
5878 delayNum
= OSNumber::withNumber(delay_ms
, 32);
5880 responseDescription
->setObject(_statsTimeMSKey
, delayNum
);
5881 delayNum
->release();
5884 if (pmStatsAppResponses
) {
5885 pmStatsAppResponses
->setObject(responseDescription
);
5888 responseDescription
->release();
5894 // MARK: PMTraceWorker
5896 //******************************************************************************
5897 // TracePoint support
5899 //******************************************************************************
5901 #define kIOPMRegisterNVRAMTracePointHandlerKey \
5902 "IOPMRegisterNVRAMTracePointHandler"
5904 IOReturn
IOPMrootDomain::callPlatformFunction(
5905 const OSSymbol
* functionName
,
5906 bool waitForFunction
,
5907 void * param1
, void * param2
,
5908 void * param3
, void * param4
)
5910 if (pmTracer
&& functionName
&&
5911 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
5912 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
)
5914 uint32_t tracePointPhases
, tracePointPCI
;
5915 uint64_t statusCode
;
5917 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
5918 pmTracer
->tracePointTarget
= (void *) param2
;
5919 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
5920 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
5921 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
5922 if ((tracePointPhases
>> 24) != kIOPMTracePointSystemUp
)
5924 MSG("Sleep failure code 0x%08x 0x%08x\n",
5925 tracePointPCI
, tracePointPhases
);
5927 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
5928 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
5930 return kIOReturnSuccess
;
5933 return super::callPlatformFunction(
5934 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
5937 void IOPMrootDomain::tracePoint( uint8_t point
)
5940 pmTracer
->tracePoint(point
);
5943 void IOPMrootDomain::tracePoint( uint8_t point
, uint8_t data
)
5946 pmTracer
->tracePoint(point
, data
);
5949 void IOPMrootDomain::traceDetail( uint32_t detail
)
5952 pmTracer
->traceDetail( detail
);
5955 //******************************************************************************
5956 // PMTraceWorker Class
5958 //******************************************************************************
5961 #define super OSObject
5962 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
5964 #define kPMBestGuessPCIDevicesCount 25
5965 #define kPMMaxRTCBitfieldSize 32
5967 PMTraceWorker
*PMTraceWorker::tracer(IOPMrootDomain
*owner
)
5971 me
= OSTypeAlloc( PMTraceWorker
);
5972 if (!me
|| !me
->init())
5977 DLOG("PMTraceWorker %p\n", me
);
5979 // Note that we cannot instantiate the PCI device -> bit mappings here, since
5980 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
5981 // this dictionary lazily.
5983 me
->pciDeviceBitMappings
= NULL
;
5984 me
->pciMappingLock
= IOLockAlloc();
5985 me
->tracePhase
= kIOPMTracePointSystemUp
;
5986 me
->loginWindowPhase
= 0;
5987 me
->traceData32
= 0;
5991 void PMTraceWorker::RTC_TRACE(void)
5993 if (tracePointHandler
&& tracePointTarget
)
5997 wordA
= (tracePhase
<< 24) | (loginWindowPhase
<< 16) |
6000 tracePointHandler( tracePointTarget
, traceData32
, wordA
);
6001 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32
, wordA
);
6005 int PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
6007 const OSSymbol
* deviceName
;
6010 IOLockLock(pciMappingLock
);
6012 if (!pciDeviceBitMappings
)
6014 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
6015 if (!pciDeviceBitMappings
)
6019 // Check for bitmask overflow.
6020 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
)
6023 if ((deviceName
= pciDevice
->copyName()) &&
6024 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
, 0) == (unsigned int)-1) &&
6025 pciDeviceBitMappings
->setObject(deviceName
))
6027 index
= pciDeviceBitMappings
->getCount() - 1;
6028 _LOG("PMTrace PCI array: set object %s => %d\n",
6029 deviceName
->getCStringNoCopy(), index
);
6032 deviceName
->release();
6033 if (!addedToRegistry
&& (index
>= 0))
6034 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
6037 IOLockUnlock(pciMappingLock
);
6041 bool PMTraceWorker::serialize(OSSerialize
*s
) const
6044 if (pciDeviceBitMappings
)
6046 IOLockLock(pciMappingLock
);
6047 ok
= pciDeviceBitMappings
->serialize(s
);
6048 IOLockUnlock(pciMappingLock
);
6053 void PMTraceWorker::tracePoint(uint8_t phase
)
6055 // clear trace detail when phase begins
6056 if (tracePhase
!= phase
)
6061 DLOG("trace point 0x%02x\n", tracePhase
);
6065 void PMTraceWorker::tracePoint(uint8_t phase
, uint8_t data8
)
6067 // clear trace detail when phase begins
6068 if (tracePhase
!= phase
)
6074 DLOG("trace point 0x%02x 0x%02x\n", tracePhase
, traceData8
);
6078 void PMTraceWorker::traceDetail(uint32_t detail
)
6080 if (kIOPMTracePointSleepPriorityClients
!= tracePhase
)
6083 traceData32
= detail
;
6084 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
6089 void PMTraceWorker::traceLoginWindowPhase(uint8_t phase
)
6091 loginWindowPhase
= phase
;
6093 DLOG("loginwindow tracepoint 0x%02x\n", loginWindowPhase
);
6097 void PMTraceWorker::tracePCIPowerChange(
6098 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
6101 uint32_t expectedFlag
;
6103 // Ignore PCI changes outside of system sleep/wake.
6104 if ((kIOPMTracePointSleepPowerPlaneDrivers
!= tracePhase
) &&
6105 (kIOPMTracePointWakePowerPlaneDrivers
!= tracePhase
))
6108 // Only record the WillChange transition when going to sleep,
6109 // and the DidChange on the way up.
6110 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
6111 expectedFlag
= (kIOPMTracePointSleepPowerPlaneDrivers
== tracePhase
) ?
6112 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
6113 if (changeFlags
!= expectedFlag
)
6116 // Mark this device off in our bitfield
6117 if (bitNum
< kPMMaxRTCBitfieldSize
)
6119 bitMask
= (1 << bitNum
);
6121 if (kPowerChangeStart
== type
)
6123 traceData32
|= bitMask
;
6124 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
6125 service
->getName(), bitNum
, bitMask
, traceData32
);
6129 traceData32
&= ~bitMask
;
6130 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
6131 service
->getName(), bitNum
, bitMask
, traceData32
);
6139 // MARK: PMHaltWorker
6141 //******************************************************************************
6142 // PMHaltWorker Class
6144 //******************************************************************************
6146 static unsigned int gPMHaltBusyCount
;
6147 static unsigned int gPMHaltIdleCount
;
6148 static int gPMHaltDepth
;
6149 static unsigned long gPMHaltEvent
;
6150 static IOLock
* gPMHaltLock
= 0;
6151 static OSArray
* gPMHaltArray
= 0;
6152 static const OSSymbol
* gPMHaltClientAcknowledgeKey
= 0;
6154 PMHaltWorker
* PMHaltWorker::worker( void )
6160 me
= OSTypeAlloc( PMHaltWorker
);
6161 if (!me
|| !me
->init())
6164 me
->lock
= IOLockAlloc();
6168 DLOG("PMHaltWorker %p\n", me
);
6169 me
->retain(); // thread holds extra retain
6170 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
))
6175 thread_deallocate(thread
);
6180 if (me
) me
->release();
6184 void PMHaltWorker::free( void )
6186 DLOG("PMHaltWorker free %p\n", this);
6192 return OSObject::free();
6195 void PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
6197 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
6199 IOLockLock( gPMHaltLock
);
6201 me
->depth
= gPMHaltDepth
;
6202 IOLockUnlock( gPMHaltLock
);
6204 while (me
->depth
>= 0)
6206 PMHaltWorker::work( me
);
6208 IOLockLock( gPMHaltLock
);
6209 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
)
6211 // This is the last thread to finish work on this level,
6212 // inform everyone to start working on next lower level.
6214 me
->depth
= gPMHaltDepth
;
6215 gPMHaltIdleCount
= 0;
6216 thread_wakeup((event_t
) &gPMHaltIdleCount
);
6220 // One or more threads are still working on this level,
6221 // this thread must wait.
6222 me
->depth
= gPMHaltDepth
- 1;
6224 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
6225 } while (me
->depth
!= gPMHaltDepth
);
6227 IOLockUnlock( gPMHaltLock
);
6230 // No more work to do, terminate thread
6231 DLOG("All done for worker: %p (visits = %u)\n", me
, me
->visits
);
6232 thread_wakeup( &gPMHaltDepth
);
6236 void PMHaltWorker::work( PMHaltWorker
* me
)
6238 IOService
* service
;
6240 AbsoluteTime startTime
;
6249 // Claim an unit of work from the shared pool
6250 IOLockLock( gPMHaltLock
);
6251 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
6254 service
= (IOService
*)inner
->getAnyObject();
6258 inner
->removeObject(service
);
6261 IOLockUnlock( gPMHaltLock
);
6263 break; // no more work at this depth
6265 clock_get_uptime(&startTime
);
6267 if (!service
->isInactive() &&
6268 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
))
6270 IOLockLock(me
->lock
);
6271 me
->startTime
= startTime
;
6272 me
->service
= service
;
6273 me
->timeout
= false;
6274 IOLockUnlock(me
->lock
);
6276 service
->systemWillShutdown( gPMHaltEvent
);
6278 // Wait for driver acknowledgement
6279 IOLockLock(me
->lock
);
6280 while (service
->getProperty(gPMHaltClientAcknowledgeKey
))
6282 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
6285 timeout
= me
->timeout
;
6286 IOLockUnlock(me
->lock
);
6289 deltaTime
= computeDeltaTimeMS(&startTime
);
6290 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
||
6291 (gIOKitDebug
& kIOLogPMRootDomain
))
6293 LOG("%s driver %s (%p) took %u ms\n",
6294 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
6295 "PowerOff" : "Restart",
6296 service
->getName(), service
,
6297 (uint32_t) deltaTime
);
6305 void PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
6308 AbsoluteTime startTime
;
6309 AbsoluteTime endTime
;
6313 IOLockLock(me
->lock
);
6314 if (me
->service
&& !me
->timeout
)
6316 startTime
= me
->startTime
;
6318 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
6320 SUB_ABSOLUTETIME(&endTime
, &startTime
);
6321 absolutetime_to_nanoseconds(endTime
, &nano
);
6323 if (nano
> 3000000000ULL)
6326 MSG("%s still waiting on %s\n",
6327 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
6328 "PowerOff" : "Restart",
6329 me
->service
->getName());
6332 IOLockUnlock(me
->lock
);
6336 //******************************************************************************
6337 // acknowledgeSystemWillShutdown
6339 // Acknowledgement from drivers that they have prepared for shutdown/restart.
6340 //******************************************************************************
6342 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
6344 PMHaltWorker
* worker
;
6350 //DLOG("%s acknowledged\n", from->getName());
6351 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
6354 worker
= (PMHaltWorker
*) prop
;
6355 IOLockLock(worker
->lock
);
6356 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
6357 thread_wakeup((event_t
) worker
);
6358 IOLockUnlock(worker
->lock
);
6363 DLOG("%s acknowledged without worker property\n",
6369 //******************************************************************************
6370 // notifySystemShutdown
6372 // Notify all objects in PM tree that system will shutdown or restart
6373 //******************************************************************************
6376 notifySystemShutdown( IOService
* root
, unsigned long event
)
6378 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
6379 IORegistryIterator
* iter
;
6380 IORegistryEntry
* entry
;
6383 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
6384 AbsoluteTime deadline
;
6385 unsigned int totalNodes
= 0;
6387 unsigned int rootDepth
;
6388 unsigned int numWorkers
;
6394 DLOG("%s event = %lx\n", __FUNCTION__
, event
);
6396 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
6398 // Iterate the entire PM tree starting from root
6400 rootDepth
= root
->getDepth( gIOPowerPlane
);
6401 if (!rootDepth
) goto done
;
6403 // debug - for repeated test runs
6404 while (PMHaltWorker::metaClass
->getInstanceCount())
6409 gPMHaltArray
= OSArray::withCapacity(40);
6410 if (!gPMHaltArray
) goto done
;
6413 gPMHaltArray
->flushCollection();
6417 gPMHaltLock
= IOLockAlloc();
6418 if (!gPMHaltLock
) goto done
;
6421 if (!gPMHaltClientAcknowledgeKey
)
6423 gPMHaltClientAcknowledgeKey
=
6424 OSSymbol::withCStringNoCopy("PMShutdown");
6425 if (!gPMHaltClientAcknowledgeKey
) goto done
;
6428 gPMHaltEvent
= event
;
6430 // Depth-first walk of PM plane
6432 iter
= IORegistryIterator::iterateOver(
6433 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
6437 while ((entry
= iter
->getNextObject()))
6439 node
= OSDynamicCast(IOService
, entry
);
6444 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
))
6447 depth
= node
->getDepth( gIOPowerPlane
);
6448 if (depth
<= rootDepth
)
6453 // adjust to zero based depth
6454 depth
-= (rootDepth
+ 1);
6456 // gPMHaltArray is an array of containers, each container
6457 // refers to nodes with the same depth.
6459 count
= gPMHaltArray
->getCount();
6460 while (depth
>= count
)
6462 // expand array and insert placeholders
6463 gPMHaltArray
->setObject(PLACEHOLDER
);
6466 count
= gPMHaltArray
->getCount();
6469 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
6470 if (inner
== PLACEHOLDER
)
6472 inner
= OSSet::withCapacity(40);
6475 gPMHaltArray
->replaceObject(depth
, inner
);
6480 // PM nodes that appear more than once in the tree will have
6481 // the same depth, OSSet will refuse to add the node twice.
6483 ok
= inner
->setObject(node
);
6486 DLOG("Skipped PM node %s\n", node
->getName());
6492 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++)
6495 if (inner
!= PLACEHOLDER
)
6496 count
= inner
->getCount();
6497 DLOG("Nodes at depth %u = %u\n", i
, count
);
6500 // strip placeholders (not all depths are populated)
6502 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); )
6504 if (inner
== PLACEHOLDER
)
6506 gPMHaltArray
->removeObject(i
);
6509 count
= inner
->getCount();
6510 if (count
> numWorkers
)
6512 totalNodes
+= count
;
6516 if (gPMHaltArray
->getCount() == 0 || !numWorkers
)
6519 gPMHaltBusyCount
= 0;
6520 gPMHaltIdleCount
= 0;
6521 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
6523 // Create multiple workers (and threads)
6525 if (numWorkers
> kPMHaltMaxWorkers
)
6526 numWorkers
= kPMHaltMaxWorkers
;
6528 DLOG("PM nodes = %u, maxDepth = %u, workers = %u\n",
6529 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
6531 for (unsigned int i
= 0; i
< numWorkers
; i
++)
6532 workers
[i
] = PMHaltWorker::worker();
6534 // Wait for workers to exhaust all available work
6536 IOLockLock(gPMHaltLock
);
6537 while (gPMHaltDepth
>= 0)
6539 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
6541 waitResult
= IOLockSleepDeadline(
6542 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
6543 if (THREAD_TIMED_OUT
== waitResult
)
6546 clock_get_uptime(&now
);
6548 IOLockUnlock(gPMHaltLock
);
6549 for (unsigned int i
= 0 ; i
< numWorkers
; i
++)
6552 PMHaltWorker::checkTimeout(workers
[i
], &now
);
6554 IOLockLock(gPMHaltLock
);
6557 IOLockUnlock(gPMHaltLock
);
6559 // Release all workers
6561 for (unsigned int i
= 0; i
< numWorkers
; i
++)
6564 workers
[i
]->release();
6565 // worker also retained by it's own thread
6569 DLOG("%s done\n", __FUNCTION__
);
6573 //*********************************************************************************
6574 // Sleep/Wake logging
6576 //*********************************************************************************
6578 IOMemoryDescriptor
*IOPMrootDomain::getPMTraceMemoryDescriptor(void)
6581 return timeline
->getPMTraceMemoryDescriptor();
6586 // Forwards external reports of detailed events to IOPMTimeline
6587 IOReturn
IOPMrootDomain::recordPMEvent(PMEventDetails
*details
)
6589 if (timeline
&& details
) {
6593 // Record a detailed driver power change event, or...
6594 if(details
->eventClassifier
== kIOPMEventClassDriverEvent
) {
6595 rc
= timeline
->recordDetailedPowerEvent( details
);
6598 // Record a system power management event
6599 else if(details
->eventClassifier
== kIOPMEventClassSystemEvent
) {
6600 rc
= timeline
->recordSystemPowerEvent( details
);
6603 return kIOReturnBadArgument
;
6606 // If we get to record this message, then we've reached the
6607 // end of another successful Sleep --> Wake cycle
6608 // At this point, we pat ourselves in the back and allow
6609 // our Sleep --> Wake UUID to be published
6610 if(details
->eventType
== kIOPMEventTypeWakeDone
) {
6611 timeline
->setSleepCycleInProgressFlag(false);
6615 // Check if its time to clear the timeline buffer
6616 if(getProperty(kIOPMSleepWakeUUIDKey)
6617 && timeline->isSleepCycleInProgress() == false
6618 && timeline->getNumEventsLoggedThisPeriod() > 500) {
6620 // Clear the old UUID
6621 if(pmPowerStateQueue) {
6622 pmPowerStateQueue->submitPowerEvent(kPowerEventPublishSleepWakeUUID, (void *)false );
6629 return kIOReturnNotReady
;
6632 IOReturn
IOPMrootDomain::recordAndReleasePMEvent(PMEventDetails
*details
)
6634 IOReturn ret
= kIOReturnBadArgument
;
6638 ret
= recordPMEvent(details
);
6645 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6647 IOPMDriverAssertionID
IOPMrootDomain::createPMAssertion(
6648 IOPMDriverAssertionType whichAssertionBits
,
6649 IOPMDriverAssertionLevel assertionLevel
,
6650 IOService
*ownerService
,
6651 const char *ownerDescription
)
6654 IOPMDriverAssertionID newAssertion
;
6659 ret
= pmAssertions
->createAssertion(whichAssertionBits
, assertionLevel
, ownerService
, ownerDescription
, &newAssertion
);
6661 if (kIOReturnSuccess
== ret
)
6662 return newAssertion
;
6667 IOReturn
IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion
)
6670 return kIOReturnInternalError
;
6672 return pmAssertions
->releaseAssertion(releaseAssertion
);
6675 IOReturn
IOPMrootDomain::setPMAssertionLevel(
6676 IOPMDriverAssertionID assertionID
,
6677 IOPMDriverAssertionLevel assertionLevel
)
6679 return pmAssertions
->setAssertionLevel(assertionID
, assertionLevel
);
6682 IOPMDriverAssertionLevel
IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion
)
6684 IOPMDriverAssertionType sysLevels
;
6686 if (!pmAssertions
|| whichAssertion
== 0)
6687 return kIOPMDriverAssertionLevelOff
;
6689 sysLevels
= pmAssertions
->getActivatedAssertions();
6691 // Check that every bit set in argument 'whichAssertion' is asserted
6692 // in the aggregate bits.
6693 if ((sysLevels
& whichAssertion
) == whichAssertion
)
6694 return kIOPMDriverAssertionLevelOn
;
6696 return kIOPMDriverAssertionLevelOff
;
6699 IOReturn
IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels
)
6702 return kIOReturnNotFound
;
6704 return pmAssertions
->setUserAssertionLevels(inLevels
);
6707 bool IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
6711 pmAssertions
->publishProperties();
6713 return( IOService::serializeProperties(s
) );
6716 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6719 // MARK: PMSettingHandle
6721 OSDefineMetaClassAndStructors( PMSettingHandle
, OSObject
)
6723 void PMSettingHandle::free( void )
6727 pmso
->clientHandleFreed();
6736 // MARK: PMSettingObject
6739 #define super OSObject
6740 OSDefineMetaClassAndFinalStructors( PMSettingObject
, OSObject
)
6743 * Static constructor/initializer for PMSettingObject
6745 PMSettingObject
*PMSettingObject::pmSettingObject(
6746 IOPMrootDomain
*parent_arg
,
6747 IOPMSettingControllerCallback handler_arg
,
6748 OSObject
*target_arg
,
6749 uintptr_t refcon_arg
,
6750 uint32_t supportedPowerSources
,
6751 const OSSymbol
* settings
[],
6752 OSObject
**handle_obj
)
6754 uint32_t settingCount
= 0;
6755 PMSettingObject
*pmso
= 0;
6756 PMSettingHandle
*pmsh
= 0;
6758 if ( !parent_arg
|| !handler_arg
|| !settings
|| !handle_obj
)
6761 // count OSSymbol entries in NULL terminated settings array
6762 while (settings
[settingCount
]) {
6765 if (0 == settingCount
)
6768 pmso
= new PMSettingObject
;
6769 if (!pmso
|| !pmso
->init())
6772 pmsh
= new PMSettingHandle
;
6773 if (!pmsh
|| !pmsh
->init())
6776 queue_init(&pmso
->calloutQueue
);
6777 pmso
->parent
= parent_arg
;
6778 pmso
->func
= handler_arg
;
6779 pmso
->target
= target_arg
;
6780 pmso
->refcon
= refcon_arg
;
6781 pmso
->settingCount
= settingCount
;
6783 pmso
->retain(); // handle holds a retain on pmso
6787 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount
);
6788 if (pmso
->publishedFeatureID
) {
6789 for (unsigned int i
=0; i
<settingCount
; i
++) {
6790 // Since there is now at least one listener to this setting, publish
6791 // PM root domain support for it.
6792 parent_arg
->publishFeature( settings
[i
]->getCStringNoCopy(),
6793 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
6801 if (pmso
) pmso
->release();
6802 if (pmsh
) pmsh
->release();
6806 void PMSettingObject::free( void )
6808 if (publishedFeatureID
) {
6809 for (uint32_t i
=0; i
<settingCount
; i
++) {
6810 if (publishedFeatureID
[i
]) {
6811 parent
->removePublishedFeature( publishedFeatureID
[i
] );
6815 IOFree(publishedFeatureID
, sizeof(uint32_t) * settingCount
);
6821 void PMSettingObject::dispatchPMSetting( const OSSymbol
* type
, OSObject
* object
)
6823 (*func
)(target
, type
, object
, refcon
);
6826 void PMSettingObject::clientHandleFreed( void )
6828 parent
->deregisterPMSettingObject(this);
6832 // MARK: IOPMTimeline
6835 #define super OSObject
6837 //*********************************************************************************
6838 //*********************************************************************************
6839 //*********************************************************************************
6841 IOPMTimeline
*IOPMTimeline::timeline(IOPMrootDomain
*root_domain
)
6843 IOPMTimeline
*myself
;
6848 myself
= new IOPMTimeline
;
6851 myself
->owner
= root_domain
;
6858 bool IOPMTimeline::init(void)
6860 if (!super::init()) {
6864 logLock
= IOLockAlloc();
6866 // Fresh timeline, no events logged yet
6867 this->numEventsLoggedThisPeriod
= 0;
6868 this->sleepCycleInProgress
= false;
6870 //this->setEventsRecordingLevel(1); // TODO
6871 this->setEventsTrackedCount(kIOPMDefaultSystemEventsTracked
);
6876 void IOPMTimeline::free(void)
6878 if (pmTraceMemoryDescriptor
) {
6879 pmTraceMemoryDescriptor
->release();
6880 pmTraceMemoryDescriptor
= NULL
;
6883 IOLockFree(logLock
);
6888 IOMemoryDescriptor
*IOPMTimeline::getPMTraceMemoryDescriptor()
6890 return pmTraceMemoryDescriptor
;
6893 //*********************************************************************************
6894 //*********************************************************************************
6895 //*********************************************************************************
6897 bool IOPMTimeline::setProperties(OSDictionary
*d
)
6900 OSBoolean
*b
= NULL
;
6901 bool changed
= false;
6903 /* Changes size of detailed events buffer */
6904 n
= (OSNumber
*)d
->getObject(kIOPMTimelineSystemNumberTrackedKey
);
6905 if (OSDynamicCast(OSNumber
, n
))
6908 this->setEventsTrackedCount(n
->unsigned32BitValue());
6912 /* enables or disables system events */
6913 b
= (OSBoolean
*)d
->getObject(kIOPMTimelineEnabledKey
);
6917 this->setEventsRecordingLevel((int)(kOSBooleanTrue
== b
));
6923 //*********************************************************************************
6924 //*********************************************************************************
6925 //*********************************************************************************
6927 OSDictionary
*IOPMTimeline::copyInfoDictionary(void)
6929 OSDictionary
*out
= OSDictionary::withCapacity(3);
6935 n
= OSNumber::withNumber(hdr
->sizeEntries
, 32);
6936 out
->setObject(kIOPMTimelineSystemNumberTrackedKey
, n
);
6939 n
= OSNumber::withNumber(hdr
->sizeBytes
, 32);
6940 out
->setObject(kIOPMTimelineSystemBufferSizeKey
, n
);
6944 out
->setObject(kIOPMTimelineEnabledKey
, eventsRecordingLevel
? kOSBooleanTrue
: kOSBooleanFalse
);
6949 //*********************************************************************************
6950 //*********************************************************************************
6951 //*********************************************************************************
6953 /* IOPMTimeline::recordSystemPowerEvent()
6955 * Expected "type" arguments are listed in IOPMPrivate.h under enum "SystemEventTypes"
6956 * Type arguments include "system events", and "Intermediate events"
6958 * - System Events have paired "start" and "stop" events.
6959 * - A start event shall be followed by a stop event.
6960 * - Any number of Intermediate Events may fall between the
6961 * start and stop events.
6962 * - Intermediate events are meaningless outside the bounds of a system event's
6963 * start & stoup routines.
6964 * - It's invalid to record a Start event without a following Stop event; e.g. two
6965 * Start events without an intervenining Stop event is invalid.
6968 * - The first recorded system event shall be preceded by an entry with type == 0
6969 * - IOPMTimeline may choose not to record intermediate events while there's not
6970 * a system event in process.
6972 IOReturn
IOPMTimeline::recordSystemPowerEvent( PMEventDetails
*details
)
6974 static bool wakeDonePending
= true;
6975 IOPMSystemEventRecord
*record_to
= NULL
;
6976 OSString
*swUUIDKey
= NULL
;
6977 uint32_t useIndex
= 0;
6980 return kIOReturnBadArgument
;
6983 return kIOReturnNotReady
;
6985 if (details
->eventType
== kIOPMEventTypeWakeDone
)
6987 if(!wakeDonePending
)
6988 return kIOReturnBadArgument
;
6991 IOLockLock(logLock
);
6993 if (details
->eventType
== kIOPMEventTypeWake
) {
6994 wakeDonePending
= true;
6995 } else if (details
->eventType
== kIOPMEventTypeWakeDone
) {
6996 wakeDonePending
= false;
6999 systemState
= details
->eventType
;
7001 useIndex
= _atomicIndexIncrement(&hdr
->index
, hdr
->sizeEntries
);
7003 // The entry immediately after the latest entry (and thus
7004 // immediately before the first entry) shall have a type 0.
7005 if (useIndex
+ 1 >= hdr
->sizeEntries
) {
7006 traceBuffer
[useIndex
+ 1].eventType
= 0;
7008 traceBuffer
[0].eventType
= 0;
7011 record_to
= &traceBuffer
[useIndex
];
7012 bzero(record_to
, sizeof(IOPMSystemEventRecord
));
7015 record_to
->eventType
= details
->eventType
;
7016 record_to
->eventReason
= details
->reason
;
7017 record_to
->eventResult
= details
->result
;
7018 pmEventTimeStamp(&record_to
->timestamp
);
7020 // If caller doesn't provide a UUID, we'll use the UUID that's posted
7021 // on IOPMrootDomain under key kIOPMSleepWakeUUIDKey
7022 if (!details
->uuid
) {
7023 swUUIDKey
= OSDynamicCast(OSString
, owner
->copyProperty(kIOPMSleepWakeUUIDKey
));
7026 details
->uuid
= swUUIDKey
->getCStringNoCopy();
7030 strncpy(record_to
->uuid
, details
->uuid
, kMaxPMStringLength
);
7033 swUUIDKey
->release();
7035 numEventsLoggedThisPeriod
++;
7038 IOLockUnlock(logLock
);
7040 return kIOReturnSuccess
;
7044 //*********************************************************************************
7045 //*********************************************************************************
7046 //*********************************************************************************
7048 IOReturn
IOPMTimeline::recordDetailedPowerEvent( PMEventDetails
*details
)
7050 IOPMSystemEventRecord
*record_to
= NULL
;
7053 if (!details
->eventType
|| !details
->ownerName
)
7054 return kIOReturnBadArgument
;
7056 IOLockLock(logLock
);
7058 useIndex
= _atomicIndexIncrement(&hdr
->index
, hdr
->sizeEntries
);
7060 record_to
= (IOPMSystemEventRecord
*)&traceBuffer
[useIndex
];
7061 bzero(record_to
, sizeof(IOPMSystemEventRecord
));
7064 record_to
->eventType
= details
->eventType
;
7065 if (details
->ownerName
&& (strlen(details
->ownerName
) > 1)) {
7066 strlcpy( record_to
->ownerName
,
7068 sizeof(record_to
->ownerName
));
7071 record_to
->ownerDisambiguateID
= details
->ownerUnique
;
7073 if (details
->interestName
&& (strlen(details
->interestName
) > 1)) {
7074 strlcpy(record_to
->interestName
,
7075 details
->interestName
,
7076 sizeof(record_to
->interestName
));
7079 record_to
->oldState
= details
->oldState
;
7080 record_to
->newState
= details
->newState
;
7081 record_to
->eventResult
= details
->result
;
7082 record_to
->elapsedTimeUS
= details
->elapsedTimeUS
;
7083 pmEventTimeStamp(&record_to
->timestamp
);
7085 numEventsLoggedThisPeriod
++;
7088 IOLockUnlock(logLock
);
7089 return kIOReturnSuccess
;
7092 uint32_t IOPMTimeline::getNumEventsLoggedThisPeriod() {
7093 return this->numEventsLoggedThisPeriod
;
7096 void IOPMTimeline::setNumEventsLoggedThisPeriod(uint32_t newCount
) {
7097 this->numEventsLoggedThisPeriod
= newCount
;
7100 bool IOPMTimeline::isSleepCycleInProgress() {
7101 return this->sleepCycleInProgress
;
7104 void IOPMTimeline::setSleepCycleInProgressFlag(bool flag
) {
7105 this->sleepCycleInProgress
= flag
;
7107 //*********************************************************************************
7108 //*********************************************************************************
7109 //*********************************************************************************
7111 void IOPMTimeline::setEventsTrackedCount(uint32_t newTracked
)
7113 size_t make_buf_size
= 0;
7115 make_buf_size
= sizeof(IOPMTraceBufferHeader
) + (newTracked
* sizeof(IOPMSystemEventRecord
));
7117 IOLockLock(logLock
);
7119 if (pmTraceMemoryDescriptor
) {
7120 pmTraceMemoryDescriptor
->release();
7121 pmTraceMemoryDescriptor
= NULL
;
7127 if (0 == newTracked
)
7129 IOLog("IOPMrootDomain -> erased buffer.\n");
7133 pmTraceMemoryDescriptor
= IOBufferMemoryDescriptor::withOptions(
7134 kIOMemoryKernelUserShared
| kIODirectionIn
, make_buf_size
);
7136 if (!pmTraceMemoryDescriptor
)
7138 IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns NULL\n", (int)make_buf_size
);
7142 pmTraceMemoryDescriptor
->prepare(kIODirectionIn
);
7144 // Header occupies the first sizeof(IOPMTraceBufferHeader) bytes
7145 hdr
= (IOPMTraceBufferHeader
*)pmTraceMemoryDescriptor
->getBytesNoCopy();
7147 // Recorded events occupy the remaining bulk of the buffer
7148 traceBuffer
= (IOPMSystemEventRecord
*)((uint8_t *)hdr
+ sizeof(IOPMTraceBufferHeader
));
7150 bzero(hdr
, make_buf_size
);
7152 hdr
->sizeBytes
= make_buf_size
;
7153 hdr
->sizeEntries
= newTracked
;
7155 IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns bufferMB with address 0x%08x\n", (int)make_buf_size
, (unsigned int)(uintptr_t)traceBuffer
);
7158 IOLockUnlock(logLock
);
7161 //*********************************************************************************
7162 //*********************************************************************************
7163 //*********************************************************************************
7165 void IOPMTimeline::setEventsRecordingLevel(uint32_t eventsTrackedBits
)
7174 /* static helper to IOPMTimeline
7176 uint32_t IOPMTimeline::_atomicIndexIncrement(uint32_t *index
, uint32_t limit
)
7186 inc_index
= (was_index
+1)%limit
;
7187 } while (!OSCompareAndSwap(was_index
, inc_index
, index
));
7193 // MARK: PMAssertionsTracker
7195 //*********************************************************************************
7196 //*********************************************************************************
7197 //*********************************************************************************
7198 // class PMAssertionsTracker Implementation
7200 #define kAssertUniqueIDStart 500
7202 PMAssertionsTracker
*PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain
*rootDomain
)
7204 PMAssertionsTracker
*myself
;
7206 myself
= new PMAssertionsTracker
;
7210 myself
->owner
= rootDomain
;
7211 myself
->issuingUniqueID
= kAssertUniqueIDStart
;
7212 myself
->assertionsArray
= OSArray::withCapacity(5);
7213 myself
->assertionsKernel
= 0;
7214 myself
->assertionsUser
= 0;
7215 myself
->assertionsCombined
= 0;
7216 myself
->assertionsArrayLock
= IOLockAlloc();
7217 myself
->tabulateProducerCount
= myself
->tabulateConsumerCount
= 0;
7219 if (!myself
->assertionsArray
|| !myself
->assertionsArrayLock
)
7227 * - Update assertionsKernel to reflect the state of all
7228 * assertions in the kernel.
7229 * - Update assertionsCombined to reflect both kernel & user space.
7231 void PMAssertionsTracker::tabulate(void)
7235 PMAssertStruct
*_a
= NULL
;
7238 IOPMDriverAssertionType oldKernel
= assertionsKernel
;
7239 IOPMDriverAssertionType oldCombined
= assertionsCombined
;
7243 assertionsKernel
= 0;
7244 assertionsCombined
= 0;
7246 if (!assertionsArray
)
7249 if ((count
= assertionsArray
->getCount()))
7251 for (i
=0; i
<count
; i
++)
7253 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
7256 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
7257 if (_a
&& (kIOPMDriverAssertionLevelOn
== _a
->level
))
7258 assertionsKernel
|= _a
->assertionBits
;
7263 tabulateProducerCount
++;
7264 assertionsCombined
= assertionsKernel
| assertionsUser
;
7266 if ((assertionsKernel
!= oldKernel
) ||
7267 (assertionsCombined
!= oldCombined
))
7269 owner
->messageClients(kIOPMMessageDriverAssertionsChanged
);
7271 if (((assertionsCombined
& kIOPMDriverAssertionPreventDisplaySleepBit
) != 0)
7272 && ((oldCombined
& kIOPMDriverAssertionPreventDisplaySleepBit
) == 0))
7274 /* We react to a new PreventDisplaySleep assertion by waking the display
7275 * with an activityTickle
7277 owner
->evaluatePolicy(kStimulusDarkWakeActivityTickle
);
7279 owner
->evaluatePolicy(kStimulusDarkWakeEvaluate
);
7284 void PMAssertionsTracker::publishProperties( void )
7286 OSArray
*assertionsSummary
= NULL
;
7288 if (tabulateConsumerCount
!= tabulateProducerCount
)
7290 IOLockLock(assertionsArrayLock
);
7292 tabulateConsumerCount
= tabulateProducerCount
;
7294 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
7296 assertionsSummary
= copyAssertionsArray();
7297 if (assertionsSummary
)
7299 owner
->setProperty(kIOPMAssertionsDriverDetailedKey
, assertionsSummary
);
7300 assertionsSummary
->release();
7304 owner
->removeProperty(kIOPMAssertionsDriverDetailedKey
);
7307 /* Publish the IOPMrootDomain property "DriverPMAssertions"
7309 owner
->setProperty(kIOPMAssertionsDriverKey
, assertionsKernel
, 64);
7311 IOLockUnlock(assertionsArrayLock
);
7315 PMAssertionsTracker::PMAssertStruct
*PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id
, int *index
)
7317 PMAssertStruct
*_a
= NULL
;
7324 && (count
= assertionsArray
->getCount()))
7326 for (i
=0; i
<count
; i
++)
7328 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
7331 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
7332 if (_a
&& (_id
== _a
->id
)) {
7349 /* PMAssertionsTracker::handleCreateAssertion
7350 * Perform assertion work on the PM workloop. Do not call directly.
7352 IOReturn
PMAssertionsTracker::handleCreateAssertion(OSData
*newAssertion
)
7358 IOLockLock(assertionsArrayLock
);
7359 assertionsArray
->setObject(newAssertion
);
7360 IOLockUnlock(assertionsArrayLock
);
7361 newAssertion
->release();
7365 return kIOReturnSuccess
;
7368 /* PMAssertionsTracker::createAssertion
7369 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
7372 IOReturn
PMAssertionsTracker::createAssertion(
7373 IOPMDriverAssertionType which
,
7374 IOPMDriverAssertionLevel level
,
7375 IOService
*serviceID
,
7376 const char *whoItIs
,
7377 IOPMDriverAssertionID
*outID
)
7379 OSData
*dataStore
= NULL
;
7380 PMAssertStruct track
;
7382 // Warning: trillions and trillions of created assertions may overflow the unique ID.
7383 track
.id
= OSIncrementAtomic64((SInt64
*) &issuingUniqueID
);
7384 track
.level
= level
;
7385 track
.assertionBits
= which
;
7386 track
.ownerString
= whoItIs
? OSSymbol::withCString(whoItIs
) : 0;
7387 track
.ownerService
= serviceID
;
7388 track
.modifiedTime
= 0;
7389 pmEventTimeStamp(&track
.createdTime
);
7391 dataStore
= OSData::withBytes(&track
, sizeof(PMAssertStruct
));
7394 if (track
.ownerString
)
7395 track
.ownerString
->release();
7396 return kIOReturnNoMemory
;
7401 if (owner
&& owner
->pmPowerStateQueue
) {
7402 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionCreate
, (void *)dataStore
);
7405 return kIOReturnSuccess
;
7408 /* PMAssertionsTracker::handleReleaseAssertion
7409 * Runs in PM workloop. Do not call directly.
7411 IOReturn
PMAssertionsTracker::handleReleaseAssertion(
7412 IOPMDriverAssertionID _id
)
7417 PMAssertStruct
*assertStruct
= detailsForID(_id
, &index
);
7420 return kIOReturnNotFound
;
7422 IOLockLock(assertionsArrayLock
);
7423 if (assertStruct
->ownerString
)
7424 assertStruct
->ownerString
->release();
7426 assertionsArray
->removeObject(index
);
7427 IOLockUnlock(assertionsArrayLock
);
7430 return kIOReturnSuccess
;
7433 /* PMAssertionsTracker::releaseAssertion
7434 * Releases an assertion and affects system behavior if appropiate.
7435 * Actual work happens on PM workloop.
7437 IOReturn
PMAssertionsTracker::releaseAssertion(
7438 IOPMDriverAssertionID _id
)
7440 if (owner
&& owner
->pmPowerStateQueue
) {
7441 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionRelease
, 0, _id
);
7443 return kIOReturnSuccess
;
7446 /* PMAssertionsTracker::handleSetAssertionLevel
7447 * Runs in PM workloop. Do not call directly.
7449 IOReturn
PMAssertionsTracker::handleSetAssertionLevel(
7450 IOPMDriverAssertionID _id
,
7451 IOPMDriverAssertionLevel _level
)
7453 PMAssertStruct
*assertStruct
= detailsForID(_id
, NULL
);
7457 if (!assertStruct
) {
7458 return kIOReturnNotFound
;
7461 IOLockLock(assertionsArrayLock
);
7462 pmEventTimeStamp(&assertStruct
->modifiedTime
);
7463 assertStruct
->level
= _level
;
7464 IOLockUnlock(assertionsArrayLock
);
7467 return kIOReturnSuccess
;
7470 /* PMAssertionsTracker::setAssertionLevel
7472 IOReturn
PMAssertionsTracker::setAssertionLevel(
7473 IOPMDriverAssertionID _id
,
7474 IOPMDriverAssertionLevel _level
)
7476 if (owner
&& owner
->pmPowerStateQueue
) {
7477 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionSetLevel
,
7478 (void *)_level
, _id
);
7481 return kIOReturnSuccess
;
7484 IOReturn
PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0
)
7486 IOPMDriverAssertionType new_user_levels
= *(IOPMDriverAssertionType
*) arg0
;
7490 if (new_user_levels
!= assertionsUser
)
7492 assertionsUser
= new_user_levels
;
7493 DLOG("assertionsUser 0x%llx\n", assertionsUser
);
7497 return kIOReturnSuccess
;
7500 IOReturn
PMAssertionsTracker::setUserAssertionLevels(
7501 IOPMDriverAssertionType new_user_levels
)
7503 if (gIOPMWorkLoop
) {
7504 gIOPMWorkLoop
->runAction(
7505 OSMemberFunctionCast(
7508 &PMAssertionsTracker::handleSetUserAssertionLevels
),
7510 (void *) &new_user_levels
, 0, 0, 0);
7513 return kIOReturnSuccess
;
7517 OSArray
*PMAssertionsTracker::copyAssertionsArray(void)
7521 OSArray
*outArray
= NULL
;
7523 if (!assertionsArray
||
7524 (0 == (count
= assertionsArray
->getCount())) ||
7525 (NULL
== (outArray
= OSArray::withCapacity(count
))))
7530 for (i
=0; i
<count
; i
++)
7532 PMAssertStruct
*_a
= NULL
;
7534 OSDictionary
*details
= NULL
;
7536 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
7537 if (_d
&& (_a
= (PMAssertStruct
*)_d
->getBytesNoCopy()))
7539 OSNumber
*_n
= NULL
;
7541 details
= OSDictionary::withCapacity(7);
7545 outArray
->setObject(details
);
7548 _n
= OSNumber::withNumber(_a
->id
, 64);
7550 details
->setObject(kIOPMDriverAssertionIDKey
, _n
);
7553 _n
= OSNumber::withNumber(_a
->createdTime
, 64);
7555 details
->setObject(kIOPMDriverAssertionCreatedTimeKey
, _n
);
7558 _n
= OSNumber::withNumber(_a
->modifiedTime
, 64);
7560 details
->setObject(kIOPMDriverAssertionModifiedTimeKey
, _n
);
7563 _n
= OSNumber::withNumber((uintptr_t)_a
->ownerService
, 64);
7565 details
->setObject(kIOPMDriverAssertionOwnerServiceKey
, _n
);
7568 _n
= OSNumber::withNumber(_a
->level
, 64);
7570 details
->setObject(kIOPMDriverAssertionLevelKey
, _n
);
7573 _n
= OSNumber::withNumber(_a
->assertionBits
, 64);
7575 details
->setObject(kIOPMDriverAssertionAssertedKey
, _n
);
7579 if (_a
->ownerString
) {
7580 details
->setObject(kIOPMDriverAssertionOwnerStringKey
, _a
->ownerString
);
7589 IOPMDriverAssertionType
PMAssertionsTracker::getActivatedAssertions(void)
7591 return assertionsCombined
;
7594 IOPMDriverAssertionLevel
PMAssertionsTracker::getAssertionLevel(
7595 IOPMDriverAssertionType type
)
7597 if (type
&& ((type
& assertionsKernel
) == assertionsKernel
))
7599 return kIOPMDriverAssertionLevelOn
;
7601 return kIOPMDriverAssertionLevelOff
;
7605 //*********************************************************************************
7606 //*********************************************************************************
7607 //*********************************************************************************
7610 static void pmEventTimeStamp(uint64_t *recordTS
)
7618 // We assume tsec fits into 32 bits; 32 bits holds enough
7619 // seconds for 136 years since the epoch in 1970.
7620 clock_get_calendar_microtime(&tsec
, &tusec
);
7623 // Pack the sec & microsec calendar time into a uint64_t, for fun.
7625 *recordTS
|= (uint32_t)tusec
;
7626 *recordTS
|= ((uint64_t)tsec
<< 32);
7632 // MARK: IORootParent
7634 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7636 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
7638 // The reason that root domain needs a root parent is to facilitate demand
7639 // sleep, since a power change from the root parent cannot be vetoed.
7641 // The above statement is no longer true since root domain now performs
7642 // demand sleep using overrides. But root parent remains to avoid changing
7643 // the power tree stacking. Root parent is parked at the max power state.
7646 static IOPMPowerState patriarchPowerStates
[2] =
7648 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
7649 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
7652 void IORootParent::initialize( void )
7656 bool IORootParent::start( IOService
* nub
)
7658 IOService::start(nub
);
7659 attachToParent( getRegistryRoot(), gIOPowerPlane
);
7661 registerPowerDriver(this, patriarchPowerStates
, 2);
7666 void IORootParent::shutDownSystem( void )
7670 void IORootParent::restartSystem( void )
7674 void IORootParent::sleepSystem( void )
7678 void IORootParent::dozeSystem( void )
7682 void IORootParent::sleepToDoze( void )
7686 void IORootParent::wakeSystem( void )
7690 OSObject
* IORootParent::copyProperty( const char * aKey
) const
7692 return (IOService::copyProperty(aKey
));