]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOPMrootDomain.cpp
xnu-3248.40.184.tar.gz
[apple/xnu.git] / iokit / Kernel / IOPMrootDomain.cpp
CommitLineData
91447636 1/*
b0d623f7 2 * Copyright (c) 1998-2008 Apple Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
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.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b 27 */
b0d623f7
A
28#include <libkern/c++/OSKext.h>
29#include <libkern/c++/OSMetaClass.h>
6d2010ae 30#include <libkern/OSAtomic.h>
0b4c1975 31#include <libkern/OSDebug.h>
1c79356b 32#include <IOKit/IOWorkLoop.h>
9bccf70c 33#include <IOKit/IOCommandGate.h>
1c79356b 34#include <IOKit/IOPlatformExpert.h>
fe8ab488 35#include <IOKit/IOCPU.h>
9bccf70c
A
36#include <IOKit/IOKitDebug.h>
37#include <IOKit/IOTimeStamp.h>
b0d623f7 38#include <IOKit/pwr_mgt/IOPMlog.h>
1c79356b 39#include <IOKit/pwr_mgt/RootDomain.h>
d52fe63f 40#include <IOKit/pwr_mgt/IOPMPrivate.h>
91447636 41#include <IOKit/IODeviceTreeSupport.h>
1c79356b 42#include <IOKit/IOMessage.h>
0c530ab8 43#include <IOKit/IOReturn.h>
39236c6e 44#include <IOKit/IONVRAM.h>
1c79356b 45#include "RootDomainUserClient.h"
0b4e3aa0 46#include "IOKit/pwr_mgt/IOPowerConnection.h"
55e303ae 47#include "IOPMPowerStateQueue.h"
91447636 48#include <IOKit/IOCatalogue.h>
39236c6e 49#include <IOKit/IOReportMacros.h>
3e170ce0 50#include "IOKitKernelInternal.h"
2d21ac55 51#if HIBERNATION
3a60a9f5 52#include <IOKit/IOHibernatePrivate.h>
2d21ac55 53#endif
13f56ec4 54#include <console/video_console.h>
2d21ac55
A
55#include <sys/syslog.h>
56#include <sys/sysctl.h>
39236c6e
A
57#include <sys/vnode.h>
58#include <sys/vnode_internal.h>
59#include <sys/fcntl.h>
60
2d21ac55 61#include <sys/time.h>
fe8ab488 62#include "IOServicePrivate.h" // _IOServiceInterestNotifier
b0d623f7 63#include "IOServicePMPrivate.h"
2d21ac55 64
b0d623f7
A
65__BEGIN_DECLS
66#include <mach/shared_region.h>
3e170ce0 67#include <kern/clock.h>
b0d623f7 68__END_DECLS
2d21ac55 69
b0d623f7 70#if defined(__i386__) || defined(__x86_64__)
2d21ac55
A
71__BEGIN_DECLS
72#include "IOPMrootDomainInternal.h"
73__END_DECLS
74#endif
75
b0d623f7 76#define kIOPMrootDomainClass "IOPMrootDomain"
6d2010ae 77#define LOG_PREFIX "PMRD: "
b0d623f7 78
39236c6e 79
6d2010ae
A
80#define MSG(x...) \
81 do { kprintf(LOG_PREFIX x); IOLog(x); } while (false)
b0d623f7 82
6d2010ae
A
83#define LOG(x...) \
84 do { kprintf(LOG_PREFIX x); } while (false)
b0d623f7
A
85
86#define DLOG(x...) do { \
fe8ab488 87 if (kIOLogPMRootDomain & gIOKitDebug) \
39236c6e 88 kprintf(LOG_PREFIX x); \
fe8ab488
A
89} while (false)
90
91#define DMSG(x...) do { \
92 if (kIOLogPMRootDomain & gIOKitDebug) { \
93 kprintf(LOG_PREFIX x); IOLog(x); \
94 } \
95} while (false)
b0d623f7 96
6d2010ae 97
fe8ab488 98#define _LOG(x...)
316670eb 99
b0d623f7
A
100#define CHECK_THREAD_CONTEXT
101#ifdef CHECK_THREAD_CONTEXT
102static IOWorkLoop * gIOPMWorkLoop = 0;
6d2010ae 103#define ASSERT_GATED() \
b0d623f7
A
104do { \
105 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
6d2010ae 106 panic("RootDomain: not inside PM gate"); \
b0d623f7
A
107 } \
108} while(false)
2d21ac55 109#else
6d2010ae 110#define ASSERT_GATED()
b0d623f7
A
111#endif /* CHECK_THREAD_CONTEXT */
112
6d2010ae
A
113#define CAP_LOSS(c) \
114 (((_pendingCapability & (c)) == 0) && \
115 ((_currentCapability & (c)) != 0))
116
117#define CAP_GAIN(c) \
118 (((_currentCapability & (c)) == 0) && \
119 ((_pendingCapability & (c)) != 0))
120
121#define CAP_CHANGE(c) \
122 (((_currentCapability ^ _pendingCapability) & (c)) != 0)
123
124#define CAP_CURRENT(c) \
125 ((_currentCapability & (c)) != 0)
126
127#define CAP_HIGHEST(c) \
128 ((_highestCapability & (c)) != 0)
129
39236c6e
A
130#if defined(__i386__) || defined(__x86_64__)
131#define DARK_TO_FULL_EVALUATE_CLAMSHELL 1
132#endif
6d2010ae 133
b0d623f7
A
134// Event types for IOPMPowerStateQueue::submitPowerEvent()
135enum {
6d2010ae
A
136 kPowerEventFeatureChanged = 1, // 1
137 kPowerEventReceivedPowerNotification, // 2
138 kPowerEventSystemBootCompleted, // 3
139 kPowerEventSystemShutdown, // 4
140 kPowerEventUserDisabledSleep, // 5
141 kPowerEventRegisterSystemCapabilityClient, // 6
142 kPowerEventRegisterKernelCapabilityClient, // 7
143 kPowerEventPolicyStimulus, // 8
144 kPowerEventAssertionCreate, // 9
145 kPowerEventAssertionRelease, // 10
146 kPowerEventAssertionSetLevel, // 11
147 kPowerEventQueueSleepWakeUUID, // 12
316670eb 148 kPowerEventPublishSleepWakeUUID, // 13
fe8ab488 149 kPowerEventSetDisplayPowerOn // 14
6d2010ae
A
150};
151
152// For evaluatePolicy()
153// List of stimuli that affects the root domain policy.
154enum {
155 kStimulusDisplayWranglerSleep, // 0
156 kStimulusDisplayWranglerWake, // 1
157 kStimulusAggressivenessChanged, // 2
158 kStimulusDemandSystemSleep, // 3
159 kStimulusAllowSystemSleepChanged, // 4
160 kStimulusDarkWakeActivityTickle, // 5
161 kStimulusDarkWakeEntry, // 6
162 kStimulusDarkWakeReentry, // 7
316670eb 163 kStimulusDarkWakeEvaluate, // 8
39236c6e 164 kStimulusNoIdleSleepPreventers, // 9
22ba694c
A
165 kStimulusEnterUserActiveState, // 10
166 kStimulusLeaveUserActiveState // 11
b0d623f7 167};
1c79356b 168
0c530ab8 169extern "C" {
b0d623f7 170IOReturn OSKextSystemSleepOrWake( UInt32 );
0c530ab8 171}
fe8ab488
A
172extern "C" ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va);
173extern "C" addr64_t kvtophys(vm_offset_t va);
39236c6e 174extern "C" int stack_snapshot_from_kernel(pid_t pid, void *buf, uint32_t size, uint32_t flags, unsigned *bytesTraced);
1c79356b 175
b0d623f7 176static void idleSleepTimerExpired( thread_call_param_t, thread_call_param_t );
3e170ce0 177static void notifySystemShutdown( IOService * root, uint32_t messageType );
6d2010ae 178static void handleAggressivesFunction( thread_call_param_t, thread_call_param_t );
0b4c1975 179static void pmEventTimeStamp(uint64_t *recordTS);
1c79356b 180
0c530ab8
A
181// "IOPMSetSleepSupported" callPlatformFunction name
182static const OSSymbol *sleepSupportedPEFunction = NULL;
0b4c1975 183static const OSSymbol *sleepMessagePEFunction = NULL;
0c530ab8 184
6d2010ae
A
185#define kIOSleepSupportedKey "IOSleepSupported"
186#define kIOPMSystemCapabilitiesKey "System Capabilities"
0c530ab8 187
39236c6e
A
188#define kIORequestWranglerIdleKey "IORequestIdle"
189#define kDefaultWranglerIdlePeriod 25 // in milliseconds
190
191#define kIOSleepWakeDebugKey "Persistent-memory-note"
192
0c530ab8
A
193#define kRD_AllPowerSources (kIOPMSupportedOnAC \
194 | kIOPMSupportedOnBatt \
195 | kIOPMSupportedOnUPS)
1c79356b 196
99c3a104
A
197#define kLocalEvalClamshellCommand (1 << 15)
198#define kIdleSleepRetryInterval (3 * 60)
0c530ab8 199
39236c6e
A
200enum {
201 kWranglerPowerStateMin = 0,
202 kWranglerPowerStateSleep = 2,
203 kWranglerPowerStateDim = 3,
204 kWranglerPowerStateMax = 4
205};
206
b0d623f7 207enum {
6d2010ae
A
208 OFF_STATE = 0,
209 RESTART_STATE = 1,
210 SLEEP_STATE = 2,
211 ON_STATE = 3,
b0d623f7
A
212 NUM_POWER_STATES
213};
214
215#define ON_POWER kIOPMPowerOn
216#define RESTART_POWER kIOPMRestart
217#define SLEEP_POWER kIOPMAuxPowerOn
b0d623f7
A
218
219static IOPMPowerState ourPowerStates[NUM_POWER_STATES] =
220{
221 {1, 0, 0, 0, 0,0,0,0,0,0,0,0},
fe8ab488 222 {1, kIOPMRestartCapability, kIOPMRestart, RESTART_POWER, 0,0,0,0,0,0,0,0},
b0d623f7 223 {1, kIOPMSleepCapability, kIOPMSleep, SLEEP_POWER, 0,0,0,0,0,0,0,0},
b0d623f7
A
224 {1, kIOPMPowerOn, kIOPMPowerOn, ON_POWER, 0,0,0,0,0,0,0,0}
225};
226
fe8ab488
A
227#define kIOPMRootDomainWakeTypeSleepService "SleepService"
228#define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
229#define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer"
230#define kIOPMrootDomainWakeTypeLowBattery "LowBattery"
231#define kIOPMRootDomainWakeTypeUser "User"
232#define kIOPMRootDomainWakeTypeAlarm "Alarm"
233#define kIOPMRootDomainWakeTypeNetwork "Network"
234#define kIOPMRootDomainWakeTypeHIDActivity "HID Activity"
235#define kIOPMRootDomainWakeTypeNotification "Notification"
236#define kIOPMRootDomainWakeTypeHibernateError "HibernateError"
b0d623f7
A
237
238// Special interest that entitles the interested client from receiving
6d2010ae 239// all system messages. Only used by powerd.
b0d623f7 240//
6d2010ae 241#define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest"
b0d623f7 242
fe8ab488
A
243#define WAKEEVENT_LOCK() IOLockLock(wakeEventLock)
244#define WAKEEVENT_UNLOCK() IOLockUnlock(wakeEventLock)
316670eb 245
b0d623f7
A
246/*
247 * Aggressiveness
248 */
249#define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
250#define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
251
252#define kAggressivesMinValue 1
253
b0d623f7
A
254enum {
255 kAggressivesStateBusy = 0x01,
256 kAggressivesStateQuickSpindown = 0x02
257};
258
259struct AggressivesRecord {
260 uint32_t flags;
261 uint32_t type;
262 uint32_t value;
263};
264
265struct AggressivesRequest {
266 queue_chain_t chain;
267 uint32_t options;
268 uint32_t dataType;
269 union {
270 IOService * service;
271 AggressivesRecord record;
272 } data;
273};
274
275enum {
276 kAggressivesRequestTypeService = 1,
277 kAggressivesRequestTypeRecord
278};
279
280enum {
281 kAggressivesOptionSynchronous = 0x00000001,
282 kAggressivesOptionQuickSpindownEnable = 0x00000100,
283 kAggressivesOptionQuickSpindownDisable = 0x00000200,
284 kAggressivesOptionQuickSpindownMask = 0x00000300
285};
286
287enum {
288 kAggressivesRecordFlagModified = 0x00000001,
289 kAggressivesRecordFlagMinValue = 0x00000002
6d2010ae
A
290};
291
292// gDarkWakeFlags
293enum {
294 kDarkWakeFlagHIDTickleEarly = 0x01, // hid tickle before gfx suppression
295 kDarkWakeFlagHIDTickleLate = 0x02, // hid tickle after gfx suppression
296 kDarkWakeFlagHIDTickleNone = 0x03, // hid tickle is not posted
297 kDarkWakeFlagHIDTickleMask = 0x03,
db609669
A
298 kDarkWakeFlagAlarmIsDark = 0x0100,
299 kDarkWakeFlagGraphicsPowerState1 = 0x0200,
300 kDarkWakeFlagAudioNotSuppressed = 0x0400
1c79356b
A
301};
302
6601e61a 303static IOPMrootDomain * gRootDomain;
6d2010ae 304static IONotifier * gSysPowerDownNotifier = 0;
6601e61a 305static UInt32 gSleepOrShutdownPending = 0;
b0d623f7 306static UInt32 gWillShutdown = 0;
6d2010ae 307static UInt32 gPagingOff = 0;
b0d623f7 308static UInt32 gSleepWakeUUIDIsSet = false;
6d2010ae 309static uint32_t gAggressivesState = 0;
39236c6e
A
310
311uuid_string_t bootsessionuuid_string;
312
fe8ab488 313static uint32_t gDarkWakeFlags = kDarkWakeFlagHIDTickleNone;
3e170ce0 314static uint32_t gNoIdleFlag = 0;
316670eb 315static PMStatsStruct gPMStats;
4452a7af 316
99c3a104
A
317#if HIBERNATION
318static IOPMSystemSleepPolicyHandler gSleepPolicyHandler = 0;
319static IOPMSystemSleepPolicyVariables * gSleepPolicyVars = 0;
320static void * gSleepPolicyTarget;
321#endif
322
2d21ac55
A
323struct timeval gIOLastSleepTime;
324struct timeval gIOLastWakeTime;
325
fe8ab488
A
326static char gWakeReasonString[128];
327static bool gWakeReasonSysctlRegistered = false;
328
3e170ce0
A
329#if defined(__i386__) || defined(__x86_64__)
330static bool gSpinDumpBufferFull = false;
331#endif
332
333static unsigned int gPMHaltBusyCount;
334static unsigned int gPMHaltIdleCount;
335static int gPMHaltDepth;
336static uint32_t gPMHaltMessageType;
337static IOLock * gPMHaltLock = 0;
338static OSArray * gPMHaltArray = 0;
339static const OSSymbol * gPMHaltClientAcknowledgeKey = 0;
340static bool gPMQuiesced;
341
2d21ac55
A
342// Constants used as arguments to IOPMrootDomain::informCPUStateChange
343#define kCPUUnknownIndex 9999999
344enum {
345 kInformAC = 0,
346 kInformLid = 1,
347 kInformableCount = 2
348};
4452a7af 349
b0d623f7
A
350const OSSymbol *gIOPMStatsApplicationResponseTimedOut;
351const OSSymbol *gIOPMStatsApplicationResponseCancel;
352const OSSymbol *gIOPMStatsApplicationResponseSlow;
fe8ab488
A
353const OSSymbol *gIOPMStatsApplicationResponsePrompt;
354const OSSymbol *gIOPMStatsDriverPSChangeSlow;
b0d623f7 355
7ddcb079
A
356#define kBadPMFeatureID 0
357
6d2010ae
A
358/*
359 * PMSettingHandle
360 * Opaque handle passed to clients of registerPMSettingController()
361 */
362class PMSettingHandle : public OSObject
363{
364 OSDeclareFinalStructors( PMSettingHandle )
365 friend class PMSettingObject;
366
367private:
368 PMSettingObject *pmso;
3e170ce0 369 void free(void) APPLE_KEXT_OVERRIDE;
6d2010ae
A
370};
371
372/*
373 * PMSettingObject
374 * Internal object to track each PM setting controller
375 */
0c530ab8
A
376class PMSettingObject : public OSObject
377{
6d2010ae
A
378 OSDeclareFinalStructors( PMSettingObject )
379 friend class IOPMrootDomain;
380
0c530ab8 381private:
6d2010ae
A
382 queue_head_t calloutQueue;
383 thread_t waitThread;
0c530ab8 384 IOPMrootDomain *parent;
6d2010ae 385 PMSettingHandle *pmsh;
0c530ab8
A
386 IOPMSettingControllerCallback func;
387 OSObject *target;
388 uintptr_t refcon;
389 uint32_t *publishedFeatureID;
6d2010ae
A
390 uint32_t settingCount;
391 bool disabled;
392
3e170ce0 393 void free(void) APPLE_KEXT_OVERRIDE;
6d2010ae 394
0c530ab8
A
395public:
396 static PMSettingObject *pmSettingObject(
6d2010ae 397 IOPMrootDomain *parent_arg,
0c530ab8 398 IOPMSettingControllerCallback handler_arg,
6d2010ae
A
399 OSObject *target_arg,
400 uintptr_t refcon_arg,
401 uint32_t supportedPowerSources,
402 const OSSymbol *settings[],
403 OSObject **handle_obj);
404
405 void dispatchPMSetting(const OSSymbol *type, OSObject *object);
406 void clientHandleFreed(void);
407};
408
409struct PMSettingCallEntry {
410 queue_chain_t link;
411 thread_t thread;
412};
0c530ab8 413
6d2010ae
A
414#define PMSETTING_LOCK() IOLockLock(settingsCtrlLock)
415#define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock)
416#define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
417#define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
0c530ab8 418
6d2010ae
A
419/*
420 * PMTraceWorker
421 * Internal helper object for logging trace points to RTC
422 * IOPMrootDomain and only IOPMrootDomain should instantiate
423 * exactly one of these.
424 */
425
426typedef void (*IOPMTracePointHandler)(
427 void * target, uint32_t code, uint32_t data );
428
429class PMTraceWorker : public OSObject
430{
431 OSDeclareDefaultStructors(PMTraceWorker)
432public:
433 typedef enum { kPowerChangeStart, kPowerChangeCompleted } change_t;
434
435 static PMTraceWorker *tracer( IOPMrootDomain * );
436 void tracePCIPowerChange(change_t, IOService *, uint32_t, uint32_t);
437 void tracePoint(uint8_t phase);
438 void tracePoint(uint8_t phase, uint8_t data8);
439 void traceDetail(uint32_t detail);
440 void traceLoginWindowPhase(uint8_t phase);
441 int recordTopLevelPCIDevice(IOService *);
442 void RTC_TRACE(void);
3e170ce0 443 virtual bool serialize(OSSerialize *s) const APPLE_KEXT_OVERRIDE;
6d2010ae
A
444
445 IOPMTracePointHandler tracePointHandler;
446 void * tracePointTarget;
39236c6e 447 uint64_t getPMStatusCode();
6d2010ae
A
448private:
449 IOPMrootDomain *owner;
450 IOLock *pciMappingLock;
451 OSArray *pciDeviceBitMappings;
452
453 uint8_t addedToRegistry;
454 uint8_t tracePhase;
455 uint8_t loginWindowPhase;
456 uint8_t traceData8;
457 uint32_t traceData32;
0c530ab8
A
458};
459
0b4c1975
A
460/*
461 * PMAssertionsTracker
462 * Tracks kernel and user space PM assertions
463 */
464class PMAssertionsTracker : public OSObject
465{
466 OSDeclareFinalStructors(PMAssertionsTracker)
467public:
468 static PMAssertionsTracker *pmAssertionsTracker( IOPMrootDomain * );
fe8ab488 469
0b4c1975
A
470 IOReturn createAssertion(IOPMDriverAssertionType, IOPMDriverAssertionLevel, IOService *, const char *, IOPMDriverAssertionID *);
471 IOReturn releaseAssertion(IOPMDriverAssertionID);
472 IOReturn setAssertionLevel(IOPMDriverAssertionID, IOPMDriverAssertionLevel);
473 IOReturn setUserAssertionLevels(IOPMDriverAssertionType);
474
475 OSArray *copyAssertionsArray(void);
476 IOPMDriverAssertionType getActivatedAssertions(void);
477 IOPMDriverAssertionLevel getAssertionLevel(IOPMDriverAssertionType);
478
479 IOReturn handleCreateAssertion(OSData *);
480 IOReturn handleReleaseAssertion(IOPMDriverAssertionID);
481 IOReturn handleSetAssertionLevel(IOPMDriverAssertionID, IOPMDriverAssertionLevel);
482 IOReturn handleSetUserAssertionLevels(void * arg0);
483 void publishProperties(void);
484
485private:
486 typedef struct {
487 IOPMDriverAssertionID id;
488 IOPMDriverAssertionType assertionBits;
489 uint64_t createdTime;
490 uint64_t modifiedTime;
491 const OSSymbol *ownerString;
492 IOService *ownerService;
39236c6e 493 uint64_t registryEntryID;
0b4c1975
A
494 IOPMDriverAssertionLevel level;
495 } PMAssertStruct;
6d2010ae 496
0b4c1975
A
497 uint32_t tabulateProducerCount;
498 uint32_t tabulateConsumerCount;
499
500 PMAssertStruct *detailsForID(IOPMDriverAssertionID, int *);
501 void tabulate(void);
fe8ab488 502
0b4c1975
A
503 IOPMrootDomain *owner;
504 OSArray *assertionsArray;
505 IOLock *assertionsArrayLock;
6d2010ae 506 IOPMDriverAssertionID issuingUniqueID __attribute__((aligned(8))); /* aligned for atomic access */
0b4c1975
A
507 IOPMDriverAssertionType assertionsKernel;
508 IOPMDriverAssertionType assertionsUser;
509 IOPMDriverAssertionType assertionsCombined;
510};
fe8ab488 511
0b4c1975 512OSDefineMetaClassAndFinalStructors(PMAssertionsTracker, OSObject);
fe8ab488 513
2d21ac55 514/*
b0d623f7 515 * PMHaltWorker
2d21ac55
A
516 * Internal helper object for Shutdown/Restart notifications.
517 */
518#define kPMHaltMaxWorkers 8
519#define kPMHaltTimeoutMS 100
520
521class PMHaltWorker : public OSObject
522{
b0d623f7 523 OSDeclareFinalStructors( PMHaltWorker )
2d21ac55
A
524
525public:
526 IOService * service; // service being worked on
527 AbsoluteTime startTime; // time when work started
528 int depth; // work on nubs at this PM-tree depth
529 int visits; // number of nodes visited (debug)
530 IOLock * lock;
531 bool timeout; // service took too long
532
533 static PMHaltWorker * worker( void );
b0d623f7 534 static void main( void * arg, wait_result_t waitResult );
2d21ac55
A
535 static void work( PMHaltWorker * me );
536 static void checkTimeout( PMHaltWorker * me, AbsoluteTime * now );
3e170ce0 537 virtual void free( void ) APPLE_KEXT_OVERRIDE;
2d21ac55
A
538};
539
b0d623f7 540OSDefineMetaClassAndFinalStructors( PMHaltWorker, OSObject )
0c530ab8
A
541
542
1c79356b 543#define super IOService
b0d623f7 544OSDefineMetaClassAndFinalStructors(IOPMrootDomain, IOService)
1c79356b 545
6d2010ae
A
546static void IOPMRootDomainWillShutdown(void)
547{
548 if (OSCompareAndSwap(0, 1, &gWillShutdown))
549 {
fe8ab488
A
550 OSKext::willShutdown();
551 for (int i = 0; i < 100; i++)
552 {
553 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending)) break;
554 IOSleep( 100 );
555 }
6d2010ae
A
556 }
557}
558
1c79356b
A
559extern "C"
560{
91447636 561 IONotifier * registerSleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
1c79356b
A
562 {
563 return gRootDomain->registerInterest( gIOGeneralInterest, handler, self, ref );
564 }
565
91447636 566 IONotifier * registerPrioritySleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
0b4e3aa0
A
567 {
568 return gRootDomain->registerInterest( gIOPriorityPowerStateInterest, handler, self, ref );
569 }
570
1c79356b
A
571 IOReturn acknowledgeSleepWakeNotification(void * PMrefcon)
572 {
573 return gRootDomain->allowPowerChange ( (unsigned long)PMrefcon );
574 }
575
0b4e3aa0
A
576 IOReturn vetoSleepWakeNotification(void * PMrefcon)
577 {
578 return gRootDomain->cancelPowerChange ( (unsigned long)PMrefcon );
579 }
fe8ab488 580
0b4e3aa0
A
581 IOReturn rootDomainRestart ( void )
582 {
583 return gRootDomain->restartSystem();
584 }
fe8ab488 585
0b4e3aa0
A
586 IOReturn rootDomainShutdown ( void )
587 {
588 return gRootDomain->shutdownSystem();
589 }
590
6d2010ae 591 void IOSystemShutdownNotification(void)
0b4e3aa0 592 {
fe8ab488 593 IOPMRootDomainWillShutdown();
3e170ce0
A
594#if HIBERNATION
595 IOHibernateSystemPostWake();
596#endif
fe8ab488
A
597 if (OSCompareAndSwap(0, 1, &gPagingOff))
598 {
599 gRootDomain->handlePlatformHaltRestart(kPEPagingOff);
600 }
0b4e3aa0
A
601 }
602
fe8ab488 603 int sync_internal(void);
1c79356b
A
604}
605
0b4e3aa0 606/*
6d2010ae
A
607A device is always in the highest power state which satisfies its driver,
608its policy-maker, and any power children it has, but within the constraint
609of the power state provided by its parent. The driver expresses its desire by
610calling changePowerStateTo(), the policy-maker expresses its desire by calling
611changePowerStateToPriv(), and the children express their desires by calling
612requestPowerDomainState().
613
614The Root Power Domain owns the policy for idle and demand sleep for the system.
615It is a power-managed IOService just like the others in the system.
616It implements several power states which map to what we see as Sleep and On.
617
618The sleep policy is as follows:
6191. Sleep is prevented if the case is open so that nobody will think the machine
620 is off and plug/unplug cards.
6212. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
6223. System cannot Sleep if some object in the tree is in a power state marked
623 kIOPMPreventSystemSleep.
624
625These three conditions are enforced using the "driver clamp" by calling
626changePowerStateTo(). For example, if the case is opened,
627changePowerStateTo(ON_STATE) is called to hold the system on regardless
628of the desires of the children of the root or the state of the other clamp.
629
630Demand Sleep is initiated by pressing the front panel power button, closing
631the clamshell, or selecting the menu item. In this case the root's parent
632actually initiates the power state change so that the root domain has no
633choice and does not give applications the opportunity to veto the change.
634
635Idle Sleep occurs if no objects in the tree are in a state marked
636kIOPMPreventIdleSleep. When this is true, the root's children are not holding
637the root on, so it sets the "policy-maker clamp" by calling
638changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
639This timer is set for the difference between the sleep timeout slider and the
640display dim timeout slider. When the timer expires, it releases its clamp and
641now nothing is holding it awake, so it falls asleep.
642
643Demand sleep is prevented when the system is booting. When preferences are
644transmitted by the loginwindow at the end of boot, a flag is cleared,
645and this allows subsequent Demand Sleep.
0b4e3aa0 646*/
2d21ac55 647
b0d623f7 648//******************************************************************************
0b4e3aa0
A
649
650IOPMrootDomain * IOPMrootDomain::construct( void )
651{
b0d623f7 652 IOPMrootDomain *root;
0b4e3aa0
A
653
654 root = new IOPMrootDomain;
655 if( root)
656 root->init();
657
658 return( root );
659}
660
3e170ce0
A
661//******************************************************************************
662// updateConsoleUsersCallout
663//
664//******************************************************************************
665
666static void updateConsoleUsersCallout(thread_call_param_t p0, thread_call_param_t p1)
4bd07ac2
A
667{
668 IOPMrootDomain * rootDomain = (IOPMrootDomain *) p0;
669 rootDomain->updateConsoleUsers();
670}
671
672void IOPMrootDomain::updateConsoleUsers(void)
3e170ce0
A
673{
674 IOService::updateConsoleUsers(NULL, kIOMessageSystemHasPoweredOn);
4bd07ac2
A
675 if (tasksSuspended)
676 {
677 tasksSuspended = FALSE;
678 tasks_system_suspend(tasksSuspended);
679 }
3e170ce0
A
680}
681
b0d623f7 682//******************************************************************************
0b4e3aa0 683
b0d623f7 684static void disk_sync_callout( thread_call_param_t p0, thread_call_param_t p1 )
0b4e3aa0 685{
6d2010ae
A
686 IOService * rootDomain = (IOService *) p0;
687 uint32_t notifyRef = (uint32_t)(uintptr_t) p1;
688 uint32_t powerState = rootDomain->getPowerState();
2d21ac55 689
6d2010ae 690 DLOG("disk_sync_callout ps=%u\n", powerState);
0b4e3aa0 691
6d2010ae
A
692 if (ON_STATE == powerState)
693 {
6d2010ae
A
694 sync_internal();
695 }
fe8ab488 696#if HIBERNATION
6d2010ae
A
697 else
698 {
699 IOHibernateSystemPostWake();
3e170ce0
A
700
701 if (gRootDomain)
702 gRootDomain->sleepWakeDebugSaveSpinDumpFile();
6d2010ae
A
703 }
704#endif
705
706 rootDomain->allowPowerChange(notifyRef);
b0d623f7 707 DLOG("disk_sync_callout finish\n");
0b4e3aa0 708}
1c79356b 709
b0d623f7 710//******************************************************************************
2d21ac55 711
fe8ab488
A
712static void hib_debugSetup_callout( thread_call_param_t p0, thread_call_param_t p1 )
713{
714 IOService * rootDomain = (IOService *) p0;
715 uint32_t notifyRef = (uint32_t)(uintptr_t) p1;
716
717#if HIBERNATION
3e170ce0 718 IOOpenDebugDataFile(kSleepWakeStackBinFilename, SWD_BUF_SIZE);
fe8ab488
A
719#endif
720
721 rootDomain->allowPowerChange(notifyRef);
722 DLOG("hib_debugSetup_callout finish\n");
723}
724//******************************************************************************
725
2d21ac55 726static UInt32 computeDeltaTimeMS( const AbsoluteTime * startTime )
0c530ab8 727{
fe8ab488
A
728 AbsoluteTime endTime;
729 UInt64 nano = 0;
2d21ac55 730
fe8ab488
A
731 clock_get_uptime(&endTime);
732 if (CMP_ABSOLUTETIME(&endTime, startTime) > 0)
733 {
734 SUB_ABSOLUTETIME(&endTime, startTime);
735 absolutetime_to_nanoseconds(endTime, &nano);
736 }
0c530ab8 737
fe8ab488 738 return (UInt32)(nano / 1000000ULL);
2d21ac55 739}
0c530ab8 740
b0d623f7 741//******************************************************************************
0b4e3aa0 742
b0d623f7
A
743static int
744sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
745{
746 struct timeval *swt = (struct timeval *)arg1;
747 struct proc *p = req->p;
748
749 if (p == kernproc) {
fe8ab488 750 return sysctl_io_opaque(req, swt, sizeof(*swt), NULL);
b0d623f7
A
751 } else if(proc_is64bit(p)) {
752 struct user64_timeval t;
753 t.tv_sec = swt->tv_sec;
754 t.tv_usec = swt->tv_usec;
755 return sysctl_io_opaque(req, &t, sizeof(t), NULL);
756 } else {
757 struct user32_timeval t;
758 t.tv_sec = swt->tv_sec;
759 t.tv_usec = swt->tv_usec;
760 return sysctl_io_opaque(req, &t, sizeof(t), NULL);
761 }
762}
763
764static SYSCTL_PROC(_kern, OID_AUTO, sleeptime,
fe8ab488
A
765 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
766 &gIOLastSleepTime, 0, sysctl_sleepwaketime, "S,timeval", "");
b0d623f7
A
767
768static SYSCTL_PROC(_kern, OID_AUTO, waketime,
fe8ab488
A
769 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
770 &gIOLastWakeTime, 0, sysctl_sleepwaketime, "S,timeval", "");
b0d623f7
A
771
772
773static int
774sysctl_willshutdown
775(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
776{
777 int new_value, changed;
778 int error = sysctl_io_number(req, gWillShutdown, sizeof(int), &new_value, &changed);
779 if (changed) {
fe8ab488
A
780 if (!gWillShutdown && (new_value == 1)) {
781 IOPMRootDomainWillShutdown();
782 } else
783 error = EINVAL;
b0d623f7
A
784 }
785 return(error);
786}
787
788static SYSCTL_PROC(_kern, OID_AUTO, willshutdown,
fe8ab488
A
789 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
790 0, 0, sysctl_willshutdown, "I", "");
b0d623f7 791
3e170ce0
A
792extern struct sysctl_oid sysctl__kern_iokittest;
793
b0d623f7
A
794
795static int
796sysctl_progressmeterenable
797(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
798{
799 int error;
800 int new_value, changed;
801
fe8ab488 802 error = sysctl_io_number(req, vc_progressmeter_enable, sizeof(int), &new_value, &changed);
b0d623f7 803
fe8ab488 804 if (changed) vc_enable_progressmeter(new_value);
b0d623f7
A
805
806 return (error);
807}
808
809static int
810sysctl_progressmeter
811(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
812{
813 int error;
814 int new_value, changed;
815
fe8ab488 816 error = sysctl_io_number(req, vc_progressmeter_value, sizeof(int), &new_value, &changed);
b0d623f7 817
fe8ab488 818 if (changed) vc_set_progressmeter(new_value);
b0d623f7
A
819
820 return (error);
821}
822
823static SYSCTL_PROC(_kern, OID_AUTO, progressmeterenable,
fe8ab488
A
824 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
825 0, 0, sysctl_progressmeterenable, "I", "");
2d21ac55 826
b0d623f7 827static SYSCTL_PROC(_kern, OID_AUTO, progressmeter,
fe8ab488
A
828 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
829 0, 0, sysctl_progressmeter, "I", "");
830
2d21ac55 831
3e170ce0
A
832
833
834static int
835sysctl_consoleoptions
836(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
837{
490019cf
A
838 int error, changed;
839 uint32_t new_value;
3e170ce0 840
490019cf 841 error = sysctl_io_number(req, vc_user_options.options, sizeof(uint32_t), &new_value, &changed);
3e170ce0 842
490019cf 843 if (changed) vc_user_options.options = new_value;
3e170ce0
A
844
845 return (error);
846}
847
848static SYSCTL_PROC(_kern, OID_AUTO, consoleoptions,
849 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
850 0, 0, sysctl_consoleoptions, "I", "");
851
490019cf
A
852
853static int
854sysctl_progressoptions SYSCTL_HANDLER_ARGS
855{
856 return sysctl_io_opaque(req, &vc_user_options, sizeof(vc_user_options), NULL);
857}
858
859static SYSCTL_PROC(_kern, OID_AUTO, progressoptions,
860 CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED | CTLFLAG_ANYBODY,
861 NULL, 0, sysctl_progressoptions, "S,vc_progress_user_options", "");
862
863
fe8ab488
A
864static int
865sysctl_wakereason SYSCTL_HANDLER_ARGS
866{
867 char wr[ sizeof(gWakeReasonString) ];
868
869 wr[0] = '\0';
870 if (gRootDomain)
871 gRootDomain->copyWakeReasonString(wr, sizeof(wr));
872
873 return sysctl_io_string(req, wr, 0, 0, NULL);
874}
875
876SYSCTL_PROC(_kern, OID_AUTO, wakereason,
877 CTLTYPE_STRING| CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
878 NULL, 0, sysctl_wakereason, "A", "wakereason");
2d21ac55 879
3e170ce0
A
880static int
881sysctl_targettype SYSCTL_HANDLER_ARGS
882{
883 IOService * root;
884 OSObject * obj;
885 OSData * data;
886 char tt[32];
887
888 tt[0] = '\0';
889 root = IOService::getServiceRoot();
890 if (root && (obj = root->copyProperty(gIODTTargetTypeKey)))
891 {
892 if ((data = OSDynamicCast(OSData, obj)))
893 {
894 strlcpy(tt, (const char *) data->getBytesNoCopy(), sizeof(tt));
895 }
896 obj->release();
897 }
898 return sysctl_io_string(req, tt, 0, 0, NULL);
899}
900
901SYSCTL_PROC(_hw, OID_AUTO, targettype,
902 CTLTYPE_STRING| CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
903 NULL, 0, sysctl_targettype, "A", "targettype");
904
6d2010ae 905static SYSCTL_INT(_debug, OID_AUTO, darkwake, CTLFLAG_RW, &gDarkWakeFlags, 0, "");
3e170ce0 906static SYSCTL_INT(_debug, OID_AUTO, noidle, CTLFLAG_RW, &gNoIdleFlag, 0, "");
6d2010ae 907
99c3a104 908static const OSSymbol * gIOPMSettingAutoWakeCalendarKey;
2d21ac55 909static const OSSymbol * gIOPMSettingAutoWakeSecondsKey;
6d2010ae 910static const OSSymbol * gIOPMSettingDebugWakeRelativeKey;
b0d623f7 911static const OSSymbol * gIOPMSettingMaintenanceWakeCalendarKey;
7ddcb079
A
912static const OSSymbol * gIOPMSettingSleepServiceWakeCalendarKey;
913static const OSSymbol * gIOPMSettingSilentRunningKey;
39236c6e
A
914static const OSSymbol * gIOPMUserTriggeredFullWakeKey;
915static const OSSymbol * gIOPMUserIsActiveKey;
b0d623f7
A
916
917//******************************************************************************
918// start
919//
920//******************************************************************************
921
7ddcb079 922#define kRootDomainSettingsCount 17
0b4e3aa0 923
b0d623f7 924bool IOPMrootDomain::start( IOService * nub )
1c79356b 925{
0c530ab8
A
926 OSIterator *psIterator;
927 OSDictionary *tmpDict;
6d2010ae 928 IORootParent * patriarch;
39236c6e
A
929#if defined(__i386__) || defined(__x86_64__)
930 IONotifier * notifier;
931#endif
2d21ac55 932
b0d623f7
A
933 super::start(nub);
934
935 gRootDomain = this;
99c3a104 936 gIOPMSettingAutoWakeCalendarKey = OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey);
2d21ac55 937 gIOPMSettingAutoWakeSecondsKey = OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey);
6d2010ae 938 gIOPMSettingDebugWakeRelativeKey = OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey);
7ddcb079
A
939 gIOPMSettingMaintenanceWakeCalendarKey = OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey);
940 gIOPMSettingSleepServiceWakeCalendarKey = OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey);
941 gIOPMSettingSilentRunningKey = OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey);
39236c6e
A
942 gIOPMUserTriggeredFullWakeKey = OSSymbol::withCStringNoCopy(kIOPMUserTriggeredFullWakeKey);
943 gIOPMUserIsActiveKey = OSSymbol::withCStringNoCopy(kIOPMUserIsActiveKey);
b0d623f7
A
944
945 gIOPMStatsApplicationResponseTimedOut = OSSymbol::withCString(kIOPMStatsResponseTimedOut);
946 gIOPMStatsApplicationResponseCancel = OSSymbol::withCString(kIOPMStatsResponseCancel);
947 gIOPMStatsApplicationResponseSlow = OSSymbol::withCString(kIOPMStatsResponseSlow);
fe8ab488
A
948 gIOPMStatsApplicationResponsePrompt = OSSymbol::withCString(kIOPMStatsResponsePrompt);
949 gIOPMStatsDriverPSChangeSlow = OSSymbol::withCString(kIOPMStatsDriverPSChangeSlow);
b0d623f7
A
950
951 sleepSupportedPEFunction = OSSymbol::withCString("IOPMSetSleepSupported");
0b4c1975 952 sleepMessagePEFunction = OSSymbol::withCString("IOPMSystemSleepMessage");
2d21ac55 953
fe8ab488 954 const OSSymbol *settingsArr[kRootDomainSettingsCount] =
0c530ab8
A
955 {
956 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey),
2d21ac55 957 gIOPMSettingAutoWakeSecondsKey,
0c530ab8 958 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey),
99c3a104 959 gIOPMSettingAutoWakeCalendarKey,
0c530ab8 960 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey),
6d2010ae 961 gIOPMSettingDebugWakeRelativeKey,
0c530ab8
A
962 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey),
963 OSSymbol::withCString(kIOPMSettingWakeOnRingKey),
964 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey),
965 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey),
966 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey),
967 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey),
2d21ac55 968 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey),
593a1d5f
A
969 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey),
970 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey),
7ddcb079
A
971 OSSymbol::withCString(kIOPMStateConsoleShutdown),
972 gIOPMSettingSilentRunningKey
0c530ab8 973 };
d52fe63f 974
6d2010ae 975 PE_parse_boot_argn("darkwake", &gDarkWakeFlags, sizeof(gDarkWakeFlags));
3e170ce0 976 PE_parse_boot_argn("noidle", &gNoIdleFlag, sizeof(gNoIdleFlag));
fe8ab488 977
b0d623f7
A
978 queue_init(&aggressivesQueue);
979 aggressivesThreadCall = thread_call_allocate(handleAggressivesFunction, this);
980 aggressivesData = OSData::withCapacity(
981 sizeof(AggressivesRecord) * (kPMLastAggressivenessType + 4));
e5568f75 982
b0d623f7 983 featuresDictLock = IOLockAlloc();
6d2010ae 984 settingsCtrlLock = IOLockAlloc();
fe8ab488 985 wakeEventLock = IOLockAlloc();
b0d623f7 986 setPMRootDomain(this);
fe8ab488 987
b0d623f7
A
988 extraSleepTimer = thread_call_allocate(
989 idleSleepTimerExpired,
990 (thread_call_param_t) this);
1c79356b 991
b0d623f7
A
992 diskSyncCalloutEntry = thread_call_allocate(
993 &disk_sync_callout,
994 (thread_call_param_t) this);
fe8ab488
A
995 hibDebugSetupEntry = thread_call_allocate(
996 &hib_debugSetup_callout,
997 (thread_call_param_t) this);
39236c6e 998
3e170ce0
A
999 updateConsoleUsersEntry = thread_call_allocate(
1000 &updateConsoleUsersCallout,
1001 (thread_call_param_t) this);
1002
39236c6e
A
1003#if DARK_TO_FULL_EVALUATE_CLAMSHELL
1004 fullWakeThreadCall = thread_call_allocate(
1005 OSMemberFunctionCast(thread_call_func_t, this,
1006 &IOPMrootDomain::fullWakeDelayedWork),
1007 (thread_call_param_t) this);
1008#endif
1009
b0d623f7
A
1010 setProperty(kIOSleepSupportedKey, true);
1011
316670eb 1012 bzero(&gPMStats, sizeof(gPMStats));
b0d623f7
A
1013
1014 pmTracer = PMTraceWorker::tracer(this);
91447636 1015
0b4c1975
A
1016 pmAssertions = PMAssertionsTracker::pmAssertionsTracker(this);
1017
2d21ac55 1018 userDisabledAllSleep = false;
1c79356b 1019 systemBooting = true;
0b4e3aa0 1020 sleepSlider = 0;
b0d623f7 1021 idleSleepTimerPending = false;
0b4e3aa0 1022 wrangler = NULL;
6d2010ae
A
1023 clamshellClosed = false;
1024 clamshellExists = false;
1025 clamshellDisabled = true;
b0d623f7 1026 acAdaptorConnected = true;
db609669 1027 clamshellSleepDisabled = false;
fe8ab488 1028 gWakeReasonString[0] = '\0';
b0d623f7 1029
22ba694c
A
1030 // Initialize to user active.
1031 // Will never transition to user inactive w/o wrangler.
39236c6e
A
1032 fullWakeReason = kFullWakeReasonLocalUser;
1033 userIsActive = userWasActive = true;
1034 setProperty(gIOPMUserIsActiveKey, kOSBooleanTrue);
1035
6d2010ae
A
1036 // Set the default system capabilities at boot.
1037 _currentCapability = kIOPMSystemCapabilityCPU |
1038 kIOPMSystemCapabilityGraphics |
1039 kIOPMSystemCapabilityAudio |
1040 kIOPMSystemCapabilityNetwork;
1041
1042 _pendingCapability = _currentCapability;
1043 _desiredCapability = _currentCapability;
1044 _highestCapability = _currentCapability;
1045 setProperty(kIOPMSystemCapabilitiesKey, _currentCapability, 64);
1046
b0d623f7 1047 queuedSleepWakeUUIDString = NULL;
39236c6e 1048 initializeBootSessionUUID();
b0d623f7
A
1049 pmStatsAppResponses = OSArray::withCapacity(5);
1050 _statsNameKey = OSSymbol::withCString(kIOPMStatsNameKey);
1051 _statsPIDKey = OSSymbol::withCString(kIOPMStatsPIDKey);
1052 _statsTimeMSKey = OSSymbol::withCString(kIOPMStatsTimeMSKey);
1053 _statsResponseTypeKey = OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey);
1054 _statsMessageTypeKey = OSSymbol::withCString(kIOPMStatsMessageTypeKey);
39236c6e 1055 _statsPowerCapsKey = OSSymbol::withCString(kIOPMStatsPowerCapabilityKey);
3e170ce0 1056 assertOnWakeSecs = -1; // Invalid value to prevent updates
2d21ac55 1057
fe8ab488 1058 pmStatsLock = IOLockAlloc();
2d21ac55
A
1059 idxPMCPUClamshell = kCPUUnknownIndex;
1060 idxPMCPULimitedPower = kCPUUnknownIndex;
fe8ab488 1061
d52fe63f
A
1062 tmpDict = OSDictionary::withCapacity(1);
1063 setProperty(kRootDomainSupportedFeatures, tmpDict);
1064 tmpDict->release();
fe8ab488 1065
0c530ab8
A
1066 settingsCallbacks = OSDictionary::withCapacity(1);
1067
1068 // Create a list of the valid PM settings that we'll relay to
1069 // interested clients in setProperties() => setPMSetting()
1070 allowedPMSettings = OSArray::withObjects(
1071 (const OSObject **)settingsArr,
1072 kRootDomainSettingsCount,
1073 0);
7ddcb079
A
1074
1075 // List of PM settings that should not automatically publish itself
1076 // as a feature when registered by a listener.
1077 noPublishPMSettings = OSArray::withObjects(
1078 (const OSObject **) &gIOPMSettingSilentRunningKey, 1, 0);
1079
0c530ab8 1080 fPMSettingsDict = OSDictionary::withCapacity(5);
316670eb
A
1081 preventIdleSleepList = OSSet::withCapacity(8);
1082 preventSystemSleepList = OSSet::withCapacity(2);
b0d623f7
A
1083
1084 PMinit(); // creates gIOPMWorkLoop
1085
1086 // Create IOPMPowerStateQueue used to queue external power
1087 // events, and to handle those events on the PM work loop.
1088 pmPowerStateQueue = IOPMPowerStateQueue::PMPowerStateQueue(
1089 this, OSMemberFunctionCast(IOEventSource::Action, this,
1090 &IOPMrootDomain::dispatchPowerEvent));
2d21ac55 1091 getPMworkloop()->addEventSource(pmPowerStateQueue);
b0d623f7
A
1092#ifdef CHECK_THREAD_CONTEXT
1093 gIOPMWorkLoop = getPMworkloop();
1094#endif
1c79356b 1095
b0d623f7 1096 // create our power parent
55e303ae 1097 patriarch = new IORootParent;
1c79356b
A
1098 patriarch->init();
1099 patriarch->attach(this);
1100 patriarch->start(this);
1c79356b 1101 patriarch->addPowerChild(this);
1c79356b 1102
b0d623f7 1103 registerPowerDriver(this, ourPowerStates, NUM_POWER_STATES);
55e303ae 1104 changePowerStateToPriv(ON_STATE);
0b4e3aa0 1105
55e303ae 1106 // install power change handler
b0d623f7 1107 gSysPowerDownNotifier = registerPrioritySleepWakeInterest( &sysPowerDownHandler, this, 0);
0b4e3aa0 1108
2d21ac55 1109#if !NO_KERNEL_HID
0b4e3aa0 1110 // Register for a notification when IODisplayWrangler is published
b0d623f7
A
1111 if ((tmpDict = serviceMatching("IODisplayWrangler")))
1112 {
fe8ab488
A
1113 _displayWranglerNotifier = addMatchingNotification(
1114 gIOPublishNotification, tmpDict,
6d2010ae 1115 (IOServiceMatchingNotificationHandler) &displayWranglerMatchPublished,
b0d623f7
A
1116 this, 0);
1117 tmpDict->release();
1118 }
2d21ac55 1119#endif
483a1d10 1120
39236c6e
A
1121#if defined(__i386__) || defined(__x86_64__)
1122
1123 if ((tmpDict = serviceMatching("IODTNVRAM")))
1124 {
fe8ab488
A
1125 notifier = addMatchingNotification(
1126 gIOFirstPublishNotification, tmpDict,
39236c6e
A
1127 (IOServiceMatchingNotificationHandler) &IONVRAMMatchPublished,
1128 this, 0);
1129 tmpDict->release();
1130 }
1131
1132 wranglerIdleSettings = NULL;
1133 OSNumber * wranglerIdlePeriod = NULL;
1134 wranglerIdleSettings = OSDictionary::withCapacity(1);
1135 wranglerIdlePeriod = OSNumber::withNumber(kDefaultWranglerIdlePeriod, 32);
1136
1137 if(wranglerIdleSettings && wranglerIdlePeriod)
1138 wranglerIdleSettings->setObject(kIORequestWranglerIdleKey,
1139 wranglerIdlePeriod);
1140
1141 if(wranglerIdlePeriod)
1142 wranglerIdlePeriod->release();
1143#endif
1144
55e303ae 1145 const OSSymbol *ucClassName = OSSymbol::withCStringNoCopy("RootDomainUserClient");
91447636 1146 setProperty(gIOUserClientClassKey, (OSObject *) ucClassName);
55e303ae
A
1147 ucClassName->release();
1148
0c530ab8
A
1149 // IOBacklightDisplay can take a long time to load at boot, or it may
1150 // not load at all if you're booting with clamshell closed. We publish
1151 // 'DisplayDims' here redundantly to get it published early and at all.
3e170ce0
A
1152 OSDictionary * matching;
1153 matching = serviceMatching("IOPMPowerSource");
1154 psIterator = getMatchingServices( matching );
1155 if (matching) matching->release();
0c530ab8 1156 if( psIterator && psIterator->getNextObject() )
91447636 1157 {
0c530ab8
A
1158 // There's at least one battery on the system, so we publish
1159 // 'DisplayDims' support for the LCD.
91447636 1160 publishFeature("DisplayDims");
0c530ab8
A
1161 }
1162 if(psIterator) {
99c3a104 1163 psIterator->release();
91447636
A
1164 }
1165
2d21ac55
A
1166 sysctl_register_oid(&sysctl__kern_sleeptime);
1167 sysctl_register_oid(&sysctl__kern_waketime);
b0d623f7 1168 sysctl_register_oid(&sysctl__kern_willshutdown);
3e170ce0
A
1169 sysctl_register_oid(&sysctl__kern_iokittest);
1170 sysctl_register_oid(&sysctl__hw_targettype);
1171
b0d623f7
A
1172 sysctl_register_oid(&sysctl__kern_progressmeterenable);
1173 sysctl_register_oid(&sysctl__kern_progressmeter);
fe8ab488 1174 sysctl_register_oid(&sysctl__kern_wakereason);
3e170ce0 1175 sysctl_register_oid(&sysctl__kern_consoleoptions);
490019cf 1176 sysctl_register_oid(&sysctl__kern_progressoptions);
2d21ac55 1177
fe8ab488 1178#if HIBERNATION
3a60a9f5 1179 IOHibernateSystemInit(this);
2d21ac55 1180#endif
91447636 1181
fe8ab488 1182 registerService(); // let clients find us
1c79356b
A
1183
1184 return true;
1185}
1186
b0d623f7 1187//******************************************************************************
9bccf70c
A
1188// setProperties
1189//
1190// Receive a setProperty call
1191// The "System Boot" property means the system is completely booted.
b0d623f7
A
1192//******************************************************************************
1193
1194IOReturn IOPMrootDomain::setProperties( OSObject * props_obj )
1195{
1196 IOReturn return_value = kIOReturnSuccess;
1197 OSDictionary *dict = OSDynamicCast(OSDictionary, props_obj);
1198 OSBoolean *b;
1199 OSNumber *n;
99c3a104 1200 const OSSymbol *key;
b0d623f7 1201 OSObject *obj;
99c3a104 1202 OSCollectionIterator * iter = 0;
0c530ab8 1203
6d2010ae
A
1204 const OSSymbol *publish_simulated_battery_string = OSSymbol::withCString("SoftwareSimulatedBatteries");
1205 const OSSymbol *boot_complete_string = OSSymbol::withCString("System Boot Complete");
1206 const OSSymbol *sys_shutdown_string = OSSymbol::withCString("System Shutdown");
1207 const OSSymbol *stall_halt_string = OSSymbol::withCString("StallSystemAtHalt");
1208 const OSSymbol *battery_warning_disabled_string = OSSymbol::withCString("BatteryWarningsDisabled");
1209 const OSSymbol *idle_seconds_string = OSSymbol::withCString("System Idle Seconds");
1210 const OSSymbol *sleepdisabled_string = OSSymbol::withCString("SleepDisabled");
1211 const OSSymbol *ondeck_sleepwake_uuid_string = OSSymbol::withCString(kIOPMSleepWakeUUIDKey);
1212 const OSSymbol *loginwindow_tracepoint_string = OSSymbol::withCString(kIOPMLoginWindowSecurityDebugKey);
fe8ab488 1213#if HIBERNATION
6d2010ae
A
1214 const OSSymbol *hibernatemode_string = OSSymbol::withCString(kIOHibernateModeKey);
1215 const OSSymbol *hibernatefile_string = OSSymbol::withCString(kIOHibernateFileKey);
db609669
A
1216 const OSSymbol *hibernatefilemin_string = OSSymbol::withCString(kIOHibernateFileMinSizeKey);
1217 const OSSymbol *hibernatefilemax_string = OSSymbol::withCString(kIOHibernateFileMaxSizeKey);
6d2010ae
A
1218 const OSSymbol *hibernatefreeratio_string = OSSymbol::withCString(kIOHibernateFreeRatioKey);
1219 const OSSymbol *hibernatefreetime_string = OSSymbol::withCString(kIOHibernateFreeTimeKey);
2d21ac55 1220#endif
fe8ab488 1221
99c3a104 1222 if (!dict)
e5568f75
A
1223 {
1224 return_value = kIOReturnBadArgument;
1225 goto exit;
1226 }
6d2010ae 1227
99c3a104
A
1228 iter = OSCollectionIterator::withCollection(dict);
1229 if (!iter)
2d21ac55 1230 {
99c3a104
A
1231 return_value = kIOReturnNoMemory;
1232 goto exit;
2d21ac55
A
1233 }
1234
99c3a104
A
1235 while ((key = (const OSSymbol *) iter->getNextObject()) &&
1236 (obj = dict->getObject(key)))
6d2010ae 1237 {
99c3a104 1238 if (key->isEqualTo(publish_simulated_battery_string))
6d2010ae 1239 {
99c3a104
A
1240 if (OSDynamicCast(OSBoolean, obj))
1241 publishResource(key, kOSBooleanTrue);
1242 }
1243 else if (key->isEqualTo(idle_seconds_string))
1244 {
1245 if ((n = OSDynamicCast(OSNumber, obj)))
1246 {
1247 setProperty(key, n);
1248 idleSeconds = n->unsigned32BitValue();
1249 }
1250 }
1251 else if (key->isEqualTo(boot_complete_string))
1252 {
1253 pmPowerStateQueue->submitPowerEvent(kPowerEventSystemBootCompleted);
1254 }
1255 else if (key->isEqualTo(sys_shutdown_string))
1256 {
1257 if ((b = OSDynamicCast(OSBoolean, obj)))
1258 pmPowerStateQueue->submitPowerEvent(kPowerEventSystemShutdown, (void *) b);
1259 }
1260 else if (key->isEqualTo(battery_warning_disabled_string))
1261 {
1262 setProperty(key, obj);
1263 }
fe8ab488 1264#if HIBERNATION
99c3a104 1265 else if (key->isEqualTo(hibernatemode_string) ||
db609669
A
1266 key->isEqualTo(hibernatefilemin_string) ||
1267 key->isEqualTo(hibernatefilemax_string) ||
99c3a104
A
1268 key->isEqualTo(hibernatefreeratio_string) ||
1269 key->isEqualTo(hibernatefreetime_string))
1270 {
1271 if ((n = OSDynamicCast(OSNumber, obj)))
1272 setProperty(key, n);
1273 }
1274 else if (key->isEqualTo(hibernatefile_string))
1275 {
1276 OSString * str = OSDynamicCast(OSString, obj);
1277 if (str) setProperty(key, str);
1278 }
fe8ab488 1279#endif
99c3a104
A
1280 else if (key->isEqualTo(sleepdisabled_string))
1281 {
1282 if ((b = OSDynamicCast(OSBoolean, obj)))
1283 {
1284 setProperty(key, b);
1285 pmPowerStateQueue->submitPowerEvent(kPowerEventUserDisabledSleep, (void *) b);
1286 }
1287 }
1288 else if (key->isEqualTo(ondeck_sleepwake_uuid_string))
1289 {
6d2010ae
A
1290 obj->retain();
1291 pmPowerStateQueue->submitPowerEvent(kPowerEventQueueSleepWakeUUID, (void *)obj);
b0d623f7 1292 }
99c3a104
A
1293 else if (key->isEqualTo(loginwindow_tracepoint_string))
1294 {
1295 if (pmTracer && (n = OSDynamicCast(OSNumber, obj)))
1296 pmTracer->traceLoginWindowPhase(n->unsigned8BitValue());
1297 }
1298 else if (key->isEqualTo(kIOPMDeepSleepEnabledKey) ||
1299 key->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey) ||
1300 key->isEqualTo(kIOPMAutoPowerOffEnabledKey) ||
1301 key->isEqualTo(stall_halt_string))
1302 {
1303 if ((b = OSDynamicCast(OSBoolean, obj)))
1304 setProperty(key, b);
1305 }
1306 else if (key->isEqualTo(kIOPMDeepSleepDelayKey) ||
db609669
A
1307 key->isEqualTo(kIOPMAutoPowerOffDelayKey) ||
1308 key->isEqualTo(kIOPMAutoPowerOffTimerKey))
99c3a104
A
1309 {
1310 if ((n = OSDynamicCast(OSNumber, obj)))
1311 setProperty(key, n);
1312 }
db609669
A
1313 else if (key->isEqualTo(kIOPMUserWakeAlarmScheduledKey))
1314 {
1315 if (kOSBooleanTrue == obj)
1316 OSBitOrAtomic(kIOPMAlarmBitCalendarWake, &_userScheduledAlarm);
1317 else
1318 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake, &_userScheduledAlarm);
1319 DLOG("_userScheduledAlarm = 0x%x\n", (uint32_t) _userScheduledAlarm);
1320 }
fe8ab488 1321
99c3a104
A
1322 // Relay our allowed PM settings onto our registered PM clients
1323 else if ((allowedPMSettings->getNextIndexOfObject(key, 0) != (unsigned int) -1))
1324 {
fe8ab488 1325 return_value = setPMSetting(key, obj);
99c3a104
A
1326 if (kIOReturnSuccess != return_value)
1327 break;
2d21ac55 1328
99c3a104 1329 if (gIOPMSettingDebugWakeRelativeKey == key)
6d2010ae 1330 {
99c3a104
A
1331 if ((n = OSDynamicCast(OSNumber, obj)) &&
1332 (_debugWakeSeconds = n->unsigned32BitValue()))
1333 {
1334 OSBitOrAtomic(kIOPMAlarmBitDebugWake, &_scheduledAlarms);
1335 }
1336 else
1337 {
1338 _debugWakeSeconds = 0;
1339 OSBitAndAtomic(~kIOPMAlarmBitDebugWake, &_scheduledAlarms);
1340 }
1341 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms);
1342 }
1343 else if (gIOPMSettingAutoWakeCalendarKey == key)
1344 {
1345 OSData * data;
1346 if ((data = OSDynamicCast(OSData, obj)) &&
1347 (data->getLength() == sizeof(IOPMCalendarStruct)))
1348 {
fe8ab488 1349 const IOPMCalendarStruct * cs =
99c3a104
A
1350 (const IOPMCalendarStruct *) data->getBytesNoCopy();
1351
1352 if (cs->year)
1353 OSBitOrAtomic(kIOPMAlarmBitCalendarWake, &_scheduledAlarms);
1354 else
1355 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake, &_scheduledAlarms);
1356 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms);
1357 }
6d2010ae
A
1358 }
1359 }
99c3a104 1360 else
6d2010ae 1361 {
99c3a104 1362 DLOG("setProperties(%s) not handled\n", key->getCStringNoCopy());
6d2010ae 1363 }
6601e61a
A
1364 }
1365
2d21ac55 1366exit:
6d2010ae 1367 if(publish_simulated_battery_string) publish_simulated_battery_string->release();
4a249263 1368 if(boot_complete_string) boot_complete_string->release();
b0d623f7 1369 if(sys_shutdown_string) sys_shutdown_string->release();
4a249263 1370 if(stall_halt_string) stall_halt_string->release();
6d2010ae 1371 if(battery_warning_disabled_string) battery_warning_disabled_string->release();
2d21ac55 1372 if(idle_seconds_string) idle_seconds_string->release();
b0d623f7
A
1373 if(sleepdisabled_string) sleepdisabled_string->release();
1374 if(ondeck_sleepwake_uuid_string) ondeck_sleepwake_uuid_string->release();
0b4c1975 1375 if(loginwindow_tracepoint_string) loginwindow_tracepoint_string->release();
fe8ab488 1376#if HIBERNATION
b0d623f7
A
1377 if(hibernatemode_string) hibernatemode_string->release();
1378 if(hibernatefile_string) hibernatefile_string->release();
1379 if(hibernatefreeratio_string) hibernatefreeratio_string->release();
1380 if(hibernatefreetime_string) hibernatefreetime_string->release();
1381#endif
99c3a104 1382 if (iter) iter->release();
e5568f75 1383 return return_value;
9bccf70c
A
1384}
1385
6d2010ae
A
1386// MARK: -
1387// MARK: Aggressiveness
1c79356b 1388
b0d623f7 1389//******************************************************************************
6d2010ae 1390// setAggressiveness
1c79356b 1391//
6d2010ae 1392// Override IOService::setAggressiveness()
b0d623f7 1393//******************************************************************************
1c79356b 1394
6d2010ae
A
1395IOReturn IOPMrootDomain::setAggressiveness(
1396 unsigned long type,
1397 unsigned long value )
1c79356b 1398{
6d2010ae
A
1399 return setAggressiveness( type, value, 0 );
1400}
d52fe63f 1401
b0d623f7
A
1402/*
1403 * Private setAggressiveness() with an internal options argument.
1404 */
1405IOReturn IOPMrootDomain::setAggressiveness(
1406 unsigned long type,
1407 unsigned long value,
1408 IOOptionBits options )
0b4e3aa0 1409{
b0d623f7
A
1410 AggressivesRequest * entry;
1411 AggressivesRequest * request;
1412 bool found = false;
2d21ac55 1413
6d2010ae
A
1414 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1415 (uint32_t) options, (uint32_t) type, (uint32_t) value);
2d21ac55 1416
b0d623f7
A
1417 request = IONew(AggressivesRequest, 1);
1418 if (!request)
1419 return kIOReturnNoMemory;
1420
1421 memset(request, 0, sizeof(*request));
1422 request->options = options;
1423 request->dataType = kAggressivesRequestTypeRecord;
1424 request->data.record.type = (uint32_t) type;
1425 request->data.record.value = (uint32_t) value;
1426
1427 AGGRESSIVES_LOCK();
1428
1429 // Update disk quick spindown flag used by getAggressiveness().
1430 // Never merge requests with quick spindown flags set.
1431
1432 if (options & kAggressivesOptionQuickSpindownEnable)
1433 gAggressivesState |= kAggressivesStateQuickSpindown;
1434 else if (options & kAggressivesOptionQuickSpindownDisable)
1435 gAggressivesState &= ~kAggressivesStateQuickSpindown;
1436 else
2d21ac55 1437 {
b0d623f7
A
1438 // Coalesce requests with identical aggressives types.
1439 // Deal with callers that calls us too "aggressively".
1440
1441 queue_iterate(&aggressivesQueue, entry, AggressivesRequest *, chain)
1442 {
1443 if ((entry->dataType == kAggressivesRequestTypeRecord) &&
1444 (entry->data.record.type == type) &&
1445 ((entry->options & kAggressivesOptionQuickSpindownMask) == 0))
1446 {
1447 entry->data.record.value = value;
1448 found = true;
1449 break;
1450 }
1451 }
2d21ac55
A
1452 }
1453
b0d623f7
A
1454 if (!found)
1455 {
1456 queue_enter(&aggressivesQueue, request, AggressivesRequest *, chain);
1457 }
0b4e3aa0 1458
b0d623f7
A
1459 AGGRESSIVES_UNLOCK();
1460
1461 if (found)
1462 IODelete(request, AggressivesRequest, 1);
1463
1464 if (options & kAggressivesOptionSynchronous)
1465 handleAggressivesRequests(); // not truly synchronous
1466 else
1467 thread_call_enter(aggressivesThreadCall);
1468
1469 return kIOReturnSuccess;
0b4e3aa0
A
1470}
1471
b0d623f7
A
1472//******************************************************************************
1473// getAggressiveness
1474//
1475// Override IOService::setAggressiveness()
1476// Fetch the aggressiveness factor with the given type.
1477//******************************************************************************
1478
1479IOReturn IOPMrootDomain::getAggressiveness (
1480 unsigned long type,
1481 unsigned long * outLevel )
d52fe63f 1482{
b0d623f7
A
1483 uint32_t value = 0;
1484 int source = 0;
d52fe63f 1485
b0d623f7
A
1486 if (!outLevel)
1487 return kIOReturnBadArgument;
1488
1489 AGGRESSIVES_LOCK();
1490
1491 // Disk quick spindown in effect, report value = 1
1492
1493 if ((gAggressivesState & kAggressivesStateQuickSpindown) &&
1494 (type == kPMMinutesToSpinDown))
1495 {
1496 value = kAggressivesMinValue;
1497 source = 1;
1498 }
1499
1500 // Consult the pending request queue.
1501
1502 if (!source)
1503 {
1504 AggressivesRequest * entry;
1505
1506 queue_iterate(&aggressivesQueue, entry, AggressivesRequest *, chain)
1507 {
1508 if ((entry->dataType == kAggressivesRequestTypeRecord) &&
1509 (entry->data.record.type == type) &&
1510 ((entry->options & kAggressivesOptionQuickSpindownMask) == 0))
1511 {
1512 value = entry->data.record.value;
1513 source = 2;
1514 break;
1515 }
1516 }
1517 }
1518
1519 // Consult the backend records.
1520
1521 if (!source && aggressivesData)
1522 {
1523 AggressivesRecord * record;
1524 int i, count;
1525
1526 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
1527 record = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
1528
1529 for (i = 0; i < count; i++, record++)
1530 {
1531 if (record->type == type)
1532 {
1533 value = record->value;
1534 source = 3;
1535 break;
1536 }
1537 }
1538 }
1539
1540 AGGRESSIVES_UNLOCK();
1541
1542 if (source)
1543 {
6d2010ae
A
1544 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1545 source, (uint32_t) type, value);
b0d623f7
A
1546 *outLevel = (unsigned long) value;
1547 return kIOReturnSuccess;
1548 }
1549 else
1550 {
1551 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type);
1552 *outLevel = 0; // default return = 0, driver may not check for error
1553 return kIOReturnInvalid;
1554 }
d52fe63f
A
1555}
1556
b0d623f7
A
1557//******************************************************************************
1558// joinAggressiveness
1c79356b 1559//
b0d623f7
A
1560// Request from IOService to join future aggressiveness broadcasts.
1561//******************************************************************************
1c79356b 1562
b0d623f7
A
1563IOReturn IOPMrootDomain::joinAggressiveness(
1564 IOService * service )
1c79356b 1565{
b0d623f7
A
1566 AggressivesRequest * request;
1567
1568 if (!service || (service == this))
1569 return kIOReturnBadArgument;
1570
39236c6e 1571 DLOG("joinAggressiveness %s %p\n", service->getName(), OBFUSCATE(service));
b0d623f7
A
1572
1573 request = IONew(AggressivesRequest, 1);
1574 if (!request)
1575 return kIOReturnNoMemory;
1576
1577 service->retain(); // released by synchronizeAggressives()
1578
1579 memset(request, 0, sizeof(*request));
1580 request->dataType = kAggressivesRequestTypeService;
1581 request->data.service = service;
1582
1583 AGGRESSIVES_LOCK();
1584 queue_enter(&aggressivesQueue, request, AggressivesRequest *, chain);
1585 AGGRESSIVES_UNLOCK();
1586
1587 thread_call_enter(aggressivesThreadCall);
3a60a9f5 1588
1c79356b
A
1589 return kIOReturnSuccess;
1590}
1591
b0d623f7
A
1592//******************************************************************************
1593// handleAggressivesRequests
1594//
1595// Backend thread processes all incoming aggressiveness requests in the queue.
1596//******************************************************************************
1597
1598static void
1599handleAggressivesFunction(
1600 thread_call_param_t param1,
1601 thread_call_param_t param2 )
1602{
1603 if (param1)
1604 {
1605 ((IOPMrootDomain *) param1)->handleAggressivesRequests();
1606 }
1607}
1608
1609void IOPMrootDomain::handleAggressivesRequests( void )
1610{
1611 AggressivesRecord * start;
1612 AggressivesRecord * record;
1613 AggressivesRequest * request;
1614 queue_head_t joinedQueue;
1615 int i, count;
1616 bool broadcast;
1617 bool found;
1618 bool pingSelf = false;
1619
1620 AGGRESSIVES_LOCK();
1621
1622 if ((gAggressivesState & kAggressivesStateBusy) || !aggressivesData ||
1623 queue_empty(&aggressivesQueue))
1624 goto unlock_done;
1625
1626 gAggressivesState |= kAggressivesStateBusy;
1627 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
1628 start = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
1629
1630 do
1631 {
1632 broadcast = false;
1633 queue_init(&joinedQueue);
1634
1635 do
1636 {
1637 // Remove request from the incoming queue in FIFO order.
1638 queue_remove_first(&aggressivesQueue, request, AggressivesRequest *, chain);
1639 switch (request->dataType)
1640 {
1641 case kAggressivesRequestTypeRecord:
1642 // Update existing record if found.
1643 found = false;
1644 for (i = 0, record = start; i < count; i++, record++)
1645 {
1646 if (record->type == request->data.record.type)
1647 {
1648 found = true;
1649
1650 if (request->options & kAggressivesOptionQuickSpindownEnable)
1651 {
1652 if ((record->flags & kAggressivesRecordFlagMinValue) == 0)
1653 {
1654 broadcast = true;
1655 record->flags |= (kAggressivesRecordFlagMinValue |
1656 kAggressivesRecordFlagModified);
6d2010ae 1657 DLOG("disk spindown accelerated, was %u min\n",
b0d623f7
A
1658 record->value);
1659 }
1660 }
1661 else if (request->options & kAggressivesOptionQuickSpindownDisable)
1662 {
1663 if (record->flags & kAggressivesRecordFlagMinValue)
1664 {
1665 broadcast = true;
1666 record->flags |= kAggressivesRecordFlagModified;
1667 record->flags &= ~kAggressivesRecordFlagMinValue;
1668 DLOG("disk spindown restored to %u min\n",
1669 record->value);
1670 }
1671 }
1672 else if (record->value != request->data.record.value)
1673 {
1674 record->value = request->data.record.value;
1675 if ((record->flags & kAggressivesRecordFlagMinValue) == 0)
1676 {
1677 broadcast = true;
1678 record->flags |= kAggressivesRecordFlagModified;
1679 }
1680 }
1681 break;
1682 }
1683 }
1684
1685 // No matching record, append a new record.
1686 if (!found &&
1687 ((request->options & kAggressivesOptionQuickSpindownDisable) == 0))
1688 {
1689 AggressivesRecord newRecord;
1690
1691 newRecord.flags = kAggressivesRecordFlagModified;
1692 newRecord.type = request->data.record.type;
1693 newRecord.value = request->data.record.value;
1694 if (request->options & kAggressivesOptionQuickSpindownEnable)
1695 {
1696 newRecord.flags |= kAggressivesRecordFlagMinValue;
1697 DLOG("disk spindown accelerated\n");
1698 }
1699
1700 aggressivesData->appendBytes(&newRecord, sizeof(newRecord));
1701
1702 // OSData may have switched to another (larger) buffer.
1703 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
1704 start = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
1705 broadcast = true;
1706 }
1707
1708 // Finished processing the request, release it.
1709 IODelete(request, AggressivesRequest, 1);
1710 break;
1711
1712 case kAggressivesRequestTypeService:
1713 // synchronizeAggressives() will free request.
1714 queue_enter(&joinedQueue, request, AggressivesRequest *, chain);
1715 break;
1716
1717 default:
1718 panic("bad aggressives request type %x\n", request->dataType);
1719 break;
1720 }
1721 } while (!queue_empty(&aggressivesQueue));
1722
1723 // Release the lock to perform work, with busy flag set.
1724 if (!queue_empty(&joinedQueue) || broadcast)
1725 {
1726 AGGRESSIVES_UNLOCK();
1727 if (!queue_empty(&joinedQueue))
1728 synchronizeAggressives(&joinedQueue, start, count);
1729 if (broadcast)
1730 broadcastAggressives(start, count);
1731 AGGRESSIVES_LOCK();
1732 }
1733
1734 // Remove the modified flag from all records.
1735 for (i = 0, record = start; i < count; i++, record++)
1736 {
1737 if ((record->flags & kAggressivesRecordFlagModified) &&
1738 ((record->type == kPMMinutesToDim) ||
1739 (record->type == kPMMinutesToSleep)))
1740 pingSelf = true;
1741
1742 record->flags &= ~kAggressivesRecordFlagModified;
1743 }
1744
1745 // Check the incoming queue again since new entries may have been
1746 // added while lock was released above.
1747
1748 } while (!queue_empty(&aggressivesQueue));
1749
1750 gAggressivesState &= ~kAggressivesStateBusy;
1751
1752unlock_done:
1753 AGGRESSIVES_UNLOCK();
1754
1755 // Root domain is interested in system and display sleep slider changes.
1756 // Submit a power event to handle those changes on the PM work loop.
1757
1758 if (pingSelf && pmPowerStateQueue) {
6d2010ae
A
1759 pmPowerStateQueue->submitPowerEvent(
1760 kPowerEventPolicyStimulus,
1761 (void *) kStimulusAggressivenessChanged );
b0d623f7
A
1762 }
1763}
1764
b0d623f7
A
1765//******************************************************************************
1766// synchronizeAggressives
1767//
1768// Push all known aggressiveness records to one or more IOService.
1769//******************************************************************************
1770
1771void IOPMrootDomain::synchronizeAggressives(
1772 queue_head_t * joinedQueue,
1773 const AggressivesRecord * array,
1774 int count )
1775{
1776 IOService * service;
1777 AggressivesRequest * request;
1778 const AggressivesRecord * record;
6d2010ae 1779 IOPMDriverCallEntry callEntry;
b0d623f7
A
1780 uint32_t value;
1781 int i;
1782
1783 while (!queue_empty(joinedQueue))
1784 {
1785 queue_remove_first(joinedQueue, request, AggressivesRequest *, chain);
1786 if (request->dataType == kAggressivesRequestTypeService)
1787 service = request->data.service;
1788 else
1789 service = 0;
1790
1791 IODelete(request, AggressivesRequest, 1);
1792 request = 0;
1793
1794 if (service)
1795 {
6d2010ae 1796 if (service->assertPMDriverCall(&callEntry))
b0d623f7
A
1797 {
1798 for (i = 0, record = array; i < count; i++, record++)
1799 {
1800 value = record->value;
1801 if (record->flags & kAggressivesRecordFlagMinValue)
1802 value = kAggressivesMinValue;
1803
6d2010ae 1804 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
b0d623f7
A
1805 record->type, value, service->getName());
1806 service->setAggressiveness(record->type, value);
1807 }
6d2010ae 1808 service->deassertPMDriverCall(&callEntry);
b0d623f7
A
1809 }
1810 service->release(); // retained by joinAggressiveness()
1811 }
1812 }
1813}
1814
b0d623f7
A
1815//******************************************************************************
1816// broadcastAggressives
1817//
1818// Traverse PM tree and call setAggressiveness() for records that have changed.
1819//******************************************************************************
1820
1821void IOPMrootDomain::broadcastAggressives(
1822 const AggressivesRecord * array,
1823 int count )
1824{
6d2010ae
A
1825 IORegistryIterator * iter;
1826 IORegistryEntry * entry;
1827 IOPowerConnection * connect;
b0d623f7
A
1828 IOService * service;
1829 const AggressivesRecord * record;
6d2010ae 1830 IOPMDriverCallEntry callEntry;
b0d623f7
A
1831 uint32_t value;
1832 int i;
1833
6d2010ae
A
1834 iter = IORegistryIterator::iterateOver(
1835 this, gIOPowerPlane, kIORegistryIterateRecursively);
b0d623f7 1836 if (iter)
6d2010ae 1837 {
b0d623f7
A
1838 do
1839 {
1840 iter->reset();
1841 while ((entry = iter->getNextObject()))
1842 {
1843 connect = OSDynamicCast(IOPowerConnection, entry);
1844 if (!connect || !connect->getReadyFlag())
1845 continue;
1846
1847 if ((service = (IOService *) connect->copyChildEntry(gIOPowerPlane)))
1848 {
6d2010ae 1849 if (service->assertPMDriverCall(&callEntry))
b0d623f7
A
1850 {
1851 for (i = 0, record = array; i < count; i++, record++)
1852 {
1853 if (record->flags & kAggressivesRecordFlagModified)
1854 {
1855 value = record->value;
1856 if (record->flags & kAggressivesRecordFlagMinValue)
1857 value = kAggressivesMinValue;
6d2010ae 1858 _LOG("broadcastAggressives %x = %u to %s\n",
b0d623f7
A
1859 record->type, value, service->getName());
1860 service->setAggressiveness(record->type, value);
1861 }
1862 }
6d2010ae 1863 service->deassertPMDriverCall(&callEntry);
b0d623f7
A
1864 }
1865 service->release();
1866 }
1867 }
1868 }
1869 while (!entry && !iter->isValid());
1870 iter->release();
1871 }
1872}
1873
6d2010ae
A
1874// MARK: -
1875// MARK: System Sleep
b0d623f7
A
1876
1877//******************************************************************************
1878// startIdleSleepTimer
1879//
1880//******************************************************************************
1881
1882void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds )
1883{
1884 AbsoluteTime deadline;
1885
1886 ASSERT_GATED();
3e170ce0
A
1887 if (gNoIdleFlag) {
1888 DLOG("idle timer not set (noidle=%d)\n", gNoIdleFlag);
1889 return;
1890 }
b0d623f7
A
1891 if (inSeconds)
1892 {
fe8ab488 1893 clock_interval_to_deadline(inSeconds, kSecondScale, &deadline);
b0d623f7
A
1894 thread_call_enter_delayed(extraSleepTimer, deadline);
1895 idleSleepTimerPending = true;
b0d623f7 1896 }
316670eb
A
1897 else
1898 {
1899 thread_call_enter(extraSleepTimer);
1900 }
1901 DLOG("idle timer set for %u seconds\n", inSeconds);
b0d623f7
A
1902}
1903
b0d623f7
A
1904//******************************************************************************
1905// cancelIdleSleepTimer
1906//
1907//******************************************************************************
1908
1909void IOPMrootDomain::cancelIdleSleepTimer( void )
1910{
1911 ASSERT_GATED();
6d2010ae 1912 if (idleSleepTimerPending)
b0d623f7
A
1913 {
1914 DLOG("idle timer cancelled\n");
1915 thread_call_cancel(extraSleepTimer);
1916 idleSleepTimerPending = false;
3e170ce0
A
1917
1918 if (!assertOnWakeSecs && systemWakeTime) {
1919 AbsoluteTime now;
1920 clock_usec_t microsecs;
1921 clock_get_uptime(&now);
1922 SUB_ABSOLUTETIME(&now, &systemWakeTime);
1923 absolutetime_to_microtime(now, &assertOnWakeSecs, &microsecs);
1924 if (assertOnWakeReport) {
1925 HISTREPORT_TALLYVALUE(assertOnWakeReport, (int64_t)assertOnWakeSecs);
1926 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs);
1927 }
1928 }
b0d623f7
A
1929 }
1930}
1931
b0d623f7
A
1932//******************************************************************************
1933// idleSleepTimerExpired
1934//
1935//******************************************************************************
1936
1937static void idleSleepTimerExpired(
1938 thread_call_param_t us, thread_call_param_t )
1939{
1940 ((IOPMrootDomain *)us)->handleSleepTimerExpiration();
1941}
1942
b0d623f7
A
1943//******************************************************************************
1944// handleSleepTimerExpiration
1945//
1946// The time between the sleep idle timeout and the next longest one has elapsed.
1947// It's time to sleep. Start that by removing the clamp that's holding us awake.
1948//******************************************************************************
1949
1950void IOPMrootDomain::handleSleepTimerExpiration( void )
1951{
1952 if (!getPMworkloop()->inGate())
1953 {
1954 getPMworkloop()->runAction(
1955 OSMemberFunctionCast(IOWorkLoop::Action, this,
1956 &IOPMrootDomain::handleSleepTimerExpiration),
1957 this);
1958 return;
1959 }
1960
1961 AbsoluteTime time;
1962
1963 DLOG("sleep timer expired\n");
1964 ASSERT_GATED();
1965
1966 idleSleepTimerPending = false;
1967
1968 clock_get_uptime(&time);
b0d623f7 1969 setQuickSpinDownTimeout();
6d2010ae 1970 adjustPowerState(true);
b0d623f7
A
1971}
1972
39236c6e
A
1973//******************************************************************************
1974// getTimeToIdleSleep
1975//
1976// Returns number of seconds left before going into idle sleep.
fe8ab488 1977// Caller has to make sure that idle sleep is allowed at the time of calling
39236c6e
A
1978// this function
1979//******************************************************************************
1980
1981uint32_t IOPMrootDomain::getTimeToIdleSleep( void )
1982{
1983
1984 AbsoluteTime now, lastActivityTime;
1985 uint64_t nanos;
1986 uint32_t minutesSinceUserInactive = 0;
1987 uint32_t sleepDelay = 0;
1988
1989 if (sleepSlider == 0)
1990 return 0xffffffff;
1991
1992 if (userActivityTime)
1993 lastActivityTime = userActivityTime;
fe8ab488 1994 else
39236c6e
A
1995 lastActivityTime = userBecameInactiveTime;
1996
1997 clock_get_uptime(&now);
1998 if (CMP_ABSOLUTETIME(&now, &lastActivityTime) > 0)
1999 {
2000 SUB_ABSOLUTETIME(&now, &lastActivityTime);
2001 absolutetime_to_nanoseconds(now, &nanos);
2002 minutesSinceUserInactive = nanos / (60000000000ULL);
fe8ab488 2003
39236c6e
A
2004 if (minutesSinceUserInactive >= sleepSlider)
2005 sleepDelay = 0;
fe8ab488 2006 else
39236c6e
A
2007 sleepDelay = sleepSlider - minutesSinceUserInactive;
2008 }
2009 else
2010 {
2011 sleepDelay = sleepSlider;
2012 }
2013
2014 DLOG("user inactive %u min, time to idle sleep %u min\n",
2015 minutesSinceUserInactive, sleepDelay);
2016
2017 return (sleepDelay * 60);
2018}
2019
b0d623f7 2020//******************************************************************************
6d2010ae 2021// setQuickSpinDownTimeout
b0d623f7
A
2022//
2023//******************************************************************************
2024
6d2010ae 2025void IOPMrootDomain::setQuickSpinDownTimeout( void )
b0d623f7 2026{
b0d623f7 2027 ASSERT_GATED();
6d2010ae
A
2028 setAggressiveness(
2029 kPMMinutesToSpinDown, 0, kAggressivesOptionQuickSpindownEnable );
2030}
b0d623f7 2031
6d2010ae
A
2032//******************************************************************************
2033// restoreUserSpinDownTimeout
2034//
2035//******************************************************************************
b0d623f7 2036
6d2010ae
A
2037void IOPMrootDomain::restoreUserSpinDownTimeout( void )
2038{
2039 ASSERT_GATED();
2040 setAggressiveness(
2041 kPMMinutesToSpinDown, 0, kAggressivesOptionQuickSpindownDisable );
b0d623f7
A
2042}
2043
b0d623f7 2044//******************************************************************************
1c79356b
A
2045// sleepSystem
2046//
b0d623f7
A
2047//******************************************************************************
2048
2d21ac55 2049/* public */
b0d623f7 2050IOReturn IOPMrootDomain::sleepSystem( void )
1c79356b 2051{
b0d623f7 2052 return sleepSystemOptions(NULL);
2d21ac55
A
2053}
2054
2055/* private */
b0d623f7 2056IOReturn IOPMrootDomain::sleepSystemOptions( OSDictionary *options )
2d21ac55 2057{
39236c6e
A
2058 OSObject *obj = NULL;
2059 OSString *reason = NULL;
fe8ab488
A
2060 /* sleepSystem is a public function, and may be called by any kernel driver.
2061 * And that's bad - drivers should sleep the system by calling
2d21ac55
A
2062 * receivePowerNotification() instead. Drivers should not use sleepSystem.
2063 *
2064 * Note that user space app calls to IOPMSleepSystem() will also travel
2065 * this code path and thus be correctly identified as software sleeps.
2066 */
39236c6e 2067
fe8ab488 2068 if (options && options->getObject("OSSwitch"))
2d21ac55 2069 {
2d21ac55 2070 // Log specific sleep cause for OS Switch hibernation
6d2010ae 2071 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate);
2d21ac55 2072 }
39236c6e 2073
fe8ab488 2074 if (options && (obj = options->getObject("Sleep Reason")))
39236c6e
A
2075 {
2076 reason = OSDynamicCast(OSString, obj);
fe8ab488 2077 if (reason && reason->isEqualTo(kIOPMDarkWakeThermalEmergencyKey))
39236c6e
A
2078 return privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency);
2079 }
2080
2081 return privateSleepSystem( kIOPMSleepReasonSoftware);
2d21ac55
A
2082}
2083
2084/* private */
0b4c1975 2085IOReturn IOPMrootDomain::privateSleepSystem( uint32_t sleepReason )
2d21ac55 2086{
39236c6e 2087 /* Called from both gated and non-gated context */
0c530ab8 2088
39236c6e 2089 if (!checkSystemSleepEnabled() || !pmPowerStateQueue)
2d21ac55 2090 {
39236c6e 2091 return kIOReturnNotPermitted;
b0d623f7
A
2092 }
2093
39236c6e 2094 pmPowerStateQueue->submitPowerEvent(
6d2010ae 2095 kPowerEventPolicyStimulus,
39236c6e
A
2096 (void *) kStimulusDemandSystemSleep,
2097 sleepReason);
0b4e3aa0 2098
6d2010ae 2099 return kIOReturnSuccess;
6d2010ae 2100}
1c79356b 2101
b0d623f7 2102//******************************************************************************
1c79356b
A
2103// powerChangeDone
2104//
2105// This overrides powerChangeDone in IOService.
b0d623f7 2106//******************************************************************************
2d21ac55 2107
6d2010ae 2108void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState )
b0d623f7 2109{
3e170ce0 2110 uint64_t now;
b0d623f7
A
2111 ASSERT_GATED();
2112 DLOG("PowerChangeDone: %u->%u\n",
6d2010ae 2113 (uint32_t) previousPowerState, (uint32_t) getPowerState());
fe8ab488 2114
6d2010ae
A
2115 switch ( getPowerState() )
2116 {
2117 case SLEEP_STATE: {
2118 if (previousPowerState != ON_STATE)
2119 break;
fe8ab488
A
2120
2121 acceptSystemWakeEvents(true);
2d21ac55 2122
6d2010ae
A
2123 // re-enable this timer for next sleep
2124 cancelIdleSleepTimer();
91447636 2125
fe8ab488
A
2126 clock_sec_t secs;
2127 clock_usec_t microsecs;
3e170ce0 2128 clock_get_calendar_absolute_and_microtime(&secs, &microsecs, &now);
6d2010ae
A
2129 logtime(secs);
2130 gIOLastSleepTime.tv_sec = secs;
2131 gIOLastSleepTime.tv_usec = microsecs;
2132 gIOLastWakeTime.tv_sec = 0;
2133 gIOLastWakeTime.tv_usec = 0;
2d21ac55 2134
3e170ce0
A
2135 if (wake2DarkwakeDelay && sleepDelaysReport) {
2136 clock_usec_t microsecs;
2137 clock_sec_t wake2DarkwakeSecs, darkwake2SleepSecs;
2138 // Update 'wake2DarkwakeDelay' histogram if this is a fullwake->sleep transition
2139
2140 SUB_ABSOLUTETIME(&now, &ts_sleepStart);
2141 absolutetime_to_microtime(now, &darkwake2SleepSecs, &microsecs);
2142 absolutetime_to_microtime(wake2DarkwakeDelay, &wake2DarkwakeSecs, &microsecs);
2143 HISTREPORT_TALLYVALUE(sleepDelaysReport,
2144 (int64_t)(wake2DarkwakeSecs+darkwake2SleepSecs));
2145
2146 DLOG("Updated sleepDelaysReport %lu %lu\n", (unsigned long)wake2DarkwakeSecs, (unsigned long)darkwake2SleepSecs);
2147 wake2DarkwakeDelay = 0;
2148 }
fe8ab488 2149#if HIBERNATION
6d2010ae 2150 LOG("System %sSleep\n", gIOHibernateState ? "Safe" : "");
3a60a9f5 2151
6d2010ae 2152 IOHibernateSystemHasSlept();
0b4c1975 2153
6d2010ae 2154 evaluateSystemSleepPolicyFinal();
2d21ac55 2155#else
6d2010ae 2156 LOG("System Sleep\n");
2d21ac55 2157#endif
a1c7dba1
A
2158 if (thermalWarningState) {
2159 const OSSymbol *event = OSSymbol::withCString(kIOPMThermalLevelWarningKey);
2160 if (event) {
2161 systemPowerEventOccurred(event, kIOPMThermalLevelUnknown);
2162 event->release();
2163 }
2164 }
3e170ce0 2165 assertOnWakeSecs = 0;
39236c6e 2166 ((IOService *)this)->stop_watchdog_timer(); //14456299
6d2010ae 2167 getPlatform()->sleepKernel();
b0d623f7 2168
6d2010ae
A
2169 // The CPU(s) are off at this point,
2170 // Code will resume execution here upon wake.
9bccf70c 2171
6d2010ae 2172 clock_get_uptime(&systemWakeTime);
db609669 2173 _highestCapability = 0;
91447636 2174
39236c6e 2175 ((IOService *)this)->start_watchdog_timer(); //14456299
fe8ab488 2176#if HIBERNATION
6d2010ae 2177 IOHibernateSystemWake();
2d21ac55 2178#endif
9bccf70c 2179
6d2010ae
A
2180 // sleep transition complete
2181 gSleepOrShutdownPending = 0;
b0d623f7 2182
3e170ce0
A
2183 // trip the reset of the calendar clock
2184 {
2185 clock_sec_t wakeSecs;
2186 clock_usec_t wakeMicrosecs;
2187
2188 clock_initialize_calendar();
2189
2190 clock_get_calendar_microtime(&wakeSecs, &wakeMicrosecs);
2191 gIOLastWakeTime.tv_sec = wakeSecs;
2192 gIOLastWakeTime.tv_usec = wakeMicrosecs;
2193 }
b0d623f7 2194
fe8ab488 2195#if HIBERNATION
6d2010ae 2196 LOG("System %sWake\n", gIOHibernateState ? "SafeSleep " : "");
2d21ac55 2197#endif
b0d623f7 2198
6d2010ae 2199 // log system wake
4b17d6b6 2200 PMDebug(kPMLogSystemWake, 0, 0);
6d2010ae
A
2201 lowBatteryCondition = false;
2202 lastSleepReason = 0;
fe8ab488 2203
7ddcb079
A
2204 _lastDebugWakeSeconds = _debugWakeSeconds;
2205 _debugWakeSeconds = 0;
99c3a104 2206 _scheduledAlarms = 0;
6d2010ae 2207
b0d623f7 2208#ifndef __LP64__
6d2010ae 2209 systemWake();
b0d623f7
A
2210#endif
2211
b0d623f7 2212#if defined(__i386__) || defined(__x86_64__)
fe8ab488
A
2213 wranglerTickled = false;
2214 graphicsSuppressed = false;
2215 darkWakePostTickle = false;
2216 darkWakeHibernateError = false;
2217 darkWakeToSleepASAP = true;
2218 logGraphicsClamp = true;
2219 sleepTimerMaintenance = false;
2220 sleepToStandby = false;
2221 wranglerTickleLatched = false;
2222 userWasActive = false;
39236c6e 2223 fullWakeReason = kFullWakeReasonNone;
6d2010ae
A
2224
2225 OSString * wakeType = OSDynamicCast(
2226 OSString, getProperty(kIOPMRootDomainWakeTypeKey));
2227 OSString * wakeReason = OSDynamicCast(
2228 OSString, getProperty(kIOPMRootDomainWakeReasonKey));
2229
fe8ab488
A
2230 if (wakeReason && (wakeReason->getLength() >= 2) &&
2231 gWakeReasonString[0] == '\0')
2232 {
2233 // Until the platform driver can claim its wake reasons
2234 strlcat(gWakeReasonString, wakeReason->getCStringNoCopy(),
2235 sizeof(gWakeReasonString));
2236 }
2237
6d2010ae
A
2238 if (wakeType && wakeType->isEqualTo(kIOPMrootDomainWakeTypeLowBattery))
2239 {
2240 lowBatteryCondition = true;
2241 darkWakeMaintenance = true;
6d2010ae
A
2242 }
2243 else if ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) != 0)
2244 {
3e170ce0 2245#if HIBERNATION
6d2010ae
A
2246 OSNumber * hibOptions = OSDynamicCast(
2247 OSNumber, getProperty(kIOHibernateOptionsKey));
7ddcb079
A
2248 if (hibernateAborted || ((hibOptions &&
2249 !(hibOptions->unsigned32BitValue() & kIOHibernateOptionDarkWake))))
0b4c1975 2250 {
7ddcb079
A
2251 // Hibernate aborted, or EFI brought up graphics
2252 wranglerTickled = true;
39236c6e
A
2253 DLOG("hibernation aborted %d, options 0x%x\n",
2254 hibernateAborted,
2255 hibOptions ? hibOptions->unsigned32BitValue() : 0);
7ddcb079
A
2256 }
2257 else
3e170ce0 2258#endif
7ddcb079
A
2259 if (wakeType && (
2260 wakeType->isEqualTo(kIOPMRootDomainWakeTypeUser) ||
2261 wakeType->isEqualTo(kIOPMRootDomainWakeTypeAlarm)))
2262 {
2263 // User wake or RTC alarm
6d2010ae 2264 wranglerTickled = true;
0b4c1975 2265 }
6d2010ae
A
2266 else
2267 if (wakeType &&
7ddcb079 2268 wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer))
0b4c1975 2269 {
7ddcb079 2270 // SMC standby timer trumps SleepX
6d2010ae 2271 darkWakeMaintenance = true;
7ddcb079
A
2272 sleepTimerMaintenance = true;
2273 }
2274 else
2275 if ((_lastDebugWakeSeconds != 0) &&
2276 ((gDarkWakeFlags & kDarkWakeFlagAlarmIsDark) == 0))
2277 {
2278 // SleepX before maintenance
2279 wranglerTickled = true;
0b4c1975 2280 }
6d2010ae
A
2281 else
2282 if (wakeType &&
7ddcb079 2283 wakeType->isEqualTo(kIOPMRootDomainWakeTypeMaintenance))
b0d623f7 2284 {
6d2010ae 2285 darkWakeMaintenance = true;
7ddcb079
A
2286 }
2287 else
2288 if (wakeType &&
2289 wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepService))
2290 {
39236c6e 2291 darkWakeMaintenance = true;
7ddcb079 2292 darkWakeSleepService = true;
3e170ce0 2293#if HIBERNATION
39236c6e
A
2294 if (kIOHibernateStateWakingFromHibernate == gIOHibernateState) {
2295 sleepToStandby = true;
2296 }
3e170ce0 2297#endif
b0d623f7
A
2298 }
2299 else
fe8ab488
A
2300 if (wakeType &&
2301 wakeType->isEqualTo(kIOPMRootDomainWakeTypeHibernateError))
2302 {
2303 darkWakeMaintenance = true;
2304 darkWakeHibernateError = true;
2305 }
2306 else
b0d623f7 2307 {
6d2010ae
A
2308 // Unidentified wake source, resume to full wake if debug
2309 // alarm is pending.
b0d623f7 2310
7ddcb079
A
2311 if (_lastDebugWakeSeconds &&
2312 (!wakeReason || wakeReason->isEqualTo("")))
6d2010ae 2313 wranglerTickled = true;
6d2010ae 2314 }
0b4e3aa0 2315 }
6d2010ae 2316 else
55e303ae 2317 {
7ddcb079
A
2318 if (wakeType &&
2319 wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer))
0b4c1975 2320 {
7ddcb079 2321 darkWakeMaintenance = true;
7ddcb079
A
2322 sleepTimerMaintenance = true;
2323 }
2324 else if (hibernateAborted || !wakeType ||
2325 !wakeType->isEqualTo(kIOPMRootDomainWakeTypeMaintenance) ||
2326 !wakeReason || !wakeReason->isEqualTo("RTC"))
2327 {
2328 // Post a HID tickle immediately - except for RTC maintenance wake.
6d2010ae 2329 wranglerTickled = true;
0b4c1975
A
2330 }
2331 else
2332 {
6d2010ae 2333 darkWakeMaintenance = true;
0b4c1975 2334 }
b0d623f7
A
2335 }
2336
6d2010ae 2337 if (wranglerTickled)
39236c6e
A
2338 {
2339 darkWakeToSleepASAP = false;
2340 fullWakeReason = kFullWakeReasonLocalUser;
6d2010ae 2341 reportUserInput();
39236c6e 2342 }
3e170ce0
A
2343 else if (displayPowerOnRequested && checkSystemCanSustainFullWake())
2344 {
2345 handleDisplayPowerOn();
2346 }
6d2010ae 2347 else if (!darkWakeMaintenance)
b0d623f7 2348 {
6d2010ae 2349 // Early/late tickle for non-maintenance wake.
fe8ab488 2350 if (((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
6d2010ae 2351 kDarkWakeFlagHIDTickleEarly) ||
fe8ab488 2352 ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
6d2010ae
A
2353 kDarkWakeFlagHIDTickleLate))
2354 {
2355 darkWakePostTickle = true;
2356 }
2357 }
2358#else /* !__i386__ && !__x86_64__ */
2359 // stay awake for at least 30 seconds
2360 wranglerTickled = true;
39236c6e 2361 fullWakeReason = kFullWakeReasonLocalUser;
6d2010ae
A
2362 startIdleSleepTimer(30);
2363#endif
39236c6e 2364 sleepCnt++;
6d2010ae 2365
3e170ce0
A
2366 thread_call_enter(updateConsoleUsersEntry);
2367
6d2010ae
A
2368 changePowerStateToPriv(ON_STATE);
2369 } break;
3e170ce0
A
2370#if !__i386__ && !__x86_64__
2371 case ON_STATE: {
2372 if (previousPowerState != ON_STATE)
2373 {
2374 DLOG("Force re-evaluating aggressiveness\n");
2375 /* Force re-evaluate the aggressiveness values to set appropriate idle sleep timer */
2376 pmPowerStateQueue->submitPowerEvent(
2377 kPowerEventPolicyStimulus,
2378 (void *) kStimulusNoIdleSleepPreventers );
2379 }
2380 break;
2381 }
2382
2383#endif
6d2010ae 2384
0b4e3aa0
A
2385 }
2386}
2387
b0d623f7 2388//******************************************************************************
6d2010ae 2389// requestPowerDomainState
0b4e3aa0 2390//
6d2010ae 2391// Extend implementation in IOService. Running on PM work loop thread.
b0d623f7
A
2392//******************************************************************************
2393
6d2010ae
A
2394IOReturn IOPMrootDomain::requestPowerDomainState (
2395 IOPMPowerFlags childDesire,
2396 IOPowerConnection * childConnection,
2397 unsigned long specification )
1c79356b 2398{
316670eb
A
2399 // Idle and system sleep prevention flags affects driver desire.
2400 // Children desire are irrelevant so they are cleared.
2401
2402 return super::requestPowerDomainState(0, childConnection, specification);
2403}
2404
3e170ce0 2405
316670eb
A
2406//******************************************************************************
2407// updatePreventIdleSleepList
2408//
2409// Called by IOService on PM work loop.
39236c6e
A
2410// Returns true if PM policy recognized the driver's desire to prevent idle
2411// sleep and updated the list of idle sleep preventers. Returns false otherwise
316670eb
A
2412//******************************************************************************
2413
39236c6e 2414bool IOPMrootDomain::updatePreventIdleSleepList(
316670eb
A
2415 IOService * service, bool addNotRemove )
2416{
2417 unsigned int oldCount, newCount;
6d2010ae
A
2418
2419 ASSERT_GATED();
2420
39236c6e 2421#if defined(__i386__) || defined(__x86_64__)
fe8ab488
A
2422 // Disregard disk I/O (besides the display wrangler) as a factor preventing
2423 // idle sleep, except in the case of legacy disk I/O
2424 if ((service != wrangler) && (service != this))
55e303ae 2425 {
39236c6e 2426 return false;
1c79356b 2427 }
39236c6e 2428#endif
fe8ab488 2429
316670eb
A
2430 oldCount = preventIdleSleepList->getCount();
2431 if (addNotRemove)
6d2010ae 2432 {
316670eb
A
2433 preventIdleSleepList->setObject(service);
2434 DLOG("prevent idle sleep list: %s+ (%u)\n",
2435 service->getName(), preventIdleSleepList->getCount());
2436 }
2437 else if (preventIdleSleepList->member(service))
2438 {
2439 preventIdleSleepList->removeObject(service);
2440 DLOG("prevent idle sleep list: %s- (%u)\n",
2441 service->getName(), preventIdleSleepList->getCount());
2442 }
2443 newCount = preventIdleSleepList->getCount();
fe8ab488 2444
316670eb
A
2445 if ((oldCount == 0) && (newCount != 0))
2446 {
2447 // Driver added to empty prevent list.
2448 // Update the driver desire to prevent idle sleep.
2449 // Driver desire does not prevent demand sleep.
fe8ab488 2450
316670eb
A
2451 changePowerStateTo(ON_STATE);
2452 }
2453 else if ((oldCount != 0) && (newCount == 0))
2454 {
2455 // Last driver removed from prevent list.
2456 // Drop the driver clamp to allow idle sleep.
0c530ab8 2457
316670eb
A
2458 changePowerStateTo(SLEEP_STATE);
2459 evaluatePolicy( kStimulusNoIdleSleepPreventers );
2460 }
3e170ce0
A
2461 messageClient(kIOPMMessageIdleSleepPreventers, systemCapabilityNotifier,
2462 &newCount, sizeof(newCount));
39236c6e
A
2463
2464#if defined(__i386__) || defined(__x86_64__)
2465 if (addNotRemove && (service == wrangler) && !checkSystemCanSustainFullWake())
2466 {
fe8ab488 2467 return false; // do not idle-cancel
39236c6e
A
2468 }
2469#endif
2470
2471 return true;
316670eb 2472}
0c530ab8 2473
316670eb
A
2474//******************************************************************************
2475// preventSystemSleepListUpdate
2476//
2477// Called by IOService on PM work loop.
2478//******************************************************************************
0c530ab8 2479
316670eb
A
2480void IOPMrootDomain::updatePreventSystemSleepList(
2481 IOService * service, bool addNotRemove )
2482{
3e170ce0 2483 unsigned int oldCount, newCount;
b0d623f7 2484
316670eb
A
2485 ASSERT_GATED();
2486 if (this == service)
2487 return;
0c530ab8 2488
316670eb
A
2489 oldCount = preventSystemSleepList->getCount();
2490 if (addNotRemove)
0c530ab8 2491 {
316670eb
A
2492 preventSystemSleepList->setObject(service);
2493 DLOG("prevent system sleep list: %s+ (%u)\n",
2494 service->getName(), preventSystemSleepList->getCount());
3e170ce0
A
2495 if (!assertOnWakeSecs && systemWakeTime) {
2496 AbsoluteTime now;
2497 clock_usec_t microsecs;
2498 clock_get_uptime(&now);
2499 SUB_ABSOLUTETIME(&now, &systemWakeTime);
2500 absolutetime_to_microtime(now, &assertOnWakeSecs, &microsecs);
2501 if (assertOnWakeReport) {
2502 HISTREPORT_TALLYVALUE(assertOnWakeReport, (int64_t)assertOnWakeSecs);
2503 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs);
2504 }
2505 }
316670eb
A
2506 }
2507 else if (preventSystemSleepList->member(service))
2508 {
2509 preventSystemSleepList->removeObject(service);
2510 DLOG("prevent system sleep list: %s- (%u)\n",
2511 service->getName(), preventSystemSleepList->getCount());
2512
2513 if ((oldCount != 0) && (preventSystemSleepList->getCount() == 0))
b0d623f7 2514 {
316670eb
A
2515 // Lost all system sleep preventers.
2516 // Send stimulus if system sleep was blocked, and is in dark wake.
2517 evaluatePolicy( kStimulusDarkWakeEvaluate );
0c530ab8 2518 }
0c530ab8 2519 }
3e170ce0
A
2520 newCount = preventSystemSleepList->getCount();
2521 messageClient(kIOPMMessageSystemSleepPreventers, systemCapabilityNotifier,
2522 &newCount, sizeof(newCount));
2523}
2524
2525void IOPMrootDomain::copySleepPreventersList(OSArray **idleSleepList, OSArray **systemSleepList)
2526{
2527
2528 OSCollectionIterator *iterator = NULL;
2529 OSObject *object = NULL;
2530 OSArray *array = NULL;
2531
2532 if (!getPMworkloop()->inGate())
2533 {
2534 getPMworkloop()->runAction(
2535 OSMemberFunctionCast(IOWorkLoop::Action, this,
2536 &IOPMrootDomain::IOPMrootDomain::copySleepPreventersList),
2537 this, (void *)idleSleepList, (void *)systemSleepList);
2538 return;
2539 }
2540
2541 if (idleSleepList && preventIdleSleepList && (preventIdleSleepList->getCount() != 0))
2542 {
2543 iterator = OSCollectionIterator::withCollection(preventIdleSleepList);
2544 array = OSArray::withCapacity(5);
2545
2546 while ((object = iterator->getNextObject()))
2547 {
2548 IOService *service = OSDynamicCast(IOService, object);
2549 if (object)
2550 {
2551 array->setObject(OSSymbol::withCString(service->getName()));
2552 }
2553 }
2554
2555 iterator->release();
2556 *idleSleepList = array;
2557 }
2558
2559 if (systemSleepList && preventSystemSleepList && (preventSystemSleepList->getCount() != 0))
2560 {
2561 iterator = OSCollectionIterator::withCollection(preventSystemSleepList);
2562 array = OSArray::withCapacity(5);
2563
2564 while ((object = iterator->getNextObject()))
2565 {
2566 IOService *service = OSDynamicCast(IOService, object);
2567 if (object)
2568 {
2569 array->setObject(OSSymbol::withCString(service->getName()));
2570 }
2571 }
2572
2573 iterator->release();
2574 *systemSleepList = array;
2575 }
0c530ab8
A
2576}
2577
b0d623f7 2578//******************************************************************************
6d2010ae 2579// tellChangeDown
0c530ab8 2580//
6d2010ae 2581// Override the superclass implementation to send a different message type.
b0d623f7
A
2582//******************************************************************************
2583
6d2010ae 2584bool IOPMrootDomain::tellChangeDown( unsigned long stateNum )
0c530ab8 2585{
6d2010ae
A
2586 DLOG("tellChangeDown %u->%u\n",
2587 (uint32_t) getPowerState(), (uint32_t) stateNum);
0c530ab8 2588
6d2010ae 2589 if (SLEEP_STATE == stateNum)
0c530ab8 2590 {
39236c6e 2591 // Legacy apps were already told in the full->dark transition
6d2010ae
A
2592 if (!ignoreTellChangeDown)
2593 tracePoint( kIOPMTracePointSleepApplications );
2594 else
fe8ab488 2595 tracePoint( kIOPMTracePointSleepPriorityClients );
0c530ab8 2596 }
6d2010ae
A
2597
2598 if ((SLEEP_STATE == stateNum) && !ignoreTellChangeDown)
0c530ab8 2599 {
6d2010ae
A
2600 userActivityAtSleep = userActivityCount;
2601 hibernateAborted = false;
2602 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep);
0c530ab8 2603
6d2010ae
A
2604 // Direct callout into OSKext so it can disable kext unloads
2605 // during sleep/wake to prevent deadlocks.
2606 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep );
0c530ab8 2607
6d2010ae 2608 IOService::updateConsoleUsers(NULL, kIOMessageSystemWillSleep);
0c530ab8 2609
6d2010ae
A
2610 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2611 // But tellClientsWithResponse() must be called for both.
2612 ignoreTellChangeDown = true;
0c530ab8 2613 }
5d5c5d0d 2614
6d2010ae
A
2615 return super::tellClientsWithResponse( kIOMessageSystemWillSleep );
2616}
5d5c5d0d 2617
b0d623f7 2618//******************************************************************************
6d2010ae 2619// askChangeDown
0c530ab8 2620//
6d2010ae
A
2621// Override the superclass implementation to send a different message type.
2622// This must be idle sleep since we don't ask during any other power change.
b0d623f7
A
2623//******************************************************************************
2624
6d2010ae 2625bool IOPMrootDomain::askChangeDown( unsigned long stateNum )
55e303ae 2626{
6d2010ae
A
2627 DLOG("askChangeDown %u->%u\n",
2628 (uint32_t) getPowerState(), (uint32_t) stateNum);
0c530ab8 2629
6d2010ae
A
2630 // Don't log for dark wake entry
2631 if (kSystemTransitionSleep == _systemTransitionType)
2632 tracePoint( kIOPMTracePointSleepApplications );
483a1d10 2633
6d2010ae 2634 return super::tellClientsWithResponse( kIOMessageCanSystemSleep );
1c79356b
A
2635}
2636
b0d623f7 2637//******************************************************************************
6d2010ae 2638// askChangeDownDone
0c530ab8 2639//
39236c6e
A
2640// An opportunity for root domain to cancel the power transition,
2641// possibily due to an assertion created by powerd in response to
2642// kIOMessageCanSystemSleep.
2643//
2644// Idle sleep:
2645// full -> dark wake transition
2646// 1. Notify apps and powerd with kIOMessageCanSystemSleep
2647// 2. askChangeDownDone()
2648// dark -> sleep transition
2649// 1. Notify powerd with kIOMessageCanSystemSleep
2650// 2. askChangeDownDone()
2651//
2652// Demand sleep:
2653// full -> dark wake transition
2654// 1. Notify powerd with kIOMessageCanSystemSleep
2655// 2. askChangeDownDone()
2656// dark -> sleep transition
2657// 1. Notify powerd with kIOMessageCanSystemSleep
2658// 2. askChangeDownDone()
b0d623f7
A
2659//******************************************************************************
2660
6d2010ae
A
2661void IOPMrootDomain::askChangeDownDone(
2662 IOPMPowerChangeFlags * inOutChangeFlags, bool * cancel )
e5568f75 2663{
6d2010ae
A
2664 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2665 *inOutChangeFlags, *cancel,
2666 _systemTransitionType,
2667 _currentCapability, _pendingCapability);
0c530ab8 2668
6d2010ae
A
2669 if ((false == *cancel) && (kSystemTransitionSleep == _systemTransitionType))
2670 {
2671 // Dark->Sleep transition.
2672 // Check if there are any deny sleep assertions.
39236c6e 2673 // lastSleepReason already set by handleOurPowerChangeStart()
0c530ab8 2674
39236c6e 2675 if (!checkSystemCanSleep(lastSleepReason))
6d2010ae
A
2676 {
2677 // Cancel dark wake to sleep transition.
2678 // Must re-scan assertions upon entering dark wake.
0c530ab8 2679
6d2010ae
A
2680 *cancel = true;
2681 DLOG("cancel dark->sleep\n");
2682 }
0c530ab8 2683 }
e5568f75
A
2684}
2685
22ba694c
A
2686//******************************************************************************
2687// systemDidNotSleep
2688//
2689// Work common to both canceled or aborted sleep.
2690//******************************************************************************
2691
2692void IOPMrootDomain::systemDidNotSleep( void )
2693{
3e170ce0
A
2694 // reset console lock state
2695 thread_call_enter(updateConsoleUsersEntry);
2696
22ba694c
A
2697 if (!wrangler)
2698 {
2699 if (idleSeconds)
2700 {
2701 // stay awake for at least idleSeconds
2702 startIdleSleepTimer(idleSeconds);
2703 }
2704 }
2705 else
2706 {
2707 if (sleepSlider && !userIsActive)
2708 {
2709 // Manually start the idle sleep timer besides waiting for
2710 // the user to become inactive.
2711 startIdleSleepTimer( kIdleSleepRetryInterval );
2712 }
2713 }
2714
2715 preventTransitionToUserActive(false);
2716 IOService::setAdvisoryTickleEnable( true );
3e170ce0
A
2717
2718 // After idle revert and cancel, send a did-change message to powerd
2719 // to balance the previous will-change message. Kernel clients do not
2720 // need this since sleep cannot be canceled once they are notified.
2721
2722 if (toldPowerdCapWillChange && systemCapabilityNotifier &&
2723 (_pendingCapability != _currentCapability) &&
2724 ((_systemMessageClientMask & kSystemMessageClientPowerd) != 0))
2725 {
2726 // Differs from a real capability gain change where notifyRef != 0,
2727 // but it is zero here since no response is expected.
2728
2729 IOPMSystemCapabilityChangeParameters params;
2730
2731 bzero(&params, sizeof(params));
2732 params.fromCapabilities = _pendingCapability;
2733 params.toCapabilities = _currentCapability;
2734 params.changeFlags = kIOPMSystemCapabilityDidChange;
2735
2736 DLOG("MESG cap %x->%x did change\n",
2737 params.fromCapabilities, params.toCapabilities);
2738 messageClient(kIOMessageSystemCapabilityChange, systemCapabilityNotifier,
2739 &params, sizeof(params));
2740 }
22ba694c
A
2741}
2742
b0d623f7 2743//******************************************************************************
6d2010ae 2744// tellNoChangeDown
0c530ab8 2745//
6d2010ae
A
2746// Notify registered applications and kernel clients that we are not dropping
2747// power.
2748//
2749// We override the superclass implementation so we can send a different message
2750// type to the client or application being notified.
2751//
2752// This must be a vetoed idle sleep, since no other power change can be vetoed.
2753//******************************************************************************
4452a7af 2754
6d2010ae
A
2755void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum )
2756{
2757 DLOG("tellNoChangeDown %u->%u\n",
2758 (uint32_t) getPowerState(), (uint32_t) stateNum);
0c530ab8 2759
fe8ab488 2760 // Sleep canceled, clear the sleep trace point.
316670eb
A
2761 tracePoint(kIOPMTracePointSystemUp);
2762
22ba694c 2763 systemDidNotSleep();
6d2010ae 2764 return tellClients( kIOMessageSystemWillNotSleep );
0c530ab8
A
2765}
2766
b0d623f7 2767//******************************************************************************
6d2010ae 2768// tellChangeUp
1c79356b 2769//
6d2010ae
A
2770// Notify registered applications and kernel clients that we are raising power.
2771//
2772// We override the superclass implementation so we can send a different message
2773// type to the client or application being notified.
b0d623f7
A
2774//******************************************************************************
2775
6d2010ae 2776void IOPMrootDomain::tellChangeUp( unsigned long stateNum )
0c530ab8 2777{
6d2010ae
A
2778 DLOG("tellChangeUp %u->%u\n",
2779 (uint32_t) getPowerState(), (uint32_t) stateNum);
2780
2781 ignoreTellChangeDown = false;
2782
2783 if ( stateNum == ON_STATE )
2784 {
2785 // Direct callout into OSKext so it can disable kext unloads
2786 // during sleep/wake to prevent deadlocks.
2787 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn );
2788
2789 // Notify platform that sleep was cancelled or resumed.
2790 getPlatform()->callPlatformFunction(
2791 sleepMessagePEFunction, false,
2792 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn,
2793 NULL, NULL, NULL);
2794
2795 if (getPowerState() == ON_STATE)
2796 {
2797 // this is a quick wake from aborted sleep
22ba694c 2798 systemDidNotSleep();
6d2010ae
A
2799 tellClients( kIOMessageSystemWillPowerOn );
2800 }
2801
22ba694c 2802 tracePoint( kIOPMTracePointWakeApplications );
6d2010ae
A
2803 tellClients( kIOMessageSystemHasPoweredOn );
2804 }
2805}
b0d623f7
A
2806
2807//******************************************************************************
6d2010ae 2808// sysPowerDownHandler
0c530ab8 2809//
6d2010ae 2810// Perform a vfs sync before system sleep.
b0d623f7
A
2811//******************************************************************************
2812
6d2010ae
A
2813IOReturn IOPMrootDomain::sysPowerDownHandler(
2814 void * target, void * refCon,
2815 UInt32 messageType, IOService * service,
2816 void * messageArgs, vm_size_t argSize )
1c79356b 2817{
39236c6e 2818 IOReturn ret = 0;
0c530ab8 2819
6d2010ae
A
2820 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType));
2821
2822 if (!gRootDomain)
2823 return kIOReturnUnsupported;
2824
fe8ab488
A
2825 if (messageType == kIOMessageSystemWillSleep)
2826 {
2827#if HIBERNATION
3e170ce0 2828 static int32_t mem_only = -1;
fe8ab488
A
2829 IOPowerStateChangeNotification *notify =
2830 (IOPowerStateChangeNotification *)messageArgs;
2831
3e170ce0
A
2832 if ((mem_only == -1) &&
2833 (PE_parse_boot_argn("swd_mem_only", &mem_only, sizeof(mem_only)) == false)) {
2834 mem_only = 0;
2835 }
fe8ab488
A
2836 if ((mem_only != 1) && (gRootDomain->sleepWakeDebugIsWdogEnabled()))
2837 {
2838 notify->returnValue = 30 * 1000 * 1000;
2839 thread_call_enter1(
2840 gRootDomain->hibDebugSetupEntry,
2841 (thread_call_param_t)(uintptr_t) notify->powerRef);
2842 }
2843#endif
2844 }
2845 else if (messageType == kIOMessageSystemCapabilityChange)
55e303ae 2846 {
6d2010ae
A
2847 IOPMSystemCapabilityChangeParameters * params =
2848 (IOPMSystemCapabilityChangeParameters *) messageArgs;
2849
2850 // Interested applications have been notified of an impending power
2851 // change and have acked (when applicable).
2852 // This is our chance to save whatever state we can before powering
2853 // down.
2854 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
2855 // via callout
2856
2857 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
2858 params->fromCapabilities, params->toCapabilities,
2859 params->changeFlags);
2860
2861 if ((params->changeFlags & kIOPMSystemCapabilityWillChange) &&
2862 (params->fromCapabilities & kIOPMSystemCapabilityCPU) &&
2863 (params->toCapabilities & kIOPMSystemCapabilityCPU) == 0)
2864 {
2865 // We will ack within 20 seconds
2866 params->maxWaitForReply = 20 * 1000 * 1000;
fe8ab488 2867#if HIBERNATION
6d2010ae 2868 gRootDomain->evaluateSystemSleepPolicyEarly();
0c530ab8 2869
6d2010ae
A
2870 // add in time we could spend freeing pages
2871 if (gRootDomain->hibernateMode && !gRootDomain->hibernateDisabled)
2872 {
2873 params->maxWaitForReply = kCapabilityClientMaxWait;
2874 }
39236c6e
A
2875 DLOG("sysPowerDownHandler max wait %d s\n",
2876 (int) (params->maxWaitForReply / 1000 / 1000));
6d2010ae
A
2877#endif
2878
bd504ef0
A
2879 // Notify platform that sleep has begun, after the early
2880 // sleep policy evaluation.
2881 getPlatform()->callPlatformFunction(
2882 sleepMessagePEFunction, false,
2883 (void *)(uintptr_t) kIOMessageSystemWillSleep,
2884 NULL, NULL, NULL);
2885
6d2010ae
A
2886 if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending ) )
2887 {
2888 // Purposely delay the ack and hope that shutdown occurs quickly.
2889 // Another option is not to schedule the thread and wait for
2890 // ack timeout...
2891 AbsoluteTime deadline;
2892 clock_interval_to_deadline( 30, kSecondScale, &deadline );
2893 thread_call_enter1_delayed(
fe8ab488 2894 gRootDomain->diskSyncCalloutEntry,
39236c6e 2895 (thread_call_param_t)(uintptr_t) params->notifyRef,
6d2010ae
A
2896 deadline );
2897 }
2898 else
2899 thread_call_enter1(
2900 gRootDomain->diskSyncCalloutEntry,
39236c6e 2901 (thread_call_param_t)(uintptr_t) params->notifyRef);
6d2010ae 2902 }
6d2010ae
A
2903 else
2904 if ((params->changeFlags & kIOPMSystemCapabilityDidChange) &&
2905 (params->toCapabilities & kIOPMSystemCapabilityCPU) &&
2906 (params->fromCapabilities & kIOPMSystemCapabilityCPU) == 0)
2907 {
fe8ab488 2908#if HIBERNATION
6d2010ae
A
2909 // We will ack within 110 seconds
2910 params->maxWaitForReply = 110 * 1000 * 1000;
0c530ab8 2911
6d2010ae
A
2912 thread_call_enter1(
2913 gRootDomain->diskSyncCalloutEntry,
39236c6e 2914 (thread_call_param_t)(uintptr_t) params->notifyRef);
6d2010ae 2915#endif
39236c6e 2916 }
6d2010ae 2917 ret = kIOReturnSuccess;
0c530ab8
A
2918 }
2919
6d2010ae
A
2920 return ret;
2921}
2922
2923//******************************************************************************
2924// handleQueueSleepWakeUUID
2925//
2926// Called from IOPMrootDomain when we're initiating a sleep,
2927// or indirectly from PM configd when PM decides to clear the UUID.
2928// PM clears the UUID several minutes after successful wake from sleep,
2929// so that we might associate App spindumps with the immediately previous
2930// sleep/wake.
2931//
2932// @param obj has a retain on it. We're responsible for releasing that retain.
2933//******************************************************************************
2934
2935void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject *obj)
fe8ab488 2936{
6d2010ae
A
2937 OSString *str = NULL;
2938
fe8ab488 2939 if (kOSBooleanFalse == obj)
55e303ae 2940 {
6d2010ae
A
2941 handlePublishSleepWakeUUID(NULL);
2942 }
fe8ab488 2943 else if ((str = OSDynamicCast(OSString, obj)))
6d2010ae 2944 {
fe8ab488 2945 // This branch caches the UUID for an upcoming sleep/wake
6d2010ae
A
2946 if (queuedSleepWakeUUIDString) {
2947 queuedSleepWakeUUIDString->release();
2948 queuedSleepWakeUUIDString = NULL;
0c530ab8 2949 }
6d2010ae
A
2950 queuedSleepWakeUUIDString = str;
2951 queuedSleepWakeUUIDString->retain();
0c530ab8 2952
6d2010ae 2953 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString->getCStringNoCopy());
d52fe63f 2954 }
0c530ab8 2955
6d2010ae
A
2956 if (obj) {
2957 obj->release();
2958 }
2959 return;
2960
2961}
2962//******************************************************************************
2963// handlePublishSleepWakeUUID
2964//
2965// Called from IOPMrootDomain when we're initiating a sleep,
2966// or indirectly from PM configd when PM decides to clear the UUID.
2967// PM clears the UUID several minutes after successful wake from sleep,
2968// so that we might associate App spindumps with the immediately previous
2969// sleep/wake.
2970//******************************************************************************
2971
2972void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish )
2973{
2974 ASSERT_GATED();
2975
fe8ab488 2976 /*
6d2010ae
A
2977 * Clear the current UUID
2978 */
2979 if (gSleepWakeUUIDIsSet)
2980 {
2981 DLOG("SleepWake UUID cleared\n");
2982
6d2010ae
A
2983 gSleepWakeUUIDIsSet = false;
2984
2985 removeProperty(kIOPMSleepWakeUUIDKey);
2986 messageClients(kIOPMMessageSleepWakeUUIDChange, kIOPMMessageSleepWakeUUIDCleared);
2987 }
2988
2989 /*
2990 * Optionally, publish a new UUID
2991 */
2992 if (queuedSleepWakeUUIDString && shouldPublish) {
2993
2994 OSString *publishThisUUID = NULL;
2995
2996 publishThisUUID = queuedSleepWakeUUIDString;
2997 publishThisUUID->retain();
2998
6d2010ae
A
2999 if (publishThisUUID)
3000 {
3001 setProperty(kIOPMSleepWakeUUIDKey, publishThisUUID);
3002 publishThisUUID->release();
3003 }
fe8ab488 3004
6d2010ae
A
3005 gSleepWakeUUIDIsSet = true;
3006 messageClients(kIOPMMessageSleepWakeUUIDChange, kIOPMMessageSleepWakeUUIDSet);
3007
3008 queuedSleepWakeUUIDString->release();
3009 queuedSleepWakeUUIDString = NULL;
3010 }
3011}
3012
39236c6e
A
3013//******************************************************************************
3014// initializeBootSessionUUID
3015//
3016// Initialize the boot session uuid at boot up and sets it into registry.
3017//******************************************************************************
3018
3019void IOPMrootDomain::initializeBootSessionUUID(void)
3020{
3021 uuid_t new_uuid;
3022 uuid_string_t new_uuid_string;
3023
3024 uuid_generate(new_uuid);
3025 uuid_unparse_upper(new_uuid, new_uuid_string);
3026 memcpy(bootsessionuuid_string, new_uuid_string, sizeof(uuid_string_t));
3027
3028 setProperty(kIOPMBootSessionUUIDKey, new_uuid_string);
3029}
3030
6d2010ae
A
3031//******************************************************************************
3032// changePowerStateTo & changePowerStateToPriv
3033//
3034// Override of these methods for logging purposes.
3035//******************************************************************************
3036
3037IOReturn IOPMrootDomain::changePowerStateTo( unsigned long ordinal )
3038{
316670eb
A
3039 DLOG("changePowerStateTo(%lu)\n", ordinal);
3040
3041 if ((ordinal != ON_STATE) && (ordinal != SLEEP_STATE))
3042 return kIOReturnUnsupported;
3043
3044 return super::changePowerStateTo(ordinal);
6d2010ae
A
3045}
3046
3047IOReturn IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal )
3048{
3049 DLOG("changePowerStateToPriv(%lu)\n", ordinal);
3050
3051 if ((ordinal != ON_STATE) && (ordinal != SLEEP_STATE))
3052 return kIOReturnUnsupported;
0c530ab8 3053
6d2010ae
A
3054 return super::changePowerStateToPriv(ordinal);
3055}
3056
3057//******************************************************************************
3058// activity detect
3059//
3060//******************************************************************************
3061
3062bool IOPMrootDomain::activitySinceSleep(void)
3063{
3064 return (userActivityCount != userActivityAtSleep);
3065}
3066
3067bool IOPMrootDomain::abortHibernation(void)
3068{
3069 bool ret = activitySinceSleep();
0c530ab8 3070
13f56ec4 3071 if (ret && !hibernateAborted && checkSystemCanSustainFullWake())
55e303ae 3072 {
6d2010ae
A
3073 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount, userActivityAtSleep);
3074 hibernateAborted = true;
d52fe63f 3075 }
6d2010ae 3076 return (ret);
0c530ab8
A
3077}
3078
6d2010ae
A
3079extern "C" int
3080hibernate_should_abort(void)
3081{
3082 if (gRootDomain)
3083 return (gRootDomain->abortHibernation());
3084 else
3085 return (0);
3086}
2d21ac55 3087
39236c6e
A
3088//******************************************************************************
3089// willNotifyPowerChildren
3090//
3091// Called after all interested drivers have all acknowledged the power change,
3092// but before any power children is informed. Dispatched though a thread call,
3093// so it is safe to perform work that might block on a sleeping disk. PM state
3094// machine (not thread) will block w/o timeout until this function returns.
3095//******************************************************************************
3096
3097void IOPMrootDomain::willNotifyPowerChildren( IOPMPowerStateIndex newPowerState )
3098{
3e170ce0
A
3099 OSDictionary *dict;
3100 OSNumber *secs;
3101
39236c6e
A
3102 if (SLEEP_STATE == newPowerState)
3103 {
4bd07ac2
A
3104 if (!tasksSuspended)
3105 {
3106 AbsoluteTime deadline;
3107 tasksSuspended = TRUE;
3108 tasks_system_suspend(tasksSuspended);
3109
3110 clock_interval_to_deadline(10, kSecondScale, &deadline);
3111 vm_pageout_wait(AbsoluteTime_to_scalar(&deadline));
3112 }
3113
3e170ce0 3114#if HIBERNATION
fe8ab488
A
3115 IOHibernateSystemSleep();
3116 IOHibernateIOKitSleep();
39236c6e 3117#endif
3e170ce0
A
3118 if (gRootDomain->activitySinceSleep()) {
3119 dict = OSDictionary::withCapacity(1);
3120 secs = OSNumber::withNumber(1, 32);
3121
3122 if (dict && secs) {
3123 dict->setObject(gIOPMSettingDebugWakeRelativeKey, secs);
3124 gRootDomain->setProperties(dict);
3125 MSG("Reverting sleep with relative wake\n");
3126 }
3127 if (dict) dict->release();
3128 if (secs) secs->release();
3129 }
3130
3131 }
39236c6e
A
3132}
3133
0c530ab8
A
3134//******************************************************************************
3135// sleepOnClamshellClosed
3136//
3137// contains the logic to determine if the system should sleep when the clamshell
3138// is closed.
3139//******************************************************************************
3140
b0d623f7 3141bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
0c530ab8 3142{
6d2010ae
A
3143 if (!clamshellExists)
3144 return false;
3145
db609669
A
3146 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d sleepDisabled %d\n",
3147 clamshellClosed, clamshellDisabled, desktopMode, acAdaptorConnected, clamshellSleepDisabled);
b0d623f7 3148
db609669 3149 return ( !clamshellDisabled && !(desktopMode && acAdaptorConnected) && !clamshellSleepDisabled );
0c530ab8
A
3150}
3151
b0d623f7 3152void IOPMrootDomain::sendClientClamshellNotification( void )
0c530ab8
A
3153{
3154 /* Only broadcast clamshell alert if clamshell exists. */
b0d623f7 3155 if (!clamshellExists)
0c530ab8 3156 return;
b0d623f7 3157
fe8ab488 3158 setProperty(kAppleClamshellStateKey,
6d2010ae 3159 clamshellClosed ? kOSBooleanTrue : kOSBooleanFalse);
0c530ab8 3160
fe8ab488 3161 setProperty(kAppleClamshellCausesSleepKey,
b0d623f7 3162 shouldSleepOnClamshellClosed() ? kOSBooleanTrue : kOSBooleanFalse);
0c530ab8 3163
fe8ab488 3164 /* Argument to message is a bitfiel of
0c530ab8 3165 * ( kClamshellStateBit | kClamshellSleepBit )
0c530ab8 3166 */
2d21ac55 3167 messageClients(kIOPMMessageClamshellStateChange,
39236c6e 3168 (void *)(uintptr_t) ( (clamshellClosed ? kClamshellStateBit : 0)
2d21ac55 3169 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit : 0)) );
0c530ab8
A
3170}
3171
2d21ac55 3172//******************************************************************************
6d2010ae 3173// getSleepSupported
2d21ac55 3174//
6d2010ae 3175// Deprecated
2d21ac55
A
3176//******************************************************************************
3177
6d2010ae 3178IOOptionBits IOPMrootDomain::getSleepSupported( void )
2d21ac55 3179{
6d2010ae
A
3180 return( platformSleepSupport );
3181}
2d21ac55 3182
6d2010ae
A
3183//******************************************************************************
3184// setSleepSupported
3185//
3186// Deprecated
3187//******************************************************************************
3188
3189void IOPMrootDomain::setSleepSupported( IOOptionBits flags )
3190{
3191 DLOG("setSleepSupported(%x)\n", (uint32_t) flags);
3192 OSBitOrAtomic(flags, &platformSleepSupport);
3193}
3194
db609669
A
3195//******************************************************************************
3196// setDisableClamShellSleep
3197//
3198//******************************************************************************
3199
3200void IOPMrootDomain::setDisableClamShellSleep( bool val )
3201{
3202 if (gIOPMWorkLoop->inGate() == false) {
3203
3204 gIOPMWorkLoop->runAction(
3205 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::setDisableClamShellSleep),
3206 (OSObject *)this,
3207 (void *)val);
3208
3209 return;
3210 }
3211 else {
3212 DLOG("setDisableClamShellSleep(%x)\n", (uint32_t) val);
3213 if ( clamshellSleepDisabled != val )
3214 {
3215 clamshellSleepDisabled = val;
3216 // If clamshellSleepDisabled is reset to 0, reevaluate if
3217 // system need to go to sleep due to clamshell state
3218 if ( !clamshellSleepDisabled && clamshellClosed)
3219 handlePowerNotification(kLocalEvalClamshellCommand);
3220 }
3221 }
3222}
3223
6d2010ae
A
3224//******************************************************************************
3225// wakeFromDoze
3226//
3227// Deprecated.
3228//******************************************************************************
3229
3230void IOPMrootDomain::wakeFromDoze( void )
3231{
3232 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
3233}
3234
3235// MARK: -
3236// MARK: Features
3237
3238//******************************************************************************
3239// publishFeature
3240//
3241// Adds a new feature to the supported features dictionary
3242//******************************************************************************
3243
3244void IOPMrootDomain::publishFeature( const char * feature )
3245{
3246 publishFeature(feature, kRD_AllPowerSources, NULL);
3247}
3248
3249//******************************************************************************
3250// publishFeature (with supported power source specified)
3251//
3252// Adds a new feature to the supported features dictionary
3253//******************************************************************************
3254
3255void IOPMrootDomain::publishFeature(
fe8ab488 3256 const char *feature,
6d2010ae
A
3257 uint32_t supportedWhere,
3258 uint32_t *uniqueFeatureID)
3259{
3260 static uint16_t next_feature_id = 500;
3261
3262 OSNumber *new_feature_data = NULL;
3263 OSNumber *existing_feature = NULL;
3264 OSArray *existing_feature_arr = NULL;
3265 OSObject *osObj = NULL;
3266 uint32_t feature_value = 0;
3267
3268 supportedWhere &= kRD_AllPowerSources; // mask off any craziness!
3269
3270 if(!supportedWhere) {
3271 // Feature isn't supported anywhere!
3272 return;
3273 }
fe8ab488 3274
6d2010ae
A
3275 if(next_feature_id > 5000) {
3276 // Far, far too many features!
3277 return;
3278 }
3279
3280 if(featuresDictLock) IOLockLock(featuresDictLock);
3281
3282 OSDictionary *features =
3283 (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
fe8ab488 3284
6d2010ae
A
3285 // Create new features dict if necessary
3286 if ( features && OSDynamicCast(OSDictionary, features)) {
3287 features = OSDictionary::withDictionary(features);
3288 } else {
3289 features = OSDictionary::withCapacity(1);
3290 }
fe8ab488 3291
6d2010ae 3292 // Create OSNumber to track new feature
fe8ab488 3293
6d2010ae
A
3294 next_feature_id += 1;
3295 if( uniqueFeatureID ) {
3296 // We don't really mind if the calling kext didn't give us a place
3297 // to stash their unique id. Many kexts don't plan to unload, and thus
3298 // have no need to remove themselves later.
3299 *uniqueFeatureID = next_feature_id;
3300 }
3301
3302 feature_value = (uint32_t)next_feature_id;
3303 feature_value <<= 16;
3304 feature_value += supportedWhere;
3305
3306 new_feature_data = OSNumber::withNumber(
3307 (unsigned long long)feature_value, 32);
3308
3309 // Does features object already exist?
3310 if( (osObj = features->getObject(feature)) )
3311 {
3312 if(( existing_feature = OSDynamicCast(OSNumber, osObj) ))
3313 {
3314 // We need to create an OSArray to hold the now 2 elements.
3315 existing_feature_arr = OSArray::withObjects(
3316 (const OSObject **)&existing_feature, 1, 2);
3317 } else if(( existing_feature_arr = OSDynamicCast(OSArray, osObj) ))
3318 {
fe8ab488 3319 // Add object to existing array
6d2010ae
A
3320 existing_feature_arr = OSArray::withArray(
3321 existing_feature_arr,
3322 existing_feature_arr->getCount() + 1);
3323 }
3324
3325 if (existing_feature_arr)
3326 {
3327 existing_feature_arr->setObject(new_feature_data);
3328 features->setObject(feature, existing_feature_arr);
3329 existing_feature_arr->release();
3330 existing_feature_arr = 0;
3331 }
3332 } else {
3333 // The easy case: no previously existing features listed. We simply
3334 // set the OSNumber at key 'feature' and we're on our way.
7ddcb079 3335 features->setObject(feature, new_feature_data);
6d2010ae 3336 }
fe8ab488 3337
6d2010ae
A
3338 new_feature_data->release();
3339
3340 setProperty(kRootDomainSupportedFeatures, features);
3341
3342 features->release();
3343
fe8ab488 3344 if(featuresDictLock) IOLockUnlock(featuresDictLock);
6d2010ae
A
3345
3346 // Notify EnergySaver and all those in user space so they might
fe8ab488 3347 // re-populate their feature specific UI
6d2010ae
A
3348 if(pmPowerStateQueue) {
3349 pmPowerStateQueue->submitPowerEvent( kPowerEventFeatureChanged );
3350 }
3351}
3352
3353//******************************************************************************
3354// removePublishedFeature
3355//
3356// Removes previously published feature
3357//******************************************************************************
3358
3359IOReturn IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID )
3360{
3361 IOReturn ret = kIOReturnError;
3362 uint32_t feature_value = 0;
3363 uint16_t feature_id = 0;
3364 bool madeAChange = false;
fe8ab488 3365
6d2010ae
A
3366 OSSymbol *dictKey = NULL;
3367 OSCollectionIterator *dictIterator = NULL;
3368 OSArray *arrayMember = NULL;
3369 OSNumber *numberMember = NULL;
3370 OSObject *osObj = NULL;
3371 OSNumber *osNum = NULL;
3372 OSArray *arrayMemberCopy;
3373
7ddcb079
A
3374 if (kBadPMFeatureID == removeFeatureID)
3375 return kIOReturnNotFound;
3376
6d2010ae
A
3377 if(featuresDictLock) IOLockLock(featuresDictLock);
3378
3379 OSDictionary *features =
3380 (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
fe8ab488 3381
6d2010ae
A
3382 if ( features && OSDynamicCast(OSDictionary, features) )
3383 {
3384 // Any modifications to the dictionary are made to the copy to prevent
3385 // races & crashes with userland clients. Dictionary updated
3386 // automically later.
3387 features = OSDictionary::withDictionary(features);
3388 } else {
3389 features = NULL;
3390 ret = kIOReturnNotFound;
3391 goto exit;
3392 }
fe8ab488 3393
6d2010ae
A
3394 // We iterate 'features' dictionary looking for an entry tagged
3395 // with 'removeFeatureID'. If found, we remove it from our tracking
3396 // structures and notify the OS via a general interest message.
fe8ab488 3397
6d2010ae
A
3398 dictIterator = OSCollectionIterator::withCollection(features);
3399 if(!dictIterator) {
3400 goto exit;
3401 }
fe8ab488 3402
6d2010ae
A
3403 while( (dictKey = OSDynamicCast(OSSymbol, dictIterator->getNextObject())) )
3404 {
3405 osObj = features->getObject(dictKey);
fe8ab488 3406
6d2010ae
A
3407 // Each Feature is either tracked by an OSNumber
3408 if( osObj && (numberMember = OSDynamicCast(OSNumber, osObj)) )
3409 {
3410 feature_value = numberMember->unsigned32BitValue();
3411 feature_id = (uint16_t)(feature_value >> 16);
3412
3413 if( feature_id == (uint16_t)removeFeatureID )
3414 {
3415 // Remove this node
3416 features->removeObject(dictKey);
3417 madeAChange = true;
3418 break;
3419 }
fe8ab488 3420
6d2010ae
A
3421 // Or tracked by an OSArray of OSNumbers
3422 } else if( osObj && (arrayMember = OSDynamicCast(OSArray, osObj)) )
3423 {
3424 unsigned int arrayCount = arrayMember->getCount();
fe8ab488 3425
6d2010ae
A
3426 for(unsigned int i=0; i<arrayCount; i++)
3427 {
3428 osNum = OSDynamicCast(OSNumber, arrayMember->getObject(i));
3429 if(!osNum) {
3430 continue;
3431 }
fe8ab488 3432
6d2010ae
A
3433 feature_value = osNum->unsigned32BitValue();
3434 feature_id = (uint16_t)(feature_value >> 16);
3435
3436 if( feature_id == (uint16_t)removeFeatureID )
3437 {
3438 // Remove this node
3439 if( 1 == arrayCount ) {
3440 // If the array only contains one element, remove
3441 // the whole thing.
3442 features->removeObject(dictKey);
3443 } else {
3444 // Otherwise remove the element from a copy of the array.
3445 arrayMemberCopy = OSArray::withArray(arrayMember);
3446 if (arrayMemberCopy)
3447 {
3448 arrayMemberCopy->removeObject(i);
3449 features->setObject(dictKey, arrayMemberCopy);
3450 arrayMemberCopy->release();
3451 }
3452 }
3453
3454 madeAChange = true;
3455 break;
3456 }
3457 }
fe8ab488 3458 }
6d2010ae 3459 }
fe8ab488 3460
6d2010ae 3461 dictIterator->release();
fe8ab488 3462
6d2010ae
A
3463 if( madeAChange )
3464 {
fe8ab488 3465 ret = kIOReturnSuccess;
6d2010ae
A
3466
3467 setProperty(kRootDomainSupportedFeatures, features);
fe8ab488 3468
6d2010ae 3469 // Notify EnergySaver and all those in user space so they might
fe8ab488 3470 // re-populate their feature specific UI
6d2010ae
A
3471 if(pmPowerStateQueue) {
3472 pmPowerStateQueue->submitPowerEvent( kPowerEventFeatureChanged );
3473 }
3474 } else {
3475 ret = kIOReturnNotFound;
3476 }
fe8ab488 3477
6d2010ae
A
3478exit:
3479 if(features) features->release();
fe8ab488 3480 if(featuresDictLock) IOLockUnlock(featuresDictLock);
6d2010ae
A
3481 return ret;
3482}
3483
7ddcb079
A
3484//******************************************************************************
3485// publishPMSetting (private)
3486//
3487// Should only be called by PMSettingObject to publish a PM Setting as a
3488// supported feature.
3489//******************************************************************************
3490
3491void IOPMrootDomain::publishPMSetting(
3492 const OSSymbol * feature, uint32_t where, uint32_t * featureID )
3493{
3494 if (noPublishPMSettings &&
3495 (noPublishPMSettings->getNextIndexOfObject(feature, 0) != (unsigned int)-1))
3496 {
3497 // Setting found in noPublishPMSettings array
3498 *featureID = kBadPMFeatureID;
3499 return;
3500 }
3501
3502 publishFeature(
3503 feature->getCStringNoCopy(), where, featureID);
3504}
3505
6d2010ae
A
3506//******************************************************************************
3507// setPMSetting (private)
3508//
3509// Internal helper to relay PM settings changes from user space to individual
3510// drivers. Should be called only by IOPMrootDomain::setProperties.
3511//******************************************************************************
3512
3513IOReturn IOPMrootDomain::setPMSetting(
3514 const OSSymbol *type,
3515 OSObject *object )
3516{
3517 PMSettingCallEntry *entries = 0;
3518 OSArray *chosen = 0;
3519 const OSArray *array;
3520 PMSettingObject *pmso;
3521 thread_t thisThread;
3522 int i, j, count, capacity;
3523
3524 if (NULL == type)
3525 return kIOReturnBadArgument;
3526
3527 PMSETTING_LOCK();
3528
fe8ab488 3529 // Update settings dict so changes are visible from copyPMSetting().
6d2010ae
A
3530 fPMSettingsDict->setObject(type, object);
3531
3532 // Prep all PMSetting objects with the given 'type' for callout.
3533 array = (const OSArray *) settingsCallbacks->getObject(type);
3534 if (!array || ((capacity = array->getCount()) == 0))
3535 goto unlock_exit;
3536
3537 // Array to retain PMSetting objects targeted for callout.
3538 chosen = OSArray::withCapacity(capacity);
3539 if (!chosen)
3540 goto unlock_exit; // error
3541
3542 entries = IONew(PMSettingCallEntry, capacity);
3543 if (!entries)
3544 goto unlock_exit; // error
3545 memset(entries, 0, sizeof(PMSettingCallEntry) * capacity);
3546
3547 thisThread = current_thread();
3548
3549 for (i = 0, j = 0; i<capacity; i++)
3550 {
3551 pmso = (PMSettingObject *) array->getObject(i);
3552 if (pmso->disabled)
3553 continue;
fe8ab488 3554 entries[j].thread = thisThread;
6d2010ae
A
3555 queue_enter(&pmso->calloutQueue, &entries[j], PMSettingCallEntry *, link);
3556 chosen->setObject(pmso);
3557 j++;
3558 }
3559 count = j;
3560 if (!count)
fe8ab488 3561 goto unlock_exit;
6d2010ae
A
3562
3563 PMSETTING_UNLOCK();
3564
3565 // Call each pmso in the chosen array.
3566 for (i=0; i<count; i++)
3567 {
3568 pmso = (PMSettingObject *) chosen->getObject(i);
3569 pmso->dispatchPMSetting(type, object);
3570 }
3571
3572 PMSETTING_LOCK();
3573 for (i=0; i<count; i++)
3574 {
3575 pmso = (PMSettingObject *) chosen->getObject(i);
3576 queue_remove(&pmso->calloutQueue, &entries[i], PMSettingCallEntry *, link);
3577 if (pmso->waitThread)
3578 {
3579 PMSETTING_WAKEUP(pmso);
3580 }
3581 }
3582unlock_exit:
3583 PMSETTING_UNLOCK();
3584
3585 if (chosen) chosen->release();
3586 if (entries) IODelete(entries, PMSettingCallEntry, capacity);
3587
3588 return kIOReturnSuccess;
3589}
3590
3591//******************************************************************************
3592// copyPMSetting (public)
3593//
3594// Allows kexts to safely read setting values, without being subscribed to
3595// notifications.
3596//******************************************************************************
3597
3598OSObject * IOPMrootDomain::copyPMSetting(
3599 OSSymbol *whichSetting)
3600{
3601 OSObject *obj = NULL;
3602
3603 if(!whichSetting) return NULL;
3604
3605 PMSETTING_LOCK();
3606 obj = fPMSettingsDict->getObject(whichSetting);
3607 if(obj) {
3608 obj->retain();
3609 }
3610 PMSETTING_UNLOCK();
fe8ab488 3611
6d2010ae
A
3612 return obj;
3613}
3614
3615//******************************************************************************
3616// registerPMSettingController (public)
3617//
3618// direct wrapper to registerPMSettingController with uint32_t power source arg
3619//******************************************************************************
3620
3621IOReturn IOPMrootDomain::registerPMSettingController(
3622 const OSSymbol * settings[],
3623 IOPMSettingControllerCallback func,
3624 OSObject *target,
3625 uintptr_t refcon,
3626 OSObject **handle)
3627{
fe8ab488 3628 return registerPMSettingController(
6d2010ae
A
3629 settings,
3630 (kIOPMSupportedOnAC | kIOPMSupportedOnBatt | kIOPMSupportedOnUPS),
3631 func, target, refcon, handle);
3632}
3633
3634//******************************************************************************
3635// registerPMSettingController (public)
3636//
3637// Kexts may register for notifications when a particular setting is changed.
3638// A list of settings is available in IOPM.h.
3639// Arguments:
3640// * settings - An OSArray containing OSSymbols. Caller should populate this
3641// array with a list of settings caller wants notifications from.
3642// * func - A C function callback of the type IOPMSettingControllerCallback
fe8ab488 3643// * target - caller may provide an OSObject *, which PM will pass as an
6d2010ae 3644// target to calls to "func"
fe8ab488 3645// * refcon - caller may provide an void *, which PM will pass as an
6d2010ae
A
3646// argument to calls to "func"
3647// * handle - This is a return argument. We will populate this pointer upon
3648// call success. Hold onto this and pass this argument to
3649// IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3650// Returns:
3651// kIOReturnSuccess on success
3652//******************************************************************************
3653
3654IOReturn IOPMrootDomain::registerPMSettingController(
3655 const OSSymbol * settings[],
3656 uint32_t supportedPowerSources,
3657 IOPMSettingControllerCallback func,
3658 OSObject *target,
3659 uintptr_t refcon,
3660 OSObject **handle)
3661{
3662 PMSettingObject *pmso = NULL;
3663 OSObject *pmsh = NULL;
3664 OSArray *list = NULL;
3665 int i;
3666
3667 if (NULL == settings ||
3668 NULL == func ||
3669 NULL == handle)
3670 {
3671 return kIOReturnBadArgument;
3672 }
3673
3674 pmso = PMSettingObject::pmSettingObject(
fe8ab488 3675 (IOPMrootDomain *) this, func, target,
6d2010ae
A
3676 refcon, supportedPowerSources, settings, &pmsh);
3677
3678 if (!pmso) {
3679 *handle = NULL;
3680 return kIOReturnInternalError;
3681 }
3682
3683 PMSETTING_LOCK();
3684 for (i=0; settings[i]; i++)
3685 {
3686 list = (OSArray *) settingsCallbacks->getObject(settings[i]);
3687 if (!list) {
3688 // New array of callbacks for this setting
3689 list = OSArray::withCapacity(1);
3690 settingsCallbacks->setObject(settings[i], list);
3691 list->release();
3692 }
3693
3694 // Add caller to the callback list
3695 list->setObject(pmso);
3696 }
3697 PMSETTING_UNLOCK();
3698
3699 // Return handle to the caller, the setting object is private.
3700 *handle = pmsh;
3701
3702 return kIOReturnSuccess;
3703}
3704
3705//******************************************************************************
3706// deregisterPMSettingObject (private)
3707//
3708// Only called from PMSettingObject.
3709//******************************************************************************
3710
3711void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject * pmso )
3712{
3713 thread_t thisThread = current_thread();
3714 PMSettingCallEntry *callEntry;
3715 OSCollectionIterator *iter;
3716 OSSymbol *sym;
3717 OSArray *array;
3718 int index;
3719 bool wait;
3720
3721 PMSETTING_LOCK();
3722
3723 pmso->disabled = true;
3724
3725 // Wait for all callout threads to finish.
3726 do {
3727 wait = false;
3728 queue_iterate(&pmso->calloutQueue, callEntry, PMSettingCallEntry *, link)
3729 {
3730 if (callEntry->thread != thisThread)
3731 {
3732 wait = true;
3733 break;
3734 }
3735 }
3736 if (wait)
3737 {
3738 assert(0 == pmso->waitThread);
3739 pmso->waitThread = thisThread;
3740 PMSETTING_WAIT(pmso);
3741 pmso->waitThread = 0;
3742 }
3743 } while (wait);
3744
3745 // Search each PM settings array in the kernel.
3746 iter = OSCollectionIterator::withCollection(settingsCallbacks);
fe8ab488 3747 if (iter)
6d2010ae
A
3748 {
3749 while ((sym = OSDynamicCast(OSSymbol, iter->getNextObject())))
3750 {
3751 array = (OSArray *) settingsCallbacks->getObject(sym);
3752 index = array->getNextIndexOfObject(pmso, 0);
3753 if (-1 != index) {
3754 array->removeObject(index);
3755 }
3756 }
3757 iter->release();
3758 }
3759
3760 PMSETTING_UNLOCK();
3761
3762 pmso->release();
3763}
3764
3765//******************************************************************************
3766// informCPUStateChange
3767//
3768// Call into PM CPU code so that CPU power savings may dynamically adjust for
3769// running on battery, with the lid closed, etc.
3770//
3771// informCPUStateChange is a no-op on non x86 systems
3772// only x86 has explicit support in the IntelCPUPowerManagement kext
3773//******************************************************************************
3774
3775void IOPMrootDomain::informCPUStateChange(
fe8ab488 3776 uint32_t type,
6d2010ae
A
3777 uint32_t value )
3778{
3779#if defined(__i386__) || defined(__x86_64__)
3780
fe8ab488 3781 pmioctlVariableInfo_t varInfoStruct;
2d21ac55
A
3782 int pmCPUret = 0;
3783 const char *varNameStr = NULL;
3784 int32_t *varIndex = NULL;
3785
3786 if (kInformAC == type) {
3787 varNameStr = kIOPMRootDomainBatPowerCString;
3788 varIndex = &idxPMCPULimitedPower;
3789 } else if (kInformLid == type) {
3790 varNameStr = kIOPMRootDomainLidCloseCString;
3791 varIndex = &idxPMCPUClamshell;
3792 } else {
3793 return;
3794 }
fe8ab488 3795
2d21ac55
A
3796 // Set the new value!
3797 // pmCPUControl will assign us a new ID if one doesn't exist yet
3798 bzero(&varInfoStruct, sizeof(pmioctlVariableInfo_t));
3799 varInfoStruct.varID = *varIndex;
3800 varInfoStruct.varType = vBool;
3801 varInfoStruct.varInitValue = value;
3802 varInfoStruct.varCurValue = value;
3803 strncpy( (char *)varInfoStruct.varName,
3804 (const char *)varNameStr,
fe8ab488
A
3805 strlen(varNameStr) + 1 );
3806
2d21ac55
A
3807 // Set!
3808 pmCPUret = pmCPUControl( PMIOCSETVARINFO, (void *)&varInfoStruct );
3809
3810 // pmCPU only assigns numerical id's when a new varName is specified
3811 if ((0 == pmCPUret)
3812 && (*varIndex == kCPUUnknownIndex))
3813 {
fe8ab488 3814 // pmCPUControl has assigned us a new variable ID.
2d21ac55
A
3815 // Let's re-read the structure we just SET to learn that ID.
3816 pmCPUret = pmCPUControl( PMIOCGETVARNAMEINFO, (void *)&varInfoStruct );
3817
fe8ab488
A
3818 if (0 == pmCPUret)
3819 {
2d21ac55
A
3820 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
3821 *varIndex = varInfoStruct.varID;
3822 }
fe8ab488
A
3823 }
3824
2d21ac55 3825 return;
fe8ab488 3826
b0d623f7 3827#endif /* __i386__ || __x86_64__ */
2d21ac55
A
3828}
3829
6d2010ae
A
3830// MARK: -
3831// MARK: Deep Sleep Policy
b0d623f7 3832
0b4c1975
A
3833#if HIBERNATION
3834
3835//******************************************************************************
3836// evaluateSystemSleepPolicy
3837//******************************************************************************
3838
99c3a104
A
3839#define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
3840
3841// Sleep flags
3842enum {
3843 kIOPMSleepFlagHibernate = 0x00000001,
3844 kIOPMSleepFlagSleepTimerEnable = 0x00000002
3845};
3846
0b4c1975
A
3847struct IOPMSystemSleepPolicyEntry
3848{
3849 uint32_t factorMask;
3850 uint32_t factorBits;
3851 uint32_t sleepFlags;
3852 uint32_t wakeEvents;
99c3a104 3853} __attribute__((packed));
0b4c1975
A
3854
3855struct IOPMSystemSleepPolicyTable
3856{
99c3a104 3857 uint32_t signature;
0b4c1975
A
3858 uint16_t version;
3859 uint16_t entryCount;
3860 IOPMSystemSleepPolicyEntry entries[];
99c3a104 3861} __attribute__((packed));
316670eb 3862
bd504ef0
A
3863enum {
3864 kIOPMSleepAttributeHibernateSetup = 0x00000001,
3865 kIOPMSleepAttributeHibernateSleep = 0x00000002
3866};
3867
3868static uint32_t
3869getSleepTypeAttributes( uint32_t sleepType )
3870{
3871 static const uint32_t sleepTypeAttributes[ kIOPMSleepTypeLast ] =
3872 {
3873 /* invalid */ 0,
3874 /* abort */ 0,
3875 /* normal */ 0,
3876 /* safesleep */ kIOPMSleepAttributeHibernateSetup,
3877 /* hibernate */ kIOPMSleepAttributeHibernateSetup | kIOPMSleepAttributeHibernateSleep,
3878 /* standby */ kIOPMSleepAttributeHibernateSetup | kIOPMSleepAttributeHibernateSleep,
3879 /* poweroff */ kIOPMSleepAttributeHibernateSetup | kIOPMSleepAttributeHibernateSleep,
3880 /* deepidle */ 0
3881 };
3882
3883 if (sleepType >= kIOPMSleepTypeLast)
3884 return 0;
3885
3886 return sleepTypeAttributes[sleepType];
3887}
3888
99c3a104 3889bool IOPMrootDomain::evaluateSystemSleepPolicy(
db609669 3890 IOPMSystemSleepParameters * params, int sleepPhase, uint32_t * hibMode )
0b4c1975
A
3891{
3892 const IOPMSystemSleepPolicyTable * pt;
3893 OSObject * prop = 0;
3894 OSData * policyData;
99c3a104
A
3895 uint64_t currentFactors = 0;
3896 uint32_t standbyDelay = 0;
3897 uint32_t powerOffDelay = 0;
db609669 3898 uint32_t powerOffTimer = 0;
99c3a104
A
3899 uint32_t mismatch;
3900 bool standbyEnabled;
3901 bool powerOffEnabled;
3902 bool found = false;
3903
3904 // Get platform's sleep policy table
3905 if (!gSleepPolicyHandler)
3906 {
3907 prop = getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey);
3908 if (!prop) goto done;
3909 }
3910
3911 // Fetch additional settings
3912 standbyEnabled = (getSleepOption(kIOPMDeepSleepDelayKey, &standbyDelay)
3913 && (getProperty(kIOPMDeepSleepEnabledKey) == kOSBooleanTrue));
3914 powerOffEnabled = (getSleepOption(kIOPMAutoPowerOffDelayKey, &powerOffDelay)
3915 && (getProperty(kIOPMAutoPowerOffEnabledKey) == kOSBooleanTrue));
db609669
A
3916 if (!getSleepOption(kIOPMAutoPowerOffTimerKey, &powerOffTimer))
3917 powerOffTimer = powerOffDelay;
3918
3919 DLOG("phase %d, standby %d delay %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
3920 sleepPhase, standbyEnabled, standbyDelay,
3921 powerOffEnabled, powerOffDelay, powerOffTimer, *hibMode);
99c3a104
A
3922
3923 // pmset level overrides
db609669 3924 if ((*hibMode & kIOHibernateModeOn) == 0)
0b4c1975 3925 {
99c3a104
A
3926 if (!gSleepPolicyHandler)
3927 {
3928 standbyEnabled = false;
3929 powerOffEnabled = false;
3930 }
0b4c1975 3931 }
db609669 3932 else if (!(*hibMode & kIOHibernateModeSleep))
316670eb 3933 {
99c3a104
A
3934 // Force hibernate (i.e. mode 25)
3935 // If standby is enabled, force standy.
3936 // If poweroff is enabled, force poweroff.
3937 if (standbyEnabled)
3938 currentFactors |= kIOPMSleepFactorStandbyForced;
3939 else if (powerOffEnabled)
3940 currentFactors |= kIOPMSleepFactorAutoPowerOffForced;
3941 else
3942 currentFactors |= kIOPMSleepFactorHibernateForced;
316670eb
A
3943 }
3944
99c3a104
A
3945 // Current factors based on environment and assertions
3946 if (sleepTimerMaintenance)
3947 currentFactors |= kIOPMSleepFactorSleepTimerWake;
15129b1c 3948 if (standbyEnabled && sleepToStandby && !gSleepPolicyHandler)
39236c6e 3949 currentFactors |= kIOPMSleepFactorSleepTimerWake;
99c3a104
A
3950 if (!clamshellClosed)
3951 currentFactors |= kIOPMSleepFactorLidOpen;
3952 if (acAdaptorConnected)
3953 currentFactors |= kIOPMSleepFactorACPower;
3954 if (lowBatteryCondition)
3955 currentFactors |= kIOPMSleepFactorBatteryLow;
3956 if (!standbyDelay)
3957 currentFactors |= kIOPMSleepFactorStandbyNoDelay;
3958 if (!standbyEnabled)
3959 currentFactors |= kIOPMSleepFactorStandbyDisabled;
0b4c1975
A
3960 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit) !=
3961 kIOPMDriverAssertionLevelOff)
3962 currentFactors |= kIOPMSleepFactorUSBExternalDevice;
3963 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit) !=
3964 kIOPMDriverAssertionLevelOff)
3965 currentFactors |= kIOPMSleepFactorBluetoothHIDDevice;
3966 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit) !=
3967 kIOPMDriverAssertionLevelOff)
3968 currentFactors |= kIOPMSleepFactorExternalMediaMounted;
99c3a104 3969 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5) !=
0b4c1975 3970 kIOPMDriverAssertionLevelOff)
99c3a104
A
3971 currentFactors |= kIOPMSleepFactorThunderboltDevice;
3972 if (_scheduledAlarms != 0)
3973 currentFactors |= kIOPMSleepFactorRTCAlarmScheduled;
3974 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit) !=
0b4c1975 3975 kIOPMDriverAssertionLevelOff)
99c3a104 3976 currentFactors |= kIOPMSleepFactorMagicPacketWakeEnabled;
fe8ab488 3977#define TCPKEEPALIVE 1
39236c6e
A
3978#if TCPKEEPALIVE
3979 if (getPMAssertionLevel(kIOPMDriverAssertionNetworkKeepAliveActiveBit) !=
3980 kIOPMDriverAssertionLevelOff)
3981 currentFactors |= kIOPMSleepFactorNetworkKeepAliveActive;
3982#endif
99c3a104
A
3983 if (!powerOffEnabled)
3984 currentFactors |= kIOPMSleepFactorAutoPowerOffDisabled;
3985 if (desktopMode)
3986 currentFactors |= kIOPMSleepFactorExternalDisplay;
39236c6e
A
3987 if (userWasActive)
3988 currentFactors |= kIOPMSleepFactorLocalUserActivity;
fe8ab488
A
3989 if (darkWakeHibernateError && !CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
3990 currentFactors |= kIOPMSleepFactorHibernateFailed;
a1c7dba1
A
3991 if (thermalWarningState)
3992 currentFactors |= kIOPMSleepFactorThermalWarning;
7ddcb079 3993
99c3a104
A
3994 DLOG("sleep factors 0x%llx\n", currentFactors);
3995
99c3a104
A
3996 if (gSleepPolicyHandler)
3997 {
db609669
A
3998 uint32_t savedHibernateMode;
3999 IOReturn result;
4000
99c3a104
A
4001 if (!gSleepPolicyVars)
4002 {
4003 gSleepPolicyVars = IONew(IOPMSystemSleepPolicyVariables, 1);
4004 if (!gSleepPolicyVars)
4005 goto done;
4006 bzero(gSleepPolicyVars, sizeof(*gSleepPolicyVars));
4007 }
4008 gSleepPolicyVars->signature = kIOPMSystemSleepPolicySignature;
4009 gSleepPolicyVars->version = kIOPMSystemSleepPolicyVersion;
db609669
A
4010 gSleepPolicyVars->currentCapability = _currentCapability;
4011 gSleepPolicyVars->highestCapability = _highestCapability;
4012 gSleepPolicyVars->sleepFactors = currentFactors;
4013 gSleepPolicyVars->sleepReason = lastSleepReason;
4014 gSleepPolicyVars->sleepPhase = sleepPhase;
4015 gSleepPolicyVars->standbyDelay = standbyDelay;
4016 gSleepPolicyVars->poweroffDelay = powerOffDelay;
4017 gSleepPolicyVars->scheduledAlarms = _scheduledAlarms | _userScheduledAlarm;
4018 gSleepPolicyVars->poweroffTimer = powerOffTimer;
4019
4020 if (kIOPMSleepPhase0 == sleepPhase)
4021 {
4022 // preserve hibernateMode
4023 savedHibernateMode = gSleepPolicyVars->hibernateMode;
4024 gSleepPolicyVars->hibernateMode = *hibMode;
4025 }
4026 else if (kIOPMSleepPhase1 == sleepPhase)
4027 {
4028 // use original hibernateMode for phase2
4029 gSleepPolicyVars->hibernateMode = *hibMode;
4030 }
4031
4032 result = gSleepPolicyHandler(gSleepPolicyTarget, gSleepPolicyVars, params);
fe8ab488 4033
db609669
A
4034 if (kIOPMSleepPhase0 == sleepPhase)
4035 {
4036 // restore hibernateMode
4037 gSleepPolicyVars->hibernateMode = savedHibernateMode;
4038 }
fe8ab488 4039
db609669
A
4040 if ((result != kIOReturnSuccess) ||
4041 (kIOPMSleepTypeInvalid == params->sleepType) ||
99c3a104
A
4042 (params->sleepType >= kIOPMSleepTypeLast) ||
4043 (kIOPMSystemSleepParametersVersion != params->version))
4044 {
4045 MSG("sleep policy handler error\n");
4046 goto done;
4047 }
4048
bd504ef0
A
4049 if ((getSleepTypeAttributes(params->sleepType) &
4050 kIOPMSleepAttributeHibernateSetup) &&
db609669 4051 ((*hibMode & kIOHibernateModeOn) == 0))
99c3a104 4052 {
db609669 4053 *hibMode |= (kIOHibernateModeOn | kIOHibernateModeSleep);
99c3a104
A
4054 }
4055
4056 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
4057 params->version, params->sleepType, params->sleepFlags,
4058 params->ecWakeEvents, params->ecWakeTimer, params->ecPoweroffTimer);
4059 found = true;
4060 goto done;
4061 }
4062
4063 // Policy table is meaningless without standby enabled
4064 if (!standbyEnabled)
4065 goto done;
4066
4067 // Validate the sleep policy table
4068 policyData = OSDynamicCast(OSData, prop);
4069 if (!policyData || (policyData->getLength() <= sizeof(IOPMSystemSleepPolicyTable)))
4070 goto done;
4071
4072 pt = (const IOPMSystemSleepPolicyTable *) policyData->getBytesNoCopy();
4073 if ((pt->signature != kIOPMSystemSleepPolicySignature) ||
4074 (pt->version != 1) || (0 == pt->entryCount))
4075 goto done;
4076
4077 if (((policyData->getLength() - sizeof(IOPMSystemSleepPolicyTable)) !=
4078 (sizeof(IOPMSystemSleepPolicyEntry) * pt->entryCount)))
4079 goto done;
0b4c1975
A
4080
4081 for (uint32_t i = 0; i < pt->entryCount; i++)
4082 {
99c3a104
A
4083 const IOPMSystemSleepPolicyEntry * entry = &pt->entries[i];
4084 mismatch = (((uint32_t)currentFactors ^ entry->factorBits) & entry->factorMask);
4085
4086 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
4087 entry->factorMask, entry->factorBits,
4088 entry->sleepFlags, entry->wakeEvents, mismatch);
4089 if (mismatch)
4090 continue;
0b4c1975 4091
99c3a104
A
4092 DLOG("^ found match\n");
4093 found = true;
0b4c1975 4094
99c3a104
A
4095 params->version = kIOPMSystemSleepParametersVersion;
4096 params->reserved1 = 1;
4097 if (entry->sleepFlags & kIOPMSleepFlagHibernate)
4098 params->sleepType = kIOPMSleepTypeStandby;
4099 else
4100 params->sleepType = kIOPMSleepTypeNormalSleep;
0b4c1975 4101
99c3a104
A
4102 params->ecWakeEvents = entry->wakeEvents;
4103 if (entry->sleepFlags & kIOPMSleepFlagSleepTimerEnable)
316670eb 4104 {
99c3a104 4105 if (kIOPMSleepPhase2 == sleepPhase)
316670eb 4106 {
99c3a104
A
4107 clock_sec_t now_secs = gIOLastSleepTime.tv_sec;
4108
4109 if (!_standbyTimerResetSeconds ||
4110 (now_secs <= _standbyTimerResetSeconds))
4111 {
4112 // Reset standby timer adjustment
4113 _standbyTimerResetSeconds = now_secs;
4114 DLOG("standby delay %u, reset %u\n",
4115 standbyDelay, (uint32_t) _standbyTimerResetSeconds);
4116 }
4117 else if (standbyDelay)
316670eb 4118 {
99c3a104
A
4119 // Shorten the standby delay timer
4120 clock_sec_t elapsed = now_secs - _standbyTimerResetSeconds;
4121 if (standbyDelay > elapsed)
4122 standbyDelay -= elapsed;
4123 else
4124 standbyDelay = 1; // must be > 0
0b4c1975 4125
99c3a104
A
4126 DLOG("standby delay %u, elapsed %u\n",
4127 standbyDelay, (uint32_t) elapsed);
316670eb 4128 }
316670eb 4129 }
99c3a104
A
4130 params->ecWakeTimer = standbyDelay;
4131 }
4132 else if (kIOPMSleepPhase2 == sleepPhase)
4133 {
4134 // A sleep that does not enable the sleep timer will reset
4135 // the standby delay adjustment.
4136 _standbyTimerResetSeconds = 0;
316670eb 4137 }
0b4c1975
A
4138 break;
4139 }
4140
4141done:
4142 if (prop)
4143 prop->release();
4144
99c3a104 4145 return found;
0b4c1975
A
4146}
4147
99c3a104
A
4148static IOPMSystemSleepParameters gEarlySystemSleepParams;
4149
0b4c1975
A
4150void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
4151{
99c3a104 4152 // Evaluate early (priority interest phase), before drivers sleep.
0b4c1975
A
4153
4154 DLOG("%s\n", __FUNCTION__);
4155 removeProperty(kIOPMSystemSleepParametersKey);
4156
316670eb
A
4157 // Full wake resets the standby timer delay adjustment
4158 if (_highestCapability & kIOPMSystemCapabilityGraphics)
4159 _standbyTimerResetSeconds = 0;
4160
0b4c1975
A
4161 hibernateDisabled = false;
4162 hibernateMode = 0;
4163 getSleepOption(kIOHibernateModeKey, &hibernateMode);
4164
99c3a104
A
4165 // Save for late evaluation if sleep is aborted
4166 bzero(&gEarlySystemSleepParams, sizeof(gEarlySystemSleepParams));
4167
db609669
A
4168 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams, kIOPMSleepPhase1,
4169 &hibernateMode))
7ddcb079 4170 {
39236c6e 4171 if (!hibernateRetry &&
bd504ef0
A
4172 ((getSleepTypeAttributes(gEarlySystemSleepParams.sleepType) &
4173 kIOPMSleepAttributeHibernateSetup) == 0))
99c3a104 4174 {
bd504ef0 4175 // skip hibernate setup
99c3a104
A
4176 hibernateDisabled = true;
4177 }
7ddcb079 4178 }
99c3a104
A
4179
4180 // Publish IOPMSystemSleepType
4181 uint32_t sleepType = gEarlySystemSleepParams.sleepType;
4182 if (sleepType == kIOPMSleepTypeInvalid)
4183 {
4184 // no sleep policy
4185 sleepType = kIOPMSleepTypeNormalSleep;
4186 if (hibernateMode & kIOHibernateModeOn)
4187 sleepType = (hibernateMode & kIOHibernateModeSleep) ?
4188 kIOPMSleepTypeSafeSleep : kIOPMSleepTypeHibernate;
4189 }
4190 else if ((sleepType == kIOPMSleepTypeStandby) &&
4191 (gEarlySystemSleepParams.ecPoweroffTimer))
4192 {
4193 // report the lowest possible sleep state
4194 sleepType = kIOPMSleepTypePowerOff;
4195 }
4196
4197 setProperty(kIOPMSystemSleepTypeKey, sleepType, 32);
0b4c1975
A
4198}
4199
4200void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
4201{
4202 IOPMSystemSleepParameters params;
4203 OSData * paramsData;
4204
99c3a104 4205 // Evaluate sleep policy after sleeping drivers but before platform sleep.
0b4c1975
A
4206
4207 DLOG("%s\n", __FUNCTION__);
4208
db609669
A
4209 bzero(&params, sizeof(params));
4210 if (evaluateSystemSleepPolicy(&params, kIOPMSleepPhase2, &hibernateMode))
0b4c1975
A
4211 {
4212 if ((hibernateDisabled || hibernateAborted) &&
bd504ef0
A
4213 (getSleepTypeAttributes(params.sleepType) &
4214 kIOPMSleepAttributeHibernateSetup))
0b4c1975 4215 {
99c3a104 4216 // Final evaluation picked a state requiring hibernation,
39236c6e
A
4217 // but hibernate setup was skipped. Arm a short sleep using
4218 // the early non-hibernate sleep parameters.
4219 // Set hibernateRetry flag to force hibernate setup on the
4220 // next sleep.
0b4c1975 4221
99c3a104
A
4222 bcopy(&gEarlySystemSleepParams, &params, sizeof(params));
4223 params.sleepType = kIOPMSleepTypeAbortedSleep;
4224 params.ecWakeTimer = 1;
39236c6e 4225 hibernateRetry = true;
0b4c1975 4226 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d\n",
99c3a104 4227 params.ecWakeTimer, hibernateDisabled, hibernateAborted);
0b4c1975
A
4228 }
4229 else
99c3a104 4230 {
39236c6e 4231 hibernateRetry = false;
99c3a104 4232 }
0b4c1975
A
4233
4234 paramsData = OSData::withBytes(&params, sizeof(params));
4235 if (paramsData)
4236 {
4237 setProperty(kIOPMSystemSleepParametersKey, paramsData);
4238 paramsData->release();
4239 }
4240
bd504ef0
A
4241 if (getSleepTypeAttributes(params.sleepType) &
4242 kIOPMSleepAttributeHibernateSleep)
0b4c1975 4243 {
bd504ef0 4244 // Disable sleep to force hibernation
0b4c1975
A
4245 gIOHibernateMode &= ~kIOHibernateModeSleep;
4246 }
4247 }
4248}
4249
4250bool IOPMrootDomain::getHibernateSettings(
99c3a104 4251 uint32_t * hibernateModePtr,
0b4c1975
A
4252 uint32_t * hibernateFreeRatio,
4253 uint32_t * hibernateFreeTime )
4254{
99c3a104
A
4255 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
4256 // has updated the hibernateDisabled flag.
4257
4258 bool ok = getSleepOption(kIOHibernateModeKey, hibernateModePtr);
0b4c1975
A
4259 getSleepOption(kIOHibernateFreeRatioKey, hibernateFreeRatio);
4260 getSleepOption(kIOHibernateFreeTimeKey, hibernateFreeTime);
4261 if (hibernateDisabled)
99c3a104
A
4262 *hibernateModePtr = 0;
4263 else if (gSleepPolicyHandler)
4264 *hibernateModePtr = hibernateMode;
4265 DLOG("hibernateMode 0x%x\n", *hibernateModePtr);
0b4c1975
A
4266 return ok;
4267}
4268
4269bool IOPMrootDomain::getSleepOption( const char * key, uint32_t * option )
4270{
4271 OSObject * optionsProp;
4272 OSDictionary * optionsDict;
4273 OSObject * obj = 0;
4274 OSNumber * num;
4275 bool ok = false;
4276
4277 optionsProp = copyProperty(kRootDomainSleepOptionsKey);
4278 optionsDict = OSDynamicCast(OSDictionary, optionsProp);
fe8ab488 4279
0b4c1975
A
4280 if (optionsDict)
4281 {
4282 obj = optionsDict->getObject(key);
4283 if (obj) obj->retain();
4284 }
4285 if (!obj)
4286 {
4287 obj = copyProperty(key);
4288 }
a1c7dba1 4289 if (obj)
0b4c1975 4290 {
a1c7dba1
A
4291 if ((num = OSDynamicCast(OSNumber, obj)))
4292 {
4293 *option = num->unsigned32BitValue();
4294 ok = true;
4295 }
4296 else if (OSDynamicCast(OSBoolean, obj))
4297 {
4298 *option = (obj == kOSBooleanTrue) ? 1 : 0;
4299 ok = true;
4300 }
0b4c1975
A
4301 }
4302
6d2010ae
A
4303 if (obj)
4304 obj->release();
4305 if (optionsProp)
4306 optionsProp->release();
4307
4308 return true;
4309}
4310#endif /* HIBERNATION */
4311
db609669
A
4312IOReturn IOPMrootDomain::getSystemSleepType( uint32_t * sleepType )
4313{
4314#if HIBERNATION
4315 IOPMSystemSleepParameters params;
4316 uint32_t hibMode = 0;
4317 bool ok;
4318
4319 if (gIOPMWorkLoop->inGate() == false)
4320 {
4321 IOReturn ret = gIOPMWorkLoop->runAction(
4322 OSMemberFunctionCast(IOWorkLoop::Action, this,
4323 &IOPMrootDomain::getSystemSleepType),
4324 (OSObject *) this,
4325 (void *) sleepType);
4326 return ret;
4327 }
4328
4329 getSleepOption(kIOHibernateModeKey, &hibMode);
4330 bzero(&params, sizeof(params));
4331
4332 ok = evaluateSystemSleepPolicy(&params, kIOPMSleepPhase0, &hibMode);
4333 if (ok)
4334 {
4335 *sleepType = params.sleepType;
4336 return kIOReturnSuccess;
4337 }
4338#endif
4339
4340 return kIOReturnUnsupported;
4341}
4342
6d2010ae
A
4343// MARK: -
4344// MARK: Shutdown and Restart
4345
4346//******************************************************************************
4347// handlePlatformHaltRestart
4348//
4349//******************************************************************************
4350
4351struct HaltRestartApplierContext {
fe8ab488
A
4352 IOPMrootDomain * RootDomain;
4353 unsigned long PowerState;
4354 IOPMPowerFlags PowerFlags;
4355 UInt32 MessageType;
4356 UInt32 Counter;
3e170ce0 4357 const char * LogString;
6d2010ae
A
4358};
4359
4360static void
4361platformHaltRestartApplier( OSObject * object, void * context )
4362{
fe8ab488
A
4363 IOPowerStateChangeNotification notify;
4364 HaltRestartApplierContext * ctx;
4365 AbsoluteTime startTime;
3e170ce0 4366 uint32_t deltaTime;
6d2010ae 4367
fe8ab488
A
4368 ctx = (HaltRestartApplierContext *) context;
4369
4370 memset(&notify, 0, sizeof(notify));
39236c6e 4371 notify.powerRef = (void *)(uintptr_t)ctx->Counter;
6d2010ae
A
4372 notify.returnValue = 0;
4373 notify.stateNumber = ctx->PowerState;
4374 notify.stateFlags = ctx->PowerFlags;
4375
fe8ab488 4376 clock_get_uptime(&startTime);
6d2010ae 4377 ctx->RootDomain->messageClient( ctx->MessageType, object, (void *)&notify );
fe8ab488 4378 deltaTime = computeDeltaTimeMS(&startTime);
6d2010ae 4379
fe8ab488 4380 if ((deltaTime > kPMHaltTimeoutMS) ||
6d2010ae 4381 (gIOKitDebug & kIOLogPMRootDomain))
fe8ab488
A
4382 {
4383 _IOServiceInterestNotifier * notifier;
4384 notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
4385
4386 // IOService children of IOPMrootDomain are not instrumented.
4387 // Only IORootParent currently falls under that group.
4388
4389 if (notifier)
4390 {
4391 LOG("%s handler %p took %u ms\n",
3e170ce0 4392 ctx->LogString, OBFUSCATE(notifier->handler), deltaTime);
fe8ab488
A
4393 }
4394 }
6d2010ae 4395
fe8ab488 4396 ctx->Counter++;
6d2010ae
A
4397}
4398
3e170ce0
A
4399static void quiescePowerTreeCallback( void * target, void * param )
4400{
4401 IOLockLock(gPMHaltLock);
4402 gPMQuiesced = true;
4403 thread_wakeup(param);
4404 IOLockUnlock(gPMHaltLock);
4405}
4406
6d2010ae
A
4407void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type )
4408{
fe8ab488
A
4409 HaltRestartApplierContext ctx;
4410 AbsoluteTime startTime;
3e170ce0 4411 uint32_t deltaTime;
6d2010ae 4412
fe8ab488
A
4413 memset(&ctx, 0, sizeof(ctx));
4414 ctx.RootDomain = this;
6d2010ae 4415
fe8ab488
A
4416 clock_get_uptime(&startTime);
4417 switch (pe_type)
4418 {
4419 case kPEHaltCPU:
6d2010ae 4420 case kPEUPSDelayHaltCPU:
fe8ab488
A
4421 ctx.PowerState = OFF_STATE;
4422 ctx.MessageType = kIOMessageSystemWillPowerOff;
3e170ce0 4423 ctx.LogString = "PowerOff";
fe8ab488
A
4424 break;
4425
4426 case kPERestartCPU:
4427 ctx.PowerState = RESTART_STATE;
4428 ctx.MessageType = kIOMessageSystemWillRestart;
3e170ce0 4429 ctx.LogString = "Restart";
fe8ab488
A
4430 break;
4431
4432 case kPEPagingOff:
4433 ctx.PowerState = ON_STATE;
4434 ctx.MessageType = kIOMessageSystemPagingOff;
3e170ce0 4435 ctx.LogString = "PagingOff";
fe8ab488
A
4436 IOService::updateConsoleUsers(NULL, kIOMessageSystemPagingOff);
4437#if HIBERNATION
4438 IOHibernateSystemRestart();
db609669 4439#endif
fe8ab488 4440 break;
6d2010ae 4441
fe8ab488
A
4442 default:
4443 return;
4444 }
6d2010ae 4445
fe8ab488
A
4446 // Notify legacy clients
4447 applyToInterested(gIOPriorityPowerStateInterest, platformHaltRestartApplier, &ctx);
6d2010ae
A
4448
4449 // For normal shutdown, turn off File Server Mode.
4450 if (kPEHaltCPU == pe_type)
4451 {
4452 const OSSymbol * setting = OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey);
4453 OSNumber * num = OSNumber::withNumber((unsigned long long) 0, 32);
4454 if (setting && num)
4455 {
4456 setPMSetting(setting, num);
4457 setting->release();
4458 num->release();
4459 }
4460 }
4461
fe8ab488
A
4462 if (kPEPagingOff != pe_type)
4463 {
4464 // Notify in power tree order
4465 notifySystemShutdown(this, ctx.MessageType);
4466 }
0b4c1975 4467
fe8ab488
A
4468 IOCPURunPlatformHaltRestartActions(pe_type);
4469
3e170ce0
A
4470 // Wait for PM to quiesce
4471 if ((kPEPagingOff != pe_type) && gPMHaltLock)
4472 {
4473 AbsoluteTime quiesceTime = mach_absolute_time();
4474
4475 IOLockLock(gPMHaltLock);
4476 gPMQuiesced = false;
4477 if (quiescePowerTree(this, &quiescePowerTreeCallback, &gPMQuiesced) ==
4478 kIOReturnSuccess)
4479 {
4480 while (!gPMQuiesced)
4481 {
4482 IOLockSleep(gPMHaltLock, &gPMQuiesced, THREAD_UNINT);
4483 }
4484 }
4485 IOLockUnlock(gPMHaltLock);
4486
4487 deltaTime = computeDeltaTimeMS(&quiesceTime);
4488 DLOG("PM quiesce took %u ms\n", deltaTime);
4489 }
4490
fe8ab488 4491 deltaTime = computeDeltaTimeMS(&startTime);
3e170ce0 4492 LOG("%s all drivers took %u ms\n", ctx.LogString, deltaTime);
0b4c1975 4493}
0b4c1975 4494
b0d623f7 4495//******************************************************************************
6d2010ae 4496// shutdownSystem
b0d623f7 4497//
b0d623f7
A
4498//******************************************************************************
4499
6d2010ae 4500IOReturn IOPMrootDomain::shutdownSystem( void )
b0d623f7 4501{
6d2010ae
A
4502 return kIOReturnUnsupported;
4503}
0b4c1975 4504
6d2010ae
A
4505//******************************************************************************
4506// restartSystem
4507//
4508//******************************************************************************
0b4c1975 4509
6d2010ae
A
4510IOReturn IOPMrootDomain::restartSystem( void )
4511{
4512 return kIOReturnUnsupported;
b0d623f7
A
4513}
4514
6d2010ae
A
4515// MARK: -
4516// MARK: System Capability
b0d623f7 4517
4a3eedf9 4518//******************************************************************************
6d2010ae 4519// tagPowerPlaneService
4a3eedf9 4520//
6d2010ae 4521// Running on PM work loop thread.
4a3eedf9 4522//******************************************************************************
b0d623f7 4523
6d2010ae
A
4524void IOPMrootDomain::tagPowerPlaneService(
4525 IOService * service,
4526 IOPMActions * actions )
4a3eedf9 4527{
6d2010ae
A
4528 uint32_t flags = 0;
4529 bool isDisplayWrangler;
4a3eedf9 4530
6d2010ae
A
4531 memset(actions, 0, sizeof(*actions));
4532 actions->target = this;
4a3eedf9 4533
6d2010ae
A
4534 if (service == this)
4535 {
4536 actions->actionPowerChangeStart =
4537 OSMemberFunctionCast(
4538 IOPMActionPowerChangeStart, this,
4539 &IOPMrootDomain::handleOurPowerChangeStart);
4a3eedf9 4540
6d2010ae
A
4541 actions->actionPowerChangeDone =
4542 OSMemberFunctionCast(
4543 IOPMActionPowerChangeDone, this,
4544 &IOPMrootDomain::handleOurPowerChangeDone);
4a3eedf9 4545
6d2010ae
A
4546 actions->actionPowerChangeOverride =
4547 OSMemberFunctionCast(
4548 IOPMActionPowerChangeOverride, this,
4549 &IOPMrootDomain::overrideOurPowerChange);
4550 return;
4551 }
4a3eedf9 4552
6d2010ae
A
4553#if !NO_KERNEL_HID
4554 isDisplayWrangler = (0 != service->metaCast("IODisplayWrangler"));
4555 if (isDisplayWrangler)
4556 {
4557 wrangler = service;
6d2010ae
A
4558 }
4559#else
4560 isDisplayWrangler = false;
4561#endif
4a3eedf9 4562
6d2010ae
A
4563#if defined(__i386__) || defined(__x86_64__)
4564 if (isDisplayWrangler)
4565 flags |= kPMActionsFlagIsDisplayWrangler;
4566 if (service->getProperty("IOPMStrictTreeOrder"))
4567 flags |= kPMActionsFlagIsGraphicsDevice;
4568 if (service->getProperty("IOPMUnattendedWakePowerState"))
4569 flags |= kPMActionsFlagIsAudioDevice;
4570#endif
4a3eedf9 4571
6d2010ae
A
4572 // Find the power connection object that is a child of the PCI host
4573 // bridge, and has a graphics/audio device attached below. Mark the
4574 // power branch for delayed child notifications.
4a3eedf9 4575
6d2010ae
A
4576 if (flags)
4577 {
4578 IORegistryEntry * child = service;
4579 IORegistryEntry * parent = child->getParentEntry(gIOPowerPlane);
4580
4581 while (child != this)
4582 {
4583 if ((parent == pciHostBridgeDriver) ||
4584 (parent == this))
4585 {
4586 if (OSDynamicCast(IOPowerConnection, child))
4587 {
4588 IOPowerConnection * conn = (IOPowerConnection *) child;
4589 conn->delayChildNotification = true;
4590 }
4591 break;
4592 }
4593 child = parent;
4594 parent = child->getParentEntry(gIOPowerPlane);
4595 }
4a3eedf9
A
4596 }
4597
6d2010ae
A
4598 if (flags)
4599 {
4600 DLOG("%s tag flags %x\n", service->getName(), flags);
4601 actions->parameter |= flags;
4602 actions->actionPowerChangeOverride =
4603 OSMemberFunctionCast(
4604 IOPMActionPowerChangeOverride, this,
4605 &IOPMrootDomain::overridePowerChangeForUIService);
4a3eedf9 4606
6d2010ae
A
4607 if (flags & kPMActionsFlagIsDisplayWrangler)
4608 {
4609 actions->actionActivityTickle =
4610 OSMemberFunctionCast(
4611 IOPMActionActivityTickle, this,
4612 &IOPMrootDomain::handleActivityTickleForDisplayWrangler);
39236c6e
A
4613
4614 actions->actionUpdatePowerClient =
4615 OSMemberFunctionCast(
4616 IOPMActionUpdatePowerClient, this,
4617 &IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler);
6d2010ae
A
4618 }
4619 return;
4620 }
4a3eedf9 4621
6d2010ae
A
4622 // Locate the first PCI host bridge for PMTrace.
4623 if (!pciHostBridgeDevice && service->metaCast("IOPCIBridge"))
4624 {
4625 IOService * provider = service->getProvider();
4626 if (OSDynamicCast(IOPlatformDevice, provider) &&
4627 provider->inPlane(gIODTPlane))
4628 {
4629 pciHostBridgeDevice = provider;
4630 pciHostBridgeDriver = service;
4631 DLOG("PMTrace found PCI host bridge %s->%s\n",
4632 provider->getName(), service->getName());
4633 }
4634 }
4a3eedf9 4635
6d2010ae 4636 // Tag top-level PCI devices. The order of PMinit() call does not
fe8ab488 4637 // change across boots and is used as the PCI bit number.
6d2010ae
A
4638 if (pciHostBridgeDevice && service->metaCast("IOPCIDevice"))
4639 {
4640 // Would prefer to check built-in property, but tagPowerPlaneService()
4641 // is called before pciDevice->registerService().
4642 IORegistryEntry * parent = service->getParentEntry(gIODTPlane);
4643 if ((parent == pciHostBridgeDevice) && service->getProperty("acpi-device"))
4644 {
4645 int bit = pmTracer->recordTopLevelPCIDevice( service );
4646 if (bit >= 0)
4647 {
fe8ab488 4648 // Save the assigned bit for fast lookup.
6d2010ae 4649 actions->parameter |= (bit & kPMActionsPCIBitNumberMask);
4a3eedf9 4650
6d2010ae
A
4651 actions->actionPowerChangeStart =
4652 OSMemberFunctionCast(
4653 IOPMActionPowerChangeStart, this,
4654 &IOPMrootDomain::handlePowerChangeStartForPCIDevice);
4a3eedf9 4655
6d2010ae
A
4656 actions->actionPowerChangeDone =
4657 OSMemberFunctionCast(
4658 IOPMActionPowerChangeDone, this,
4659 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice);
4660 }
4661 }
4662 }
4a3eedf9
A
4663}
4664
0c530ab8 4665//******************************************************************************
6d2010ae 4666// PM actions for root domain
0c530ab8
A
4667//******************************************************************************
4668
6d2010ae 4669void IOPMrootDomain::overrideOurPowerChange(
39236c6e
A
4670 IOService * service,
4671 IOPMActions * actions,
4672 IOPMPowerStateIndex * inOutPowerState,
4673 IOPMPowerChangeFlags * inOutChangeFlags,
4674 IOPMRequestTag requestTag )
b0d623f7 4675{
39236c6e
A
4676 uint32_t powerState = (uint32_t) *inOutPowerState;
4677 uint32_t changeFlags = *inOutChangeFlags;
4678 uint32_t currentPowerState = (uint32_t) getPowerState();
6d2010ae 4679
bd504ef0 4680 if (changeFlags & kIOPMParentInitiated)
6d2010ae 4681 {
6d2010ae 4682 // Root parent is permanently pegged at max power,
39236c6e
A
4683 // a parent initiated power change is unexpected.
4684 *inOutChangeFlags |= kIOPMNotDone;
6d2010ae
A
4685 return;
4686 }
4687
4688 if (powerState < currentPowerState)
4689 {
6d2010ae
A
4690 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics))
4691 {
4692 // Root domain is dropping power state ON->SLEEP.
fe8ab488
A
4693 // If system is in full wake, first enter dark wake by
4694 // converting the power drop to a capability change.
4695 // Once in dark wake, transition to sleep state ASAP.
6d2010ae
A
4696
4697 darkWakeToSleepASAP = true;
4698
fe8ab488 4699 // Drop graphics and audio capability
6d2010ae
A
4700 _desiredCapability &= ~(
4701 kIOPMSystemCapabilityGraphics |
4702 kIOPMSystemCapabilityAudio );
4703
fe8ab488 4704 // Convert to capability change (ON->ON)
6d2010ae
A
4705 *inOutPowerState = ON_STATE;
4706 *inOutChangeFlags |= kIOPMSynchronize;
4707
fe8ab488 4708 // Revert device desire from SLEEP to ON
6d2010ae
A
4709 changePowerStateToPriv(ON_STATE);
4710 }
bd504ef0
A
4711 else
4712 {
fe8ab488
A
4713 // System is in dark wake, ok to drop power state.
4714 // Broadcast root powering down to entire tree.
bd504ef0
A
4715 *inOutChangeFlags |= kIOPMRootChangeDown;
4716 }
4717 }
4718 else if (powerState > currentPowerState)
4719 {
4720 if ((_currentCapability & kIOPMSystemCapabilityCPU) == 0)
4721 {
4722 // Broadcast power up when waking from sleep, but not for the
4723 // initial power change at boot by checking for cpu capability.
4724 *inOutChangeFlags |= kIOPMRootChangeUp;
4725 }
6d2010ae 4726 }
b0d623f7
A
4727}
4728
6d2010ae 4729void IOPMrootDomain::handleOurPowerChangeStart(
39236c6e
A
4730 IOService * service,
4731 IOPMActions * actions,
4732 IOPMPowerStateIndex powerState,
4733 IOPMPowerChangeFlags * inOutChangeFlags,
4734 IOPMRequestTag requestTag )
0c530ab8 4735{
39236c6e
A
4736 uint32_t changeFlags = *inOutChangeFlags;
4737 uint32_t currentPowerState = (uint32_t) getPowerState();
4738 uint32_t sleepReason = requestTag ? requestTag : kIOPMSleepReasonIdle;
4739 bool publishSleepReason = false;
0c530ab8 4740
6d2010ae
A
4741 _systemTransitionType = kSystemTransitionNone;
4742 _systemMessageClientMask = 0;
4743 capabilityLoss = false;
3e170ce0 4744 toldPowerdCapWillChange = false;
b0d623f7 4745
fe8ab488
A
4746 if (lowBatteryCondition)
4747 {
4748 // Low battery notification may arrive after the initial sleep request
4749 // has been queued. Override the sleep reason so powerd and others can
4750 // treat this as an emergency sleep.
4751 sleepReason = kIOPMSleepReasonLowPower;
4752 }
4753
6d2010ae
A
4754 // 1. Explicit capability change.
4755
4756 if (changeFlags & kIOPMSynchronize)
55e303ae 4757 {
6d2010ae
A
4758 if (powerState == ON_STATE)
4759 {
4760 if (changeFlags & kIOPMSyncNoChildNotify)
4761 _systemTransitionType = kSystemTransitionNewCapClient;
4762 else
4763 _systemTransitionType = kSystemTransitionCapability;
4764 }
d52fe63f 4765 }
0c530ab8 4766
6d2010ae
A
4767 // 2. Going to sleep (cancellation still possible).
4768
4769 else if (powerState < currentPowerState)
4770 _systemTransitionType = kSystemTransitionSleep;
4771
4772 // 3. Woke from (idle or demand) sleep.
4773
4774 else if (!systemBooting &&
4775 (changeFlags & kIOPMSelfInitiated) &&
4776 (powerState > currentPowerState))
55e303ae 4777 {
6d2010ae
A
4778 _systemTransitionType = kSystemTransitionWake;
4779 _desiredCapability = kIOPMSystemCapabilityCPU |
4780 kIOPMSystemCapabilityNetwork;
4781
39236c6e
A
4782 // Early exit from dark wake to full (e.g. LID open)
4783 if (kFullWakeReasonNone != fullWakeReason)
6d2010ae
A
4784 {
4785 _desiredCapability |= (
4786 kIOPMSystemCapabilityGraphics |
4787 kIOPMSystemCapabilityAudio );
4788 }
39236c6e 4789#if HIBERNATION
fe8ab488 4790 IOHibernateSetWakeCapabilities(_desiredCapability);
39236c6e 4791#endif
d52fe63f
A
4792 }
4793
6d2010ae
A
4794 // Update pending wake capability at the beginning of every
4795 // state transition (including synchronize). This will become
4796 // the current capability at the end of the transition.
4797
4798 if (kSystemTransitionSleep == _systemTransitionType)
55e303ae 4799 {
6d2010ae
A
4800 _pendingCapability = 0;
4801 capabilityLoss = true;
fe8ab488
A
4802
4803 // Clear previous stats
4804 IOLockLock(pmStatsLock);
4805 if (pmStatsAppResponses)
4806 {
4807 pmStatsAppResponses->release();
4808 pmStatsAppResponses = OSArray::withCapacity(5);
4809 }
4810 IOLockUnlock(pmStatsLock);
4811
d52fe63f 4812 }
6d2010ae 4813 else if (kSystemTransitionNewCapClient != _systemTransitionType)
55e303ae 4814 {
6d2010ae
A
4815 _pendingCapability = _desiredCapability |
4816 kIOPMSystemCapabilityCPU |
4817 kIOPMSystemCapabilityNetwork;
4818
4819 if (_pendingCapability & kIOPMSystemCapabilityGraphics)
4820 _pendingCapability |= kIOPMSystemCapabilityAudio;
4821
4822 if ((kSystemTransitionCapability == _systemTransitionType) &&
4823 (_pendingCapability == _currentCapability))
4824 {
4825 // Cancel the PM state change.
4826 _systemTransitionType = kSystemTransitionNone;
4827 *inOutChangeFlags |= kIOPMNotDone;
4828 }
4829 if (__builtin_popcount(_pendingCapability) <
4830 __builtin_popcount(_currentCapability))
4831 capabilityLoss = true;
1c79356b 4832 }
6d2010ae
A
4833
4834 // 1. Capability change.
4835
4836 if (kSystemTransitionCapability == _systemTransitionType)
55e303ae 4837 {
6d2010ae
A
4838 // Dark to Full transition.
4839 if (CAP_GAIN(kIOPMSystemCapabilityGraphics))
4840 {
4841 tracePoint( kIOPMTracePointDarkWakeExit );
6d2010ae 4842
39236c6e 4843 willEnterFullWake();
6d2010ae
A
4844 }
4845
4846 // Full to Dark transition.
4847 if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
4848 {
4849 tracePoint( kIOPMTracePointDarkWakeEntry );
4850 *inOutChangeFlags |= kIOPMSyncTellPowerDown;
39236c6e
A
4851 _systemMessageClientMask = kSystemMessageClientPowerd |
4852 kSystemMessageClientLegacyApp;
22ba694c 4853
fe8ab488 4854
22ba694c
A
4855 // rdar://15971327
4856 // Prevent user active transitions before notifying clients
4857 // that system will sleep.
4858 preventTransitionToUserActive(true);
4859
db609669 4860 IOService::setAdvisoryTickleEnable( false );
22ba694c 4861
39236c6e
A
4862 // Publish the sleep reason for full to dark wake
4863 publishSleepReason = true;
4864 lastSleepReason = fullToDarkReason = sleepReason;
fe8ab488 4865
39236c6e
A
4866 // Publish a UUID for the Sleep --> Wake cycle
4867 handlePublishSleepWakeUUID(true);
3e170ce0
A
4868 if (sleepDelaysReport) {
4869 clock_get_uptime(&ts_sleepStart);
4870 DLOG("sleepDelaysReport f->9 start at 0x%llx\n", ts_sleepStart);
4871 }
6d2010ae 4872 }
1c79356b
A
4873 }
4874
6d2010ae
A
4875 // 2. System sleep.
4876
4877 else if (kSystemTransitionSleep == _systemTransitionType)
0c530ab8 4878 {
6d2010ae
A
4879 // Beginning of a system sleep transition.
4880 // Cancellation is still possible.
39236c6e 4881 tracePoint( kIOPMTracePointSleepStarted, sleepReason );
0b4c1975 4882
6d2010ae
A
4883 _systemMessageClientMask = kSystemMessageClientAll;
4884 if ((_currentCapability & kIOPMSystemCapabilityGraphics) == 0)
39236c6e 4885 _systemMessageClientMask &= ~kSystemMessageClientLegacyApp;
6d2010ae
A
4886 if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0)
4887 _systemMessageClientMask &= ~kSystemMessageClientKernel;
4888
39236c6e
A
4889 // Record the reason for dark wake back to sleep
4890 // System may not have ever achieved full wake
4891
4892 publishSleepReason = true;
4893 lastSleepReason = sleepReason;
3e170ce0
A
4894 if (sleepDelaysReport) {
4895 clock_get_uptime(&ts_sleepStart);
4896 DLOG("sleepDelaysReport 9->0 start at 0x%llx\n", ts_sleepStart);
4897 }
6d2010ae 4898 }
2d21ac55 4899
6d2010ae 4900 // 3. System wake.
0b4c1975 4901
6d2010ae
A
4902 else if (kSystemTransitionWake == _systemTransitionType)
4903 {
39236c6e 4904 tracePoint( kIOPMTracePointWakeWillPowerOnClients );
fe8ab488 4905 // Clear stats about sleep
6d2010ae
A
4906
4907 if (_pendingCapability & kIOPMSystemCapabilityGraphics)
4908 {
39236c6e 4909 willEnterFullWake();
6d2010ae
A
4910 }
4911 else
4912 {
39236c6e
A
4913 // Message powerd only
4914 _systemMessageClientMask = kSystemMessageClientPowerd;
4915 tellClients(kIOMessageSystemWillPowerOn);
6d2010ae 4916 }
39236c6e 4917 }
6d2010ae 4918
39236c6e
A
4919 // The only location where the sleep reason is published. At this point
4920 // sleep can still be cancelled, but sleep reason should be published
4921 // early for logging purposes.
4922
4923 if (publishSleepReason)
4924 {
4925 static const char * IOPMSleepReasons[] =
4926 {
4927 kIOPMClamshellSleepKey,
4928 kIOPMPowerButtonSleepKey,
4929 kIOPMSoftwareSleepKey,
4930 kIOPMOSSwitchHibernationKey,
4931 kIOPMIdleSleepKey,
4932 kIOPMLowPowerSleepKey,
4933 kIOPMThermalEmergencySleepKey,
4934 kIOPMMaintenanceSleepKey,
4935 kIOPMSleepServiceExitKey,
4936 kIOPMDarkWakeThermalEmergencyKey
4937 };
4938
4939 // Record sleep cause in IORegistry
4940 uint32_t reasonIndex = sleepReason - kIOPMSleepReasonClamshell;
4941 if (reasonIndex < sizeof(IOPMSleepReasons)/sizeof(IOPMSleepReasons[0])) {
4942 DLOG("sleep reason %s\n", IOPMSleepReasons[reasonIndex]);
4943 setProperty(kRootDomainSleepReasonKey, IOPMSleepReasons[reasonIndex]);
4944 }
0b4c1975 4945 }
0c530ab8 4946
6d2010ae
A
4947 if ((kSystemTransitionNone != _systemTransitionType) &&
4948 (kSystemTransitionNewCapClient != _systemTransitionType))
0c530ab8 4949 {
6d2010ae
A
4950 _systemStateGeneration++;
4951 systemDarkWake = false;
0c530ab8 4952
6d2010ae
A
4953 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4954 "dcp %x:%x:%x\n",
39236c6e 4955 currentPowerState, (uint32_t) powerState, *inOutChangeFlags,
6d2010ae
A
4956 _systemTransitionType, _systemStateGeneration,
4957 _systemMessageClientMask,
4958 _desiredCapability, _currentCapability, _pendingCapability);
4959 }
4960}
2d21ac55 4961
6d2010ae 4962void IOPMrootDomain::handleOurPowerChangeDone(
39236c6e
A
4963 IOService * service,
4964 IOPMActions * actions,
4965 IOPMPowerStateIndex powerState,
4966 IOPMPowerChangeFlags changeFlags,
4967 IOPMRequestTag requestTag __unused )
6d2010ae
A
4968{
4969 if (kSystemTransitionNewCapClient == _systemTransitionType)
4970 {
4971 _systemTransitionType = kSystemTransitionNone;
4972 return;
0c530ab8
A
4973 }
4974
6d2010ae 4975 if (_systemTransitionType != kSystemTransitionNone)
4452a7af 4976 {
6d2010ae 4977 uint32_t currentPowerState = (uint32_t) getPowerState();
0c530ab8 4978
6d2010ae
A
4979 if (changeFlags & kIOPMNotDone)
4980 {
4981 // Power down was cancelled or vetoed.
4982 _pendingCapability = _currentCapability;
4983 lastSleepReason = 0;
0c530ab8 4984
39236c6e
A
4985 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics) &&
4986 CAP_CURRENT(kIOPMSystemCapabilityCPU))
6d2010ae
A
4987 {
4988 pmPowerStateQueue->submitPowerEvent(
4989 kPowerEventPolicyStimulus,
4990 (void *) kStimulusDarkWakeReentry,
39236c6e 4991 _systemStateGeneration );
6d2010ae 4992 }
fe8ab488 4993
6d2010ae
A
4994 // Revert device desire to max.
4995 changePowerStateToPriv(ON_STATE);
4996 }
4997 else
4452a7af 4998 {
6d2010ae
A
4999 // Send message on dark wake to full wake promotion.
5000 // tellChangeUp() handles the normal SLEEP->ON case.
5001
5002 if (kSystemTransitionCapability == _systemTransitionType)
5003 {
5004 if (CAP_GAIN(kIOPMSystemCapabilityGraphics))
5005 {
39236c6e 5006 lastSleepReason = 0; // stop logging wrangler tickles
6d2010ae 5007 tellClients(kIOMessageSystemHasPoweredOn);
6d2010ae
A
5008 }
5009 if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
39236c6e
A
5010 {
5011 // Going dark, reset full wake state
5012 // userIsActive will be cleared by wrangler powering down
6d2010ae 5013 wranglerTickled = false;
39236c6e 5014 fullWakeReason = kFullWakeReasonNone;
3e170ce0
A
5015
5016 if (ts_sleepStart) {
5017 clock_get_uptime(&wake2DarkwakeDelay);
5018 SUB_ABSOLUTETIME(&wake2DarkwakeDelay, &ts_sleepStart);
5019 DLOG("sleepDelaysReport f->9 end 0x%llx\n", wake2DarkwakeDelay);
5020 ts_sleepStart = 0;
5021 }
39236c6e 5022 }
6d2010ae
A
5023 }
5024
5025 // Reset state after exiting from dark wake.
5026
5027 if (CAP_GAIN(kIOPMSystemCapabilityGraphics) ||
5028 CAP_LOSS(kIOPMSystemCapabilityCPU))
5029 {
5030 darkWakeMaintenance = false;
5031 darkWakeToSleepASAP = false;
5032 pciCantSleepValid = false;
316670eb 5033 darkWakeSleepService = false;
fe8ab488 5034
39236c6e
A
5035 if (CAP_LOSS(kIOPMSystemCapabilityCPU))
5036 {
5037 // Remove the influence of display power assertion
5038 // before next system wake.
5039 if (wrangler) wrangler->changePowerStateForRootDomain(
5040 kWranglerPowerStateMin );
5041 removeProperty(gIOPMUserTriggeredFullWakeKey);
5042 }
6d2010ae
A
5043 }
5044
5045 // Entered dark mode.
5046
5047 if (((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) &&
5048 (_pendingCapability & kIOPMSystemCapabilityCPU))
5049 {
6d2010ae
A
5050 // Queue an evaluation of whether to remain in dark wake,
5051 // and for how long. This serves the purpose of draining
5052 // any assertions from the queue.
5053
5054 pmPowerStateQueue->submitPowerEvent(
5055 kPowerEventPolicyStimulus,
5056 (void *) kStimulusDarkWakeEntry,
5057 _systemStateGeneration );
5058 }
0c530ab8 5059 }
4452a7af 5060
6d2010ae
A
5061 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5062 "dcp %x:%x:%x, dbgtimer %u\n",
39236c6e 5063 currentPowerState, (uint32_t) powerState, changeFlags,
6d2010ae
A
5064 _systemTransitionType, _systemStateGeneration,
5065 _systemMessageClientMask,
5066 _desiredCapability, _currentCapability, _pendingCapability,
7ddcb079 5067 _lastDebugWakeSeconds);
b0d623f7 5068
39236c6e
A
5069 if (_pendingCapability & kIOPMSystemCapabilityGraphics)
5070 {
5071 displayWakeCnt++;
5072#if DARK_TO_FULL_EVALUATE_CLAMSHELL
5073 if (clamshellExists && fullWakeThreadCall &&
5074 CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
5075 {
5076 // Not the initial graphics full power, graphics won't
5077 // send a power notification to trigger a lid state
5078 // evaluation.
2d21ac55 5079
39236c6e
A
5080 AbsoluteTime deadline;
5081 clock_interval_to_deadline(45, kSecondScale, &deadline);
5082 thread_call_enter_delayed(fullWakeThreadCall, deadline);
5083 }
5084#endif
5085 }
5086 else if (CAP_GAIN(kIOPMSystemCapabilityCPU))
5087 darkWakeCnt++;
5088
5089 // Update current system capability.
6d2010ae
A
5090 if (_currentCapability != _pendingCapability)
5091 _currentCapability = _pendingCapability;
0c530ab8 5092
6d2010ae
A
5093 // Update highest system capability.
5094
db609669 5095 _highestCapability |= _currentCapability;
6d2010ae
A
5096
5097 if (darkWakePostTickle &&
5098 (kSystemTransitionWake == _systemTransitionType) &&
5099 (gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
5100 kDarkWakeFlagHIDTickleLate)
0c530ab8 5101 {
6d2010ae
A
5102 darkWakePostTickle = false;
5103 reportUserInput();
4452a7af 5104 }
6d2010ae
A
5105
5106 // Reset tracepoint at completion of capability change,
5107 // completion of wake transition, and aborted sleep transition.
5108
5109 if ((_systemTransitionType == kSystemTransitionCapability) ||
5110 (_systemTransitionType == kSystemTransitionWake) ||
5111 ((_systemTransitionType == kSystemTransitionSleep) &&
5112 (changeFlags & kIOPMNotDone)))
0c530ab8 5113 {
6d2010ae
A
5114 setProperty(kIOPMSystemCapabilitiesKey, _currentCapability, 64);
5115 tracePoint( kIOPMTracePointSystemUp, 0 );
0c530ab8
A
5116 }
5117
6d2010ae
A
5118 _systemTransitionType = kSystemTransitionNone;
5119 _systemMessageClientMask = 0;
3e170ce0 5120 toldPowerdCapWillChange = false;
0c530ab8 5121
6d2010ae 5122 logGraphicsClamp = false;
0c530ab8 5123 }
6d2010ae 5124}
0c530ab8 5125
6d2010ae
A
5126//******************************************************************************
5127// PM actions for graphics and audio.
5128//******************************************************************************
5129
5130void IOPMrootDomain::overridePowerChangeForUIService(
39236c6e
A
5131 IOService * service,
5132 IOPMActions * actions,
5133 IOPMPowerStateIndex * inOutPowerState,
5134 IOPMPowerChangeFlags * inOutChangeFlags )
6d2010ae
A
5135{
5136 uint32_t powerState = (uint32_t) *inOutPowerState;
5137 uint32_t changeFlags = (uint32_t) *inOutChangeFlags;
5138
5139 if (kSystemTransitionNone == _systemTransitionType)
5140 {
5141 // Not in midst of a system transition.
5142 // Do not modify power limit enable state.
0c530ab8 5143 }
6d2010ae
A
5144 else if ((actions->parameter & kPMActionsFlagLimitPower) == 0)
5145 {
5146 // Activate power limiter.
0c530ab8 5147
6d2010ae 5148 if ((actions->parameter & kPMActionsFlagIsDisplayWrangler) &&
316670eb
A
5149 ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) &&
5150 (changeFlags & kIOPMSynchronize))
6d2010ae
A
5151 {
5152 actions->parameter |= kPMActionsFlagLimitPower;
5153 }
5154 else if ((actions->parameter & kPMActionsFlagIsAudioDevice) &&
db609669 5155 ((gDarkWakeFlags & kDarkWakeFlagAudioNotSuppressed) == 0) &&
316670eb
A
5156 ((_pendingCapability & kIOPMSystemCapabilityAudio) == 0) &&
5157 (changeFlags & kIOPMSynchronize))
6d2010ae
A
5158 {
5159 actions->parameter |= kPMActionsFlagLimitPower;
5160 }
5161 else if ((actions->parameter & kPMActionsFlagIsGraphicsDevice) &&
5162 (_systemTransitionType == kSystemTransitionSleep))
5163 {
5164 // For graphics devices, arm the limiter when entering
5165 // system sleep. Not when dropping to dark wake.
fe8ab488 5166 actions->parameter |= kPMActionsFlagLimitPower;
6d2010ae
A
5167 }
5168
5169 if (actions->parameter & kPMActionsFlagLimitPower)
5170 {
5171 DLOG("+ plimit %s %p\n",
39236c6e 5172 service->getName(), OBFUSCATE(service));
6d2010ae
A
5173 }
5174 }
5175 else
0c530ab8 5176 {
6d2010ae 5177 // Remove power limit.
0c530ab8 5178
6d2010ae
A
5179 if ((actions->parameter & (
5180 kPMActionsFlagIsDisplayWrangler |
5181 kPMActionsFlagIsGraphicsDevice )) &&
5182 (_pendingCapability & kIOPMSystemCapabilityGraphics))
5183 {
5184 actions->parameter &= ~kPMActionsFlagLimitPower;
5185 }
5186 else if ((actions->parameter & kPMActionsFlagIsAudioDevice) &&
5187 (_pendingCapability & kIOPMSystemCapabilityAudio))
5188 {
5189 actions->parameter &= ~kPMActionsFlagLimitPower;
5190 }
0c530ab8 5191
6d2010ae
A
5192 if ((actions->parameter & kPMActionsFlagLimitPower) == 0)
5193 {
5194 DLOG("- plimit %s %p\n",
39236c6e 5195 service->getName(), OBFUSCATE(service));
6d2010ae 5196 }
4452a7af
A
5197 }
5198
6d2010ae 5199 if (actions->parameter & kPMActionsFlagLimitPower)
2d21ac55 5200 {
6d2010ae
A
5201 uint32_t maxPowerState = (uint32_t)(-1);
5202
5203 if (changeFlags & (kIOPMDomainDidChange | kIOPMDomainWillChange))
55e303ae 5204 {
6d2010ae
A
5205 // Enforce limit for system power/cap transitions.
5206
5207 maxPowerState = 0;
39236c6e
A
5208 if ((service->getPowerState() > maxPowerState) &&
5209 (actions->parameter & kPMActionsFlagIsDisplayWrangler))
6d2010ae 5210 {
39236c6e
A
5211 maxPowerState++;
5212
5213 // Remove lingering effects of any tickle before entering
5214 // dark wake. It will take a new tickle to return to full
5215 // wake, so the existing tickle state is useless.
5216
5217 if (changeFlags & kIOPMDomainDidChange)
5218 *inOutChangeFlags |= kIOPMExpireIdleTimer;
6d2010ae 5219 }
99c3a104
A
5220 else if (actions->parameter & kPMActionsFlagIsGraphicsDevice)
5221 {
39236c6e 5222 maxPowerState++;
99c3a104 5223 }
6d2010ae
A
5224 }
5225 else
5226 {
5227 // Deny all self-initiated changes when power is limited.
5228 // Wrangler tickle should never defeat the limiter.
5229
5230 maxPowerState = service->getPowerState();
5231 }
5232
5233 if (powerState > maxPowerState)
5234 {
5235 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
39236c6e 5236 service->getName(), OBFUSCATE(service), powerState, maxPowerState,
6d2010ae
A
5237 changeFlags);
5238 *inOutPowerState = maxPowerState;
5239
5240 if (darkWakePostTickle &&
5241 (actions->parameter & kPMActionsFlagIsDisplayWrangler) &&
5242 (changeFlags & kIOPMDomainWillChange) &&
5243 ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
5244 kDarkWakeFlagHIDTickleEarly))
5245 {
5246 darkWakePostTickle = false;
5247 reportUserInput();
5248 }
0b4e3aa0 5249 }
6d2010ae
A
5250
5251 if (!graphicsSuppressed && (changeFlags & kIOPMDomainDidChange))
5252 {
5253 if (logGraphicsClamp)
5254 {
5255 AbsoluteTime now;
5256 uint64_t nsec;
5257
5258 clock_get_uptime(&now);
5259 SUB_ABSOLUTETIME(&now, &systemWakeTime);
5260 absolutetime_to_nanoseconds(now, &nsec);
39236c6e
A
5261 if (kIOLogPMRootDomain & gIOKitDebug)
5262 MSG("Graphics suppressed %u ms\n",
5263 ((int)((nsec) / 1000000ULL)));
0c530ab8 5264 }
6d2010ae 5265 graphicsSuppressed = true;
1c79356b 5266 }
0b4e3aa0 5267 }
6d2010ae 5268}
0b4e3aa0 5269
6d2010ae
A
5270void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
5271 IOService * service,
5272 IOPMActions * actions )
5273{
22ba694c 5274#if !NO_KERNEL_HID
6d2010ae
A
5275 // Warning: Not running in PM work loop context - don't modify state !!!
5276 // Trap tickle directed to IODisplayWrangler while running with graphics
5277 // capability suppressed.
5278
5279 assert(service == wrangler);
5280
39236c6e
A
5281 clock_get_uptime(&userActivityTime);
5282 bool aborting = ((lastSleepReason == kIOPMSleepReasonIdle)
3e170ce0
A
5283 || (lastSleepReason == kIOPMSleepReasonMaintenance)
5284 || (lastSleepReason == kIOPMSleepReasonSoftware));
39236c6e
A
5285 if (aborting) {
5286 userActivityCount++;
5287 DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
5288 userActivityCount, lastSleepReason);
1c79356b
A
5289 }
5290
13f56ec4 5291 if (!wranglerTickled &&
6d2010ae
A
5292 ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0))
5293 {
5294 DLOG("display wrangler tickled\n");
5295 if (kIOLogPMRootDomain & gIOKitDebug)
5296 OSReportWithBacktrace("Dark wake display tickle");
5297 if (pmPowerStateQueue)
5298 {
5299 pmPowerStateQueue->submitPowerEvent(
5300 kPowerEventPolicyStimulus,
fe8ab488
A
5301 (void *) kStimulusDarkWakeActivityTickle,
5302 true /* set wake type */ );
0b4e3aa0 5303 }
1c79356b 5304 }
22ba694c 5305#endif
1c79356b
A
5306}
5307
39236c6e
A
5308void IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
5309 IOService * service,
5310 IOPMActions * actions,
5311 const OSSymbol * powerClient,
5312 IOPMPowerStateIndex oldPowerState,
5313 IOPMPowerStateIndex newPowerState )
5314{
22ba694c 5315#if !NO_KERNEL_HID
39236c6e 5316 assert(service == wrangler);
fe8ab488 5317
22ba694c
A
5318 // This function implements half of the user active detection
5319 // by monitoring changes to the display wrangler's device desire.
39236c6e 5320 //
22ba694c
A
5321 // User becomes active when either:
5322 // 1. Wrangler's DeviceDesire increases to max, but wrangler is already
5323 // in max power state. This desire change in absence of a power state
5324 // change is detected within. This handles the case when user becomes
5325 // active while the display is already lit by setDisplayPowerOn().
39236c6e 5326 //
22ba694c
A
5327 // 2. Power state change to max, and DeviceDesire is also at max.
5328 // Handled by displayWranglerNotification().
5329 //
5330 // User becomes inactive when DeviceDesire drops to sleep state or below.
39236c6e 5331
22ba694c 5332 DLOG("wrangler %s (ps %u, %u->%u)\n",
39236c6e
A
5333 powerClient->getCStringNoCopy(),
5334 (uint32_t) service->getPowerState(),
5335 (uint32_t) oldPowerState, (uint32_t) newPowerState);
5336
5337 if (powerClient == gIOPMPowerClientDevice)
5338 {
5339 if ((newPowerState > oldPowerState) &&
5340 (newPowerState == kWranglerPowerStateMax) &&
5341 (service->getPowerState() == kWranglerPowerStateMax))
5342 {
22ba694c 5343 evaluatePolicy( kStimulusEnterUserActiveState );
39236c6e
A
5344 }
5345 else
5346 if ((newPowerState < oldPowerState) &&
5347 (newPowerState <= kWranglerPowerStateSleep))
5348 {
22ba694c 5349 evaluatePolicy( kStimulusLeaveUserActiveState );
39236c6e
A
5350 }
5351 }
22ba694c
A
5352#endif
5353}
5354
5355//******************************************************************************
5356// User active state management
5357//******************************************************************************
5358
5359void IOPMrootDomain::preventTransitionToUserActive( bool prevent )
5360{
5361#if !NO_KERNEL_HID
5362 _preventUserActive = prevent;
5363 if (wrangler && !_preventUserActive)
5364 {
5365 // Allowing transition to user active, but the wrangler may have
5366 // already powered ON in case of sleep cancel/revert. Poll the
5367 // same conditions checked for in displayWranglerNotification()
5368 // to bring the user active state up to date.
5369
5370 if ((wrangler->getPowerState() == kWranglerPowerStateMax) &&
5371 (wrangler->getPowerStateForClient(gIOPMPowerClientDevice) ==
5372 kWranglerPowerStateMax))
5373 {
5374 evaluatePolicy( kStimulusEnterUserActiveState );
5375 }
5376 }
5377#endif
39236c6e
A
5378}
5379
b0d623f7 5380//******************************************************************************
6d2010ae 5381// Approve usage of delayed child notification by PM.
b0d623f7 5382//******************************************************************************
1c79356b 5383
6d2010ae
A
5384bool IOPMrootDomain::shouldDelayChildNotification(
5385 IOService * service )
1c79356b 5386{
6d2010ae 5387 if (((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) != 0) &&
39236c6e 5388 (kFullWakeReasonNone == fullWakeReason) &&
6d2010ae
A
5389 (kSystemTransitionWake == _systemTransitionType))
5390 {
5391 DLOG("%s: delay child notify\n", service->getName());
5392 return true;
5393 }
5394 return false;
b0d623f7 5395}
0b4e3aa0 5396
b0d623f7 5397//******************************************************************************
6d2010ae 5398// PM actions for PCI device.
b0d623f7
A
5399//******************************************************************************
5400
6d2010ae 5401void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
39236c6e 5402 IOService * service,
fe8ab488 5403 IOPMActions * actions,
39236c6e
A
5404 IOPMPowerStateIndex powerState,
5405 IOPMPowerChangeFlags * inOutChangeFlags )
b0d623f7 5406{
6d2010ae
A
5407 pmTracer->tracePCIPowerChange(
5408 PMTraceWorker::kPowerChangeStart,
5409 service, *inOutChangeFlags,
5410 (actions->parameter & kPMActionsPCIBitNumberMask));
0b4e3aa0
A
5411}
5412
6d2010ae 5413void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
39236c6e 5414 IOService * service,
fe8ab488 5415 IOPMActions * actions,
39236c6e
A
5416 IOPMPowerStateIndex powerState,
5417 IOPMPowerChangeFlags changeFlags )
6d2010ae
A
5418{
5419 pmTracer->tracePCIPowerChange(
5420 PMTraceWorker::kPowerChangeCompleted,
5421 service, changeFlags,
5422 (actions->parameter & kPMActionsPCIBitNumberMask));
5423}
b0d623f7
A
5424
5425//******************************************************************************
6d2010ae 5426// registerInterest
0b4e3aa0 5427//
6d2010ae 5428// Override IOService::registerInterest() to intercept special clients.
b0d623f7 5429//******************************************************************************
0b4e3aa0 5430
fe8ab488
A
5431class IOPMServiceInterestNotifier: public _IOServiceInterestNotifier
5432{
5433
5434 friend class IOPMrootDomain;
5435 OSDeclareDefaultStructors(IOPMServiceInterestNotifier)
5436
5437protected:
5438 uint32_t ackTimeoutCnt;
5439
5440};
5441
5442OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier, _IOServiceInterestNotifier)
5443
6d2010ae
A
5444IONotifier * IOPMrootDomain::registerInterest(
5445 const OSSymbol * typeOfInterest,
5446 IOServiceInterestHandler handler,
5447 void * target, void * ref )
0b4e3aa0 5448{
fe8ab488 5449 IOPMServiceInterestNotifier *notifier = 0;
6d2010ae
A
5450 bool isSystemCapabilityClient;
5451 bool isKernelCapabilityClient;
fe8ab488 5452 IOReturn rc = kIOReturnError;;
2d21ac55 5453
6d2010ae
A
5454 isSystemCapabilityClient =
5455 typeOfInterest &&
5456 typeOfInterest->isEqualTo(kIOPMSystemCapabilityInterest);
5457
5458 isKernelCapabilityClient =
5459 typeOfInterest &&
5460 typeOfInterest->isEqualTo(gIOPriorityPowerStateInterest);
b0d623f7 5461
6d2010ae
A
5462 if (isSystemCapabilityClient)
5463 typeOfInterest = gIOAppPowerStateInterest;
5464
fe8ab488
A
5465 notifier = new IOPMServiceInterestNotifier;
5466 if (!notifier) return NULL;
5467
5468 if (notifier->init()) {
5469 rc = super::registerInterestForNotifer(notifier, typeOfInterest, handler, target, ref);
5470 }
5471 if (rc != kIOReturnSuccess) {
5472 notifier->release();
5473 notifier = 0;
5474 }
5475 if (pmPowerStateQueue)
b0d623f7 5476 {
fe8ab488 5477 notifier->ackTimeoutCnt = 0;
6d2010ae
A
5478 if (isSystemCapabilityClient)
5479 {
5480 notifier->retain();
5481 if (pmPowerStateQueue->submitPowerEvent(
5482 kPowerEventRegisterSystemCapabilityClient, notifier) == false)
5483 notifier->release();
5484 }
5485
5486 if (isKernelCapabilityClient)
5487 {
5488 notifier->retain();
5489 if (pmPowerStateQueue->submitPowerEvent(
5490 kPowerEventRegisterKernelCapabilityClient, notifier) == false)
5491 notifier->release();
5492 }
b0d623f7 5493 }
55e303ae 5494
6d2010ae
A
5495 return notifier;
5496}
0b4e3aa0 5497
6d2010ae
A
5498//******************************************************************************
5499// systemMessageFilter
5500//
5501//******************************************************************************
0b4e3aa0 5502
6d2010ae
A
5503bool IOPMrootDomain::systemMessageFilter(
5504 void * object, void * arg1, void * arg2, void * arg3 )
5505{
5506 const IOPMInterestContext * context = (const IOPMInterestContext *) arg1;
5507 bool isCapMsg = (context->messageType == kIOMessageSystemCapabilityChange);
5508 bool isCapClient = false;
5509 bool allow = false;
55e303ae 5510
6d2010ae
A
5511 do {
5512 if ((kSystemTransitionNewCapClient == _systemTransitionType) &&
5513 (!isCapMsg || !_joinedCapabilityClients ||
5514 !_joinedCapabilityClients->containsObject((OSObject *) object)))
5515 break;
5516
5517 // Capability change message for app and kernel clients.
5518
5519 if (isCapMsg)
55e303ae 5520 {
6d2010ae
A
5521 if ((context->notifyType == kNotifyPriority) ||
5522 (context->notifyType == kNotifyCapabilityChangePriority))
5523 isCapClient = true;
2d21ac55 5524
6d2010ae
A
5525 if ((context->notifyType == kNotifyCapabilityChangeApps) &&
5526 (object == (void *) systemCapabilityNotifier))
5527 isCapClient = true;
5528 }
2d21ac55 5529
6d2010ae
A
5530 if (isCapClient)
5531 {
5532 IOPMSystemCapabilityChangeParameters * capArgs =
5533 (IOPMSystemCapabilityChangeParameters *) arg2;
2d21ac55 5534
6d2010ae
A
5535 if (kSystemTransitionNewCapClient == _systemTransitionType)
5536 {
5537 capArgs->fromCapabilities = 0;
5538 capArgs->toCapabilities = _currentCapability;
5539 capArgs->changeFlags = 0;
5540 }
5541 else
5542 {
5543 capArgs->fromCapabilities = _currentCapability;
5544 capArgs->toCapabilities = _pendingCapability;
5545
5546 if (context->isPreChange)
5547 capArgs->changeFlags = kIOPMSystemCapabilityWillChange;
2d21ac55 5548 else
6d2010ae 5549 capArgs->changeFlags = kIOPMSystemCapabilityDidChange;
3e170ce0
A
5550
5551 if ((object == (void *) systemCapabilityNotifier) &&
5552 context->isPreChange)
5553 {
5554 toldPowerdCapWillChange = true;
5555 }
6d2010ae 5556 }
b0d623f7 5557
fe8ab488 5558 // Capability change messages only go to the PM configd plugin.
6d2010ae
A
5559 // Wait for response post-change if capabilitiy is increasing.
5560 // Wait for response pre-change if capability is decreasing.
2d21ac55 5561
6d2010ae
A
5562 if ((context->notifyType == kNotifyCapabilityChangeApps) && arg3 &&
5563 ( (capabilityLoss && context->isPreChange) ||
5564 (!capabilityLoss && !context->isPreChange) ) )
5565 {
5566 // app has not replied yet, wait for it
5567 *((OSObject **) arg3) = kOSBooleanFalse;
0b4e3aa0 5568 }
6d2010ae
A
5569
5570 allow = true;
5571 break;
0b4e3aa0 5572 }
b0d623f7 5573
6d2010ae 5574 // Capability client will always see kIOMessageCanSystemSleep,
39236c6e
A
5575 // even for demand sleep. It will also have a chance to veto
5576 // sleep one last time after all clients have responded to
5577 // kIOMessageSystemWillSleep
b0d623f7 5578
6d2010ae
A
5579 if ((kIOMessageCanSystemSleep == context->messageType) ||
5580 (kIOMessageSystemWillNotSleep == context->messageType))
b0d623f7 5581 {
6d2010ae 5582 if (object == (OSObject *) systemCapabilityNotifier)
b0d623f7 5583 {
6d2010ae
A
5584 allow = true;
5585 break;
5586 }
fe8ab488 5587
6d2010ae
A
5588 // Not idle sleep, don't ask apps.
5589 if (context->changeFlags & kIOPMSkipAskPowerDown)
5590 {
5591 break;
b0d623f7
A
5592 }
5593 }
6d2010ae 5594
39236c6e
A
5595 if (kIOPMMessageLastCallBeforeSleep == context->messageType)
5596 {
5597 if ((object == (OSObject *) systemCapabilityNotifier) &&
5598 CAP_HIGHEST(kIOPMSystemCapabilityGraphics) &&
5599 (fullToDarkReason == kIOPMSleepReasonIdle))
5600 allow = true;
5601 break;
5602 }
5603
5604 // Reject capability change messages for legacy clients.
6d2010ae
A
5605 // Reject legacy system sleep messages for capability client.
5606
5607 if (isCapMsg || (object == (OSObject *) systemCapabilityNotifier))
b0d623f7 5608 {
6d2010ae 5609 break;
b0d623f7 5610 }
2d21ac55 5611
6d2010ae 5612 // Filter system sleep messages.
0b4e3aa0 5613
6d2010ae 5614 if ((context->notifyType == kNotifyApps) &&
39236c6e 5615 (_systemMessageClientMask & kSystemMessageClientLegacyApp))
6d2010ae 5616 {
fe8ab488 5617 IOPMServiceInterestNotifier *notify;
6d2010ae 5618 allow = true;
fe8ab488
A
5619
5620 if ((notify = OSDynamicCast(IOPMServiceInterestNotifier, (OSObject *)object))
5621 && arg3) {
5622
5623 if (notify->ackTimeoutCnt >= 3)
5624 *((OSObject **) arg3) = kOSBooleanFalse;
5625 else
5626 *((OSObject **) arg3) = kOSBooleanTrue;
5627 }
6d2010ae
A
5628 }
5629 else if ((context->notifyType == kNotifyPriority) &&
5630 (_systemMessageClientMask & kSystemMessageClientKernel))
5631 {
5632 allow = true;
5633 }
5634 }
5635 while (false);
0b4e3aa0 5636
6d2010ae
A
5637 if (allow && isCapMsg && _joinedCapabilityClients)
5638 {
5639 _joinedCapabilityClients->removeObject((OSObject *) object);
5640 if (_joinedCapabilityClients->getCount() == 0)
5641 {
5642 DLOG("destroyed capability client set %p\n",
fe8ab488 5643 OBFUSCATE(_joinedCapabilityClients));
6d2010ae
A
5644 _joinedCapabilityClients->release();
5645 _joinedCapabilityClients = 0;
5646 }
5647 }
1c79356b 5648
6d2010ae 5649 return allow;
1c79356b
A
5650}
5651
b0d623f7 5652//******************************************************************************
6d2010ae 5653// setMaintenanceWakeCalendar
2d21ac55 5654//
b0d623f7 5655//******************************************************************************
2d21ac55 5656
6d2010ae
A
5657IOReturn IOPMrootDomain::setMaintenanceWakeCalendar(
5658 const IOPMCalendarStruct * calendar )
2d21ac55 5659{
6d2010ae 5660 OSData * data;
39236c6e 5661 IOReturn ret = 0;
2d21ac55 5662
6d2010ae
A
5663 if (!calendar)
5664 return kIOReturnBadArgument;
fe8ab488 5665
6d2010ae
A
5666 data = OSData::withBytesNoCopy((void *) calendar, sizeof(*calendar));
5667 if (!data)
5668 return kIOReturnNoMemory;
7ddcb079
A
5669
5670 if (kPMCalendarTypeMaintenance == calendar->selector) {
5671 ret = setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey, data);
99c3a104
A
5672 if (kIOReturnSuccess == ret)
5673 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake, &_scheduledAlarms);
fe8ab488 5674 } else
7ddcb079
A
5675 if (kPMCalendarTypeSleepService == calendar->selector)
5676 {
5677 ret = setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey, data);
99c3a104
A
5678 if (kIOReturnSuccess == ret)
5679 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake, &_scheduledAlarms);
7ddcb079 5680 }
99c3a104 5681 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms);
fe8ab488 5682
6d2010ae
A
5683 data->release();
5684 return ret;
5685}
2d21ac55 5686
6d2010ae
A
5687// MARK: -
5688// MARK: Display Wrangler
2d21ac55 5689
6d2010ae
A
5690//******************************************************************************
5691// displayWranglerNotification
5692//
5693// Handle the notification when the IODisplayWrangler changes power state.
5694//******************************************************************************
2d21ac55 5695
6d2010ae
A
5696IOReturn IOPMrootDomain::displayWranglerNotification(
5697 void * target, void * refCon,
5698 UInt32 messageType, IOService * service,
5699 void * messageArgument, vm_size_t argSize )
5700{
5701#if !NO_KERNEL_HID
5702 int displayPowerState;
5703 IOPowerStateChangeNotification * params =
5704 (IOPowerStateChangeNotification *) messageArgument;
2d21ac55 5705
6d2010ae
A
5706 if ((messageType != kIOMessageDeviceWillPowerOff) &&
5707 (messageType != kIOMessageDeviceHasPoweredOn))
5708 return kIOReturnUnsupported;
2d21ac55 5709
6d2010ae
A
5710 ASSERT_GATED();
5711 if (!gRootDomain)
5712 return kIOReturnUnsupported;
2d21ac55 5713
6d2010ae 5714 displayPowerState = params->stateNumber;
22ba694c
A
5715 DLOG("wrangler %s ps %d\n",
5716 getIOMessageString(messageType), displayPowerState);
2d21ac55 5717
6d2010ae
A
5718 switch (messageType) {
5719 case kIOMessageDeviceWillPowerOff:
6d2010ae
A
5720 // Display wrangler has dropped power due to display idle
5721 // or force system sleep.
5722 //
39236c6e
A
5723 // 4 Display ON kWranglerPowerStateMax
5724 // 3 Display Dim kWranglerPowerStateDim
5725 // 2 Display Sleep kWranglerPowerStateSleep
6d2010ae 5726 // 1 Not visible to user
39236c6e 5727 // 0 Not visible to user kWranglerPowerStateMin
6d2010ae 5728
39236c6e
A
5729 if (displayPowerState <= kWranglerPowerStateSleep)
5730 gRootDomain->evaluatePolicy( kStimulusDisplayWranglerSleep );
6d2010ae 5731 break;
2d21ac55 5732
6d2010ae 5733 case kIOMessageDeviceHasPoweredOn:
fe8ab488 5734 // Display wrangler has powered on due to user activity
6d2010ae 5735 // or wake from sleep.
b0d623f7 5736
39236c6e
A
5737 if (kWranglerPowerStateMax == displayPowerState)
5738 {
5739 gRootDomain->evaluatePolicy( kStimulusDisplayWranglerWake );
2d21ac55 5740
39236c6e
A
5741 // See comment in handleUpdatePowerClientForDisplayWrangler
5742 if (service->getPowerStateForClient(gIOPMPowerClientDevice) ==
5743 kWranglerPowerStateMax)
5744 {
22ba694c 5745 gRootDomain->evaluatePolicy( kStimulusEnterUserActiveState );
39236c6e
A
5746 }
5747 }
6d2010ae
A
5748 break;
5749 }
5750#endif
5751 return kIOReturnUnsupported;
b0d623f7
A
5752}
5753
13f56ec4 5754//******************************************************************************
6d2010ae 5755// displayWranglerMatchPublished
b0d623f7 5756//
6d2010ae
A
5757// Receives a notification when the IODisplayWrangler is published.
5758// When it's published we install a power state change handler.
b0d623f7
A
5759//******************************************************************************
5760
fe8ab488 5761bool IOPMrootDomain::displayWranglerMatchPublished(
99c3a104 5762 void * target,
6d2010ae
A
5763 void * refCon,
5764 IOService * newService,
5765 IONotifier * notifier __unused)
b0d623f7 5766{
6d2010ae
A
5767#if !NO_KERNEL_HID
5768 // found the display wrangler, now install a handler
fe8ab488
A
5769 if( !newService->registerInterest( gIOGeneralInterest,
5770 &displayWranglerNotification, target, 0) )
b0d623f7 5771 {
6d2010ae 5772 return false;
b0d623f7
A
5773 }
5774#endif
6d2010ae 5775 return true;
b0d623f7
A
5776}
5777
39236c6e
A
5778#if defined(__i386__) || defined(__x86_64__)
5779
fe8ab488 5780bool IOPMrootDomain::IONVRAMMatchPublished(
39236c6e
A
5781 void * target,
5782 void * refCon,
5783 IOService * newService,
5784 IONotifier * notifier)
5785{
5786 unsigned int len = 0;
5787 IOPMrootDomain *rd = (IOPMrootDomain *)target;
fe8ab488 5788 OSNumber *statusCode = NULL;
39236c6e
A
5789
5790 if (PEReadNVRAMProperty(kIOSleepWakeDebugKey, NULL, &len))
5791 {
fe8ab488
A
5792 statusCode = OSDynamicCast(OSNumber, rd->getProperty(kIOPMSleepWakeFailureCodeKey));
5793 if (statusCode != NULL) {
5794 if (statusCode->unsigned64BitValue() != 0) {
5795 rd->swd_flags |= SWD_BOOT_BY_SW_WDOG;
5796 MSG("System was rebooted due to Sleep/Wake failure\n");
5797 }
5798 else {
5799 rd->swd_flags |= SWD_BOOT_BY_OSX_WDOG;
5800 MSG("System was non-responsive and was rebooted by watchdog\n");
5801 }
39236c6e 5802 }
fe8ab488
A
5803
5804 rd->swd_logBufMap = rd->sleepWakeDebugRetrieve();
39236c6e
A
5805 }
5806 if (notifier) notifier->remove();
5807 return true;
5808}
5809
5810#else
fe8ab488 5811bool IOPMrootDomain::IONVRAMMatchPublished(
39236c6e
A
5812 void * target,
5813 void * refCon,
5814 IOService * newService,
5815 IONotifier * notifier __unused)
5816{
5817 return false;
5818}
5819
5820#endif
5821
6d2010ae
A
5822//******************************************************************************
5823// reportUserInput
5824//
5825//******************************************************************************
5826
5827void IOPMrootDomain::reportUserInput( void )
b0d623f7 5828{
6d2010ae
A
5829#if !NO_KERNEL_HID
5830 OSIterator * iter;
3e170ce0 5831 OSDictionary * matching;
b0d623f7 5832
fe8ab488 5833 if(!wrangler)
b0d623f7 5834 {
3e170ce0
A
5835 matching = serviceMatching("IODisplayWrangler");
5836 iter = getMatchingServices(matching);
5837 if (matching) matching->release();
fe8ab488 5838 if(iter)
6d2010ae
A
5839 {
5840 wrangler = (IOService *) iter->getNextObject();
5841 iter->release();
5842 }
b0d623f7
A
5843 }
5844
6d2010ae
A
5845 if(wrangler)
5846 wrangler->activityTickle(0,0);
b0d623f7 5847#endif
2d21ac55
A
5848}
5849
13f56ec4 5850//******************************************************************************
39236c6e 5851// latchDisplayWranglerTickle
13f56ec4
A
5852//******************************************************************************
5853
5854bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch )
5855{
5856#if !NO_KERNEL_HID
5857 if (latch)
5858 {
13f56ec4
A
5859 if (!(_currentCapability & kIOPMSystemCapabilityGraphics) &&
5860 !(_pendingCapability & kIOPMSystemCapabilityGraphics) &&
5861 !checkSystemCanSustainFullWake())
5862 {
fe8ab488
A
5863 // Currently in dark wake, and not transitioning to full wake.
5864 // Full wake is unsustainable, so latch the tickle to prevent
5865 // the display from lighting up momentarily.
13f56ec4
A
5866 wranglerTickleLatched = true;
5867 }
5868 else
5869 {
5870 wranglerTickleLatched = false;
5871 }
5872 }
5873 else if (wranglerTickleLatched && checkSystemCanSustainFullWake())
5874 {
5875 wranglerTickleLatched = false;
5876
5877 pmPowerStateQueue->submitPowerEvent(
5878 kPowerEventPolicyStimulus,
5879 (void *) kStimulusDarkWakeActivityTickle );
5880 }
5881
5882 return wranglerTickleLatched;
5883#else
5884 return false;
5885#endif
5886}
5887
39236c6e
A
5888//******************************************************************************
5889// setDisplayPowerOn
5890//
5891// For root domain user client
5892//******************************************************************************
5893
5894void IOPMrootDomain::setDisplayPowerOn( uint32_t options )
5895{
3e170ce0
A
5896 pmPowerStateQueue->submitPowerEvent( kPowerEventSetDisplayPowerOn,
5897 (void *) 0, options );
39236c6e
A
5898}
5899
6d2010ae
A
5900// MARK: -
5901// MARK: Battery
2d21ac55 5902
b0d623f7 5903//******************************************************************************
6d2010ae 5904// batteryPublished
1c79356b 5905//
6d2010ae 5906// Notification on battery class IOPowerSource appearance
b0d623f7 5907//******************************************************************************
1c79356b 5908
fe8ab488
A
5909bool IOPMrootDomain::batteryPublished(
5910 void * target,
6d2010ae
A
5911 void * root_domain,
5912 IOService * resourceService,
5913 IONotifier * notifier __unused )
fe8ab488
A
5914{
5915 // rdar://2936060&4435589
6d2010ae
A
5916 // All laptops have dimmable LCD displays
5917 // All laptops have batteries
5918 // So if this machine has a battery, publish the fact that the backlight
5919 // supports dimming.
5920 ((IOPMrootDomain *)root_domain)->publishFeature("DisplayDims");
b0d623f7 5921
6d2010ae
A
5922 return (true);
5923}
b0d623f7 5924
6d2010ae
A
5925// MARK: -
5926// MARK: System PM Policy
0c530ab8 5927
6d2010ae 5928//******************************************************************************
39236c6e 5929// checkSystemSleepAllowed
6d2010ae
A
5930//
5931//******************************************************************************
0b4c1975 5932
39236c6e
A
5933bool IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options,
5934 uint32_t sleepReason )
6d2010ae
A
5935{
5936 int err = 0;
b0d623f7 5937
6d2010ae 5938 // Conditions that prevent idle and demand system sleep.
b0d623f7 5939
6d2010ae
A
5940 do {
5941 if (userDisabledAllSleep)
5942 {
5943 err = 1; // 1. user-space sleep kill switch
5944 break;
5945 }
b0d623f7 5946
39236c6e 5947 if (systemBooting || systemShutdown || gWillShutdown)
6d2010ae
A
5948 {
5949 err = 2; // 2. restart or shutdown in progress
5950 break;
5951 }
b0d623f7 5952
6d2010ae
A
5953 if (options == 0)
5954 break;
0b4c1975 5955
6d2010ae
A
5956 // Conditions above pegs the system at full wake.
5957 // Conditions below prevent system sleep but does not prevent
5958 // dark wake, and must be called from gated context.
b0d623f7 5959
6d2010ae
A
5960#if !CONFIG_SLEEP
5961 err = 3; // 3. config does not support sleep
5962 break;
b0d623f7 5963#endif
b0d623f7 5964
a1c7dba1 5965 if (lowBatteryCondition || thermalWarningState)
6d2010ae 5966 {
a1c7dba1 5967 break; // always sleep on low battery or when in thermal warning state
6d2010ae 5968 }
b0d623f7 5969
39236c6e 5970 if (sleepReason == kIOPMSleepReasonDarkWakeThermalEmergency)
316670eb
A
5971 {
5972 break; // always sleep on dark wake thermal emergencies
5973 }
5974
5975 if (preventSystemSleepList->getCount() != 0)
6d2010ae
A
5976 {
5977 err = 4; // 4. child prevent system sleep clamp
b0d623f7 5978 break;
6d2010ae 5979 }
1c79356b 5980
6d2010ae
A
5981 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit ) ==
5982 kIOPMDriverAssertionLevelOn)
5983 {
5984 err = 5; // 5. CPU assertion
5985 break;
5986 }
1c79356b 5987
6d2010ae
A
5988 if (pciCantSleepValid)
5989 {
5990 if (pciCantSleepFlag)
5991 err = 6; // 6. PCI card does not support PM (cached)
5992 break;
5993 }
5994 else if (sleepSupportedPEFunction &&
5995 CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
39236c6e 5996 {
6d2010ae
A
5997 IOReturn ret;
5998 OSBitAndAtomic(~kPCICantSleep, &platformSleepSupport);
5999 ret = getPlatform()->callPlatformFunction(
6000 sleepSupportedPEFunction, false,
6001 NULL, NULL, NULL, NULL);
6002 pciCantSleepValid = true;
6003 pciCantSleepFlag = false;
6004 if ((platformSleepSupport & kPCICantSleep) ||
6005 ((ret != kIOReturnSuccess) && (ret != kIOReturnUnsupported)))
6006 {
6007 err = 6; // 6. PCI card does not support PM
6008 pciCantSleepFlag = true;
6009 break;
6010 }
6011 }
6012 }
6013 while (false);
b0d623f7 6014
6d2010ae
A
6015 if (err)
6016 {
6017 DLOG("System sleep prevented by %d\n", err);
6018 return false;
6019 }
6020 return true;
1c79356b
A
6021}
6022
39236c6e
A
6023bool IOPMrootDomain::checkSystemSleepEnabled( void )
6024{
6025 return checkSystemSleepAllowed(0, 0);
6026}
6027
6028bool IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason )
6029{
6030 ASSERT_GATED();
6031 return checkSystemSleepAllowed(1, sleepReason);
6032}
6033
13f56ec4
A
6034//******************************************************************************
6035// checkSystemCanSustainFullWake
6036//******************************************************************************
6037
6038bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
6039{
6040#if !NO_KERNEL_HID
a1c7dba1 6041 if (lowBatteryCondition || thermalWarningState)
13f56ec4
A
6042 {
6043 // Low battery wake, or received a low battery notification
fe8ab488
A
6044 // while system is awake. This condition will persist until
6045 // the following wake.
13f56ec4
A
6046 return false;
6047 }
6048
39236c6e 6049 if (clamshellExists && clamshellClosed && !clamshellSleepDisabled)
13f56ec4 6050 {
fe8ab488
A
6051 // Graphics state is unknown and external display might not be probed.
6052 // Do not incorporate state that requires graphics to be in max power
6053 // such as desktopMode or clamshellDisabled.
6054
39236c6e
A
6055 if (!acAdaptorConnected)
6056 {
6057 DLOG("full wake check: no AC\n");
6058 return false;
6059 }
13f56ec4
A
6060 }
6061#endif
6062 return true;
6063}
6064
b0d623f7 6065//******************************************************************************
6d2010ae 6066// adjustPowerState
0b4e3aa0 6067//
6d2010ae
A
6068// Conditions that affect our wake/sleep decision has changed.
6069// If conditions dictate that the system must remain awake, clamp power
6070// state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
6071// is TRUE, then remove the power clamp and allow the power state to drop
6072// to SLEEP_STATE.
b0d623f7 6073//******************************************************************************
1c79356b 6074
6d2010ae 6075void IOPMrootDomain::adjustPowerState( bool sleepASAP )
1c79356b 6076{
6d2010ae
A
6077 DLOG("adjustPowerState ps %u, asap %d, slider %ld\n",
6078 (uint32_t) getPowerState(), sleepASAP, sleepSlider);
b0d623f7 6079
6d2010ae 6080 ASSERT_GATED();
b0d623f7 6081
39236c6e 6082 if ((sleepSlider == 0) || !checkSystemSleepEnabled())
2d21ac55 6083 {
6d2010ae
A
6084 changePowerStateToPriv(ON_STATE);
6085 }
6086 else if ( sleepASAP )
6087 {
6088 changePowerStateToPriv(SLEEP_STATE);
2d21ac55 6089 }
1c79356b
A
6090}
6091
3e170ce0
A
6092void IOPMrootDomain::handleDisplayPowerOn( )
6093{
6094 if (!wrangler) return;
6095 if (displayPowerOnRequested)
6096 {
6097 if (!checkSystemCanSustainFullWake()) return;
6098
6099 // Force wrangler to max power state. If system is in dark wake
6100 // this alone won't raise the wrangler's power state.
6101
6102 wrangler->changePowerStateForRootDomain(kWranglerPowerStateMax);
6103
6104 // System in dark wake, always requesting full wake should
6105 // not have any bad side-effects, even if the request fails.
6106
6107 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics))
6108 {
6109 setProperty(kIOPMRootDomainWakeTypeKey, kIOPMRootDomainWakeTypeNotification);
6110 requestFullWake( kFullWakeReasonDisplayOn );
6111 }
6112 }
6113 else
6114 {
6115 // Relenquish desire to power up display.
6116 // Must first transition to state 1 since wrangler doesn't
6117 // power off the displays at state 0. At state 0 the root
6118 // domain is removed from the wrangler's power client list.
6119
6120 wrangler->changePowerStateForRootDomain(kWranglerPowerStateMin + 1);
6121 wrangler->changePowerStateForRootDomain(kWranglerPowerStateMin);
6122
6123 }
6124
6125}
6126
b0d623f7 6127//******************************************************************************
6d2010ae 6128// dispatchPowerEvent
1c79356b 6129//
6d2010ae 6130// IOPMPowerStateQueue callback function. Running on PM work loop thread.
b0d623f7 6131//******************************************************************************
1c79356b 6132
6d2010ae
A
6133void IOPMrootDomain::dispatchPowerEvent(
6134 uint32_t event, void * arg0, uint64_t arg1 )
1c79356b 6135{
fe8ab488 6136 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6d2010ae 6137 ASSERT_GATED();
b0d623f7 6138
6d2010ae 6139 switch (event)
55e303ae 6140 {
6d2010ae
A
6141 case kPowerEventFeatureChanged:
6142 messageClients(kIOPMMessageFeatureChange, this);
6143 break;
0b4c1975 6144
6d2010ae
A
6145 case kPowerEventReceivedPowerNotification:
6146 handlePowerNotification( (UInt32)(uintptr_t) arg0 );
6147 break;
fe8ab488 6148
6d2010ae
A
6149 case kPowerEventSystemBootCompleted:
6150 if (systemBooting)
b0d623f7 6151 {
6d2010ae 6152 systemBooting = false;
b0d623f7 6153
99c3a104
A
6154 if (lowBatteryCondition)
6155 {
6156 privateSleepSystem (kIOPMSleepReasonLowPower);
6157
6158 // The rest is unnecessary since the system is expected
6159 // to sleep immediately. The following wake will update
6160 // everything.
6161 break;
6162 }
6163
39236c6e 6164 if (swd_flags & SWD_VALID_LOGS) {
fe8ab488
A
6165 if (swd_flags & SWD_LOGS_IN_MEM) {
6166 sleepWakeDebugDumpFromMem(swd_logBufMap);
6167 swd_logBufMap->release();
6168 swd_logBufMap = 0;
6169 }
6170 else if (swd_flags & SWD_LOGS_IN_FILE)
6171 sleepWakeDebugDumpFromFile();
39236c6e 6172 }
fe8ab488
A
6173 else if (swd_flags & (SWD_BOOT_BY_SW_WDOG|SWD_BOOT_BY_OSX_WDOG)) {
6174 // If logs are invalid, write the failure code
6175 sleepWakeDebugDumpFromMem(NULL);
39236c6e 6176 }
6d2010ae
A
6177 // If lid is closed, re-send lid closed notification
6178 // now that booting is complete.
6179 if ( clamshellClosed )
6180 {
6181 handlePowerNotification(kLocalEvalClamshellCommand);
6182 }
6183 evaluatePolicy( kStimulusAllowSystemSleepChanged );
39236c6e 6184
6d2010ae
A
6185 }
6186 break;
b0d623f7 6187
6d2010ae
A
6188 case kPowerEventSystemShutdown:
6189 if (kOSBooleanTrue == (OSBoolean *) arg0)
6190 {
6191 /* We set systemShutdown = true during shutdown
6192 to prevent sleep at unexpected times while loginwindow is trying
6193 to shutdown apps and while the OS is trying to transition to
6194 complete power of.
fe8ab488 6195
6d2010ae
A
6196 Set to true during shutdown, as soon as loginwindow shows
6197 the "shutdown countdown dialog", through individual app
6198 termination, and through black screen kernel shutdown.
6199 */
6200 systemShutdown = true;
6201 } else {
6202 /*
6203 A shutdown was initiated, but then the shutdown
6204 was cancelled, clearing systemShutdown to false here.
6205 */
fe8ab488 6206 systemShutdown = false;
6d2010ae
A
6207 }
6208 break;
1c79356b 6209
6d2010ae
A
6210 case kPowerEventUserDisabledSleep:
6211 userDisabledAllSleep = (kOSBooleanTrue == (OSBoolean *) arg0);
6212 break;
b0d623f7 6213
6d2010ae
A
6214 case kPowerEventRegisterSystemCapabilityClient:
6215 if (systemCapabilityNotifier)
6216 {
6217 systemCapabilityNotifier->release();
6218 systemCapabilityNotifier = 0;
6219 }
6220 if (arg0)
6221 {
6222 systemCapabilityNotifier = (IONotifier *) arg0;
6223 systemCapabilityNotifier->retain();
6224 }
6225 /* intentional fall-through */
0b4e3aa0 6226
6d2010ae
A
6227 case kPowerEventRegisterKernelCapabilityClient:
6228 if (!_joinedCapabilityClients)
6229 _joinedCapabilityClients = OSSet::withCapacity(8);
6230 if (arg0)
6231 {
6232 IONotifier * notify = (IONotifier *) arg0;
6233 if (_joinedCapabilityClients)
6234 {
6235 _joinedCapabilityClients->setObject(notify);
6236 synchronizePowerTree( kIOPMSyncNoChildNotify );
6237 }
6238 notify->release();
6239 }
6240 break;
1c79356b 6241
6d2010ae
A
6242 case kPowerEventPolicyStimulus:
6243 if (arg0)
6244 {
6245 int stimulus = (uintptr_t) arg0;
6246 evaluatePolicy( stimulus, (uint32_t) arg1 );
6247 }
6248 break;
0b4e3aa0 6249
6d2010ae
A
6250 case kPowerEventAssertionCreate:
6251 if (pmAssertions) {
6252 pmAssertions->handleCreateAssertion((OSData *)arg0);
6253 }
6254 break;
0b4e3aa0 6255
b0d623f7 6256
6d2010ae
A
6257 case kPowerEventAssertionRelease:
6258 if (pmAssertions) {
6259 pmAssertions->handleReleaseAssertion(arg1);
6260 }
6261 break;
0b4e3aa0 6262
6d2010ae
A
6263 case kPowerEventAssertionSetLevel:
6264 if (pmAssertions) {
6265 pmAssertions->handleSetAssertionLevel(arg1, (IOPMDriverAssertionLevel)(uintptr_t)arg0);
6266 }
6267 break;
fe8ab488 6268
6d2010ae
A
6269 case kPowerEventQueueSleepWakeUUID:
6270 handleQueueSleepWakeUUID((OSObject *)arg0);
6271 break;
6272 case kPowerEventPublishSleepWakeUUID:
6273 handlePublishSleepWakeUUID((bool)arg0);
6274 break;
fe8ab488 6275
39236c6e
A
6276 case kPowerEventSetDisplayPowerOn:
6277 if (!wrangler) break;
6278 if (arg1 != 0)
6279 {
3e170ce0 6280 displayPowerOnRequested = true;
39236c6e
A
6281 }
6282 else
6283 {
3e170ce0 6284 displayPowerOnRequested = false;
39236c6e 6285 }
3e170ce0 6286 handleDisplayPowerOn();
39236c6e 6287 break;
6d2010ae 6288 }
0b4e3aa0
A
6289}
6290
b0d623f7 6291//******************************************************************************
6d2010ae
A
6292// systemPowerEventOccurred
6293//
6294// The power controller is notifying us of a hardware-related power management
fe8ab488 6295// event that we must handle.
0b4e3aa0 6296//
6d2010ae
A
6297// systemPowerEventOccurred covers the same functionality that
6298// receivePowerNotification does; it simply provides a richer API for conveying
6299// more information.
b0d623f7
A
6300//******************************************************************************
6301
6d2010ae
A
6302IOReturn IOPMrootDomain::systemPowerEventOccurred(
6303 const OSSymbol *event,
6304 uint32_t intValue)
b0d623f7 6305{
6d2010ae
A
6306 IOReturn attempt = kIOReturnSuccess;
6307 OSNumber *newNumber = NULL;
6308
fe8ab488 6309 if (!event)
6d2010ae 6310 return kIOReturnBadArgument;
fe8ab488 6311
6d2010ae
A
6312 newNumber = OSNumber::withNumber(intValue, 8*sizeof(intValue));
6313 if (!newNumber)
6314 return kIOReturnInternalError;
b0d623f7 6315
6d2010ae 6316 attempt = systemPowerEventOccurred(event, (OSObject *)newNumber);
b0d623f7 6317
6d2010ae 6318 newNumber->release();
b0d623f7 6319
6d2010ae 6320 return attempt;
b0d623f7
A
6321}
6322
a1c7dba1
A
6323void IOPMrootDomain::setThermalState(OSObject *value)
6324{
6325 OSNumber * num;
6326
6327 if (gIOPMWorkLoop->inGate() == false) {
6328 gIOPMWorkLoop->runAction(
6329 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::setThermalState),
6330 (OSObject *)this,
6331 (void *)value);
6332
6333 return;
6334 }
6335 if (value && (num = OSDynamicCast(OSNumber, value))) {
6336 thermalWarningState = ((num->unsigned32BitValue() == kIOPMThermalLevelWarning) ||
6337 (num->unsigned32BitValue() == kIOPMThermalLevelTrap)) ? 1 : 0;
6338 }
6339}
6340
6d2010ae
A
6341IOReturn IOPMrootDomain::systemPowerEventOccurred(
6342 const OSSymbol *event,
6343 OSObject *value)
b0d623f7 6344{
6d2010ae
A
6345 OSDictionary *thermalsDict = NULL;
6346 bool shouldUpdate = true;
fe8ab488
A
6347
6348 if (!event || !value)
6d2010ae 6349 return kIOReturnBadArgument;
b0d623f7 6350
6d2010ae
A
6351 // LOCK
6352 // We reuse featuresDict Lock because it already exists and guards
6353 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
6354 // of stepping on that lock.
6355 if (featuresDictLock) IOLockLock(featuresDictLock);
b0d623f7 6356
6d2010ae 6357 thermalsDict = (OSDictionary *)getProperty(kIOPMRootDomainPowerStatusKey);
fe8ab488 6358
6d2010ae 6359 if (thermalsDict && OSDynamicCast(OSDictionary, thermalsDict)) {
fe8ab488 6360 thermalsDict = OSDictionary::withDictionary(thermalsDict);
6d2010ae
A
6361 } else {
6362 thermalsDict = OSDictionary::withCapacity(1);
6363 }
b0d623f7 6364
6d2010ae
A
6365 if (!thermalsDict) {
6366 shouldUpdate = false;
6367 goto exit;
b0d623f7
A
6368 }
6369
6d2010ae 6370 thermalsDict->setObject (event, value);
b0d623f7 6371
6d2010ae 6372 setProperty (kIOPMRootDomainPowerStatusKey, thermalsDict);
0b4c1975 6373
6d2010ae 6374 thermalsDict->release();
0b4c1975 6375
6d2010ae
A
6376exit:
6377 // UNLOCK
6378 if (featuresDictLock) IOLockUnlock(featuresDictLock);
0b4c1975 6379
a1c7dba1
A
6380 if (shouldUpdate) {
6381 if (event &&
6382 event->isEqualTo(kIOPMThermalLevelWarningKey)) {
6383 setThermalState(value);
6384 }
6d2010ae 6385 messageClients (kIOPMMessageSystemPowerEventOccurred, (void *)NULL);
a1c7dba1 6386 }
0b4c1975 6387
6d2010ae 6388 return kIOReturnSuccess;
0b4c1975 6389}
b0d623f7
A
6390
6391//******************************************************************************
6d2010ae 6392// receivePowerNotification
b0d623f7 6393//
6d2010ae
A
6394// The power controller is notifying us of a hardware-related power management
6395// event that we must handle. This may be a result of an 'environment' interrupt
6396// from the power mgt micro.
b0d623f7
A
6397//******************************************************************************
6398
6d2010ae 6399IOReturn IOPMrootDomain::receivePowerNotification( UInt32 msg )
b0d623f7 6400{
6d2010ae 6401 pmPowerStateQueue->submitPowerEvent(
39236c6e 6402 kPowerEventReceivedPowerNotification, (void *)(uintptr_t) msg );
6d2010ae 6403 return kIOReturnSuccess;
b0d623f7
A
6404}
6405
6d2010ae
A
6406void IOPMrootDomain::handlePowerNotification( UInt32 msg )
6407{
6408 bool eval_clamshell = false;
b0d623f7 6409
6d2010ae 6410 ASSERT_GATED();
b0d623f7 6411
6d2010ae
A
6412 /*
6413 * Local (IOPMrootDomain only) eval clamshell command
6414 */
6415 if (msg & kLocalEvalClamshellCommand)
6416 {
6417 eval_clamshell = true;
6418 }
b0d623f7 6419
6d2010ae
A
6420 /*
6421 * Overtemp
6422 */
6423 if (msg & kIOPMOverTemp)
b0d623f7 6424 {
6d2010ae
A
6425 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
6426 privateSleepSystem (kIOPMSleepReasonThermalEmergency);
b0d623f7
A
6427 }
6428
39236c6e 6429 /*
3e170ce0 6430 * Forward DW thermal notification to client, if system is not going to sleep
39236c6e 6431 */
3e170ce0 6432 if ((msg & kIOPMDWOverTemp) && (_systemTransitionType != kSystemTransitionSleep))
316670eb 6433 {
39236c6e
A
6434 DLOG("DarkWake thermal limits message received!\n");
6435
39236c6e 6436 messageClients(kIOPMMessageDarkWakeThermalEmergency);
316670eb
A
6437 }
6438
6d2010ae
A
6439 /*
6440 * Sleep Now!
6441 */
fe8ab488 6442 if (msg & kIOPMSleepNow)
b0d623f7 6443 {
6d2010ae
A
6444 privateSleepSystem (kIOPMSleepReasonSoftware);
6445 }
fe8ab488 6446
6d2010ae
A
6447 /*
6448 * Power Emergency
6449 */
fe8ab488 6450 if (msg & kIOPMPowerEmergency)
6d2010ae
A
6451 {
6452 lowBatteryCondition = true;
6453 privateSleepSystem (kIOPMSleepReasonLowPower);
b0d623f7
A
6454 }
6455
6d2010ae
A
6456 /*
6457 * Clamshell OPEN
6458 */
fe8ab488 6459 if (msg & kIOPMClamshellOpened)
b0d623f7 6460 {
6d2010ae
A
6461 // Received clamshel open message from clamshell controlling driver
6462 // Update our internal state and tell general interest clients
6463 clamshellClosed = false;
6464 clamshellExists = true;
6465
13f56ec4 6466 // Don't issue a hid tickle when lid is open and polled on wake
6d2010ae 6467 if (msg & kIOPMSetValue)
b0d623f7 6468 {
316670eb 6469 setProperty(kIOPMRootDomainWakeTypeKey, "Lid Open");
6d2010ae
A
6470 reportUserInput();
6471 }
b0d623f7 6472
6d2010ae
A
6473 // Tell PMCPU
6474 informCPUStateChange(kInformLid, 0);
b0d623f7 6475
fe8ab488 6476 // Tell general interest clients
6d2010ae 6477 sendClientClamshellNotification();
b0d623f7 6478
6d2010ae 6479 bool aborting = ((lastSleepReason == kIOPMSleepReasonClamshell)
fe8ab488 6480 || (lastSleepReason == kIOPMSleepReasonIdle)
0b4c1975
A
6481 || (lastSleepReason == kIOPMSleepReasonMaintenance));
6482 if (aborting) userActivityCount++;
6d2010ae 6483 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount, lastSleepReason);
13f56ec4 6484 }
b0d623f7 6485
fe8ab488 6486 /*
6d2010ae 6487 * Clamshell CLOSED
fe8ab488 6488 * Send the clamshell interest notification since the lid is closing.
6d2010ae
A
6489 */
6490 if (msg & kIOPMClamshellClosed)
b0d623f7 6491 {
6d2010ae
A
6492 // Received clamshel open message from clamshell controlling driver
6493 // Update our internal state and tell general interest clients
6494 clamshellClosed = true;
6495 clamshellExists = true;
b0d623f7 6496
6d2010ae
A
6497 // Tell PMCPU
6498 informCPUStateChange(kInformLid, 1);
b0d623f7 6499
6d2010ae
A
6500 // Tell general interest clients
6501 sendClientClamshellNotification();
fe8ab488
A
6502
6503 // And set eval_clamshell = so we can attempt
6d2010ae
A
6504 eval_clamshell = true;
6505 }
b0d623f7 6506
6d2010ae
A
6507 /*
6508 * Set Desktop mode (sent from graphics)
6509 *
6510 * -> reevaluate lid state
6511 */
fe8ab488 6512 if (msg & kIOPMSetDesktopMode)
6d2010ae
A
6513 {
6514 desktopMode = (0 != (msg & kIOPMSetValue));
6515 msg &= ~(kIOPMSetDesktopMode | kIOPMSetValue);
b0d623f7 6516
6d2010ae 6517 sendClientClamshellNotification();
b0d623f7 6518
6d2010ae 6519 // Re-evaluate the lid state
39236c6e 6520 eval_clamshell = true;
6d2010ae 6521 }
fe8ab488 6522
6d2010ae
A
6523 /*
6524 * AC Adaptor connected
6525 *
6526 * -> reevaluate lid state
6527 */
fe8ab488 6528 if (msg & kIOPMSetACAdaptorConnected)
6d2010ae
A
6529 {
6530 acAdaptorConnected = (0 != (msg & kIOPMSetValue));
6531 msg &= ~(kIOPMSetACAdaptorConnected | kIOPMSetValue);
b0d623f7 6532
6d2010ae
A
6533 // Tell CPU PM
6534 informCPUStateChange(kInformAC, !acAdaptorConnected);
b0d623f7 6535
6d2010ae
A
6536 // Tell BSD if AC is connected
6537 // 0 == external power source; 1 == on battery
6538 post_sys_powersource(acAdaptorConnected ? 0:1);
b0d623f7 6539
6d2010ae
A
6540 sendClientClamshellNotification();
6541
6542 // Re-evaluate the lid state
39236c6e 6543 eval_clamshell = true;
13f56ec4
A
6544
6545 // Lack of AC may have latched a display wrangler tickle.
6546 // This mirrors the hardware's USB wake event latch, where a latched
6547 // USB wake event followed by an AC attach will trigger a full wake.
6548 latchDisplayWranglerTickle( false );
316670eb
A
6549
6550#if HIBERNATION
6551 // AC presence will reset the standy timer delay adjustment.
6552 _standbyTimerResetSeconds = 0;
6553#endif
39236c6e
A
6554 if (!userIsActive) {
6555 // Reset userActivityTime when power supply is changed(rdr 13789330)
6556 clock_get_uptime(&userActivityTime);
6557 }
b0d623f7 6558 }
fe8ab488 6559
6d2010ae
A
6560 /*
6561 * Enable Clamshell (external display disappear)
6562 *
6563 * -> reevaluate lid state
6564 */
fe8ab488 6565 if (msg & kIOPMEnableClamshell)
b0d623f7 6566 {
6d2010ae
A
6567 // Re-evaluate the lid state
6568 // System should sleep on external display disappearance
6569 // in lid closed operation.
39236c6e 6570 if (true == clamshellDisabled)
6d2010ae
A
6571 {
6572 eval_clamshell = true;
6573 }
b0d623f7 6574
6d2010ae 6575 clamshellDisabled = false;
6d2010ae 6576 sendClientClamshellNotification();
b0d623f7 6577 }
fe8ab488 6578
6d2010ae
A
6579 /*
6580 * Disable Clamshell (external display appeared)
6581 * We don't bother re-evaluating clamshell state. If the system is awake,
fe8ab488 6582 * the lid is probably open.
6d2010ae 6583 */
fe8ab488 6584 if (msg & kIOPMDisableClamshell)
6d2010ae
A
6585 {
6586 clamshellDisabled = true;
6d2010ae
A
6587 sendClientClamshellNotification();
6588 }
b0d623f7 6589
6d2010ae
A
6590 /*
6591 * Evaluate clamshell and SLEEP if appropiate
6592 */
39236c6e 6593 if (eval_clamshell && clamshellClosed)
b0d623f7 6594 {
39236c6e
A
6595 if (shouldSleepOnClamshellClosed())
6596 privateSleepSystem (kIOPMSleepReasonClamshell);
6597 else
6598 evaluatePolicy( kStimulusDarkWakeEvaluate );
6d2010ae 6599 }
b0d623f7 6600
6d2010ae
A
6601 /*
6602 * Power Button
6603 */
fe8ab488 6604 if (msg & kIOPMPowerButton)
6d2010ae
A
6605 {
6606 if (!wranglerAsleep)
b0d623f7 6607 {
6d2010ae
A
6608 OSString *pbs = OSString::withCString("DisablePowerButtonSleep");
6609 // Check that power button sleep is enabled
6610 if( pbs ) {
6611 if( kOSBooleanTrue != getProperty(pbs))
6612 privateSleepSystem (kIOPMSleepReasonPowerButton);
b0d623f7
A
6613 }
6614 }
6615 else
6d2010ae 6616 reportUserInput();
b0d623f7 6617 }
0b4e3aa0
A
6618}
6619
b0d623f7 6620//******************************************************************************
6d2010ae 6621// evaluatePolicy
0b4e3aa0 6622//
6d2010ae 6623// Evaluate root-domain policy in response to external changes.
b0d623f7 6624//******************************************************************************
0b4e3aa0 6625
6d2010ae 6626void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
0b4e3aa0 6627{
6d2010ae
A
6628 union {
6629 struct {
6630 int idleSleepEnabled : 1;
6631 int idleSleepDisabled : 1;
6632 int displaySleep : 1;
6633 int sleepDelayChanged : 1;
6634 int evaluateDarkWake : 1;
316670eb 6635 int adjustPowerState : 1;
39236c6e 6636 int userBecameInactive : 1;
6d2010ae
A
6637 } bit;
6638 uint32_t u32;
6639 } flags;
6640
6641 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
fa4905b1 6642
6d2010ae
A
6643 ASSERT_GATED();
6644 flags.u32 = 0;
b0d623f7 6645
6d2010ae 6646 switch (stimulus)
b0d623f7 6647 {
6d2010ae
A
6648 case kStimulusDisplayWranglerSleep:
6649 if (!wranglerAsleep)
b0d623f7 6650 {
39236c6e 6651 // first transition to wrangler sleep or lower
6d2010ae 6652 wranglerAsleep = true;
6d2010ae 6653 flags.bit.displaySleep = true;
b0d623f7 6654 }
6d2010ae 6655 break;
b0d623f7 6656
6d2010ae 6657 case kStimulusDisplayWranglerWake:
39236c6e 6658 displayIdleForDemandSleep = false;
6d2010ae 6659 wranglerAsleep = false;
39236c6e
A
6660 break;
6661
22ba694c
A
6662 case kStimulusEnterUserActiveState:
6663 if (_preventUserActive)
6664 {
6665 DLOG("user active dropped\n");
6666 break;
6667 }
39236c6e
A
6668 if (!userIsActive)
6669 {
6670 userIsActive = true;
6671 userWasActive = true;
22ba694c 6672
39236c6e
A
6673 // Stay awake after dropping demand for display power on
6674 if (kFullWakeReasonDisplayOn == fullWakeReason)
6675 fullWakeReason = fFullWakeReasonDisplayOnAndLocalUser;
6676
6677 setProperty(gIOPMUserIsActiveKey, kOSBooleanTrue);
6678 messageClients(kIOPMMessageUserIsActiveChanged);
6679 }
6d2010ae
A
6680 flags.bit.idleSleepDisabled = true;
6681 break;
0b4e3aa0 6682
22ba694c 6683 case kStimulusLeaveUserActiveState:
39236c6e
A
6684 if (userIsActive)
6685 {
6686 userIsActive = false;
6687 clock_get_uptime(&userBecameInactiveTime);
6688 flags.bit.userBecameInactive = true;
6689
6690 setProperty(gIOPMUserIsActiveKey, kOSBooleanFalse);
6691 messageClients(kIOPMMessageUserIsActiveChanged);
6692 }
6693 break;
6694
6d2010ae
A
6695 case kStimulusAggressivenessChanged:
6696 {
6697 unsigned long minutesToIdleSleep = 0;
6698 unsigned long minutesToDisplayDim = 0;
6699 unsigned long minutesDelta = 0;
0b4e3aa0 6700
6d2010ae
A
6701 // Fetch latest display and system sleep slider values.
6702 getAggressiveness(kPMMinutesToSleep, &minutesToIdleSleep);
6703 getAggressiveness(kPMMinutesToDim, &minutesToDisplayDim);
6704 DLOG("aggressiveness changed: system %u->%u, display %u\n",
6705 (uint32_t) sleepSlider,
6706 (uint32_t) minutesToIdleSleep,
6707 (uint32_t) minutesToDisplayDim);
b0d623f7 6708
6d2010ae
A
6709 DLOG("idle time -> %ld secs (ena %d)\n",
6710 idleSeconds, (minutesToIdleSleep != 0));
2d21ac55 6711
6d2010ae
A
6712 if (0x7fffffff == minutesToIdleSleep)
6713 minutesToIdleSleep = idleSeconds;
b0d623f7 6714
6d2010ae
A
6715 // How long to wait before sleeping the system once
6716 // the displays turns off is indicated by 'extraSleepDelay'.
b0d623f7 6717
6d2010ae
A
6718 if ( minutesToIdleSleep > minutesToDisplayDim )
6719 minutesDelta = minutesToIdleSleep - minutesToDisplayDim;
39236c6e 6720 else if ( minutesToIdleSleep == minutesToDisplayDim )
316670eb 6721 minutesDelta = 1;
2d21ac55 6722
6d2010ae
A
6723 if ((sleepSlider == 0) && (minutesToIdleSleep != 0))
6724 flags.bit.idleSleepEnabled = true;
2d21ac55 6725
6d2010ae
A
6726 if ((sleepSlider != 0) && (minutesToIdleSleep == 0))
6727 flags.bit.idleSleepDisabled = true;
6728
fe8ab488 6729 if (((minutesDelta != extraSleepDelay) ||
39236c6e 6730 (userActivityTime != userActivityTime_prev)) &&
6d2010ae
A
6731 !flags.bit.idleSleepEnabled && !flags.bit.idleSleepDisabled)
6732 flags.bit.sleepDelayChanged = true;
2d21ac55 6733
6d2010ae
A
6734 if (systemDarkWake && !darkWakeToSleepASAP &&
6735 (flags.bit.idleSleepEnabled || flags.bit.idleSleepDisabled))
b0d623f7 6736 {
6d2010ae
A
6737 // Reconsider decision to remain in dark wake
6738 flags.bit.evaluateDarkWake = true;
b0d623f7 6739 }
2d21ac55 6740
6d2010ae
A
6741 sleepSlider = minutesToIdleSleep;
6742 extraSleepDelay = minutesDelta;
39236c6e 6743 userActivityTime_prev = userActivityTime;
6d2010ae 6744 } break;
0b4e3aa0 6745
6d2010ae 6746 case kStimulusDemandSystemSleep:
39236c6e 6747 displayIdleForDemandSleep = true;
fe8ab488 6748 if (wrangler && wranglerIdleSettings)
39236c6e
A
6749 {
6750 // Request wrangler idle only when demand sleep is triggered
6751 // from full wake.
6752 if(CAP_CURRENT(kIOPMSystemCapabilityGraphics))
6753 {
6754 wrangler->setProperties(wranglerIdleSettings);
6755 DLOG("Requested wrangler idle\n");
6756 }
6757 }
6758 // arg = sleepReason
6759 changePowerStateWithOverrideTo( SLEEP_STATE, arg );
2d21ac55 6760 break;
0b4e3aa0 6761
6d2010ae 6762 case kStimulusAllowSystemSleepChanged:
316670eb 6763 flags.bit.adjustPowerState = true;
6d2010ae 6764 break;
2d21ac55 6765
6d2010ae 6766 case kStimulusDarkWakeActivityTickle:
fe8ab488
A
6767 // arg == true implies real and not self generated wrangler tickle.
6768 // Update wake type on PM work loop instead of the tickle thread to
6769 // eliminate the possibility of an early tickle clobbering the wake
6770 // type set by the platform driver.
6771 if (arg == true)
6772 setProperty(kIOPMRootDomainWakeTypeKey, kIOPMRootDomainWakeTypeHIDActivity);
6773
6d2010ae
A
6774 if (false == wranglerTickled)
6775 {
13f56ec4
A
6776 if (latchDisplayWranglerTickle(true))
6777 {
6778 DLOG("latched tickle\n");
6779 break;
6780 }
6781
6d2010ae 6782 wranglerTickled = true;
39236c6e
A
6783 DLOG("Requesting full wake after dark wake activity tickle\n");
6784 requestFullWake( kFullWakeReasonLocalUser );
6d2010ae 6785 }
0b4e3aa0
A
6786 break;
6787
6d2010ae
A
6788 case kStimulusDarkWakeEntry:
6789 case kStimulusDarkWakeReentry:
6790 // Any system transitions since the last dark wake transition
6791 // will invalid the stimulus.
0b4e3aa0 6792
6d2010ae
A
6793 if (arg == _systemStateGeneration)
6794 {
6795 DLOG("dark wake entry\n");
6796 systemDarkWake = true;
39236c6e
A
6797
6798 // Keep wranglerAsleep an invariant when wrangler is absent
6799 if (wrangler)
6800 wranglerAsleep = true;
6801
6802 if (kStimulusDarkWakeEntry == stimulus)
6803 {
6804 clock_get_uptime(&userBecameInactiveTime);
6805 flags.bit.evaluateDarkWake = true;
6806 }
0b4e3aa0 6807
6d2010ae
A
6808 // Always accelerate disk spindown while in dark wake,
6809 // even if system does not support/allow sleep.
0b4e3aa0 6810
6d2010ae
A
6811 cancelIdleSleepTimer();
6812 setQuickSpinDownTimeout();
6d2010ae
A
6813 }
6814 break;
b0d623f7 6815
6d2010ae
A
6816 case kStimulusDarkWakeEvaluate:
6817 if (systemDarkWake)
6818 {
6819 flags.bit.evaluateDarkWake = true;
6820 }
6d2010ae 6821 break;
1c79356b 6822
316670eb
A
6823 case kStimulusNoIdleSleepPreventers:
6824 flags.bit.adjustPowerState = true;
6825 break;
6826
6d2010ae 6827 } /* switch(stimulus) */
b0d623f7 6828
39236c6e 6829 if (flags.bit.evaluateDarkWake && (kFullWakeReasonNone == fullWakeReason))
6d2010ae
A
6830 {
6831 if (darkWakeToSleepASAP ||
6832 (clamshellClosed && !(desktopMode && acAdaptorConnected)))
6833 {
39236c6e 6834 uint32_t newSleepReason;
0c530ab8 6835
39236c6e 6836 if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
6d2010ae 6837 {
39236c6e
A
6838 // System was previously in full wake. Sleep reason from
6839 // full to dark already recorded in fullToDarkReason.
6840
6d2010ae 6841 if (lowBatteryCondition)
39236c6e
A
6842 newSleepReason = kIOPMSleepReasonLowPower;
6843 else
6844 newSleepReason = fullToDarkReason;
6d2010ae
A
6845 }
6846 else
6847 {
39236c6e
A
6848 // In dark wake from system sleep.
6849
6850 if (darkWakeSleepService)
6851 newSleepReason = kIOPMSleepReasonSleepServiceExit;
6852 else
6853 newSleepReason = kIOPMSleepReasonMaintenance;
6854 }
fe8ab488 6855
39236c6e
A
6856 if (checkSystemCanSleep(newSleepReason))
6857 {
6858 privateSleepSystem(newSleepReason);
6d2010ae 6859 }
316670eb
A
6860 }
6861 else // non-maintenance (network) dark wake
6d2010ae 6862 {
39236c6e 6863 if (checkSystemCanSleep(kIOPMSleepReasonIdle))
6d2010ae
A
6864 {
6865 // Release power clamp, and wait for children idle.
6866 adjustPowerState(true);
6867 }
6868 else
6869 {
6870 changePowerStateToPriv(ON_STATE);
6871 }
6d2010ae
A
6872 }
6873 }
0c530ab8 6874
6d2010ae
A
6875 if (systemDarkWake)
6876 {
6877 // The rest are irrelevant while system is in dark wake.
6878 flags.u32 = 0;
6879 }
483a1d10 6880
39236c6e
A
6881 if ((flags.bit.displaySleep) &&
6882 (kFullWakeReasonDisplayOn == fullWakeReason))
6883 {
6884 // kIOPMSleepReasonMaintenance?
6885 changePowerStateWithOverrideTo( SLEEP_STATE, kIOPMSleepReasonMaintenance );
6886 }
6887
6888 if (flags.bit.userBecameInactive || flags.bit.sleepDelayChanged)
6d2010ae
A
6889 {
6890 bool cancelQuickSpindown = false;
b0d623f7 6891
6d2010ae
A
6892 if (flags.bit.sleepDelayChanged)
6893 {
39236c6e
A
6894 // Cancel existing idle sleep timer and quick disk spindown.
6895 // New settings will be applied by the idleSleepEnabled flag
6896 // handler below if idle sleep is enabled.
6897
6d2010ae
A
6898 DLOG("extra sleep timer changed\n");
6899 cancelIdleSleepTimer();
6900 cancelQuickSpindown = true;
6901 }
6902 else
6903 {
fe8ab488 6904 DLOG("user inactive\n");
6d2010ae 6905 }
0b4e3aa0 6906
22ba694c 6907 if (!userIsActive && sleepSlider)
6d2010ae 6908 {
39236c6e 6909 startIdleSleepTimer(getTimeToIdleSleep());
6d2010ae 6910 }
fe8ab488 6911
6d2010ae
A
6912 if (cancelQuickSpindown)
6913 restoreUserSpinDownTimeout();
6914 }
b0d623f7 6915
6d2010ae 6916 if (flags.bit.idleSleepEnabled)
0c530ab8 6917 {
6d2010ae
A
6918 DLOG("idle sleep timer enabled\n");
6919 if (!wrangler)
55e303ae 6920 {
6d2010ae
A
6921 changePowerStateToPriv(ON_STATE);
6922 if (idleSeconds)
6923 {
6924 startIdleSleepTimer( idleSeconds );
6925 }
6926 }
6927 else
6928 {
39236c6e
A
6929 // Start idle timer if prefs now allow system sleep
6930 // and user is already inactive. Disk spindown is
6d2010ae
A
6931 // accelerated upon timer expiration.
6932
39236c6e 6933 if (!userIsActive)
6d2010ae 6934 {
39236c6e 6935 startIdleSleepTimer(getTimeToIdleSleep());
6d2010ae 6936 }
0c530ab8
A
6937 }
6938 }
6d2010ae
A
6939
6940 if (flags.bit.idleSleepDisabled)
6941 {
6942 DLOG("idle sleep timer disabled\n");
6943 cancelIdleSleepTimer();
6944 restoreUserSpinDownTimeout();
6945 adjustPowerState();
6946 }
316670eb
A
6947
6948 if (flags.bit.adjustPowerState)
6949 {
6950 bool sleepASAP = false;
6951
6952 if (!systemBooting && (preventIdleSleepList->getCount() == 0))
6953 {
6954 if (!wrangler)
6955 {
6956 changePowerStateToPriv(ON_STATE);
6957 if (idleSeconds)
6958 {
6959 // stay awake for at least idleSeconds
6960 startIdleSleepTimer(idleSeconds);
6961 }
6962 }
6963 else if (!extraSleepDelay && !idleSleepTimerPending && !systemDarkWake)
6964 {
6965 sleepASAP = true;
6966 }
6967 }
316670eb
A
6968
6969 adjustPowerState(sleepASAP);
6970 }
0c530ab8
A
6971}
6972
39236c6e
A
6973//******************************************************************************
6974// requestFullWake
6975//
6976// Request transition from dark wake to full wake
6977//******************************************************************************
6978
6979void IOPMrootDomain::requestFullWake( FullWakeReason reason )
6980{
6981 uint32_t options = 0;
6982 IOService * pciRoot = 0;
fe8ab488 6983 bool promotion = false;
39236c6e
A
6984
6985 // System must be in dark wake and a valid reason for entering full wake
6986 if ((kFullWakeReasonNone == reason) ||
6987 (kFullWakeReasonNone != fullWakeReason) ||
6988 (CAP_CURRENT(kIOPMSystemCapabilityGraphics)))
6989 {
6990 return;
6991 }
6992
6993 // Will clear reason upon exit from full wake
6994 fullWakeReason = reason;
6995
6996 _desiredCapability |= (kIOPMSystemCapabilityGraphics |
6997 kIOPMSystemCapabilityAudio);
6998
6999 if ((kSystemTransitionWake == _systemTransitionType) &&
7000 !(_pendingCapability & kIOPMSystemCapabilityGraphics) &&
7001 !graphicsSuppressed)
7002 {
39236c6e
A
7003 // Promote to full wake while waking up to dark wake due to tickle.
7004 // PM will hold off notifying the graphics subsystem about system wake
7005 // as late as possible, so if a HID tickle does arrive, graphics can
7006 // power up on this same wake cycle. The latency to power up graphics
7007 // on the next cycle can be huge on some systems. However, once any
7008 // graphics suppression has taken effect, it is too late. All other
7009 // graphics devices must be similarly suppressed. But the delay till
7010 // the following cycle should be short.
7011
7012 _pendingCapability |= (kIOPMSystemCapabilityGraphics |
7013 kIOPMSystemCapabilityAudio);
7014
7015 // Immediately bring up audio and graphics
7016 pciRoot = pciHostBridgeDriver;
7017 willEnterFullWake();
fe8ab488 7018 promotion = true;
39236c6e
A
7019 }
7020
7021 // Unsafe to cancel once graphics was powered.
7022 // If system woke from dark wake, the return to sleep can
7023 // be cancelled. "awake -> dark -> sleep" transition
7024 // can be canceled also, during the "dark --> sleep" phase
7025 // *prior* to driver power down.
7026 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics) ||
7027 _pendingCapability == 0) {
7028 options |= kIOPMSyncCancelPowerDown;
7029 }
7030
7031 synchronizePowerTree(options, pciRoot);
7032 if (kFullWakeReasonLocalUser == fullWakeReason)
7033 {
7034 // IOGraphics doesn't light the display even though graphics is
7035 // enabled in kIOMessageSystemCapabilityChange message(radar 9502104)
7036 // So, do an explicit activity tickle
7037 if (wrangler)
7038 wrangler->activityTickle(0,0);
7039 }
7040
fe8ab488
A
7041 // Log a timestamp for the initial full wake request.
7042 // System may not always honor this full wake request.
7043 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
39236c6e
A
7044 {
7045 AbsoluteTime now;
7046 uint64_t nsec;
7047
39236c6e
A
7048 clock_get_uptime(&now);
7049 SUB_ABSOLUTETIME(&now, &systemWakeTime);
7050 absolutetime_to_nanoseconds(now, &nsec);
fe8ab488
A
7051 MSG("full wake %s (reason %u) %u ms\n",
7052 promotion ? "promotion" : "request",
39236c6e
A
7053 fullWakeReason, ((int)((nsec) / 1000000ULL)));
7054 }
7055}
7056
7057//******************************************************************************
7058// willEnterFullWake
7059//
7060// System will enter full wake from sleep, from dark wake, or from dark
7061// wake promotion. This function aggregate things that are in common to
7062// all three full wake transitions.
7063//
7064// Assumptions: fullWakeReason was updated
7065//******************************************************************************
7066
7067void IOPMrootDomain::willEnterFullWake( void )
7068{
7069 hibernateRetry = false;
39236c6e 7070 sleepToStandby = false;
22ba694c 7071 sleepTimerMaintenance = false;
39236c6e
A
7072
7073 _systemMessageClientMask = kSystemMessageClientPowerd |
7074 kSystemMessageClientLegacyApp;
7075
7076 if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0)
7077 {
7078 // Initial graphics full power
7079 _systemMessageClientMask |= kSystemMessageClientKernel;
7080
7081 // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics
7082 setProperty(gIOPMUserTriggeredFullWakeKey,
7083 (kFullWakeReasonLocalUser == fullWakeReason) ?
7084 kOSBooleanTrue : kOSBooleanFalse);
7085 }
8a3053a0
A
7086#if HIBERNATION
7087 IOHibernateSetWakeCapabilities(_pendingCapability);
7088#endif
39236c6e
A
7089
7090 IOService::setAdvisoryTickleEnable( true );
7091 tellClients(kIOMessageSystemWillPowerOn);
22ba694c 7092 preventTransitionToUserActive(false);
39236c6e
A
7093}
7094
7095//******************************************************************************
7096// fullWakeDelayedWork
7097//
7098// System has already entered full wake. Invoked by a delayed thread call.
7099//******************************************************************************
7100
7101void IOPMrootDomain::fullWakeDelayedWork( void )
7102{
7103#if DARK_TO_FULL_EVALUATE_CLAMSHELL
7104 // Not gated, don't modify state
7105 if ((kSystemTransitionNone == _systemTransitionType) &&
7106 CAP_CURRENT(kIOPMSystemCapabilityGraphics))
7107 {
7108 receivePowerNotification( kLocalEvalClamshellCommand );
7109 }
7110#endif
7111}
7112
7ddcb079
A
7113//******************************************************************************
7114// evaluateAssertions
7115//
7116//******************************************************************************
7117void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions, IOPMDriverAssertionType oldAssertions)
7118{
7119 IOPMDriverAssertionType changedBits = newAssertions ^ oldAssertions;
7120
fe8ab488 7121 messageClients(kIOPMMessageDriverAssertionsChanged);
7ddcb079
A
7122
7123 if (changedBits & kIOPMDriverAssertionPreventDisplaySleepBit) {
7124
7125 if (wrangler) {
db609669 7126 bool value = (newAssertions & kIOPMDriverAssertionPreventDisplaySleepBit) ? true : false;
39236c6e 7127
7ddcb079
A
7128 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value);
7129 wrangler->setIgnoreIdleTimer( value );
7130 }
7131 }
316670eb 7132
3e170ce0 7133 if (changedBits & kIOPMDriverAssertionCPUBit) {
7ddcb079 7134 evaluatePolicy(kStimulusDarkWakeEvaluate);
3e170ce0
A
7135 if (!assertOnWakeSecs && systemWakeTime) {
7136 AbsoluteTime now;
7137 clock_usec_t microsecs;
7138 clock_get_uptime(&now);
7139 SUB_ABSOLUTETIME(&now, &systemWakeTime);
7140 absolutetime_to_microtime(now, &assertOnWakeSecs, &microsecs);
7141 if (assertOnWakeReport) {
7142 HISTREPORT_TALLYVALUE(assertOnWakeReport, (int64_t)assertOnWakeSecs);
7143 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs);
7144 }
7145 }
7146 }
316670eb
A
7147
7148 if (changedBits & kIOPMDriverAssertionReservedBit7) {
7149 bool value = (newAssertions & kIOPMDriverAssertionReservedBit7) ? true : false;
7150 if (value) {
7151 DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
7152 updatePreventIdleSleepList(this, true);
7153 }
7154 else {
7155 DLOG("Driver assertion ReservedBit7 dropped\n");
7156 updatePreventIdleSleepList(this, false);
7157 }
316670eb 7158 }
7ddcb079
A
7159}
7160
6d2010ae
A
7161// MARK: -
7162// MARK: Statistics
7163
7164//******************************************************************************
7165// pmStats
7166//
7167//******************************************************************************
7168
b0d623f7
A
7169void IOPMrootDomain::pmStatsRecordEvent(
7170 int eventIndex,
7171 AbsoluteTime timestamp)
7172{
7173 bool starting = eventIndex & kIOPMStatsEventStartFlag ? true:false;
7174 bool stopping = eventIndex & kIOPMStatsEventStopFlag ? true:false;
7175 uint64_t delta;
7176 uint64_t nsec;
316670eb 7177 OSData *publishPMStats = NULL;
b0d623f7
A
7178
7179 eventIndex &= ~(kIOPMStatsEventStartFlag | kIOPMStatsEventStopFlag);
7180
7181 absolutetime_to_nanoseconds(timestamp, &nsec);
7182
7183 switch (eventIndex) {
7184 case kIOPMStatsHibernateImageWrite:
7185 if (starting)
316670eb 7186 gPMStats.hibWrite.start = nsec;
b0d623f7 7187 else if (stopping)
316670eb 7188 gPMStats.hibWrite.stop = nsec;
b0d623f7
A
7189
7190 if (stopping) {
316670eb 7191 delta = gPMStats.hibWrite.stop - gPMStats.hibWrite.start;
b0d623f7
A
7192 IOLog("PMStats: Hibernate write took %qd ms\n", delta/1000000ULL);
7193 }
7194 break;
7195 case kIOPMStatsHibernateImageRead:
7196 if (starting)
316670eb 7197 gPMStats.hibRead.start = nsec;
b0d623f7 7198 else if (stopping)
316670eb 7199 gPMStats.hibRead.stop = nsec;
b0d623f7
A
7200
7201 if (stopping) {
316670eb 7202 delta = gPMStats.hibRead.stop - gPMStats.hibRead.start;
b0d623f7 7203 IOLog("PMStats: Hibernate read took %qd ms\n", delta/1000000ULL);
316670eb
A
7204
7205 publishPMStats = OSData::withBytes(&gPMStats, sizeof(gPMStats));
7206 setProperty(kIOPMSleepStatisticsKey, publishPMStats);
7207 publishPMStats->release();
7208 bzero(&gPMStats, sizeof(gPMStats));
b0d623f7
A
7209 }
7210 break;
7211 }
7212}
7213
7214/*
7215 * Appends a record of the application response to
7216 * IOPMrootDomain::pmStatsAppResponses
7217 */
7218void IOPMrootDomain::pmStatsRecordApplicationResponse(
fe8ab488
A
7219 const OSSymbol *response,
7220 const char *name,
7221 int messageType,
b0d623f7 7222 uint32_t delay_ms,
fe8ab488
A
7223 int app_pid,
7224 OSObject *object,
7225 IOPMPowerStateIndex powerState)
b0d623f7
A
7226{
7227 OSDictionary *responseDescription = NULL;
7228 OSNumber *delayNum = NULL;
39236c6e 7229 OSNumber *powerCaps = NULL;
b0d623f7
A
7230 OSNumber *pidNum = NULL;
7231 OSNumber *msgNum = NULL;
7232 const OSSymbol *appname;
fe8ab488
A
7233 const OSSymbol *sleep = NULL, *wake = NULL;
7234 IOPMServiceInterestNotifier *notify = 0;
b0d623f7 7235
fe8ab488 7236 if (object && (notify = OSDynamicCast(IOPMServiceInterestNotifier, object)))
b0d623f7 7237 {
fe8ab488
A
7238 if (response->isEqualTo(gIOPMStatsApplicationResponseTimedOut))
7239 notify->ackTimeoutCnt++;
7240 else
7241 notify->ackTimeoutCnt = 0;
7242
b0d623f7
A
7243 }
7244
fe8ab488
A
7245 if (response->isEqualTo(gIOPMStatsApplicationResponsePrompt) ||
7246 (_systemTransitionType == kSystemTransitionNone) || (_systemTransitionType == kSystemTransitionNewCapClient))
7247 return;
7248
7249
b0d623f7 7250 responseDescription = OSDictionary::withCapacity(5);
fe8ab488 7251 if (responseDescription)
b0d623f7
A
7252 {
7253 if (response) {
7254 responseDescription->setObject(_statsResponseTypeKey, response);
7255 }
fe8ab488
A
7256
7257 msgNum = OSNumber::withNumber(messageType, 32);
7258 if (msgNum) {
7259 responseDescription->setObject(_statsMessageTypeKey, msgNum);
7260 msgNum->release();
b0d623f7
A
7261 }
7262
7263 if (name && (strlen(name) > 0))
7264 {
7265 appname = OSSymbol::withCString(name);
7266 if (appname) {
7267 responseDescription->setObject(_statsNameKey, appname);
7268 appname->release();
7269 }
7270 }
7271
7272 if (app_pid != -1) {
7273 pidNum = OSNumber::withNumber(app_pid, 32);
7274 if (pidNum) {
7275 responseDescription->setObject(_statsPIDKey, pidNum);
7276 pidNum->release();
7277 }
7278 }
7279
7280 delayNum = OSNumber::withNumber(delay_ms, 32);
7281 if (delayNum) {
7282 responseDescription->setObject(_statsTimeMSKey, delayNum);
7283 delayNum->release();
7284 }
7285
fe8ab488
A
7286 if (response->isEqualTo(gIOPMStatsDriverPSChangeSlow)) {
7287 powerCaps = OSNumber::withNumber(powerState, 32);
7288
3e170ce0 7289#if !defined(__i386__) && !defined(__x86_64__) && (DEVELOPMENT || DEBUG)
fe8ab488
A
7290 IOLog("%s::powerStateChange type(%d) to(%lu) async took %d ms\n",
7291 name, messageType,
7292 powerState, delay_ms);
7293#endif
7294
7295 }
7296 else {
7297 powerCaps = OSNumber::withNumber(_pendingCapability, 32);
7298 }
39236c6e
A
7299 if (powerCaps) {
7300 responseDescription->setObject(_statsPowerCapsKey, powerCaps);
7301 powerCaps->release();
7302 }
7303
fe8ab488
A
7304 sleep = OSSymbol::withCString("Sleep");
7305 wake = OSSymbol::withCString("Wake");
7306 if (_systemTransitionType == kSystemTransitionSleep) {
7307 responseDescription->setObject(kIOPMStatsSystemTransitionKey, sleep);
b0d623f7 7308 }
fe8ab488
A
7309 else if (_systemTransitionType == kSystemTransitionWake) {
7310 responseDescription->setObject(kIOPMStatsSystemTransitionKey, wake);
7311 }
7312 else if (_systemTransitionType == kSystemTransitionCapability) {
7313 if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
7314 responseDescription->setObject(kIOPMStatsSystemTransitionKey, sleep);
7315 else if (CAP_GAIN(kIOPMSystemCapabilityGraphics))
7316 responseDescription->setObject(kIOPMStatsSystemTransitionKey, wake);
7317 }
7318 if (sleep) sleep->release();
7319 if (wake) wake->release();
b0d623f7 7320
39236c6e 7321
39236c6e 7322
fe8ab488
A
7323 IOLockLock(pmStatsLock);
7324 if (pmStatsAppResponses && pmStatsAppResponses->getCount() < 50) {
7325 pmStatsAppResponses->setObject(responseDescription);
7326 }
7327 IOLockUnlock(pmStatsLock);
39236c6e 7328
fe8ab488 7329 responseDescription->release();
39236c6e 7330 }
39236c6e 7331
b0d623f7
A
7332 return;
7333}
7334
6d2010ae
A
7335// MARK: -
7336// MARK: PMTraceWorker
b0d623f7
A
7337
7338//******************************************************************************
7339// TracePoint support
7340//
7341//******************************************************************************
7342
fe8ab488
A
7343#define kIOPMRegisterNVRAMTracePointHandlerKey \
7344 "IOPMRegisterNVRAMTracePointHandler"
b0d623f7
A
7345
7346IOReturn IOPMrootDomain::callPlatformFunction(
7347 const OSSymbol * functionName,
7348 bool waitForFunction,
7349 void * param1, void * param2,
7350 void * param3, void * param4 )
7351{
7352 if (pmTracer && functionName &&
7353 functionName->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey) &&
7354 !pmTracer->tracePointHandler && !pmTracer->tracePointTarget)
7355 {
7356 uint32_t tracePointPhases, tracePointPCI;
fe8ab488 7357 uint64_t statusCode;
b0d623f7
A
7358
7359 pmTracer->tracePointHandler = (IOPMTracePointHandler) param1;
7360 pmTracer->tracePointTarget = (void *) param2;
fe8ab488
A
7361 tracePointPCI = (uint32_t)(uintptr_t) param3;
7362 tracePointPhases = (uint32_t)(uintptr_t) param4;
b0d623f7 7363 statusCode = (((uint64_t)tracePointPCI) << 32) | tracePointPhases;
fe8ab488 7364 if ((tracePointPhases >> 24) != kIOPMTracePointSystemUp)
b0d623f7 7365 {
6d2010ae 7366 MSG("Sleep failure code 0x%08x 0x%08x\n",
b0d623f7
A
7367 tracePointPCI, tracePointPhases);
7368 }
fe8ab488 7369 setProperty(kIOPMSleepWakeFailureCodeKey, statusCode, 64);
b0d623f7
A
7370 pmTracer->tracePointHandler( pmTracer->tracePointTarget, 0, 0 );
7371
7372 return kIOReturnSuccess;
7373 }
99c3a104
A
7374#if HIBERNATION
7375 else if (functionName &&
7376 functionName->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey))
7377 {
7378 if (gSleepPolicyHandler)
7379 return kIOReturnExclusiveAccess;
7380 if (!param1)
7381 return kIOReturnBadArgument;
7382 gSleepPolicyHandler = (IOPMSystemSleepPolicyHandler) param1;
7383 gSleepPolicyTarget = (void *) param2;
7384 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue);
7385 return kIOReturnSuccess;
7386 }
7387#endif
b0d623f7
A
7388
7389 return super::callPlatformFunction(
7390 functionName, waitForFunction, param1, param2, param3, param4);
7391}
7392
7393void IOPMrootDomain::tracePoint( uint8_t point )
7394{
316670eb
A
7395 if (systemBooting) return;
7396
fe8ab488
A
7397 if (kIOPMTracePointWakeCapabilityClients == point)
7398 acceptSystemWakeEvents(false);
7399
4b17d6b6 7400 PMDebug(kPMLogSleepWakeTracePoint, point, 0);
316670eb 7401 pmTracer->tracePoint(point);
6d2010ae
A
7402}
7403
7404void IOPMrootDomain::tracePoint( uint8_t point, uint8_t data )
7405{
4b17d6b6
A
7406 if (systemBooting) return;
7407
7408 PMDebug(kPMLogSleepWakeTracePoint, point, data);
7409 pmTracer->tracePoint(point, data);
6d2010ae
A
7410}
7411
7412void IOPMrootDomain::traceDetail( uint32_t detail )
7413{
7414 if (!systemBooting)
7415 pmTracer->traceDetail( detail );
b0d623f7
A
7416}
7417
39236c6e 7418
3e170ce0
A
7419void IOPMrootDomain::configureReportGated(uint64_t channel_id, uint64_t action, void *result)
7420{
7421 size_t reportSize;
7422 void **report = NULL;
7423 uint32_t bktCnt;
7424 uint32_t bktSize;
7425 uint32_t *clientCnt;
7426
7427 ASSERT_GATED();
7428
7429 report = NULL;
7430 if (channel_id == kAssertDelayChID) {
7431 report = &assertOnWakeReport;
7432 bktCnt = kAssertDelayBcktCnt;
7433 bktSize = kAssertDelayBcktSize;
7434 clientCnt = &assertOnWakeClientCnt;
7435 }
7436 else if (channel_id == kSleepDelaysChID) {
7437 report = &sleepDelaysReport;
7438 bktCnt = kSleepDelaysBcktCnt;
7439 bktSize = kSleepDelaysBcktSize;
7440 clientCnt = &sleepDelaysClientCnt;
7441 }
7442
7443 switch (action)
7444 {
7445 case kIOReportEnable:
7446
7447 if (*report) {
7448 (*clientCnt)++;
7449 break;
7450 }
7451
7452 reportSize = HISTREPORT_BUFSIZE(bktCnt);
7453 *report = IOMalloc(reportSize);
7454 if (*report == NULL) {
7455 break;
7456 }
7457 bzero(*report, reportSize);
7458 HISTREPORT_INIT(bktCnt, bktSize, *report, reportSize,
7459 getRegistryEntryID(), channel_id, kIOReportCategoryPower);
7460
7461 if (channel_id == kAssertDelayChID)
7462 assertOnWakeSecs = 0;
7463
7464 break;
7465
7466 case kIOReportDisable:
7467 if (*clientCnt == 0) {
7468 break;
7469 }
7470 if (*clientCnt == 1)
7471 {
7472 IOFree(*report, HISTREPORT_BUFSIZE(bktCnt));
7473 *report = NULL;
7474 }
7475 (*clientCnt)--;
7476
7477 if (channel_id == kAssertDelayChID)
7478 assertOnWakeSecs = -1; // Invalid value to prevent updates
7479
7480 break;
7481
7482 case kIOReportGetDimensions:
7483 if (*report) {
7484 HISTREPORT_UPDATERES(*report, kIOReportGetDimensions, result);
7485 }
7486 break;
7487 }
7488
7489 return;
7490}
7491
39236c6e
A
7492IOReturn IOPMrootDomain::configureReport(IOReportChannelList *channelList,
7493 IOReportConfigureAction action,
7494 void *result,
7495 void *destination)
7496{
7497 unsigned cnt;
3e170ce0 7498 uint64_t configAction = (uint64_t)action;
39236c6e
A
7499
7500 for (cnt = 0; cnt < channelList->nchannels; cnt++) {
7501 if ( (channelList->channels[cnt].channel_id == kSleepCntChID) ||
7502 (channelList->channels[cnt].channel_id == kDarkWkCntChID) ||
7503 (channelList->channels[cnt].channel_id == kUserWkCntChID) ) {
3e170ce0 7504 if (action != kIOReportGetDimensions) continue;
39236c6e
A
7505 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions, result);
7506 }
3e170ce0
A
7507 else if ((channelList->channels[cnt].channel_id == kAssertDelayChID) ||
7508 (channelList->channels[cnt].channel_id == kSleepDelaysChID)) {
7509 gIOPMWorkLoop->runAction(
7510 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::configureReportGated),
7511 (OSObject *)this, (void *)channelList->channels[cnt].channel_id,
7512 (void *)configAction, (void *)result);
7513 }
39236c6e
A
7514 }
7515
39236c6e
A
7516 return super::configureReport(channelList, action, result, destination);
7517}
7518
3e170ce0
A
7519IOReturn IOPMrootDomain::updateReportGated(uint64_t ch_id, void *result, IOBufferMemoryDescriptor *dest)
7520{
7521
7522 uint32_t size2cpy;
7523 void *data2cpy;
7524 void **report;
7525
7526 ASSERT_GATED();
7527
7528 report = NULL;
7529 if (ch_id == kAssertDelayChID) {
7530 report = &assertOnWakeReport;
7531 }
7532 else if (ch_id == kSleepDelaysChID) {
7533 report = &sleepDelaysReport;
7534 }
7535
7536 if (*report == NULL) {
7537 return kIOReturnNotOpen;
7538 }
7539
7540 HISTREPORT_UPDATEPREP(*report, data2cpy, size2cpy);
7541 if (size2cpy > (dest->getCapacity() - dest->getLength()) ) {
7542 return kIOReturnOverrun;
7543 }
7544
7545 HISTREPORT_UPDATERES(*report, kIOReportCopyChannelData, result);
7546 dest->appendBytes(data2cpy, size2cpy);
7547
7548 return kIOReturnSuccess;
7549}
39236c6e
A
7550
7551IOReturn IOPMrootDomain::updateReport(IOReportChannelList *channelList,
7552 IOReportUpdateAction action,
7553 void *result,
7554 void *destination)
7555{
7556 uint32_t size2cpy;
7557 void *data2cpy;
7558 uint8_t buf[SIMPLEREPORT_BUFSIZE];
7559 IOBufferMemoryDescriptor *dest = OSDynamicCast(IOBufferMemoryDescriptor, (OSObject *)destination);
7560 unsigned cnt;
7561 uint64_t ch_id;
7562
7563 if (action != kIOReportCopyChannelData) goto exit;
7564
7565 for (cnt = 0; cnt < channelList->nchannels; cnt++) {
7566 ch_id = channelList->channels[cnt].channel_id ;
7567
3e170ce0
A
7568 if ((ch_id == kAssertDelayChID) || (ch_id == kSleepDelaysChID)) {
7569 gIOPMWorkLoop->runAction(
7570 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::updateReportGated),
7571 (OSObject *)this, (void *)ch_id,
7572 (void *)result, (void *)dest);
7573 continue;
7574
7575 }
7576 else if ((ch_id == kSleepCntChID) ||
39236c6e
A
7577 (ch_id == kDarkWkCntChID) || (ch_id == kUserWkCntChID)) {
7578 SIMPLEREPORT_INIT(buf, sizeof(buf), getRegistryEntryID(), ch_id, kIOReportCategoryPower);
7579 }
7580 else continue;
7581
7582 if (ch_id == kSleepCntChID)
7583 SIMPLEREPORT_SETVALUE(buf, sleepCnt);
7584 else if (ch_id == kDarkWkCntChID)
7585 SIMPLEREPORT_SETVALUE(buf, darkWakeCnt);
7586 else if (ch_id == kUserWkCntChID)
7587 SIMPLEREPORT_SETVALUE(buf, displayWakeCnt);
7588
7589 SIMPLEREPORT_UPDATEPREP(buf, data2cpy, size2cpy);
7590 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData, result);
fe8ab488 7591 dest->appendBytes(data2cpy, size2cpy);
39236c6e
A
7592 }
7593
7594exit:
7595 return super::updateReport(channelList, action, result, destination);
7596}
7597
7598
b0d623f7
A
7599//******************************************************************************
7600// PMTraceWorker Class
7601//
7602//******************************************************************************
7603
7604#undef super
7605#define super OSObject
7606OSDefineMetaClassAndStructors(PMTraceWorker, OSObject)
7607
7608#define kPMBestGuessPCIDevicesCount 25
7609#define kPMMaxRTCBitfieldSize 32
7610
7611PMTraceWorker *PMTraceWorker::tracer(IOPMrootDomain *owner)
7612{
7613 PMTraceWorker *me;
fe8ab488 7614
b0d623f7
A
7615 me = OSTypeAlloc( PMTraceWorker );
7616 if (!me || !me->init())
7617 {
7618 return NULL;
7619 }
7620
39236c6e 7621 DLOG("PMTraceWorker %p\n", OBFUSCATE(me));
b0d623f7
A
7622
7623 // Note that we cannot instantiate the PCI device -> bit mappings here, since
7624 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
7625 // this dictionary lazily.
7626 me->owner = owner;
7627 me->pciDeviceBitMappings = NULL;
7628 me->pciMappingLock = IOLockAlloc();
7629 me->tracePhase = kIOPMTracePointSystemUp;
7630 me->loginWindowPhase = 0;
6d2010ae 7631 me->traceData32 = 0;
b0d623f7
A
7632 return me;
7633}
7634
7635void PMTraceWorker::RTC_TRACE(void)
7636{
fe8ab488
A
7637 if (tracePointHandler && tracePointTarget)
7638 {
7639 uint32_t wordA;
b0d623f7 7640
6d2010ae
A
7641 wordA = (tracePhase << 24) | (loginWindowPhase << 16) |
7642 (traceData8 << 8);
b0d623f7 7643
6d2010ae 7644 tracePointHandler( tracePointTarget, traceData32, wordA );
fe8ab488
A
7645 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32, wordA);
7646 }
b0d623f7
A
7647}
7648
7649int PMTraceWorker::recordTopLevelPCIDevice(IOService * pciDevice)
7650{
7651 const OSSymbol * deviceName;
7652 int index = -1;
7653
7654 IOLockLock(pciMappingLock);
7655
7656 if (!pciDeviceBitMappings)
7657 {
7658 pciDeviceBitMappings = OSArray::withCapacity(kPMBestGuessPCIDevicesCount);
7659 if (!pciDeviceBitMappings)
7660 goto exit;
7661 }
7662
7663 // Check for bitmask overflow.
7664 if (pciDeviceBitMappings->getCount() >= kPMMaxRTCBitfieldSize)
7665 goto exit;
7666
7667 if ((deviceName = pciDevice->copyName()) &&
7668 (pciDeviceBitMappings->getNextIndexOfObject(deviceName, 0) == (unsigned int)-1) &&
7669 pciDeviceBitMappings->setObject(deviceName))
7670 {
7671 index = pciDeviceBitMappings->getCount() - 1;
6d2010ae 7672 _LOG("PMTrace PCI array: set object %s => %d\n",
b0d623f7
A
7673 deviceName->getCStringNoCopy(), index);
7674 }
7675 if (deviceName)
7676 deviceName->release();
7677 if (!addedToRegistry && (index >= 0))
7678 addedToRegistry = owner->setProperty("PCITopLevel", this);
7679
7680exit:
7681 IOLockUnlock(pciMappingLock);
7682 return index;
7683}
7684
7685bool PMTraceWorker::serialize(OSSerialize *s) const
7686{
7687 bool ok = false;
7688 if (pciDeviceBitMappings)
7689 {
7690 IOLockLock(pciMappingLock);
7691 ok = pciDeviceBitMappings->serialize(s);
7692 IOLockUnlock(pciMappingLock);
7693 }
7694 return ok;
7695}
7696
7697void PMTraceWorker::tracePoint(uint8_t phase)
7698{
6d2010ae
A
7699 // clear trace detail when phase begins
7700 if (tracePhase != phase)
7701 traceData32 = 0;
7702
7703 tracePhase = phase;
7704
7705 DLOG("trace point 0x%02x\n", tracePhase);
7706 RTC_TRACE();
7707}
7708
7709void PMTraceWorker::tracePoint(uint8_t phase, uint8_t data8)
7710{
7711 // clear trace detail when phase begins
7712 if (tracePhase != phase)
7713 traceData32 = 0;
7714
b0d623f7 7715 tracePhase = phase;
6d2010ae
A
7716 traceData8 = data8;
7717
7718 DLOG("trace point 0x%02x 0x%02x\n", tracePhase, traceData8);
7719 RTC_TRACE();
7720}
7721
7722void PMTraceWorker::traceDetail(uint32_t detail)
7723{
7724 if (kIOPMTracePointSleepPriorityClients != tracePhase)
7725 return;
7726
7727 traceData32 = detail;
7728 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase, traceData32);
b0d623f7 7729
b0d623f7
A
7730 RTC_TRACE();
7731}
7732
7733void PMTraceWorker::traceLoginWindowPhase(uint8_t phase)
7734{
7735 loginWindowPhase = phase;
7736
6d2010ae 7737 DLOG("loginwindow tracepoint 0x%02x\n", loginWindowPhase);
b0d623f7
A
7738 RTC_TRACE();
7739}
7740
7741void PMTraceWorker::tracePCIPowerChange(
fe8ab488 7742 change_t type, IOService *service, uint32_t changeFlags, uint32_t bitNum)
b0d623f7 7743{
fe8ab488
A
7744 uint32_t bitMask;
7745 uint32_t expectedFlag;
b0d623f7 7746
fe8ab488 7747 // Ignore PCI changes outside of system sleep/wake.
6d2010ae
A
7748 if ((kIOPMTracePointSleepPowerPlaneDrivers != tracePhase) &&
7749 (kIOPMTracePointWakePowerPlaneDrivers != tracePhase))
b0d623f7
A
7750 return;
7751
fe8ab488
A
7752 // Only record the WillChange transition when going to sleep,
7753 // and the DidChange on the way up.
7754 changeFlags &= (kIOPMDomainWillChange | kIOPMDomainDidChange);
7755 expectedFlag = (kIOPMTracePointSleepPowerPlaneDrivers == tracePhase) ?
7756 kIOPMDomainWillChange : kIOPMDomainDidChange;
7757 if (changeFlags != expectedFlag)
7758 return;
b0d623f7
A
7759
7760 // Mark this device off in our bitfield
7761 if (bitNum < kPMMaxRTCBitfieldSize)
7762 {
7763 bitMask = (1 << bitNum);
7764
7765 if (kPowerChangeStart == type)
7766 {
6d2010ae
A
7767 traceData32 |= bitMask;
7768 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
7769 service->getName(), bitNum, bitMask, traceData32);
b0d623f7
A
7770 }
7771 else
7772 {
6d2010ae
A
7773 traceData32 &= ~bitMask;
7774 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
7775 service->getName(), bitNum, bitMask, traceData32);
b0d623f7
A
7776 }
7777
39236c6e 7778 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase, traceData32);
6d2010ae 7779 RTC_TRACE();
b0d623f7
A
7780 }
7781}
7782
39236c6e
A
7783uint64_t PMTraceWorker::getPMStatusCode( )
7784{
3e170ce0 7785 return (((uint64_t)traceData32 << 32) | ((uint64_t)tracePhase << 24) |
39236c6e
A
7786 (loginWindowPhase << 16) | (traceData8 << 8));
7787
7788}
7789
6d2010ae
A
7790// MARK: -
7791// MARK: PMHaltWorker
b0d623f7
A
7792
7793//******************************************************************************
2d21ac55
A
7794// PMHaltWorker Class
7795//
b0d623f7 7796//******************************************************************************
2d21ac55 7797
2d21ac55
A
7798PMHaltWorker * PMHaltWorker::worker( void )
7799{
fe8ab488
A
7800 PMHaltWorker * me;
7801 IOThread thread;
2d21ac55 7802
fe8ab488
A
7803 do {
7804 me = OSTypeAlloc( PMHaltWorker );
7805 if (!me || !me->init())
7806 break;
2d21ac55 7807
fe8ab488
A
7808 me->lock = IOLockAlloc();
7809 if (!me->lock)
7810 break;
2d21ac55 7811
fe8ab488
A
7812 DLOG("PMHaltWorker %p\n", OBFUSCATE(me));
7813 me->retain(); // thread holds extra retain
7814 if (KERN_SUCCESS != kernel_thread_start(&PMHaltWorker::main, (void *) me, &thread))
7815 {
7816 me->release();
7817 break;
7818 }
7819 thread_deallocate(thread);
7820 return me;
2d21ac55 7821
fe8ab488 7822 } while (false);
2d21ac55 7823
fe8ab488
A
7824 if (me) me->release();
7825 return 0;
2d21ac55
A
7826}
7827
7828void PMHaltWorker::free( void )
7829{
fe8ab488
A
7830 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
7831 if (lock)
7832 {
7833 IOLockFree(lock);
7834 lock = 0;
7835 }
7836 return OSObject::free();
2d21ac55
A
7837}
7838
b0d623f7 7839void PMHaltWorker::main( void * arg, wait_result_t waitResult )
2d21ac55 7840{
fe8ab488
A
7841 PMHaltWorker * me = (PMHaltWorker *) arg;
7842
7843 IOLockLock( gPMHaltLock );
7844 gPMHaltBusyCount++;
7845 me->depth = gPMHaltDepth;
7846 IOLockUnlock( gPMHaltLock );
7847
7848 while (me->depth >= 0)
7849 {
7850 PMHaltWorker::work( me );
7851
7852 IOLockLock( gPMHaltLock );
7853 if (++gPMHaltIdleCount >= gPMHaltBusyCount)
7854 {
7855 // This is the last thread to finish work on this level,
7856 // inform everyone to start working on next lower level.
7857 gPMHaltDepth--;
7858 me->depth = gPMHaltDepth;
7859 gPMHaltIdleCount = 0;
7860 thread_wakeup((event_t) &gPMHaltIdleCount);
7861 }
7862 else
7863 {
7864 // One or more threads are still working on this level,
7865 // this thread must wait.
7866 me->depth = gPMHaltDepth - 1;
7867 do {
7868 IOLockSleep(gPMHaltLock, &gPMHaltIdleCount, THREAD_UNINT);
7869 } while (me->depth != gPMHaltDepth);
7870 }
7871 IOLockUnlock( gPMHaltLock );
7872 }
2d21ac55 7873
fe8ab488
A
7874 // No more work to do, terminate thread
7875 DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me), me->visits);
7876 thread_wakeup( &gPMHaltDepth );
7877 me->release();
2d21ac55
A
7878}
7879
7880void PMHaltWorker::work( PMHaltWorker * me )
7881{
fe8ab488
A
7882 IOService * service;
7883 OSSet * inner;
7884 AbsoluteTime startTime;
7885 UInt32 deltaTime;
7886 bool timeout;
7887
7888 while (true)
7889 {
7890 service = 0;
7891 timeout = false;
7892
7893 // Claim an unit of work from the shared pool
7894 IOLockLock( gPMHaltLock );
7895 inner = (OSSet *)gPMHaltArray->getObject(me->depth);
7896 if (inner)
7897 {
7898 service = (IOService *)inner->getAnyObject();
7899 if (service)
7900 {
7901 service->retain();
7902 inner->removeObject(service);
7903 }
7904 }
7905 IOLockUnlock( gPMHaltLock );
7906 if (!service)
7907 break; // no more work at this depth
7908
7909 clock_get_uptime(&startTime);
7910
7911 if (!service->isInactive() &&
7912 service->setProperty(gPMHaltClientAcknowledgeKey, me))
7913 {
7914 IOLockLock(me->lock);
7915 me->startTime = startTime;
7916 me->service = service;
7917 me->timeout = false;
7918 IOLockUnlock(me->lock);
7919
3e170ce0 7920 service->systemWillShutdown( gPMHaltMessageType );
fe8ab488
A
7921
7922 // Wait for driver acknowledgement
7923 IOLockLock(me->lock);
7924 while (service->getProperty(gPMHaltClientAcknowledgeKey))
7925 {
7926 IOLockSleep(me->lock, me, THREAD_UNINT);
7927 }
7928 me->service = 0;
7929 timeout = me->timeout;
7930 IOLockUnlock(me->lock);
7931 }
7932
7933 deltaTime = computeDeltaTimeMS(&startTime);
7934 if ((deltaTime > kPMHaltTimeoutMS) || timeout ||
7935 (gIOKitDebug & kIOLogPMRootDomain))
7936 {
3e170ce0
A
7937 LOG("%s driver %s (0x%llx) took %u ms\n",
7938 (gPMHaltMessageType == kIOMessageSystemWillPowerOff) ?
fe8ab488 7939 "PowerOff" : "Restart",
3e170ce0 7940 service->getName(), service->getRegistryEntryID(),
fe8ab488
A
7941 (uint32_t) deltaTime );
7942 }
7943
7944 service->release();
7945 me->visits++;
7946 }
2d21ac55
A
7947}
7948
7949void PMHaltWorker::checkTimeout( PMHaltWorker * me, AbsoluteTime * now )
7950{
fe8ab488
A
7951 UInt64 nano;
7952 AbsoluteTime startTime;
7953 AbsoluteTime endTime;
7954
7955 endTime = *now;
7956
7957 IOLockLock(me->lock);
7958 if (me->service && !me->timeout)
7959 {
7960 startTime = me->startTime;
7961 nano = 0;
7962 if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0)
7963 {
7964 SUB_ABSOLUTETIME(&endTime, &startTime);
7965 absolutetime_to_nanoseconds(endTime, &nano);
7966 }
7967 if (nano > 3000000000ULL)
7968 {
7969 me->timeout = true;
7970 MSG("%s still waiting on %s\n",
3e170ce0 7971 (gPMHaltMessageType == kIOMessageSystemWillPowerOff) ?
fe8ab488
A
7972 "PowerOff" : "Restart",
7973 me->service->getName());
7974 }
7975 }
7976 IOLockUnlock(me->lock);
2d21ac55
A
7977}
7978
b0d623f7 7979//******************************************************************************
2d21ac55
A
7980// acknowledgeSystemWillShutdown
7981//
7982// Acknowledgement from drivers that they have prepared for shutdown/restart.
b0d623f7 7983//******************************************************************************
2d21ac55
A
7984
7985void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService * from )
7986{
fe8ab488
A
7987 PMHaltWorker * worker;
7988 OSObject * prop;
7989
7990 if (!from)
7991 return;
7992
7993 //DLOG("%s acknowledged\n", from->getName());
7994 prop = from->copyProperty( gPMHaltClientAcknowledgeKey );
7995 if (prop)
7996 {
7997 worker = (PMHaltWorker *) prop;
7998 IOLockLock(worker->lock);
7999 from->removeProperty( gPMHaltClientAcknowledgeKey );
8000 thread_wakeup((event_t) worker);
8001 IOLockUnlock(worker->lock);
8002 worker->release();
8003 }
8004 else
8005 {
8006 DLOG("%s acknowledged without worker property\n",
8007 from->getName());
8008 }
2d21ac55
A
8009}
8010
b0d623f7
A
8011
8012//******************************************************************************
2d21ac55
A
8013// notifySystemShutdown
8014//
8015// Notify all objects in PM tree that system will shutdown or restart
b0d623f7 8016//******************************************************************************
2d21ac55
A
8017
8018static void
3e170ce0 8019notifySystemShutdown( IOService * root, uint32_t messageType )
2d21ac55
A
8020{
8021#define PLACEHOLDER ((OSSet *)gPMHaltArray)
fe8ab488
A
8022 IORegistryIterator * iter;
8023 IORegistryEntry * entry;
8024 IOService * node;
8025 OSSet * inner;
8026 PMHaltWorker * workers[kPMHaltMaxWorkers];
8027 AbsoluteTime deadline;
8028 unsigned int totalNodes = 0;
8029 unsigned int depth;
8030 unsigned int rootDepth;
8031 unsigned int numWorkers;
8032 unsigned int count;
8033 int waitResult;
8034 void * baseFunc;
8035 bool ok;
2d21ac55 8036
3e170ce0 8037 DLOG("%s msgType = 0x%x\n", __FUNCTION__, messageType);
2d21ac55 8038
fe8ab488 8039 baseFunc = OSMemberFunctionCast(void *, root, &IOService::systemWillShutdown);
2d21ac55 8040
fe8ab488 8041 // Iterate the entire PM tree starting from root
2d21ac55 8042
fe8ab488
A
8043 rootDepth = root->getDepth( gIOPowerPlane );
8044 if (!rootDepth) goto done;
2d21ac55 8045
fe8ab488
A
8046 // debug - for repeated test runs
8047 while (PMHaltWorker::metaClass->getInstanceCount())
8048 IOSleep(1);
2d21ac55 8049
fe8ab488
A
8050 if (!gPMHaltArray)
8051 {
8052 gPMHaltArray = OSArray::withCapacity(40);
8053 if (!gPMHaltArray) goto done;
8054 }
8055 else // debug
8056 gPMHaltArray->flushCollection();
2d21ac55 8057
fe8ab488
A
8058 if (!gPMHaltLock)
8059 {
8060 gPMHaltLock = IOLockAlloc();
8061 if (!gPMHaltLock) goto done;
8062 }
2d21ac55 8063
fe8ab488
A
8064 if (!gPMHaltClientAcknowledgeKey)
8065 {
8066 gPMHaltClientAcknowledgeKey =
8067 OSSymbol::withCStringNoCopy("PMShutdown");
8068 if (!gPMHaltClientAcknowledgeKey) goto done;
8069 }
2d21ac55 8070
3e170ce0 8071 gPMHaltMessageType = messageType;
2d21ac55 8072
fe8ab488 8073 // Depth-first walk of PM plane
2d21ac55 8074
fe8ab488
A
8075 iter = IORegistryIterator::iterateOver(
8076 root, gIOPowerPlane, kIORegistryIterateRecursively);
2d21ac55 8077
fe8ab488
A
8078 if (iter)
8079 {
8080 while ((entry = iter->getNextObject()))
8081 {
8082 node = OSDynamicCast(IOService, entry);
8083 if (!node)
8084 continue;
2d21ac55 8085
fe8ab488
A
8086 if (baseFunc ==
8087 OSMemberFunctionCast(void *, node, &IOService::systemWillShutdown))
8088 continue;
2d21ac55 8089
fe8ab488
A
8090 depth = node->getDepth( gIOPowerPlane );
8091 if (depth <= rootDepth)
8092 continue;
2d21ac55 8093
fe8ab488 8094 ok = false;
2d21ac55 8095
fe8ab488
A
8096 // adjust to zero based depth
8097 depth -= (rootDepth + 1);
6d2010ae 8098
fe8ab488
A
8099 // gPMHaltArray is an array of containers, each container
8100 // refers to nodes with the same depth.
6d2010ae 8101
fe8ab488
A
8102 count = gPMHaltArray->getCount();
8103 while (depth >= count)
8104 {
8105 // expand array and insert placeholders
8106 gPMHaltArray->setObject(PLACEHOLDER);
8107 count++;
8108 }
8109 count = gPMHaltArray->getCount();
8110 if (depth < count)
8111 {
8112 inner = (OSSet *)gPMHaltArray->getObject(depth);
8113 if (inner == PLACEHOLDER)
8114 {
8115 inner = OSSet::withCapacity(40);
8116 if (inner)
8117 {
8118 gPMHaltArray->replaceObject(depth, inner);
8119 inner->release();
8120 }
8121 }
6d2010ae 8122
fe8ab488
A
8123 // PM nodes that appear more than once in the tree will have
8124 // the same depth, OSSet will refuse to add the node twice.
8125 if (inner)
8126 ok = inner->setObject(node);
8127 }
8128 if (!ok)
8129 DLOG("Skipped PM node %s\n", node->getName());
8130 }
8131 iter->release();
8132 }
39236c6e 8133
fe8ab488
A
8134 // debug only
8135 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); i++)
8136 {
8137 count = 0;
8138 if (inner != PLACEHOLDER)
8139 count = inner->getCount();
8140 DLOG("Nodes at depth %u = %u\n", i, count);
8141 }
6d2010ae 8142
fe8ab488
A
8143 // strip placeholders (not all depths are populated)
8144 numWorkers = 0;
8145 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); )
8146 {
8147 if (inner == PLACEHOLDER)
8148 {
8149 gPMHaltArray->removeObject(i);
8150 continue;
8151 }
8152 count = inner->getCount();
8153 if (count > numWorkers)
8154 numWorkers = count;
8155 totalNodes += count;
8156 i++;
8157 }
6d2010ae 8158
fe8ab488
A
8159 if (gPMHaltArray->getCount() == 0 || !numWorkers)
8160 goto done;
39236c6e 8161
fe8ab488
A
8162 gPMHaltBusyCount = 0;
8163 gPMHaltIdleCount = 0;
8164 gPMHaltDepth = gPMHaltArray->getCount() - 1;
39236c6e 8165
fe8ab488 8166 // Create multiple workers (and threads)
6d2010ae 8167
fe8ab488
A
8168 if (numWorkers > kPMHaltMaxWorkers)
8169 numWorkers = kPMHaltMaxWorkers;
6d2010ae 8170
fe8ab488
A
8171 DLOG("PM nodes %u, maxDepth %u, workers %u\n",
8172 totalNodes, gPMHaltArray->getCount(), numWorkers);
8173
8174 for (unsigned int i = 0; i < numWorkers; i++)
8175 workers[i] = PMHaltWorker::worker();
8176
8177 // Wait for workers to exhaust all available work
8178
8179 IOLockLock(gPMHaltLock);
8180 while (gPMHaltDepth >= 0)
39236c6e 8181 {
fe8ab488
A
8182 clock_interval_to_deadline(1000, kMillisecondScale, &deadline);
8183
8184 waitResult = IOLockSleepDeadline(
8185 gPMHaltLock, &gPMHaltDepth, deadline, THREAD_UNINT);
8186 if (THREAD_TIMED_OUT == waitResult)
8187 {
8188 AbsoluteTime now;
8189 clock_get_uptime(&now);
8190
8191 IOLockUnlock(gPMHaltLock);
8192 for (unsigned int i = 0 ; i < numWorkers; i++)
8193 {
8194 if (workers[i])
8195 PMHaltWorker::checkTimeout(workers[i], &now);
8196 }
8197 IOLockLock(gPMHaltLock);
8198 }
39236c6e 8199 }
fe8ab488 8200 IOLockUnlock(gPMHaltLock);
39236c6e 8201
fe8ab488 8202 // Release all workers
2d21ac55 8203
fe8ab488 8204 for (unsigned int i = 0; i < numWorkers; i++)
6d2010ae 8205 {
fe8ab488
A
8206 if (workers[i])
8207 workers[i]->release();
8208 // worker also retained by it's own thread
6d2010ae 8209 }
2d21ac55 8210
fe8ab488
A
8211done:
8212 DLOG("%s done\n", __FUNCTION__);
8213 return;
2d21ac55
A
8214}
8215
39236c6e
A
8216// MARK: -
8217// MARK: Kernel Assertion
8218
0b4c1975
A
8219/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8220
8221IOPMDriverAssertionID IOPMrootDomain::createPMAssertion(
8222 IOPMDriverAssertionType whichAssertionBits,
8223 IOPMDriverAssertionLevel assertionLevel,
8224 IOService *ownerService,
8225 const char *ownerDescription)
8226{
8227 IOReturn ret;
8228 IOPMDriverAssertionID newAssertion;
fe8ab488 8229
0b4c1975
A
8230 if (!pmAssertions)
8231 return 0;
fe8ab488 8232
0b4c1975
A
8233 ret = pmAssertions->createAssertion(whichAssertionBits, assertionLevel, ownerService, ownerDescription, &newAssertion);
8234
8235 if (kIOReturnSuccess == ret)
8236 return newAssertion;
8237 else
8238 return 0;
8239}
8240
8241IOReturn IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion)
8242{
8243 if (!pmAssertions)
8244 return kIOReturnInternalError;
fe8ab488 8245
0b4c1975
A
8246 return pmAssertions->releaseAssertion(releaseAssertion);
8247}
8248
fe8ab488 8249
0b4c1975 8250IOReturn IOPMrootDomain::setPMAssertionLevel(
fe8ab488 8251 IOPMDriverAssertionID assertionID,
0b4c1975
A
8252 IOPMDriverAssertionLevel assertionLevel)
8253{
8254 return pmAssertions->setAssertionLevel(assertionID, assertionLevel);
8255}
8256
8257IOPMDriverAssertionLevel IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion)
8258{
8259 IOPMDriverAssertionType sysLevels;
8260
fe8ab488 8261 if (!pmAssertions || whichAssertion == 0)
0b4c1975
A
8262 return kIOPMDriverAssertionLevelOff;
8263
8264 sysLevels = pmAssertions->getActivatedAssertions();
fe8ab488 8265
0b4c1975
A
8266 // Check that every bit set in argument 'whichAssertion' is asserted
8267 // in the aggregate bits.
8268 if ((sysLevels & whichAssertion) == whichAssertion)
8269 return kIOPMDriverAssertionLevelOn;
8270 else
8271 return kIOPMDriverAssertionLevelOff;
8272}
8273
8274IOReturn IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels)
8275{
8276 if (!pmAssertions)
8277 return kIOReturnNotFound;
8278
8279 return pmAssertions->setUserAssertionLevels(inLevels);
8280}
8281
8282bool IOPMrootDomain::serializeProperties( OSSerialize * s ) const
8283{
8284 if (pmAssertions)
8285 {
8286 pmAssertions->publishProperties();
8287 }
8288 return( IOService::serializeProperties(s) );
8289}
2d21ac55 8290
39236c6e
A
8291OSObject * IOPMrootDomain::copyProperty( const char * aKey) const
8292{
8293 OSObject *obj = NULL;
8294 obj = IOService::copyProperty(aKey);
8295
8296 if (obj) return obj;
8297
fe8ab488 8298 if (!strncmp(aKey, kIOPMSleepWakeWdogRebootKey,
39236c6e 8299 sizeof(kIOPMSleepWakeWdogRebootKey))) {
fe8ab488 8300 if (swd_flags & SWD_BOOT_BY_SW_WDOG)
3e170ce0 8301 return kOSBooleanTrue;
fe8ab488 8302 else
3e170ce0 8303 return kOSBooleanFalse;
fe8ab488 8304
39236c6e
A
8305 }
8306
fe8ab488 8307 if (!strncmp(aKey, kIOPMSleepWakeWdogLogsValidKey,
39236c6e 8308 sizeof(kIOPMSleepWakeWdogLogsValidKey))) {
fe8ab488 8309 if (swd_flags & SWD_VALID_LOGS)
3e170ce0 8310 return kOSBooleanTrue;
fe8ab488 8311 else
3e170ce0 8312 return kOSBooleanFalse;
fe8ab488 8313
39236c6e
A
8314 }
8315
fe8ab488
A
8316 /*
8317 * XXX: We should get rid of "DesktopMode" property when 'kAppleClamshellCausesSleepKey'
8318 * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
39236c6e
A
8319 * issued by DisplayWrangler on darkwake.
8320 */
8321 if (!strcmp(aKey, "DesktopMode")) {
8322 if (desktopMode)
3e170ce0 8323 return kOSBooleanTrue;
fe8ab488 8324 else
3e170ce0 8325 return kOSBooleanFalse;
39236c6e
A
8326 }
8327 if (!strcmp(aKey, "DisplayIdleForDemandSleep")) {
8328 if (displayIdleForDemandSleep) {
3e170ce0 8329 return kOSBooleanTrue;
39236c6e
A
8330 }
8331 else {
3e170ce0 8332 return kOSBooleanFalse;
39236c6e
A
8333 }
8334 }
fe8ab488
A
8335
8336 if (!strcmp(aKey, kIOPMDriverWakeEventsKey))
8337 {
8338 OSArray * array = 0;
8339 WAKEEVENT_LOCK();
3e170ce0
A
8340 if (_systemWakeEventsArray && _systemWakeEventsArray->getCount()) {
8341 OSCollection *collection = _systemWakeEventsArray->copyCollection();
8342 if (collection && !(array = OSDynamicCast(OSArray, collection))) {
8343 collection->release();
8344 }
8345 }
fe8ab488
A
8346 WAKEEVENT_UNLOCK();
8347 return array;
8348 }
8349
8350 if (!strcmp(aKey, kIOPMSleepStatisticsAppsKey))
8351 {
8352 OSArray * array = 0;
8353 IOLockLock(pmStatsLock);
8354 if (pmStatsAppResponses && pmStatsAppResponses->getCount()) {
3e170ce0
A
8355 OSCollection *collection = pmStatsAppResponses->copyCollection();
8356 if (collection && !(array = OSDynamicCast(OSArray, collection))) {
8357 collection->release();
8358 }
fe8ab488
A
8359 pmStatsAppResponses->flushCollection();
8360 }
8361 IOLockUnlock(pmStatsLock);
8362 return array;
8363 }
8364
3e170ce0
A
8365 if (!strcmp(aKey, kIOPMIdleSleepPreventersKey))
8366 {
8367 OSArray *idleSleepList = NULL;
8368 gRootDomain->copySleepPreventersList(&idleSleepList, NULL);
8369 return idleSleepList;
8370 }
8371
8372 if (!strcmp(aKey, kIOPMSystemSleepPreventersKey))
8373 {
8374 OSArray *systemSleepList = NULL;
8375 gRootDomain->copySleepPreventersList(NULL, &systemSleepList);
8376 return systemSleepList;
8377 }
8378
39236c6e 8379 return NULL;
fe8ab488
A
8380}
8381
8382// MARK: -
8383// MARK: Wake Event Reporting
8384
8385void IOPMrootDomain::copyWakeReasonString( char * outBuf, size_t bufSize )
8386{
8387 WAKEEVENT_LOCK();
8388 strlcpy(outBuf, gWakeReasonString, bufSize);
8389 WAKEEVENT_UNLOCK();
8390}
8391
8392//******************************************************************************
8393// acceptSystemWakeEvents
8394//
8395// Private control for the acceptance of driver wake event claims.
8396//******************************************************************************
8397
8398void IOPMrootDomain::acceptSystemWakeEvents( bool accept )
8399{
8400 bool logWakeReason = false;
8401
8402 WAKEEVENT_LOCK();
8403 if (accept)
8404 {
8405 gWakeReasonString[0] = '\0';
8406 if (!_systemWakeEventsArray)
8407 _systemWakeEventsArray = OSArray::withCapacity(4);
8408 if ((_acceptSystemWakeEvents = (_systemWakeEventsArray != 0)))
8409 _systemWakeEventsArray->flushCollection();
8410 }
8411 else
8412 {
8413 _acceptSystemWakeEvents = false;
8414 }
8415 WAKEEVENT_UNLOCK();
8416
8417 if (logWakeReason)
8418 MSG("system wake events:%s\n", gWakeReasonString);
8419}
8420
8421//******************************************************************************
8422// claimSystemWakeEvent
8423//
8424// For a driver to claim a device is the source/conduit of a system wake event.
8425//******************************************************************************
8426
8427void IOPMrootDomain::claimSystemWakeEvent(
8428 IOService * device,
8429 IOOptionBits flags,
8430 const char * reason,
8431 OSObject * details )
8432{
8433 const OSSymbol * deviceName = 0;
8434 OSNumber * deviceRegId = 0;
8435 OSNumber * claimTime = 0;
8436 OSData * flagsData = 0;
8437 OSString * reasonString = 0;
8438 OSDictionary * d = 0;
8439 uint64_t timestamp;
8440 bool ok = false;
8441
8442 pmEventTimeStamp(&timestamp);
8443
8444 if (!device || !reason) return;
8445
8446 deviceName = device->copyName(gIOServicePlane);
8447 deviceRegId = OSNumber::withNumber(device->getRegistryEntryID(), 64);
8448 claimTime = OSNumber::withNumber(timestamp, 64);
8449 flagsData = OSData::withBytes(&flags, sizeof(flags));
8450 reasonString = OSString::withCString(reason);
8451 d = OSDictionary::withCapacity(5 + (details ? 1 : 0));
8452 if (!deviceName || !deviceRegId || !claimTime || !flagsData || !reasonString)
8453 goto done;
8454
8455 d->setObject(gIONameKey, deviceName);
8456 d->setObject(gIORegistryEntryIDKey, deviceRegId);
8457 d->setObject(kIOPMWakeEventTimeKey, claimTime);
8458 d->setObject(kIOPMWakeEventFlagsKey, flagsData);
8459 d->setObject(kIOPMWakeEventReasonKey, reasonString);
8460 if (details)
8461 d->setObject(kIOPMWakeEventDetailsKey, details);
39236c6e 8462
fe8ab488
A
8463 WAKEEVENT_LOCK();
8464 if (!gWakeReasonSysctlRegistered)
8465 {
8466 // Lazy registration until the platform driver stops registering
8467 // the same name.
8468 gWakeReasonSysctlRegistered = true;
8469 }
8470 if (_acceptSystemWakeEvents)
8471 {
8472 ok = _systemWakeEventsArray->setObject(d);
8473 if (gWakeReasonString[0] != '\0')
8474 strlcat(gWakeReasonString, " ", sizeof(gWakeReasonString));
8475 strlcat(gWakeReasonString, reason, sizeof(gWakeReasonString));
8476 }
8477 WAKEEVENT_UNLOCK();
39236c6e 8478
fe8ab488
A
8479done:
8480 if (deviceName) deviceName->release();
8481 if (deviceRegId) deviceRegId->release();
8482 if (claimTime) claimTime->release();
8483 if (flagsData) flagsData->release();
8484 if (reasonString) reasonString->release();
8485 if (d) d->release();
39236c6e
A
8486}
8487
0c530ab8
A
8488/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8489
6d2010ae
A
8490// MARK: -
8491// MARK: PMSettingHandle
0c530ab8 8492
6d2010ae 8493OSDefineMetaClassAndStructors( PMSettingHandle, OSObject )
0c530ab8 8494
6d2010ae 8495void PMSettingHandle::free( void )
0c530ab8 8496{
6d2010ae
A
8497 if (pmso)
8498 {
8499 pmso->clientHandleFreed();
8500 pmso->release();
8501 pmso = 0;
8502 }
8503
8504 OSObject::free();
0c530ab8
A
8505}
8506
6d2010ae
A
8507// MARK: -
8508// MARK: PMSettingObject
8509
8510#undef super
8511#define super OSObject
8512OSDefineMetaClassAndFinalStructors( PMSettingObject, OSObject )
8513
fe8ab488 8514/*
0c530ab8
A
8515 * Static constructor/initializer for PMSettingObject
8516 */
8517PMSettingObject *PMSettingObject::pmSettingObject(
8518 IOPMrootDomain *parent_arg,
8519 IOPMSettingControllerCallback handler_arg,
8520 OSObject *target_arg,
8521 uintptr_t refcon_arg,
8522 uint32_t supportedPowerSources,
6d2010ae
A
8523 const OSSymbol * settings[],
8524 OSObject **handle_obj)
0c530ab8 8525{
6d2010ae
A
8526 uint32_t settingCount = 0;
8527 PMSettingObject *pmso = 0;
8528 PMSettingHandle *pmsh = 0;
0c530ab8 8529
6d2010ae
A
8530 if ( !parent_arg || !handler_arg || !settings || !handle_obj )
8531 return NULL;
0c530ab8 8532
6d2010ae
A
8533 // count OSSymbol entries in NULL terminated settings array
8534 while (settings[settingCount]) {
8535 settingCount++;
0c530ab8 8536 }
6d2010ae
A
8537 if (0 == settingCount)
8538 return NULL;
0c530ab8
A
8539
8540 pmso = new PMSettingObject;
6d2010ae
A
8541 if (!pmso || !pmso->init())
8542 goto fail;
8543
8544 pmsh = new PMSettingHandle;
8545 if (!pmsh || !pmsh->init())
8546 goto fail;
8547
8548 queue_init(&pmso->calloutQueue);
8549 pmso->parent = parent_arg;
8550 pmso->func = handler_arg;
8551 pmso->target = target_arg;
8552 pmso->refcon = refcon_arg;
8553 pmso->settingCount = settingCount;
8554
8555 pmso->retain(); // handle holds a retain on pmso
8556 pmsh->pmso = pmso;
8557 pmso->pmsh = pmsh;
8558
8559 pmso->publishedFeatureID = (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount);
8560 if (pmso->publishedFeatureID) {
8561 for (unsigned int i=0; i<settingCount; i++) {
0c530ab8
A
8562 // Since there is now at least one listener to this setting, publish
8563 // PM root domain support for it.
7ddcb079 8564 parent_arg->publishPMSetting( settings[i],
0c530ab8
A
8565 supportedPowerSources, &pmso->publishedFeatureID[i] );
8566 }
8567 }
6d2010ae
A
8568
8569 *handle_obj = pmsh;
0c530ab8 8570 return pmso;
6d2010ae
A
8571
8572fail:
8573 if (pmso) pmso->release();
8574 if (pmsh) pmsh->release();
8575 return NULL;
0c530ab8
A
8576}
8577
6d2010ae 8578void PMSettingObject::free( void )
0c530ab8 8579{
6d2010ae
A
8580 if (publishedFeatureID) {
8581 for (uint32_t i=0; i<settingCount; i++) {
8582 if (publishedFeatureID[i]) {
0c530ab8 8583 parent->removePublishedFeature( publishedFeatureID[i] );
0b4e3aa0
A
8584 }
8585 }
6d2010ae
A
8586
8587 IOFree(publishedFeatureID, sizeof(uint32_t) * settingCount);
8588 }
8589
8590 super::free();
8591}
8592
8593void PMSettingObject::dispatchPMSetting( const OSSymbol * type, OSObject * object )
8594{
8595 (*func)(target, type, object, refcon);
8596}
8597
8598void PMSettingObject::clientHandleFreed( void )
8599{
8600 parent->deregisterPMSettingObject(this);
8601}
8602
0b4c1975
A
8603// MARK: -
8604// MARK: PMAssertionsTracker
8605
8606//*********************************************************************************
8607//*********************************************************************************
8608//*********************************************************************************
8609// class PMAssertionsTracker Implementation
8610
8611#define kAssertUniqueIDStart 500
8612
8613PMAssertionsTracker *PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain *rootDomain )
8614{
8615 PMAssertionsTracker *myself;
fe8ab488 8616
0b4c1975 8617 myself = new PMAssertionsTracker;
fe8ab488 8618
0b4c1975
A
8619 if (myself) {
8620 myself->init();
8621 myself->owner = rootDomain;
fe8ab488 8622 myself->issuingUniqueID = kAssertUniqueIDStart;
0b4c1975
A
8623 myself->assertionsArray = OSArray::withCapacity(5);
8624 myself->assertionsKernel = 0;
8625 myself->assertionsUser = 0;
8626 myself->assertionsCombined = 0;
8627 myself->assertionsArrayLock = IOLockAlloc();
8628 myself->tabulateProducerCount = myself->tabulateConsumerCount = 0;
fe8ab488 8629
0b4c1975
A
8630 if (!myself->assertionsArray || !myself->assertionsArrayLock)
8631 myself = NULL;
8632 }
8633
8634 return myself;
8635}
8636
8637/* tabulate
8638 * - Update assertionsKernel to reflect the state of all
8639 * assertions in the kernel.
8640 * - Update assertionsCombined to reflect both kernel & user space.
8641 */
8642void PMAssertionsTracker::tabulate(void)
8643{
8644 int i;
8645 int count;
8646 PMAssertStruct *_a = NULL;
8647 OSData *_d = NULL;
8648
8649 IOPMDriverAssertionType oldKernel = assertionsKernel;
8650 IOPMDriverAssertionType oldCombined = assertionsCombined;
8651
8652 ASSERT_GATED();
8653
8654 assertionsKernel = 0;
8655 assertionsCombined = 0;
8656
8657 if (!assertionsArray)
8658 return;
8659
8660 if ((count = assertionsArray->getCount()))
8661 {
8662 for (i=0; i<count; i++)
8663 {
8664 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
8665 if (_d)
8666 {
8667 _a = (PMAssertStruct *)_d->getBytesNoCopy();
8668 if (_a && (kIOPMDriverAssertionLevelOn == _a->level))
8669 assertionsKernel |= _a->assertionBits;
8670 }
8671 }
8672 }
8673
8674 tabulateProducerCount++;
8675 assertionsCombined = assertionsKernel | assertionsUser;
8676
8677 if ((assertionsKernel != oldKernel) ||
8678 (assertionsCombined != oldCombined))
fe8ab488 8679 {
7ddcb079 8680 owner->evaluateAssertions(assertionsCombined, oldCombined);
0b4c1975
A
8681 }
8682}
8683
8684void PMAssertionsTracker::publishProperties( void )
8685{
8686 OSArray *assertionsSummary = NULL;
8687
8688 if (tabulateConsumerCount != tabulateProducerCount)
8689 {
8690 IOLockLock(assertionsArrayLock);
8691
8692 tabulateConsumerCount = tabulateProducerCount;
8693
8694 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
8695 */
8696 assertionsSummary = copyAssertionsArray();
8697 if (assertionsSummary)
8698 {
8699 owner->setProperty(kIOPMAssertionsDriverDetailedKey, assertionsSummary);
8700 assertionsSummary->release();
8701 }
8702 else
8703 {
8704 owner->removeProperty(kIOPMAssertionsDriverDetailedKey);
8705 }
8706
8707 /* Publish the IOPMrootDomain property "DriverPMAssertions"
8708 */
8709 owner->setProperty(kIOPMAssertionsDriverKey, assertionsKernel, 64);
8710
8711 IOLockUnlock(assertionsArrayLock);
8712 }
8713}
8714
8715PMAssertionsTracker::PMAssertStruct *PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id, int *index)
8716{
8717 PMAssertStruct *_a = NULL;
8718 OSData *_d = NULL;
8719 int found = -1;
8720 int count = 0;
8721 int i = 0;
8722
8723 if (assertionsArray
8724 && (count = assertionsArray->getCount()))
8725 {
8726 for (i=0; i<count; i++)
8727 {
8728 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
8729 if (_d)
8730 {
8731 _a = (PMAssertStruct *)_d->getBytesNoCopy();
8732 if (_a && (_id == _a->id)) {
8733 found = i;
8734 break;
8735 }
8736 }
8737 }
8738 }
8739
8740 if (-1 == found) {
8741 return NULL;
8742 } else {
8743 if (index)
8744 *index = found;
8745 return _a;
8746 }
8747}
8748
8749/* PMAssertionsTracker::handleCreateAssertion
8750 * Perform assertion work on the PM workloop. Do not call directly.
8751 */
8752IOReturn PMAssertionsTracker::handleCreateAssertion(OSData *newAssertion)
8753{
8754 ASSERT_GATED();
8755
8756 if (newAssertion)
8757 {
8758 IOLockLock(assertionsArrayLock);
8759 assertionsArray->setObject(newAssertion);
8760 IOLockUnlock(assertionsArrayLock);
8761 newAssertion->release();
8762
8763 tabulate();
8764 }
8765 return kIOReturnSuccess;
8766}
8767
8768/* PMAssertionsTracker::createAssertion
fe8ab488 8769 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
0b4c1975
A
8770 * appropiate.
8771 */
8772IOReturn PMAssertionsTracker::createAssertion(
8773 IOPMDriverAssertionType which,
8774 IOPMDriverAssertionLevel level,
fe8ab488
A
8775 IOService *serviceID,
8776 const char *whoItIs,
0b4c1975
A
8777 IOPMDriverAssertionID *outID)
8778{
8779 OSData *dataStore = NULL;
8780 PMAssertStruct track;
8781
8782 // Warning: trillions and trillions of created assertions may overflow the unique ID.
0b4c1975 8783 track.id = OSIncrementAtomic64((SInt64*) &issuingUniqueID);
0b4c1975
A
8784 track.level = level;
8785 track.assertionBits = which;
39236c6e 8786 track.ownerString = whoItIs ? OSSymbol::withCString(whoItIs):0;
0b4c1975 8787 track.ownerService = serviceID;
39236c6e 8788 track.registryEntryID = serviceID ? serviceID->getRegistryEntryID():0;
0b4c1975
A
8789 track.modifiedTime = 0;
8790 pmEventTimeStamp(&track.createdTime);
fe8ab488 8791
0b4c1975
A
8792 dataStore = OSData::withBytes(&track, sizeof(PMAssertStruct));
8793 if (!dataStore)
8794 {
8795 if (track.ownerString)
8796 track.ownerString->release();
8797 return kIOReturnNoMemory;
8798 }
8799
8800 *outID = track.id;
fe8ab488 8801
0b4c1975
A
8802 if (owner && owner->pmPowerStateQueue) {
8803 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionCreate, (void *)dataStore);
8804 }
fe8ab488 8805
0b4c1975
A
8806 return kIOReturnSuccess;
8807}
1c79356b 8808
0b4c1975
A
8809/* PMAssertionsTracker::handleReleaseAssertion
8810 * Runs in PM workloop. Do not call directly.
8811 */
8812IOReturn PMAssertionsTracker::handleReleaseAssertion(
8813 IOPMDriverAssertionID _id)
8814{
8815 ASSERT_GATED();
8816
8817 int index;
8818 PMAssertStruct *assertStruct = detailsForID(_id, &index);
fe8ab488 8819
0b4c1975
A
8820 if (!assertStruct)
8821 return kIOReturnNotFound;
8822
8823 IOLockLock(assertionsArrayLock);
fe8ab488 8824 if (assertStruct->ownerString)
0b4c1975
A
8825 assertStruct->ownerString->release();
8826
8827 assertionsArray->removeObject(index);
8828 IOLockUnlock(assertionsArrayLock);
fe8ab488 8829
0b4c1975
A
8830 tabulate();
8831 return kIOReturnSuccess;
8832}
8833
8834/* PMAssertionsTracker::releaseAssertion
8835 * Releases an assertion and affects system behavior if appropiate.
8836 * Actual work happens on PM workloop.
8837 */
8838IOReturn PMAssertionsTracker::releaseAssertion(
8839 IOPMDriverAssertionID _id)
8840{
8841 if (owner && owner->pmPowerStateQueue) {
8842 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionRelease, 0, _id);
8843 }
8844 return kIOReturnSuccess;
8845}
8846
8847/* PMAssertionsTracker::handleSetAssertionLevel
8848 * Runs in PM workloop. Do not call directly.
8849 */
8850IOReturn PMAssertionsTracker::handleSetAssertionLevel(
fe8ab488 8851 IOPMDriverAssertionID _id,
0b4c1975
A
8852 IOPMDriverAssertionLevel _level)
8853{
8854 PMAssertStruct *assertStruct = detailsForID(_id, NULL);
8855
8856 ASSERT_GATED();
8857
8858 if (!assertStruct) {
8859 return kIOReturnNotFound;
8860 }
8861
8862 IOLockLock(assertionsArrayLock);
8863 pmEventTimeStamp(&assertStruct->modifiedTime);
8864 assertStruct->level = _level;
8865 IOLockUnlock(assertionsArrayLock);
8866
8867 tabulate();
8868 return kIOReturnSuccess;
8869}
8870
8871/* PMAssertionsTracker::setAssertionLevel
8872 */
8873IOReturn PMAssertionsTracker::setAssertionLevel(
fe8ab488 8874 IOPMDriverAssertionID _id,
0b4c1975
A
8875 IOPMDriverAssertionLevel _level)
8876{
8877 if (owner && owner->pmPowerStateQueue) {
8878 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionSetLevel,
39236c6e 8879 (void *)(uintptr_t)_level, _id);
0b4c1975
A
8880 }
8881
fe8ab488 8882 return kIOReturnSuccess;
0b4c1975
A
8883}
8884
8885IOReturn PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0)
8886{
8887 IOPMDriverAssertionType new_user_levels = *(IOPMDriverAssertionType *) arg0;
8888
8889 ASSERT_GATED();
8890
8891 if (new_user_levels != assertionsUser)
8892 {
8893 assertionsUser = new_user_levels;
8894 DLOG("assertionsUser 0x%llx\n", assertionsUser);
8895 }
8896
8897 tabulate();
8898 return kIOReturnSuccess;
8899}
8900
8901IOReturn PMAssertionsTracker::setUserAssertionLevels(
8902 IOPMDriverAssertionType new_user_levels)
8903{
8904 if (gIOPMWorkLoop) {
8905 gIOPMWorkLoop->runAction(
8906 OSMemberFunctionCast(
8907 IOWorkLoop::Action,
8908 this,
8909 &PMAssertionsTracker::handleSetUserAssertionLevels),
8910 this,
8911 (void *) &new_user_levels, 0, 0, 0);
8912 }
8913
8914 return kIOReturnSuccess;
8915}
8916
8917
8918OSArray *PMAssertionsTracker::copyAssertionsArray(void)
8919{
8920 int count;
8921 int i;
8922 OSArray *outArray = NULL;
8923
8924 if (!assertionsArray ||
8925 (0 == (count = assertionsArray->getCount())) ||
8926 (NULL == (outArray = OSArray::withCapacity(count))))
8927 {
8928 goto exit;
8929 }
8930
8931 for (i=0; i<count; i++)
8932 {
8933 PMAssertStruct *_a = NULL;
8934 OSData *_d = NULL;
8935 OSDictionary *details = NULL;
8936
8937 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
8938 if (_d && (_a = (PMAssertStruct *)_d->getBytesNoCopy()))
8939 {
8940 OSNumber *_n = NULL;
8941
8942 details = OSDictionary::withCapacity(7);
8943 if (!details)
8944 continue;
8945
8946 outArray->setObject(details);
8947 details->release();
fe8ab488 8948
0b4c1975 8949 _n = OSNumber::withNumber(_a->id, 64);
fe8ab488 8950 if (_n) {
0b4c1975
A
8951 details->setObject(kIOPMDriverAssertionIDKey, _n);
8952 _n->release();
8953 }
8954 _n = OSNumber::withNumber(_a->createdTime, 64);
fe8ab488 8955 if (_n) {
0b4c1975
A
8956 details->setObject(kIOPMDriverAssertionCreatedTimeKey, _n);
8957 _n->release();
8958 }
8959 _n = OSNumber::withNumber(_a->modifiedTime, 64);
fe8ab488 8960 if (_n) {
0b4c1975
A
8961 details->setObject(kIOPMDriverAssertionModifiedTimeKey, _n);
8962 _n->release();
8963 }
39236c6e 8964 _n = OSNumber::withNumber((uintptr_t)_a->registryEntryID, 64);
fe8ab488 8965 if (_n) {
39236c6e 8966 details->setObject(kIOPMDriverAssertionRegistryEntryIDKey, _n);
0b4c1975
A
8967 _n->release();
8968 }
8969 _n = OSNumber::withNumber(_a->level, 64);
fe8ab488 8970 if (_n) {
0b4c1975
A
8971 details->setObject(kIOPMDriverAssertionLevelKey, _n);
8972 _n->release();
8973 }
8974 _n = OSNumber::withNumber(_a->assertionBits, 64);
fe8ab488 8975 if (_n) {
0b4c1975
A
8976 details->setObject(kIOPMDriverAssertionAssertedKey, _n);
8977 _n->release();
8978 }
fe8ab488 8979
0b4c1975
A
8980 if (_a->ownerString) {
8981 details->setObject(kIOPMDriverAssertionOwnerStringKey, _a->ownerString);
8982 }
8983 }
8984 }
8985
8986exit:
8987 return outArray;
8988}
8989
8990IOPMDriverAssertionType PMAssertionsTracker::getActivatedAssertions(void)
8991{
8992 return assertionsCombined;
8993}
8994
8995IOPMDriverAssertionLevel PMAssertionsTracker::getAssertionLevel(
8996 IOPMDriverAssertionType type)
8997{
8998 if (type && ((type & assertionsKernel) == assertionsKernel))
8999 {
9000 return kIOPMDriverAssertionLevelOn;
9001 } else {
9002 return kIOPMDriverAssertionLevelOff;
9003 }
9004}
9005
9006//*********************************************************************************
9007//*********************************************************************************
9008//*********************************************************************************
9009
6d2010ae 9010
0b4c1975
A
9011static void pmEventTimeStamp(uint64_t *recordTS)
9012{
9013 clock_sec_t tsec;
9014 clock_usec_t tusec;
9015
9016 if (!recordTS)
9017 return;
fe8ab488 9018
0b4c1975
A
9019 // We assume tsec fits into 32 bits; 32 bits holds enough
9020 // seconds for 136 years since the epoch in 1970.
9021 clock_get_calendar_microtime(&tsec, &tusec);
9022
9023
9024 // Pack the sec & microsec calendar time into a uint64_t, for fun.
9025 *recordTS = 0;
9026 *recordTS |= (uint32_t)tusec;
9027 *recordTS |= ((uint64_t)tsec << 32);
9028
9029 return;
9030}
0c530ab8 9031
6d2010ae
A
9032// MARK: -
9033// MARK: IORootParent
1c79356b 9034
6d2010ae 9035/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1c79356b 9036
b0d623f7 9037OSDefineMetaClassAndFinalStructors(IORootParent, IOService)
1c79356b 9038
6d2010ae
A
9039// The reason that root domain needs a root parent is to facilitate demand
9040// sleep, since a power change from the root parent cannot be vetoed.
9041//
9042// The above statement is no longer true since root domain now performs
9043// demand sleep using overrides. But root parent remains to avoid changing
9044// the power tree stacking. Root parent is parked at the max power state.
9045
1c79356b 9046
6d2010ae 9047static IOPMPowerState patriarchPowerStates[2] =
b0d623f7 9048{
6d2010ae
A
9049 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0},
9050 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0},
1c79356b
A
9051};
9052
6d2010ae
A
9053void IORootParent::initialize( void )
9054{
9055}
9056
b0d623f7 9057bool IORootParent::start( IOService * nub )
1c79356b 9058{
6d2010ae 9059 IOService::start(nub);
b0d623f7 9060 attachToParent( getRegistryRoot(), gIOPowerPlane );
1c79356b 9061 PMinit();
6d2010ae
A
9062 registerPowerDriver(this, patriarchPowerStates, 2);
9063 makeUsable();
1c79356b
A
9064 return true;
9065}
9066
b0d623f7 9067void IORootParent::shutDownSystem( void )
1c79356b 9068{
0b4e3aa0
A
9069}
9070
b0d623f7 9071void IORootParent::restartSystem( void )
0b4e3aa0 9072{
1c79356b
A
9073}
9074
b0d623f7 9075void IORootParent::sleepSystem( void )
1c79356b 9076{
0b4e3aa0
A
9077}
9078
b0d623f7 9079void IORootParent::dozeSystem( void )
0b4e3aa0 9080{
0b4e3aa0
A
9081}
9082
b0d623f7 9083void IORootParent::sleepToDoze( void )
0b4e3aa0 9084{
1c79356b
A
9085}
9086
b0d623f7 9087void IORootParent::wakeSystem( void )
1c79356b 9088{
1c79356b 9089}
6d2010ae
A
9090
9091OSObject * IORootParent::copyProperty( const char * aKey) const
9092{
9093 return (IOService::copyProperty(aKey));
9094}
9095
39236c6e
A
9096
9097#if defined(__i386__) || defined(__x86_64__)
fe8ab488
A
9098IOReturn IOPMrootDomain::restartWithStackshot()
9099{
9100 if ((swd_flags & SWD_WDOG_ENABLED) == 0)
9101 return kIOReturnError;
39236c6e 9102
3e170ce0 9103 takeStackshot(true, true, false);
39236c6e 9104
fe8ab488 9105 return kIOReturnSuccess;
39236c6e
A
9106}
9107
9108void IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger)
fe8ab488 9109{
3e170ce0 9110 takeStackshot(wdogTrigger, false, false);
fe8ab488
A
9111}
9112
3e170ce0 9113void IOPMrootDomain::takeStackshot(bool wdogTrigger, bool isOSXWatchdog, bool isSpinDump)
39236c6e
A
9114{
9115 swd_hdr * hdr = NULL;
9116 addr64_t data[3];
9117 uint32_t wdog_panic = 0;
fe8ab488
A
9118 int cnt = 0;
9119 pid_t pid = 0;
9120 uint32_t flags;
39236c6e
A
9121
9122 char * dstAddr;
fe8ab488 9123 uint32_t size;
39236c6e
A
9124 uint32_t bytesRemaining;
9125 unsigned int len;
9126 OSString * UUIDstring = NULL;
9127 uint64_t code;
9128 IOMemoryMap * logBufMap = NULL;
9129
fe8ab488 9130 swd_stackshot_hdr *stackshotHdr = NULL;
3e170ce0
A
9131
9132 uint32_t bufSize;
9133 uint32_t initialStackSize;
9134
9135 if (isSpinDump) {
9136 if (_systemTransitionType != kSystemTransitionSleep &&
9137 _systemTransitionType != kSystemTransitionWake)
9138 return;
9139 } else {
9140 if ( kIOSleepWakeWdogOff & gIOKitDebug )
9141 return;
9142 }
39236c6e
A
9143
9144 if (wdogTrigger) {
fe8ab488 9145 if (PE_parse_boot_argn("swd_panic", &wdog_panic, sizeof(wdog_panic)) &&
39236c6e
A
9146 (wdog_panic == 1)) {
9147 // If boot-arg is set to panic on sleep/wake hang, call panic
9148 panic("Sleep/Wake hang detected\n");
9149 return;
9150 }
fe8ab488 9151 else if (swd_flags & SWD_BOOT_BY_SW_WDOG) {
39236c6e
A
9152 // If current boot is due to this watch dog trigger restart in previous boot,
9153 // then don't trigger again until at least 1 successful sleep & wake.
3e170ce0 9154 if (!(sleepCnt && (displayWakeCnt || darkWakeCnt))) {
fe8ab488
A
9155 IOLog("Shutting down due to repeated Sleep/Wake failures\n");
9156 PEHaltRestart(kPEHaltCPU);
39236c6e
A
9157 return;
9158 }
9159 }
9160
9161 }
9162
3e170ce0
A
9163 if (isSpinDump) {
9164 if (gSpinDumpBufferFull)
9165 return;
9166 if (swd_spindump_buffer == NULL) {
9167 sleepWakeDebugSpinDumpMemAlloc();
9168 if (swd_spindump_buffer == NULL) return;
9169 }
9170
9171 bufSize = SWD_SPINDUMP_SIZE;
9172 initialStackSize = SWD_INITIAL_SPINDUMP_SIZE;
9173 } else {
9174 if (sleepWakeDebugIsWdogEnabled() == false)
9175 return;
fe8ab488 9176
3e170ce0
A
9177 if (swd_buffer == NULL) {
9178 sleepWakeDebugMemAlloc();
9179 if (swd_buffer == NULL) return;
9180 }
9181
9182 bufSize = SWD_BUF_SIZE;
9183 initialStackSize = SWD_INITIAL_STACK_SIZE;
39236c6e
A
9184 }
9185
9186 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
9187 return;
9188
3e170ce0
A
9189 if (isSpinDump)
9190 hdr = (swd_hdr *)swd_spindump_buffer;
9191 else
9192 hdr = (swd_hdr *)swd_buffer;
fe8ab488 9193 memset(hdr->UUID, 0x20, sizeof(hdr->UUID));
39236c6e
A
9194 if ((UUIDstring = OSDynamicCast(OSString, getProperty(kIOPMSleepWakeUUIDKey))) != NULL ) {
9195
9196 if (wdogTrigger || (!UUIDstring->isEqualTo(hdr->UUID))) {
9197 const char *str = UUIDstring->getCStringNoCopy();
fe8ab488 9198 snprintf(hdr->UUID, sizeof(hdr->UUID), "UUID: %s", str);
39236c6e
A
9199 }
9200 else {
9201 DLOG("Data for current UUID already exists\n");
9202 goto exit;
9203 }
9204 }
9205
9206 dstAddr = (char*)hdr + hdr->spindump_offset;
3e170ce0 9207 bytesRemaining = bufSize - hdr->spindump_offset;
39236c6e 9208
fe8ab488
A
9209 /* if AppleOSXWatchdog triggered the stackshot, set the flag in the heaer */
9210 hdr->is_osx_watchdog = isOSXWatchdog;
39236c6e
A
9211
9212 DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining);
fe8ab488
A
9213
9214 while (bytesRemaining > sizeof(swd_stackshot_hdr)) {
9215
9216 stackshotHdr = (swd_stackshot_hdr *)dstAddr;
9217 stackshotHdr->magic = SWD_STACKSHOTHDR_MAGIC;
9218 stackshotHdr->size = 0;
9219 bytesRemaining -= sizeof(swd_stackshot_hdr);
9220 dstAddr += sizeof(swd_stackshot_hdr);
9221
9222 if (isOSXWatchdog) {
9223 pid = -1;
9224 size = bytesRemaining;
9225 flags = STACKSHOT_SAVE_LOADINFO | STACKSHOT_SAVE_KEXT_LOADINFO;
9226 }
9227 else if (cnt == 0) {
9228 /*
9229 * Take stackshot of all process on first sample. Size is restricted
9230 * to SWD_INITIAL_STACK_SIZE
9231 */
9232 pid = -1;
3e170ce0 9233 size = (bytesRemaining > initialStackSize) ? initialStackSize : bytesRemaining;
fe8ab488
A
9234 flags = STACKSHOT_SAVE_LOADINFO | STACKSHOT_SAVE_KEXT_LOADINFO|STACKSHOT_SAVE_KERNEL_FRAMES_ONLY;
9235 }
9236 else {
9237 /* Take sample of kernel threads only */
9238 pid = 0;
9239 size = bytesRemaining;
9240 flags = 0;
9241 }
9242
9243 stack_snapshot_from_kernel(pid, dstAddr, size, flags, &stackshotHdr->size);
9244
9245 dstAddr += stackshotHdr->size;
9246 bytesRemaining -= stackshotHdr->size;
9247
9248 DLOG("Sample: %d size: %d bytesRemaining: %d\n", cnt, stackshotHdr->size, bytesRemaining);
9249 if ((stackshotHdr->size == 0) || (++cnt == 10))
9250 break;
9251 IOSleep(10); // 10 ms
39236c6e
A
9252 }
9253
3e170ce0 9254 hdr->spindump_size = (bufSize - bytesRemaining - hdr->spindump_offset);
fe8ab488
A
9255
9256
9257 memset(hdr->cps, 0x20, sizeof(hdr->cps));
9258 snprintf(hdr->cps, sizeof(hdr->cps), "\ncps: %d", ((IOService*)this)->getPowerState());
39236c6e 9259 code = pmTracer->getPMStatusCode();
fe8ab488
A
9260 memset(hdr->PMStatusCode, 0x20, sizeof(hdr->PMStatusCode));
9261 snprintf(hdr->PMStatusCode, sizeof(hdr->PMStatusCode), "\nCode: %08x %08x",
39236c6e 9262 (uint32_t)((code >> 32) & 0xffffffff), (uint32_t)(code & 0xffffffff));
fe8ab488 9263 memset(hdr->reason, 0x20, sizeof(hdr->reason));
3e170ce0
A
9264 if (isSpinDump) {
9265 snprintf(hdr->reason, sizeof(hdr->reason), "\nStackshot reason: PSC Delay\n\n");
9266 gRootDomain->swd_lock = 0;
9267 gSpinDumpBufferFull = true;
9268 return;
9269 }
fe8ab488 9270 snprintf(hdr->reason, sizeof(hdr->reason), "\nStackshot reason: Watchdog\n\n");
39236c6e
A
9271
9272
fe8ab488 9273 data[0] = round_page(sizeof(swd_hdr) + hdr->spindump_size);
39236c6e 9274 /* Header & rootdomain log is constantly changing and is not covered by CRC */
fe8ab488
A
9275 data[1] = hdr->crc = crc32(0, ((char*)swd_buffer+hdr->spindump_offset), hdr->spindump_size);
9276 data[2] = kvtophys((vm_offset_t)swd_buffer);
39236c6e
A
9277 len = sizeof(addr64_t)*3;
9278 DLOG("bytes: 0x%llx crc:0x%llx paddr:0x%llx\n",
9279 data[0], data[1], data[2]);
9280
9281 if (PEWriteNVRAMProperty(kIOSleepWakeDebugKey, data, len) == false)
9282 {
9283 DLOG("Failed to update nvram boot-args\n");
9284 goto exit;
9285 }
9286
9287exit:
9288
9289 gRootDomain->swd_lock = 0;
9290
9291 if (wdogTrigger) {
9292 IOLog("Restarting to collect Sleep wake debug logs\n");
9293 PEHaltRestart(kPERestartCPU);
9294 }
9295 else {
9296 logBufMap = sleepWakeDebugRetrieve();
9297 if (logBufMap) {
fe8ab488 9298 sleepWakeDebugDumpFromMem(logBufMap);
39236c6e
A
9299 logBufMap->release();
9300 logBufMap = 0;
9301 }
9302 }
9303}
9304
9305void IOPMrootDomain::sleepWakeDebugMemAlloc( )
9306{
9307 vm_size_t size = SWD_BUF_SIZE;
9308
9309 swd_hdr *hdr = NULL;
9310
9311 IOBufferMemoryDescriptor *memDesc = NULL;
9312
9313
9314 if ( kIOSleepWakeWdogOff & gIOKitDebug )
9315 return;
9316
9317 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
9318 return;
9319
fe8ab488
A
9320 // Try allocating above 4GB. If that fails, try at 2GB
9321 memDesc = IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
39236c6e
A
9322 kernel_task, kIOMemoryPhysicallyContiguous|kIOMemoryMapperNone,
9323 size, 0xFFFFFFFF00000000ULL);
9324 if (!memDesc) {
fe8ab488 9325 memDesc = IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
39236c6e
A
9326 kernel_task, kIOMemoryPhysicallyContiguous|kIOMemoryMapperNone,
9327 size, 0xFFFFFFFF10000000ULL);
9328 }
9329
fe8ab488 9330 if (memDesc == NULL)
39236c6e
A
9331 {
9332 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
9333 goto exit;
9334 }
9335
9336
9337 hdr = (swd_hdr *)memDesc->getBytesNoCopy();
fe8ab488 9338 memset(hdr, 0, sizeof(swd_hdr));
39236c6e 9339
fe8ab488 9340 hdr->signature = SWD_HDR_SIGNATURE;
39236c6e
A
9341 hdr->alloc_size = size;
9342
fe8ab488 9343 hdr->spindump_offset = sizeof(swd_hdr);
39236c6e 9344 swd_buffer = (void *)hdr;
fe8ab488 9345 DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr->alloc_size, hdr->spindump_offset);
39236c6e
A
9346
9347exit:
9348 gRootDomain->swd_lock = 0;
9349}
9350
3e170ce0
A
9351void IOPMrootDomain::sleepWakeDebugSpinDumpMemAlloc( )
9352{
9353 vm_size_t size = SWD_SPINDUMP_SIZE;
9354
9355 swd_hdr *hdr = NULL;
9356
9357 IOBufferMemoryDescriptor *memDesc = NULL;
9358
9359 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
9360 return;
9361
9362 memDesc = IOBufferMemoryDescriptor::inTaskWithOptions(
9363 kernel_task, kIODirectionIn|kIOMemoryMapperNone,
9364 SWD_SPINDUMP_SIZE);
9365
9366 if (memDesc == NULL)
9367 {
9368 DLOG("Failed to allocate Memory descriptor for sleepWake debug spindump\n");
9369 goto exit;
9370 }
9371
9372
9373 hdr = (swd_hdr *)memDesc->getBytesNoCopy();
9374 memset(hdr, 0, sizeof(swd_hdr));
9375
9376 hdr->signature = SWD_HDR_SIGNATURE;
9377 hdr->alloc_size = size;
9378
9379 hdr->spindump_offset = sizeof(swd_hdr);
9380 swd_spindump_buffer = (void *)hdr;
9381
9382exit:
9383 gRootDomain->swd_lock = 0;
9384}
9385
39236c6e
A
9386void IOPMrootDomain::sleepWakeDebugEnableWdog()
9387{
9388 swd_flags |= SWD_WDOG_ENABLED;
9389 if (!swd_buffer)
9390 sleepWakeDebugMemAlloc();
9391}
9392
9393bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
9394{
9395 return ((swd_flags & SWD_WDOG_ENABLED) &&
3e170ce0
A
9396 !systemBooting && !systemShutdown && !gWillShutdown);
9397}
9398
9399void IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
9400{
9401 swd_hdr *hdr = NULL;
9402 errno_t error = EIO;
9403
9404 if (swd_spindump_buffer && gSpinDumpBufferFull) {
9405 hdr = (swd_hdr *)swd_spindump_buffer;
9406
9407 error = sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayStacks.dump",
9408 (char*)hdr+hdr->spindump_offset, hdr->spindump_size);
9409
9410 if (error) return;
9411
9412 sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayLog.dump",
9413 (char*)hdr+offsetof(swd_hdr, UUID),
9414 sizeof(swd_hdr)-offsetof(swd_hdr, UUID));
9415
9416 gSpinDumpBufferFull = false;
9417 }
39236c6e
A
9418}
9419
9420errno_t IOPMrootDomain::sleepWakeDebugSaveFile(const char *name, char *buf, int len)
9421{
9422 struct vnode *vp = NULL;
fe8ab488 9423 vfs_context_t ctx = vfs_context_create(vfs_context_current());
39236c6e
A
9424 kauth_cred_t cred = vfs_context_ucred(ctx);
9425 struct vnode_attr va;
9426 errno_t error = EIO;
9427
fe8ab488
A
9428 if (vnode_open(name, (O_CREAT | FWRITE | O_NOFOLLOW),
9429 S_IRUSR|S_IRGRP|S_IROTH, VNODE_LOOKUP_NOFOLLOW, &vp, ctx) != 0)
39236c6e
A
9430 {
9431 IOLog("Failed to open the file %s\n", name);
9432 goto exit;
9433 }
9434 VATTR_INIT(&va);
9435 VATTR_WANTED(&va, va_nlink);
9436 /* Don't dump to non-regular files or files with links. */
9437 if (vp->v_type != VREG ||
9438 vnode_getattr(vp, &va, ctx) || va.va_nlink != 1) {
9439 IOLog("Bailing as this is not a regular file\n");
9440 goto exit;
fe8ab488
A
9441 }
9442 VATTR_INIT(&va);
39236c6e
A
9443 VATTR_SET(&va, va_data_size, 0);
9444 vnode_setattr(vp, &va, ctx);
fe8ab488 9445
39236c6e
A
9446
9447 error = vn_rdwr(UIO_WRITE, vp, buf, len, 0,
9448 UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *) 0, vfs_context_proc(ctx));
fe8ab488 9449 if (error != 0)
39236c6e
A
9450 IOLog("Failed to save sleep wake log. err 0x%x\n", error);
9451 else
9452 DLOG("Saved %d bytes to file %s\n",len, name);
9453
9454exit:
9455 if (vp) vnode_close(vp, FWRITE, ctx);
fe8ab488
A
9456 if (ctx) vfs_context_rele(ctx);
9457
9458 return error;
9459
9460}
9461
9462errno_t IOPMrootDomain::sleepWakeDebugCopyFile(
9463 struct vnode *srcVp,
9464 vfs_context_t srcCtx,
9465 char *tmpBuf, uint64_t tmpBufSize,
9466 uint64_t srcOffset,
9467 const char *dstFname,
9468 uint64_t numBytes,
9469 uint32_t crc)
9470{
9471 struct vnode *vp = NULL;
9472 vfs_context_t ctx = vfs_context_create(vfs_context_current());
9473 struct vnode_attr va;
9474 errno_t error = EIO;
9475 uint64_t bytesToRead, bytesToWrite;
9476 uint64_t readFileOffset, writeFileOffset, srcDataOffset;
9477 uint32_t newcrc = 0;
9478
9479 if (vnode_open(dstFname, (O_CREAT | FWRITE | O_NOFOLLOW),
9480 S_IRUSR|S_IRGRP|S_IROTH, VNODE_LOOKUP_NOFOLLOW, &vp, ctx) != 0)
9481 {
9482 DLOG("Failed to open the file %s\n", dstFname);
9483 goto exit;
9484 }
9485 VATTR_INIT(&va);
9486 VATTR_WANTED(&va, va_nlink);
9487 /* Don't dump to non-regular files or files with links. */
9488 if (vp->v_type != VREG ||
9489 vnode_getattr(vp, &va, ctx) || va.va_nlink != 1) {
9490 DLOG("Bailing as this is not a regular file\n");
9491 goto exit;
9492 }
9493 VATTR_INIT(&va);
9494 VATTR_SET(&va, va_data_size, 0);
9495 vnode_setattr(vp, &va, ctx);
9496
9497 writeFileOffset = 0;
9498 while(numBytes) {
9499 bytesToRead = (round_page(numBytes) > tmpBufSize) ? tmpBufSize : round_page(numBytes);
9500 readFileOffset = trunc_page(srcOffset);
9501
3e170ce0 9502 DLOG("Read file (numBytes:0x%llx offset:0x%llx)\n", bytesToRead, readFileOffset);
fe8ab488
A
9503 error = vn_rdwr(UIO_READ, srcVp, tmpBuf, bytesToRead, readFileOffset,
9504 UIO_SYSSPACE, IO_SKIP_ENCRYPTION|IO_SYNC|IO_NODELOCKED|IO_UNIT|IO_NOCACHE,
9505 vfs_context_ucred(srcCtx), (int *) 0,
9506 vfs_context_proc(srcCtx));
9507 if (error) {
9508 DLOG("Failed to read file(numBytes:0x%llx)\n", bytesToRead);
9509 break;
9510 }
9511
9512 srcDataOffset = (uint64_t)tmpBuf + (srcOffset - readFileOffset);
9513 bytesToWrite = bytesToRead - (srcOffset - readFileOffset);
9514 if (bytesToWrite > numBytes) bytesToWrite = numBytes;
9515
9516 if (crc) {
9517 newcrc = crc32(newcrc, (void *)srcDataOffset, bytesToWrite);
9518 }
3e170ce0 9519 DLOG("Write file (numBytes:0x%llx offset:0x%llx)\n", bytesToWrite, writeFileOffset);
fe8ab488
A
9520 error = vn_rdwr(UIO_WRITE, vp, (char *)srcDataOffset, bytesToWrite, writeFileOffset,
9521 UIO_SYSSPACE, IO_SYNC|IO_NODELOCKED|IO_UNIT,
9522 vfs_context_ucred(ctx), (int *) 0,
9523 vfs_context_proc(ctx));
9524 if (error) {
9525 DLOG("Failed to write file(numBytes:0x%llx)\n", bytesToWrite);
9526 break;
9527 }
9528
9529 writeFileOffset += bytesToWrite;
9530 numBytes -= bytesToWrite;
9531 srcOffset += bytesToWrite;
9532
9533 }
9534 if (crc != newcrc) {
9535 swd_stackshot_hdr *shdr = (swd_stackshot_hdr *)tmpBuf;;
9536
9537 /* Set statckshot size to 0 if crc doesn't match */
9538 shdr->magic = SWD_STACKSHOTHDR_MAGIC;
9539 shdr->size = 0;
9540
9541 assert(tmpBufSize > sizeof(swd_stackshot_hdr));
9542 bytesToWrite = round_page(sizeof(swd_stackshot_hdr));
9543 vn_rdwr(UIO_WRITE, vp, (char *)tmpBuf, bytesToWrite, 0,
9544 UIO_SYSSPACE, IO_SYNC|IO_NODELOCKED|IO_UNIT,
9545 vfs_context_ucred(ctx), (int *) 0,
9546 vfs_context_proc(ctx));
9547
9548 DLOG("CRC check failed. expected:0x%x actual:0x%x\n", crc, newcrc);
9549 error = EFAULT;
9550 }
9551exit:
9552 if (vp) {
9553 error = vnode_close(vp, FWRITE, ctx);
9554 DLOG("vnode_close returned 0x%x\n", error);
9555 }
9556 if (ctx) vfs_context_rele(ctx);
39236c6e
A
9557
9558 return error;
9559
fe8ab488
A
9560
9561
3e170ce0
A
9562}
9563void IOPMrootDomain::checkForValidDebugData(const char *fname, vfs_context_t *ctx,
9564 void *tmpBuf, struct vnode **vp)
9565{
9566 int rc;
9567 uint64_t hdrOffset;
9568
9569 struct vnode_attr va;
9570 IOHibernateImageHeader *imageHdr;
9571
9572 *vp = NULL;
9573 if (vnode_open(fname, (FREAD | O_NOFOLLOW), 0,
9574 VNODE_LOOKUP_NOFOLLOW, vp, *ctx) != 0)
9575 {
9576 DMSG("sleepWakeDebugDumpFromFile: Failed to open the file %s\n", fname);
9577 goto err;
9578 }
9579 VATTR_INIT(&va);
9580 VATTR_WANTED(&va, va_nlink);
9581 VATTR_WANTED(&va, va_data_alloc);
9582 if ((*vp)->v_type != VREG ||
9583 vnode_getattr((*vp), &va, *ctx) || va.va_nlink != 1) {
9584 DMSG("sleepWakeDebugDumpFromFile: Bailing as %s is not a regular file\n", fname);
9585 goto err;
9586 }
9587
9588 /* Read the sleepimage file header */
9589 rc = vn_rdwr(UIO_READ, *vp, (char *)tmpBuf, round_page(sizeof(IOHibernateImageHeader)), 0,
9590 UIO_SYSSPACE, IO_SKIP_ENCRYPTION|IO_SYNC|IO_NODELOCKED|IO_UNIT|IO_NOCACHE,
9591 vfs_context_ucred(*ctx), (int *) 0,
9592 vfs_context_proc(*ctx));
9593 if (rc != 0) {
9594 DMSG("sleepWakeDebugDumpFromFile: Failed to read header size %lu(rc=%d) from %s\n",
9595 round_page(sizeof(IOHibernateImageHeader)), rc, fname);
9596 goto err;
9597 }
9598
9599 imageHdr = ((IOHibernateImageHeader *)tmpBuf);
9600 if (imageHdr->signature != kIOHibernateHeaderDebugDataSignature) {
9601 DMSG("sleepWakeDebugDumpFromFile: File %s header has unexpected value 0x%x\n",
9602 fname, imageHdr->signature);
9603 goto err;
9604 }
9605
9606 /* Sleep/Wake debug header(swd_hdr) is at the beggining of the second block */
9607 hdrOffset = imageHdr->deviceBlockSize;
9608 if (hdrOffset + sizeof(swd_hdr) >= va.va_data_alloc) {
9609 DMSG("sleepWakeDebugDumpFromFile: header is crossing file size(0x%llx) in file %s\n",
9610 va.va_data_alloc, fname);
9611 goto err;
9612 }
9613
9614 return;
9615
9616err:
9617 if (*vp) vnode_close(*vp, FREAD, *ctx);
9618 *vp = NULL;
9619
9620 return;
39236c6e 9621}
fe8ab488
A
9622
9623void IOPMrootDomain::sleepWakeDebugDumpFromFile( )
9624{
3e170ce0 9625#if HIBERNATION
fe8ab488
A
9626 int rc;
9627 char hibernateFilename[MAXPATHLEN+1];
9628 char PMStatusCode[100];
9629 void *tmpBuf;
9630 swd_hdr *hdr = NULL;
9631 uint32_t stacksSize, logSize;
9632 uint64_t tmpBufSize;
9633 uint64_t hdrOffset, stacksOffset, logOffset;
9634 errno_t error = EIO;
9635 OSObject *obj = NULL;
9636 OSString *str = NULL;
9637 OSNumber *failStat = NULL;
9638 struct vnode *vp = NULL;
9639 vfs_context_t ctx = NULL;
9640
fe8ab488 9641 IOBufferMemoryDescriptor *tmpBufDesc = NULL;
fe8ab488
A
9642
9643 DLOG("sleepWakeDebugDumpFromFile\n");
9644 if ((swd_flags & SWD_LOGS_IN_FILE) == 0)
9645 return;
9646
9647 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
9648 return;
9649
9650
fe8ab488
A
9651 /* Allocate a temp buffer to copy data between files */
9652 tmpBufSize = 2*4096;
9653 tmpBufDesc = IOBufferMemoryDescriptor::
9654 inTaskWithOptions(kernel_task, kIODirectionOutIn | kIOMemoryMapperNone,
9655 tmpBufSize, PAGE_SIZE);
9656
9657 if (!tmpBufDesc) {
9658 DMSG("sleepWakeDebugDumpFromFile: Fail to allocate temp buf\n");
9659 goto exit;
9660 }
9661
9662 tmpBuf = tmpBufDesc->getBytesNoCopy();
9663
9664 ctx = vfs_context_create(vfs_context_current());
fe8ab488 9665
3e170ce0
A
9666 /* First check if 'kSleepWakeStackBinFilename' has valid data */
9667 checkForValidDebugData(kSleepWakeStackBinFilename, &ctx, tmpBuf, &vp);
9668 if (vp == NULL) {
9669 /* Check if the debug data is saved to hibernation file */
9670 hibernateFilename[0] = 0;
9671 if ((obj = copyProperty(kIOHibernateFileKey)))
9672 {
9673 if ((str = OSDynamicCast(OSString, obj)))
9674 strlcpy(hibernateFilename, str->getCStringNoCopy(),
9675 sizeof(hibernateFilename));
9676 obj->release();
9677 }
9678 if (!hibernateFilename[0]) {
9679 DMSG("sleepWakeDebugDumpFromFile: Failed to get hibernation file name\n");
9680 goto exit;
9681 }
fe8ab488 9682
3e170ce0
A
9683 checkForValidDebugData(hibernateFilename, &ctx, tmpBuf, &vp);
9684 if (vp == NULL) {
9685 DMSG("sleepWakeDebugDumpFromFile: No valid debug data is found\n");
9686 goto exit;
9687 }
9688 DLOG("Getting SW Stacks image from file %s\n", hibernateFilename);
fe8ab488 9689 }
3e170ce0
A
9690 else {
9691 DLOG("Getting SW Stacks image from file %s\n", kSleepWakeStackBinFilename);
fe8ab488
A
9692 }
9693
3e170ce0
A
9694 hdrOffset = ((IOHibernateImageHeader *)tmpBuf)->deviceBlockSize;
9695
fe8ab488
A
9696 DLOG("Reading swd_hdr len 0x%lx offset 0x%lx\n", round_page(sizeof(swd_hdr)), trunc_page(hdrOffset));
9697 /* Read the sleep/wake debug header(swd_hdr) */
9698 rc = vn_rdwr(UIO_READ, vp, (char *)tmpBuf, round_page(sizeof(swd_hdr)), trunc_page(hdrOffset),
9699 UIO_SYSSPACE, IO_SKIP_ENCRYPTION|IO_SYNC|IO_NODELOCKED|IO_UNIT|IO_NOCACHE,
9700 vfs_context_ucred(ctx), (int *) 0,
9701 vfs_context_proc(ctx));
9702 if (rc != 0) {
9703 DMSG("sleepWakeDebugDumpFromFile: Failed to debug read header size %lu. rc=%d\n",
9704 round_page(sizeof(swd_hdr)), rc);
9705 goto exit;
9706 }
9707
9708 hdr = (swd_hdr *)((char *)tmpBuf + (hdrOffset - trunc_page(hdrOffset)));
9709 if ((hdr->signature != SWD_HDR_SIGNATURE) || (hdr->alloc_size > SWD_BUF_SIZE) ||
9710 (hdr->spindump_offset > SWD_BUF_SIZE) || (hdr->spindump_size > SWD_BUF_SIZE)) {
9711 DMSG("sleepWakeDebugDumpFromFile: Invalid data in debug header. sign:0x%x size:0x%x spindump_offset:0x%x spindump_size:0x%x\n",
9712 hdr->signature, hdr->alloc_size, hdr->spindump_offset, hdr->spindump_size);
9713 goto exit;
9714 }
9715 stacksSize = hdr->spindump_size;
9716
9717 /* Get stacks & log offsets in the image file */
9718 stacksOffset = hdrOffset + hdr->spindump_offset;
9719 logOffset = hdrOffset + offsetof(swd_hdr, UUID);
9720 logSize = sizeof(swd_hdr)-offsetof(swd_hdr, UUID);
9721
9722 error = sleepWakeDebugCopyFile(vp, ctx, (char *)tmpBuf, tmpBufSize, stacksOffset,
9723 getDumpStackFilename(hdr), stacksSize, hdr->crc);
9724 if (error == EFAULT) {
9725 DMSG("sleepWakeDebugDumpFromFile: Stackshot CRC doesn't match\n");
9726 goto exit;
9727 }
9728 error = sleepWakeDebugCopyFile(vp, ctx, (char *)tmpBuf, tmpBufSize, logOffset,
9729 getDumpLogFilename(hdr), logSize, 0);
9730 if (error) {
9731 DMSG("sleepWakeDebugDumpFromFile: Failed to write the log file(0x%x)\n", error);
9732 goto exit;
9733 }
9734exit:
9735 if (error) {
9736 // Write just the SleepWakeLog.dump with failure code
9737 uint64_t fcode = 0;
9738 const char *fname;
9739 if (swd_flags & SWD_BOOT_BY_SW_WDOG) {
9740 failStat = OSDynamicCast(OSNumber, getProperty(kIOPMSleepWakeFailureCodeKey));
9741 fcode = failStat->unsigned64BitValue();
9742 fname = kSleepWakeLogFilename;
9743 }
9744 else {
9745 fname = kAppleOSXWatchdogLogFilename;
9746 }
9747 memset(PMStatusCode, 0x20, sizeof(PMStatusCode)); // Fill with spaces
9748 PMStatusCode[sizeof(PMStatusCode)-1] = 0xa; // And an end-of-line at the end
9749 snprintf(PMStatusCode, sizeof(PMStatusCode)-1, "Code: 0x%llx", fcode);
9750 sleepWakeDebugSaveFile(fname, PMStatusCode, sizeof(PMStatusCode));
9751 }
9752 gRootDomain->swd_lock = 0;
9753
9754 if (vp) vnode_close(vp, FREAD, ctx);
9755 if (ctx) vfs_context_rele(ctx);
9756 if (tmpBufDesc) tmpBufDesc->release();
3e170ce0 9757#endif /* HIBERNATION */
fe8ab488
A
9758}
9759
9760void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap *logBufMap)
39236c6e
A
9761{
9762 IOVirtualAddress srcBuf = NULL;
9763 char *stackBuf = NULL, *logOffset = NULL;
9764 int logSize = 0;
9765
9766 errno_t error = EIO;
9767 uint64_t bufSize = 0;
9768 swd_hdr *hdr = NULL;
9769 char PMStatusCode[100];
9770 OSNumber *failStat = NULL;
9771
9772 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
9773 return;
9774
9775 if ((logBufMap == 0) || ( (srcBuf = logBufMap->getVirtualAddress()) == 0) )
9776 {
9777 DLOG("Nothing saved to dump to file\n");
9778 goto exit;
9779 }
9780
9781 hdr = (swd_hdr *)srcBuf;
9782 bufSize = logBufMap->getLength();
9783 if (bufSize <= sizeof(swd_hdr))
9784 {
9785 IOLog("SleepWake log buffer contents are invalid\n");
9786 goto exit;
9787 }
9788
9789 stackBuf = (char*)hdr+hdr->spindump_offset;
9790
fe8ab488 9791 error = sleepWakeDebugSaveFile(getDumpStackFilename(hdr), stackBuf, hdr->spindump_size);
39236c6e
A
9792 if (error) goto exit;
9793
9794 logOffset = (char*)hdr+offsetof(swd_hdr, UUID);
9795 logSize = sizeof(swd_hdr)-offsetof(swd_hdr, UUID);
fe8ab488
A
9796
9797 error = sleepWakeDebugSaveFile(getDumpLogFilename(hdr), logOffset, logSize);
39236c6e
A
9798 if (error) goto exit;
9799
9800 hdr->spindump_size = 0;
9801 error = 0;
9802
9803exit:
9804 if (error) {
9805 // Write just the SleepWakeLog.dump with failure code
fe8ab488
A
9806 uint64_t fcode = 0;
9807 const char *sname, *lname;
9808 swd_stackshot_hdr shdr;
9809
9810 /* Try writing an empty stacks file */
9811 shdr.magic = SWD_STACKSHOTHDR_MAGIC;
9812 shdr.size = 0;
9813
9814
9815 if (swd_flags & SWD_BOOT_BY_SW_WDOG) {
9816 failStat = OSDynamicCast(OSNumber, getProperty(kIOPMSleepWakeFailureCodeKey));
9817 fcode = failStat->unsigned64BitValue();
9818 lname = kSleepWakeLogFilename;
9819 sname = kSleepWakeStackFilename;
39236c6e 9820 }
fe8ab488
A
9821 else {
9822 lname = kAppleOSXWatchdogLogFilename;
9823 sname= kAppleOSXWatchdogStackFilename;
9824 }
9825
9826 sleepWakeDebugSaveFile(sname, (char*)(&shdr), sizeof(shdr));
9827 memset(PMStatusCode, 0x20, sizeof(PMStatusCode)); // Fill with spaces
9828 PMStatusCode[sizeof(PMStatusCode)-1] = 0xa; // And an end-of-line at the end
9829 snprintf(PMStatusCode, sizeof(PMStatusCode)-1, "Code: 0x%llx", fcode);
9830 sleepWakeDebugSaveFile(lname, PMStatusCode, sizeof(PMStatusCode));
39236c6e
A
9831 }
9832 gRootDomain->swd_lock = 0;
9833}
9834
9835IOMemoryMap *IOPMrootDomain::sleepWakeDebugRetrieve( )
9836{
9837 IOVirtualAddress vaddr = NULL;
9838 IOMemoryDescriptor * desc = NULL;
9839 IOMemoryMap * logBufMap = NULL;
9840
9841 uint32_t len;
9842 addr64_t data[3];
9843 uint64_t bufSize = 0;
9844 uint64_t crc = 0;
9845 uint64_t newcrc = 0;
9846 uint64_t paddr = 0;
9847 swd_hdr *hdr = NULL;
9848 bool ret = false;
fe8ab488 9849 char str[20];
39236c6e
A
9850
9851
9852 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
9853 return NULL;
9854
fe8ab488 9855 if (!PEReadNVRAMProperty(kIOSleepWakeDebugKey, 0, &len)) {
39236c6e 9856 DLOG("No sleepWakeDebug note to read\n");
fe8ab488 9857 goto exit;
39236c6e 9858 }
39236c6e 9859
fe8ab488
A
9860 if (len == strlen("sleepimage")) {
9861 str[0] = 0;
9862 PEReadNVRAMProperty(kIOSleepWakeDebugKey, str, &len);
39236c6e 9863
fe8ab488
A
9864 if (!strncmp((char*)str, "sleepimage", strlen("sleepimage"))) {
9865 DLOG("sleepWakeDebugRetrieve: in file logs\n");
9866 swd_flags |= SWD_LOGS_IN_FILE|SWD_VALID_LOGS;
9867 goto exit;
9868 }
9869 }
9870 else if (len == sizeof(addr64_t)*3)
9871 PEReadNVRAMProperty(kIOSleepWakeDebugKey, data, &len);
9872 else {
9873 DLOG("Invalid sleepWakeDebug note length(%d)\n", len);
9874 goto exit;
9875 }
9876
9877
9878
9879 DLOG("sleepWakeDebugRetrieve: data[0]:0x%llx data[1]:0x%llx data[2]:0x%llx\n",
9880 data[0], data[1], data[2]);
9881 DLOG("sleepWakeDebugRetrieve: in mem logs\n");
39236c6e
A
9882 bufSize = data[0];
9883 crc = data[1];
9884 paddr = data[2];
9885 if ( (bufSize <= sizeof(swd_hdr)) ||(bufSize > SWD_BUF_SIZE) || (crc == 0) )
9886 {
9887 IOLog("SleepWake log buffer contents are invalid\n");
9888 return NULL;
9889 }
9890
9891 DLOG("size:0x%llx crc:0x%llx paddr:0x%llx\n",
9892 bufSize, crc, paddr);
9893
fe8ab488 9894
39236c6e
A
9895 desc = IOMemoryDescriptor::withAddressRange( paddr, bufSize,
9896 kIODirectionOutIn | kIOMemoryMapperNone, NULL);
9897 if (desc == NULL)
9898 {
9899 IOLog("Fail to map SleepWake log buffer\n");
9900 goto exit;
9901 }
9902
9903 logBufMap = desc->map();
9904
9905 vaddr = logBufMap->getVirtualAddress();
9906
9907
9908 if ( (logBufMap->getLength() <= sizeof(swd_hdr)) || (vaddr == NULL) ) {
9909 IOLog("Fail to map SleepWake log buffer\n");
9910 goto exit;
9911 }
9912
9913 hdr = (swd_hdr *)vaddr;
fe8ab488 9914 if (hdr->spindump_offset+hdr->spindump_size > bufSize)
39236c6e
A
9915 {
9916 IOLog("SleepWake log buffer contents are invalid\n");
9917 goto exit;
9918 }
9919
9920 hdr->crc = crc;
fe8ab488 9921 newcrc = crc32(0, (void *)((char*)vaddr+hdr->spindump_offset),
39236c6e
A
9922 hdr->spindump_size);
9923 if (newcrc != crc) {
9924 IOLog("SleepWake log buffer contents are invalid\n");
9925 goto exit;
9926 }
9927
9928 ret = true;
fe8ab488 9929 swd_flags |= SWD_LOGS_IN_MEM | SWD_VALID_LOGS;
39236c6e
A
9930
9931
9932exit:
fe8ab488 9933 PERemoveNVRAMProperty(kIOSleepWakeDebugKey);
39236c6e
A
9934 if (!ret) {
9935 if (logBufMap) logBufMap->release();
9936 logBufMap = 0;
9937 }
9938 if (desc) desc->release();
9939 gRootDomain->swd_lock = 0;
39236c6e 9940
fe8ab488 9941 return logBufMap;
39236c6e
A
9942}
9943
9944#else
9945
fe8ab488 9946void IOPMrootDomain::sleepWakeDebugTrig(bool restart)
39236c6e
A
9947{
9948}
9949
3e170ce0 9950void IOPMrootDomain::takeStackshot(bool restart, bool isOSXWatchdog, bool isSpinDump)
39236c6e 9951{
fe8ab488
A
9952#pragma unused(restart)
9953#pragma unused(isOSXWatchdog)
39236c6e
A
9954}
9955
9956void IOPMrootDomain::sleepWakeDebugMemAlloc( )
9957{
9958}
fe8ab488
A
9959void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap *map)
9960{
9961}
9962errno_t IOPMrootDomain::sleepWakeDebugCopyFile(
9963 struct vnode *srcVp,
9964 vfs_context_t srcCtx,
9965 char *tmpBuf, uint64_t tmpBufSize,
9966 uint64_t srcOffset,
9967 const char *dstFname,
9968 uint64_t numBytes,
9969 uint32_t crc)
9970{
9971 return EIO;
9972}
39236c6e 9973
fe8ab488 9974void IOPMrootDomain::sleepWakeDebugDumpFromFile()
39236c6e
A
9975{
9976}
9977
9978IOMemoryMap *IOPMrootDomain::sleepWakeDebugRetrieve( )
9979{
9980 return NULL;
9981}
9982
9983void IOPMrootDomain::sleepWakeDebugEnableWdog()
9984{
9985}
9986
9987bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
9988{
9989 return false;
9990}
9991
9992errno_t IOPMrootDomain::sleepWakeDebugSaveFile(const char *name, char *buf, int len)
9993{
9994 return 0;
9995}
9996
39236c6e
A
9997#endif
9998