]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOPMrootDomain.cpp
xnu-1699.22.81.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>
9bccf70c
A
35#include <IOKit/IOKitDebug.h>
36#include <IOKit/IOTimeStamp.h>
b0d623f7 37#include <IOKit/pwr_mgt/IOPMlog.h>
1c79356b 38#include <IOKit/pwr_mgt/RootDomain.h>
d52fe63f 39#include <IOKit/pwr_mgt/IOPMPrivate.h>
91447636 40#include <IOKit/IODeviceTreeSupport.h>
1c79356b 41#include <IOKit/IOMessage.h>
0c530ab8 42#include <IOKit/IOReturn.h>
1c79356b 43#include "RootDomainUserClient.h"
0b4e3aa0 44#include "IOKit/pwr_mgt/IOPowerConnection.h"
55e303ae 45#include "IOPMPowerStateQueue.h"
91447636 46#include <IOKit/IOCatalogue.h>
2d21ac55 47#if HIBERNATION
3a60a9f5 48#include <IOKit/IOHibernatePrivate.h>
2d21ac55
A
49#endif
50#include <sys/syslog.h>
51#include <sys/sysctl.h>
52#include <sys/time.h>
53#include "IOServicePrivate.h" // _IOServiceInterestNotifier
b0d623f7 54#include "IOServicePMPrivate.h"
2d21ac55 55
b0d623f7
A
56__BEGIN_DECLS
57#include <mach/shared_region.h>
58__END_DECLS
2d21ac55 59
b0d623f7 60#if defined(__i386__) || defined(__x86_64__)
2d21ac55
A
61__BEGIN_DECLS
62#include "IOPMrootDomainInternal.h"
63__END_DECLS
64#endif
65
b0d623f7 66#define kIOPMrootDomainClass "IOPMrootDomain"
6d2010ae 67#define LOG_PREFIX "PMRD: "
b0d623f7 68
6d2010ae
A
69#define MSG(x...) \
70 do { kprintf(LOG_PREFIX x); IOLog(x); } while (false)
b0d623f7 71
6d2010ae
A
72#define LOG(x...) \
73 do { kprintf(LOG_PREFIX x); } while (false)
b0d623f7
A
74
75#define DLOG(x...) do { \
76 if (kIOLogPMRootDomain & gIOKitDebug) \
77 kprintf(LOG_PREFIX x); } while (false)
78
6d2010ae
A
79#define _LOG(x...)
80
b0d623f7
A
81#define CHECK_THREAD_CONTEXT
82#ifdef CHECK_THREAD_CONTEXT
83static IOWorkLoop * gIOPMWorkLoop = 0;
6d2010ae 84#define ASSERT_GATED() \
b0d623f7
A
85do { \
86 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
6d2010ae 87 panic("RootDomain: not inside PM gate"); \
b0d623f7
A
88 } \
89} while(false)
2d21ac55 90#else
6d2010ae 91#define ASSERT_GATED()
b0d623f7
A
92#endif /* CHECK_THREAD_CONTEXT */
93
6d2010ae
A
94#define CAP_LOSS(c) \
95 (((_pendingCapability & (c)) == 0) && \
96 ((_currentCapability & (c)) != 0))
97
98#define CAP_GAIN(c) \
99 (((_currentCapability & (c)) == 0) && \
100 ((_pendingCapability & (c)) != 0))
101
102#define CAP_CHANGE(c) \
103 (((_currentCapability ^ _pendingCapability) & (c)) != 0)
104
105#define CAP_CURRENT(c) \
106 ((_currentCapability & (c)) != 0)
107
108#define CAP_HIGHEST(c) \
109 ((_highestCapability & (c)) != 0)
110
111#define DARK_TO_FULL_EVALUATE_CLAMSHELL 0
112
b0d623f7
A
113// Event types for IOPMPowerStateQueue::submitPowerEvent()
114enum {
6d2010ae
A
115 kPowerEventFeatureChanged = 1, // 1
116 kPowerEventReceivedPowerNotification, // 2
117 kPowerEventSystemBootCompleted, // 3
118 kPowerEventSystemShutdown, // 4
119 kPowerEventUserDisabledSleep, // 5
120 kPowerEventRegisterSystemCapabilityClient, // 6
121 kPowerEventRegisterKernelCapabilityClient, // 7
122 kPowerEventPolicyStimulus, // 8
123 kPowerEventAssertionCreate, // 9
124 kPowerEventAssertionRelease, // 10
125 kPowerEventAssertionSetLevel, // 11
126 kPowerEventQueueSleepWakeUUID, // 12
127 kPowerEventPublishSleepWakeUUID // 13
128};
129
130// For evaluatePolicy()
131// List of stimuli that affects the root domain policy.
132enum {
133 kStimulusDisplayWranglerSleep, // 0
134 kStimulusDisplayWranglerWake, // 1
135 kStimulusAggressivenessChanged, // 2
136 kStimulusDemandSystemSleep, // 3
137 kStimulusAllowSystemSleepChanged, // 4
138 kStimulusDarkWakeActivityTickle, // 5
139 kStimulusDarkWakeEntry, // 6
140 kStimulusDarkWakeReentry, // 7
141 kStimulusDarkWakeEvaluate // 8
b0d623f7 142};
1c79356b 143
0c530ab8 144extern "C" {
b0d623f7 145IOReturn OSKextSystemSleepOrWake( UInt32 );
0c530ab8 146}
1c79356b 147
b0d623f7 148static void idleSleepTimerExpired( thread_call_param_t, thread_call_param_t );
2d21ac55 149static void notifySystemShutdown( IOService * root, unsigned long event );
6d2010ae 150static void handleAggressivesFunction( thread_call_param_t, thread_call_param_t );
0b4c1975 151static void pmEventTimeStamp(uint64_t *recordTS);
1c79356b 152
0c530ab8
A
153// "IOPMSetSleepSupported" callPlatformFunction name
154static const OSSymbol *sleepSupportedPEFunction = NULL;
0b4c1975 155static const OSSymbol *sleepMessagePEFunction = NULL;
0c530ab8 156
6d2010ae
A
157#define kIOSleepSupportedKey "IOSleepSupported"
158#define kIOPMSystemCapabilitiesKey "System Capabilities"
0c530ab8
A
159
160#define kRD_AllPowerSources (kIOPMSupportedOnAC \
161 | kIOPMSupportedOnBatt \
162 | kIOPMSupportedOnUPS)
1c79356b 163
2d21ac55
A
164enum
165{
166 // not idle around autowake time, secs
167 kAutoWakePreWindow = 45,
168 kAutoWakePostWindow = 15
169};
170
0c530ab8
A
171#define kLocalEvalClamshellCommand (1 << 15)
172
b0d623f7 173enum {
6d2010ae
A
174 OFF_STATE = 0,
175 RESTART_STATE = 1,
176 SLEEP_STATE = 2,
177 ON_STATE = 3,
b0d623f7
A
178 NUM_POWER_STATES
179};
180
181#define ON_POWER kIOPMPowerOn
182#define RESTART_POWER kIOPMRestart
183#define SLEEP_POWER kIOPMAuxPowerOn
b0d623f7
A
184
185static IOPMPowerState ourPowerStates[NUM_POWER_STATES] =
186{
187 {1, 0, 0, 0, 0,0,0,0,0,0,0,0},
188 {1, kIOPMRestartCapability, kIOPMRestart, RESTART_POWER, 0,0,0,0,0,0,0,0},
189 {1, kIOPMSleepCapability, kIOPMSleep, SLEEP_POWER, 0,0,0,0,0,0,0,0},
b0d623f7
A
190 {1, kIOPMPowerOn, kIOPMPowerOn, ON_POWER, 0,0,0,0,0,0,0,0}
191};
192
b0d623f7 193#define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
0b4c1975
A
194#define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer"
195#define kIOPMrootDomainWakeTypeLowBattery "LowBattery"
6d2010ae
A
196#define kIOPMRootDomainWakeTypeUser "User"
197#define kIOPMRootDomainWakeTypeAlarm "Alarm"
198#define kIOPMRootDomainWakeTypeNetwork "Network"
b0d623f7
A
199
200// Special interest that entitles the interested client from receiving
6d2010ae 201// all system messages. Only used by powerd.
b0d623f7 202//
6d2010ae 203#define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest"
b0d623f7
A
204
205/*
206 * Aggressiveness
207 */
208#define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
209#define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
210
211#define kAggressivesMinValue 1
212
b0d623f7
A
213enum {
214 kAggressivesStateBusy = 0x01,
215 kAggressivesStateQuickSpindown = 0x02
216};
217
218struct AggressivesRecord {
219 uint32_t flags;
220 uint32_t type;
221 uint32_t value;
222};
223
224struct AggressivesRequest {
225 queue_chain_t chain;
226 uint32_t options;
227 uint32_t dataType;
228 union {
229 IOService * service;
230 AggressivesRecord record;
231 } data;
232};
233
234enum {
235 kAggressivesRequestTypeService = 1,
236 kAggressivesRequestTypeRecord
237};
238
239enum {
240 kAggressivesOptionSynchronous = 0x00000001,
241 kAggressivesOptionQuickSpindownEnable = 0x00000100,
242 kAggressivesOptionQuickSpindownDisable = 0x00000200,
243 kAggressivesOptionQuickSpindownMask = 0x00000300
244};
245
246enum {
247 kAggressivesRecordFlagModified = 0x00000001,
248 kAggressivesRecordFlagMinValue = 0x00000002
6d2010ae
A
249};
250
251// gDarkWakeFlags
252enum {
253 kDarkWakeFlagHIDTickleEarly = 0x01, // hid tickle before gfx suppression
254 kDarkWakeFlagHIDTickleLate = 0x02, // hid tickle after gfx suppression
255 kDarkWakeFlagHIDTickleNone = 0x03, // hid tickle is not posted
256 kDarkWakeFlagHIDTickleMask = 0x03,
257 kDarkWakeFlagIgnoreDiskIOInDark = 0x04, // ignore disk idle in DW
258 kDarkWakeFlagIgnoreDiskIOAlways = 0x08, // always ignore disk idle
259 kDarkWakeFlagIgnoreDiskIOMask = 0x0C,
260 kDarkWakeFlagAlarmIsDark = 0x0100
1c79356b
A
261};
262
6601e61a 263static IOPMrootDomain * gRootDomain;
6d2010ae 264static IONotifier * gSysPowerDownNotifier = 0;
6601e61a 265static UInt32 gSleepOrShutdownPending = 0;
b0d623f7 266static UInt32 gWillShutdown = 0;
6d2010ae 267static UInt32 gPagingOff = 0;
b0d623f7 268static UInt32 gSleepWakeUUIDIsSet = false;
6d2010ae
A
269static uint32_t gAggressivesState = 0;
270static uint32_t gDarkWakeFlags = kDarkWakeFlagHIDTickleNone;
7ee9d059 271static bool gRAMDiskImageBoot = false;
4452a7af 272
2d21ac55
A
273struct timeval gIOLastSleepTime;
274struct timeval gIOLastWakeTime;
275
276// Constants used as arguments to IOPMrootDomain::informCPUStateChange
277#define kCPUUnknownIndex 9999999
278enum {
279 kInformAC = 0,
280 kInformLid = 1,
281 kInformableCount = 2
282};
4452a7af 283
b0d623f7
A
284const OSSymbol *gIOPMStatsApplicationResponseTimedOut;
285const OSSymbol *gIOPMStatsApplicationResponseCancel;
286const OSSymbol *gIOPMStatsApplicationResponseSlow;
287
6d2010ae
A
288/*
289 * PMSettingHandle
290 * Opaque handle passed to clients of registerPMSettingController()
291 */
292class PMSettingHandle : public OSObject
293{
294 OSDeclareFinalStructors( PMSettingHandle )
295 friend class PMSettingObject;
296
297private:
298 PMSettingObject *pmso;
299 void free(void);
300};
301
302/*
303 * PMSettingObject
304 * Internal object to track each PM setting controller
305 */
0c530ab8
A
306class PMSettingObject : public OSObject
307{
6d2010ae
A
308 OSDeclareFinalStructors( PMSettingObject )
309 friend class IOPMrootDomain;
310
0c530ab8 311private:
6d2010ae
A
312 queue_head_t calloutQueue;
313 thread_t waitThread;
0c530ab8 314 IOPMrootDomain *parent;
6d2010ae 315 PMSettingHandle *pmsh;
0c530ab8
A
316 IOPMSettingControllerCallback func;
317 OSObject *target;
318 uintptr_t refcon;
319 uint32_t *publishedFeatureID;
6d2010ae
A
320 uint32_t settingCount;
321 bool disabled;
322
323 void free(void);
324
0c530ab8
A
325public:
326 static PMSettingObject *pmSettingObject(
6d2010ae 327 IOPMrootDomain *parent_arg,
0c530ab8 328 IOPMSettingControllerCallback handler_arg,
6d2010ae
A
329 OSObject *target_arg,
330 uintptr_t refcon_arg,
331 uint32_t supportedPowerSources,
332 const OSSymbol *settings[],
333 OSObject **handle_obj);
334
335 void dispatchPMSetting(const OSSymbol *type, OSObject *object);
336 void clientHandleFreed(void);
337};
338
339struct PMSettingCallEntry {
340 queue_chain_t link;
341 thread_t thread;
342};
0c530ab8 343
6d2010ae
A
344#define PMSETTING_LOCK() IOLockLock(settingsCtrlLock)
345#define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock)
346#define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
347#define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
0c530ab8 348
6d2010ae
A
349//*********************************************************************************
350//*********************************************************************************
351//*********************************************************************************
352
353/* @class IOPMTimeline
354 * @astract Tracks & records PM activity.
355 * @discussion Intended for use only as a helper-class to IOPMrootDomain.
356 * Do not subclass or directly invoke iOPMTimeline
357 */
358class IOPMTimeline : public OSObject
359{
360 OSDeclareDefaultStructors( IOPMTimeline );
361
362public:
363 static IOPMTimeline* timeline(IOPMrootDomain *root_domain);
364
365 bool setProperties(OSDictionary *d);
366 OSDictionary *copyInfoDictionary(void);
367
368 IOReturn recordSystemPowerEvent( PMEventDetails *details );
369
370 IOReturn recordDetailedPowerEvent( PMEventDetails *details );
371
372 IOMemoryDescriptor *getPMTraceMemoryDescriptor();
373
374 uint32_t getNumEventsLoggedThisPeriod();
375 void setNumEventsLoggedThisPeriod(uint32_t newCount);
376 bool isSleepCycleInProgress();
377 void setSleepCycleInProgressFlag(bool flag);
378private:
379 bool init(void);
380 void free(void);
381
382 void setEventsTrackedCount(uint32_t newTracked);
383 void setEventsRecordingLevel(uint32_t eventsTrackedBits);
384 static uint32_t _atomicIndexIncrement(uint32_t *index, uint32_t limit);
385
386 enum {
387 kPMTimelineRecordTardyDrivers = 1 << 0,
388 kPMTmielineRecordSystemEvents = 1 << 1,
389 kPMTimelineRecordAllDrivers = 1 << 2,
390 kPMTimelineRecordOff = 0,
391 kPMTimelineRecordDefault = 3,
392 kPMTimelineRecordDebug = 7
393 };
394
395 // eventsRecordingLevel is a bitfield defining which PM driver events will get logged
396 // into the PM buffer.
397 uint32_t eventsRecordingLevel;
398
399 // pmTraceMemoryDescriptor represents the memory block that IOPMTimeLine records PM trace points into.
400 IOBufferMemoryDescriptor *pmTraceMemoryDescriptor;
401
402 // Pointer to starting address in pmTraceMemoryDescriptor
403 IOPMSystemEventRecord *traceBuffer;
404 IOPMTraceBufferHeader *hdr;
405
406 uint16_t systemState;
407
408 IOLock *logLock;
409 IOPMrootDomain *owner;
410
411 uint32_t numEventsLoggedThisPeriod;
412 bool sleepCycleInProgress;
413};
414
415OSDefineMetaClassAndStructors( IOPMTimeline, OSObject )
416
417/*
418 * PMTraceWorker
419 * Internal helper object for logging trace points to RTC
420 * IOPMrootDomain and only IOPMrootDomain should instantiate
421 * exactly one of these.
422 */
423
424typedef void (*IOPMTracePointHandler)(
425 void * target, uint32_t code, uint32_t data );
426
427class PMTraceWorker : public OSObject
428{
429 OSDeclareDefaultStructors(PMTraceWorker)
430public:
431 typedef enum { kPowerChangeStart, kPowerChangeCompleted } change_t;
432
433 static PMTraceWorker *tracer( IOPMrootDomain * );
434 void tracePCIPowerChange(change_t, IOService *, uint32_t, uint32_t);
435 void tracePoint(uint8_t phase);
436 void tracePoint(uint8_t phase, uint8_t data8);
437 void traceDetail(uint32_t detail);
438 void traceLoginWindowPhase(uint8_t phase);
439 int recordTopLevelPCIDevice(IOService *);
440 void RTC_TRACE(void);
441 virtual bool serialize(OSSerialize *s) const;
442
443 IOPMTracePointHandler tracePointHandler;
444 void * tracePointTarget;
445private:
446 IOPMrootDomain *owner;
447 IOLock *pciMappingLock;
448 OSArray *pciDeviceBitMappings;
449
450 uint8_t addedToRegistry;
451 uint8_t tracePhase;
452 uint8_t loginWindowPhase;
453 uint8_t traceData8;
454 uint32_t traceData32;
0c530ab8
A
455};
456
0b4c1975
A
457/*
458 * PMAssertionsTracker
459 * Tracks kernel and user space PM assertions
460 */
461class PMAssertionsTracker : public OSObject
462{
463 OSDeclareFinalStructors(PMAssertionsTracker)
464public:
465 static PMAssertionsTracker *pmAssertionsTracker( IOPMrootDomain * );
6d2010ae 466
0b4c1975
A
467 IOReturn createAssertion(IOPMDriverAssertionType, IOPMDriverAssertionLevel, IOService *, const char *, IOPMDriverAssertionID *);
468 IOReturn releaseAssertion(IOPMDriverAssertionID);
469 IOReturn setAssertionLevel(IOPMDriverAssertionID, IOPMDriverAssertionLevel);
470 IOReturn setUserAssertionLevels(IOPMDriverAssertionType);
471
472 OSArray *copyAssertionsArray(void);
473 IOPMDriverAssertionType getActivatedAssertions(void);
474 IOPMDriverAssertionLevel getAssertionLevel(IOPMDriverAssertionType);
475
476 IOReturn handleCreateAssertion(OSData *);
477 IOReturn handleReleaseAssertion(IOPMDriverAssertionID);
478 IOReturn handleSetAssertionLevel(IOPMDriverAssertionID, IOPMDriverAssertionLevel);
479 IOReturn handleSetUserAssertionLevels(void * arg0);
480 void publishProperties(void);
481
482private:
483 typedef struct {
484 IOPMDriverAssertionID id;
485 IOPMDriverAssertionType assertionBits;
486 uint64_t createdTime;
487 uint64_t modifiedTime;
488 const OSSymbol *ownerString;
489 IOService *ownerService;
490 IOPMDriverAssertionLevel level;
491 } PMAssertStruct;
6d2010ae 492
0b4c1975
A
493 uint32_t tabulateProducerCount;
494 uint32_t tabulateConsumerCount;
495
496 PMAssertStruct *detailsForID(IOPMDriverAssertionID, int *);
497 void tabulate(void);
498
499 IOPMrootDomain *owner;
500 OSArray *assertionsArray;
501 IOLock *assertionsArrayLock;
6d2010ae 502 IOPMDriverAssertionID issuingUniqueID __attribute__((aligned(8))); /* aligned for atomic access */
0b4c1975
A
503 IOPMDriverAssertionType assertionsKernel;
504 IOPMDriverAssertionType assertionsUser;
505 IOPMDriverAssertionType assertionsCombined;
506};
6d2010ae 507
0b4c1975 508OSDefineMetaClassAndFinalStructors(PMAssertionsTracker, OSObject);
6d2010ae 509
2d21ac55 510/*
b0d623f7 511 * PMHaltWorker
2d21ac55
A
512 * Internal helper object for Shutdown/Restart notifications.
513 */
514#define kPMHaltMaxWorkers 8
515#define kPMHaltTimeoutMS 100
516
517class PMHaltWorker : public OSObject
518{
b0d623f7 519 OSDeclareFinalStructors( PMHaltWorker )
2d21ac55
A
520
521public:
522 IOService * service; // service being worked on
523 AbsoluteTime startTime; // time when work started
524 int depth; // work on nubs at this PM-tree depth
525 int visits; // number of nodes visited (debug)
526 IOLock * lock;
527 bool timeout; // service took too long
528
529 static PMHaltWorker * worker( void );
b0d623f7 530 static void main( void * arg, wait_result_t waitResult );
2d21ac55
A
531 static void work( PMHaltWorker * me );
532 static void checkTimeout( PMHaltWorker * me, AbsoluteTime * now );
533 virtual void free( void );
534};
535
b0d623f7 536OSDefineMetaClassAndFinalStructors( PMHaltWorker, OSObject )
0c530ab8
A
537
538
1c79356b 539#define super IOService
b0d623f7 540OSDefineMetaClassAndFinalStructors(IOPMrootDomain, IOService)
1c79356b 541
6d2010ae
A
542static void IOPMRootDomainWillShutdown(void)
543{
544 if (OSCompareAndSwap(0, 1, &gWillShutdown))
545 {
546 OSKext::willShutdown();
547 for (int i = 0; i < 100; i++)
548 {
549 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending)) break;
550 IOSleep( 100 );
551 }
552 }
553}
554
1c79356b
A
555extern "C"
556{
91447636 557 IONotifier * registerSleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
1c79356b
A
558 {
559 return gRootDomain->registerInterest( gIOGeneralInterest, handler, self, ref );
560 }
561
91447636 562 IONotifier * registerPrioritySleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
0b4e3aa0
A
563 {
564 return gRootDomain->registerInterest( gIOPriorityPowerStateInterest, handler, self, ref );
565 }
566
1c79356b
A
567 IOReturn acknowledgeSleepWakeNotification(void * PMrefcon)
568 {
569 return gRootDomain->allowPowerChange ( (unsigned long)PMrefcon );
570 }
571
0b4e3aa0
A
572 IOReturn vetoSleepWakeNotification(void * PMrefcon)
573 {
574 return gRootDomain->cancelPowerChange ( (unsigned long)PMrefcon );
575 }
576
577 IOReturn rootDomainRestart ( void )
578 {
579 return gRootDomain->restartSystem();
580 }
581
582 IOReturn rootDomainShutdown ( void )
583 {
584 return gRootDomain->shutdownSystem();
585 }
586
6d2010ae 587 void IOSystemShutdownNotification(void)
0b4e3aa0 588 {
6d2010ae
A
589 IOPMRootDomainWillShutdown();
590 if (OSCompareAndSwap(0, 1, &gPagingOff))
591 {
592#if !CONFIG_EMBEDDED
593 gRootDomain->handlePlatformHaltRestart(kPEPagingOff);
594#endif
595 }
0b4e3aa0
A
596 }
597
598 int sync_internal(void);
1c79356b
A
599}
600
0b4e3aa0 601/*
6d2010ae
A
602A device is always in the highest power state which satisfies its driver,
603its policy-maker, and any power children it has, but within the constraint
604of the power state provided by its parent. The driver expresses its desire by
605calling changePowerStateTo(), the policy-maker expresses its desire by calling
606changePowerStateToPriv(), and the children express their desires by calling
607requestPowerDomainState().
608
609The Root Power Domain owns the policy for idle and demand sleep for the system.
610It is a power-managed IOService just like the others in the system.
611It implements several power states which map to what we see as Sleep and On.
612
613The sleep policy is as follows:
6141. Sleep is prevented if the case is open so that nobody will think the machine
615 is off and plug/unplug cards.
6162. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
6173. System cannot Sleep if some object in the tree is in a power state marked
618 kIOPMPreventSystemSleep.
619
620These three conditions are enforced using the "driver clamp" by calling
621changePowerStateTo(). For example, if the case is opened,
622changePowerStateTo(ON_STATE) is called to hold the system on regardless
623of the desires of the children of the root or the state of the other clamp.
624
625Demand Sleep is initiated by pressing the front panel power button, closing
626the clamshell, or selecting the menu item. In this case the root's parent
627actually initiates the power state change so that the root domain has no
628choice and does not give applications the opportunity to veto the change.
629
630Idle Sleep occurs if no objects in the tree are in a state marked
631kIOPMPreventIdleSleep. When this is true, the root's children are not holding
632the root on, so it sets the "policy-maker clamp" by calling
633changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
634This timer is set for the difference between the sleep timeout slider and the
635display dim timeout slider. When the timer expires, it releases its clamp and
636now nothing is holding it awake, so it falls asleep.
637
638Demand sleep is prevented when the system is booting. When preferences are
639transmitted by the loginwindow at the end of boot, a flag is cleared,
640and this allows subsequent Demand Sleep.
0b4e3aa0 641*/
2d21ac55 642
b0d623f7 643//******************************************************************************
0b4e3aa0
A
644
645IOPMrootDomain * IOPMrootDomain::construct( void )
646{
b0d623f7 647 IOPMrootDomain *root;
0b4e3aa0
A
648
649 root = new IOPMrootDomain;
650 if( root)
651 root->init();
652
653 return( root );
654}
655
b0d623f7 656//******************************************************************************
0b4e3aa0 657
b0d623f7 658static void disk_sync_callout( thread_call_param_t p0, thread_call_param_t p1 )
0b4e3aa0 659{
6d2010ae
A
660 IOService * rootDomain = (IOService *) p0;
661 uint32_t notifyRef = (uint32_t)(uintptr_t) p1;
662 uint32_t powerState = rootDomain->getPowerState();
2d21ac55 663
6d2010ae 664 DLOG("disk_sync_callout ps=%u\n", powerState);
0b4e3aa0 665
6d2010ae
A
666 if (ON_STATE == powerState)
667 {
2d21ac55 668#if HIBERNATION
6d2010ae 669 IOHibernateSystemSleep();
2d21ac55 670#endif
6d2010ae
A
671 sync_internal();
672 }
673#if HIBERNATION
674 else
675 {
676 IOHibernateSystemPostWake();
677 }
678#endif
679
680 rootDomain->allowPowerChange(notifyRef);
b0d623f7 681 DLOG("disk_sync_callout finish\n");
0b4e3aa0 682}
1c79356b 683
b0d623f7 684//******************************************************************************
2d21ac55
A
685
686static UInt32 computeDeltaTimeMS( const AbsoluteTime * startTime )
0c530ab8 687{
2d21ac55
A
688 AbsoluteTime endTime;
689 UInt64 nano = 0;
690
691 clock_get_uptime(&endTime);
692 if (CMP_ABSOLUTETIME(&endTime, startTime) > 0)
693 {
694 SUB_ABSOLUTETIME(&endTime, startTime);
695 absolutetime_to_nanoseconds(endTime, &nano);
696 }
0c530ab8 697
2d21ac55
A
698 return (UInt32)(nano / 1000000ULL);
699}
0c530ab8 700
b0d623f7 701//******************************************************************************
0b4e3aa0 702
b0d623f7
A
703static int
704sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
705{
706 struct timeval *swt = (struct timeval *)arg1;
707 struct proc *p = req->p;
708
709 if (p == kernproc) {
710 return sysctl_io_opaque(req, swt, sizeof(*swt), NULL);
711 } else if(proc_is64bit(p)) {
712 struct user64_timeval t;
713 t.tv_sec = swt->tv_sec;
714 t.tv_usec = swt->tv_usec;
715 return sysctl_io_opaque(req, &t, sizeof(t), NULL);
716 } else {
717 struct user32_timeval t;
718 t.tv_sec = swt->tv_sec;
719 t.tv_usec = swt->tv_usec;
720 return sysctl_io_opaque(req, &t, sizeof(t), NULL);
721 }
722}
723
724static SYSCTL_PROC(_kern, OID_AUTO, sleeptime,
6d2010ae 725 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
b0d623f7
A
726 &gIOLastSleepTime, 0, sysctl_sleepwaketime, "S,timeval", "");
727
728static SYSCTL_PROC(_kern, OID_AUTO, waketime,
6d2010ae 729 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
b0d623f7
A
730 &gIOLastWakeTime, 0, sysctl_sleepwaketime, "S,timeval", "");
731
732
733static int
734sysctl_willshutdown
735(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
736{
737 int new_value, changed;
738 int error = sysctl_io_number(req, gWillShutdown, sizeof(int), &new_value, &changed);
739 if (changed) {
740 if (!gWillShutdown && (new_value == 1)) {
6d2010ae 741 IOPMRootDomainWillShutdown();
b0d623f7
A
742 } else
743 error = EINVAL;
744 }
745 return(error);
746}
747
748static SYSCTL_PROC(_kern, OID_AUTO, willshutdown,
6d2010ae 749 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
b0d623f7
A
750 0, 0, sysctl_willshutdown, "I", "");
751
752#if !CONFIG_EMBEDDED
753
754static int
755sysctl_progressmeterenable
756(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
757{
758 int error;
759 int new_value, changed;
760
761 error = sysctl_io_number(req, vc_progress_meter_enable, sizeof(int), &new_value, &changed);
762
763 if (changed)
764 vc_enable_progressmeter(new_value);
765
766 return (error);
767}
768
769static int
770sysctl_progressmeter
771(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
772{
773 int error;
774 int new_value, changed;
775
776 error = sysctl_io_number(req, vc_progress_meter_value, sizeof(int), &new_value, &changed);
777
778 if (changed)
779 vc_set_progressmeter(new_value);
780
781 return (error);
782}
783
784static SYSCTL_PROC(_kern, OID_AUTO, progressmeterenable,
6d2010ae 785 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
b0d623f7 786 0, 0, sysctl_progressmeterenable, "I", "");
2d21ac55 787
b0d623f7 788static SYSCTL_PROC(_kern, OID_AUTO, progressmeter,
6d2010ae 789 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
b0d623f7 790 0, 0, sysctl_progressmeter, "I", "");
2d21ac55 791
b0d623f7 792#endif
2d21ac55 793
6d2010ae
A
794static SYSCTL_INT(_debug, OID_AUTO, darkwake, CTLFLAG_RW, &gDarkWakeFlags, 0, "");
795
2d21ac55 796static const OSSymbol * gIOPMSettingAutoWakeSecondsKey;
6d2010ae 797static const OSSymbol * gIOPMSettingDebugWakeRelativeKey;
b0d623f7
A
798static const OSSymbol * gIOPMSettingMaintenanceWakeCalendarKey;
799
800//******************************************************************************
801// start
802//
803//******************************************************************************
804
805#define kRootDomainSettingsCount 16
0b4e3aa0 806
b0d623f7 807bool IOPMrootDomain::start( IOService * nub )
1c79356b 808{
0c530ab8
A
809 OSIterator *psIterator;
810 OSDictionary *tmpDict;
6d2010ae 811 IORootParent * patriarch;
2d21ac55 812
b0d623f7
A
813 super::start(nub);
814
815 gRootDomain = this;
2d21ac55 816 gIOPMSettingAutoWakeSecondsKey = OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey);
6d2010ae 817 gIOPMSettingDebugWakeRelativeKey = OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey);
b0d623f7
A
818 gIOPMSettingMaintenanceWakeCalendarKey =
819 OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey);
820
821 gIOPMStatsApplicationResponseTimedOut = OSSymbol::withCString(kIOPMStatsResponseTimedOut);
822 gIOPMStatsApplicationResponseCancel = OSSymbol::withCString(kIOPMStatsResponseCancel);
823 gIOPMStatsApplicationResponseSlow = OSSymbol::withCString(kIOPMStatsResponseSlow);
824
825 sleepSupportedPEFunction = OSSymbol::withCString("IOPMSetSleepSupported");
0b4c1975 826 sleepMessagePEFunction = OSSymbol::withCString("IOPMSystemSleepMessage");
2d21ac55 827
0c530ab8
A
828 const OSSymbol *settingsArr[kRootDomainSettingsCount] =
829 {
830 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey),
2d21ac55 831 gIOPMSettingAutoWakeSecondsKey,
0c530ab8
A
832 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey),
833 OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey),
834 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey),
6d2010ae 835 gIOPMSettingDebugWakeRelativeKey,
0c530ab8
A
836 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey),
837 OSSymbol::withCString(kIOPMSettingWakeOnRingKey),
838 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey),
839 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey),
840 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey),
841 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey),
2d21ac55 842 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey),
593a1d5f
A
843 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey),
844 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey),
845 OSSymbol::withCString(kIOPMStateConsoleShutdown)
0c530ab8 846 };
d52fe63f 847
6d2010ae 848 PE_parse_boot_argn("darkwake", &gDarkWakeFlags, sizeof(gDarkWakeFlags));
7ee9d059
A
849
850 IORegistryEntry * chosenEntry = IORegistryEntry::fromPath("/chosen", gIODTPlane);
851 if (chosenEntry)
852 {
853 if (chosenEntry->getProperty("boot-ramdmg-size") &&
854 chosenEntry->getProperty("boot-ramdmg-extents"))
855 {
856 gRAMDiskImageBoot = true;
857 }
858 chosenEntry->release();
859 }
6d2010ae 860
b0d623f7
A
861 queue_init(&aggressivesQueue);
862 aggressivesThreadCall = thread_call_allocate(handleAggressivesFunction, this);
863 aggressivesData = OSData::withCapacity(
864 sizeof(AggressivesRecord) * (kPMLastAggressivenessType + 4));
e5568f75 865
b0d623f7 866 featuresDictLock = IOLockAlloc();
6d2010ae 867 settingsCtrlLock = IOLockAlloc();
b0d623f7
A
868 setPMRootDomain(this);
869
870 extraSleepTimer = thread_call_allocate(
871 idleSleepTimerExpired,
872 (thread_call_param_t) this);
1c79356b 873
b0d623f7
A
874 diskSyncCalloutEntry = thread_call_allocate(
875 &disk_sync_callout,
876 (thread_call_param_t) this);
0c530ab8 877
b0d623f7
A
878 setProperty(kIOSleepSupportedKey, true);
879
880 bzero(&pmStats, sizeof(pmStats));
881
882 pmTracer = PMTraceWorker::tracer(this);
91447636 883
0b4c1975
A
884 pmAssertions = PMAssertionsTracker::pmAssertionsTracker(this);
885
2d21ac55 886 userDisabledAllSleep = false;
1c79356b 887 systemBooting = true;
0b4e3aa0 888 sleepSlider = 0;
b0d623f7 889 idleSleepTimerPending = false;
0b4e3aa0 890 wrangler = NULL;
6d2010ae
A
891 clamshellClosed = false;
892 clamshellExists = false;
893 clamshellDisabled = true;
b0d623f7
A
894 acAdaptorConnected = true;
895
6d2010ae
A
896 // Set the default system capabilities at boot.
897 _currentCapability = kIOPMSystemCapabilityCPU |
898 kIOPMSystemCapabilityGraphics |
899 kIOPMSystemCapabilityAudio |
900 kIOPMSystemCapabilityNetwork;
901
902 _pendingCapability = _currentCapability;
903 _desiredCapability = _currentCapability;
904 _highestCapability = _currentCapability;
905 setProperty(kIOPMSystemCapabilitiesKey, _currentCapability, 64);
906
b0d623f7
A
907 queuedSleepWakeUUIDString = NULL;
908 pmStatsAppResponses = OSArray::withCapacity(5);
909 _statsNameKey = OSSymbol::withCString(kIOPMStatsNameKey);
910 _statsPIDKey = OSSymbol::withCString(kIOPMStatsPIDKey);
911 _statsTimeMSKey = OSSymbol::withCString(kIOPMStatsTimeMSKey);
912 _statsResponseTypeKey = OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey);
913 _statsMessageTypeKey = OSSymbol::withCString(kIOPMStatsMessageTypeKey);
2d21ac55
A
914
915 idxPMCPUClamshell = kCPUUnknownIndex;
916 idxPMCPULimitedPower = kCPUUnknownIndex;
917
d52fe63f
A
918 tmpDict = OSDictionary::withCapacity(1);
919 setProperty(kRootDomainSupportedFeatures, tmpDict);
920 tmpDict->release();
91447636 921
0c530ab8
A
922 settingsCallbacks = OSDictionary::withCapacity(1);
923
924 // Create a list of the valid PM settings that we'll relay to
925 // interested clients in setProperties() => setPMSetting()
926 allowedPMSettings = OSArray::withObjects(
927 (const OSObject **)settingsArr,
928 kRootDomainSettingsCount,
929 0);
930
931 fPMSettingsDict = OSDictionary::withCapacity(5);
b0d623f7
A
932
933 PMinit(); // creates gIOPMWorkLoop
934
935 // Create IOPMPowerStateQueue used to queue external power
936 // events, and to handle those events on the PM work loop.
937 pmPowerStateQueue = IOPMPowerStateQueue::PMPowerStateQueue(
938 this, OSMemberFunctionCast(IOEventSource::Action, this,
939 &IOPMrootDomain::dispatchPowerEvent));
2d21ac55 940 getPMworkloop()->addEventSource(pmPowerStateQueue);
b0d623f7
A
941#ifdef CHECK_THREAD_CONTEXT
942 gIOPMWorkLoop = getPMworkloop();
943#endif
1c79356b 944
b0d623f7 945 // create our power parent
55e303ae 946 patriarch = new IORootParent;
1c79356b
A
947 patriarch->init();
948 patriarch->attach(this);
949 patriarch->start(this);
1c79356b 950 patriarch->addPowerChild(this);
1c79356b 951
b0d623f7 952 registerPowerDriver(this, ourPowerStates, NUM_POWER_STATES);
55e303ae 953 changePowerStateToPriv(ON_STATE);
0b4e3aa0 954
6d2010ae
A
955 if (gIOKitDebug & (kIOLogDriverPower1 | kIOLogDriverPower2))
956 {
957 // Setup our PM logging & recording code
958 timeline = IOPMTimeline::timeline(this);
959 if (timeline) {
960 OSDictionary *tlInfo = timeline->copyInfoDictionary();
961
962 if (tlInfo)
963 {
964 setProperty(kIOPMTimelineDictionaryKey, tlInfo);
965 tlInfo->release();
966 }
967 }
968 }
969
55e303ae 970 // install power change handler
b0d623f7 971 gSysPowerDownNotifier = registerPrioritySleepWakeInterest( &sysPowerDownHandler, this, 0);
0b4e3aa0 972
2d21ac55 973#if !NO_KERNEL_HID
0b4e3aa0 974 // Register for a notification when IODisplayWrangler is published
b0d623f7
A
975 if ((tmpDict = serviceMatching("IODisplayWrangler")))
976 {
977 _displayWranglerNotifier = addMatchingNotification(
978 gIOPublishNotification, tmpDict,
6d2010ae 979 (IOServiceMatchingNotificationHandler) &displayWranglerMatchPublished,
b0d623f7
A
980 this, 0);
981 tmpDict->release();
982 }
2d21ac55 983#endif
483a1d10 984
55e303ae 985 const OSSymbol *ucClassName = OSSymbol::withCStringNoCopy("RootDomainUserClient");
91447636 986 setProperty(gIOUserClientClassKey, (OSObject *) ucClassName);
55e303ae
A
987 ucClassName->release();
988
0c530ab8
A
989 // IOBacklightDisplay can take a long time to load at boot, or it may
990 // not load at all if you're booting with clamshell closed. We publish
991 // 'DisplayDims' here redundantly to get it published early and at all.
992 psIterator = getMatchingServices( serviceMatching("IOPMPowerSource") );
993 if( psIterator && psIterator->getNextObject() )
91447636 994 {
0c530ab8
A
995 // There's at least one battery on the system, so we publish
996 // 'DisplayDims' support for the LCD.
91447636 997 publishFeature("DisplayDims");
0c530ab8
A
998 }
999 if(psIterator) {
1000 psIterator->release();
91447636
A
1001 }
1002
2d21ac55
A
1003 sysctl_register_oid(&sysctl__kern_sleeptime);
1004 sysctl_register_oid(&sysctl__kern_waketime);
b0d623f7
A
1005 sysctl_register_oid(&sysctl__kern_willshutdown);
1006#if !CONFIG_EMBEDDED
1007 sysctl_register_oid(&sysctl__kern_progressmeterenable);
1008 sysctl_register_oid(&sysctl__kern_progressmeter);
1009#endif /* !CONFIG_EMBEDDED */
2d21ac55
A
1010
1011#if HIBERNATION
3a60a9f5 1012 IOHibernateSystemInit(this);
2d21ac55 1013#endif
91447636 1014
1c79356b
A
1015 registerService(); // let clients find us
1016
1017 return true;
1018}
1019
b0d623f7 1020//******************************************************************************
9bccf70c
A
1021// setProperties
1022//
1023// Receive a setProperty call
1024// The "System Boot" property means the system is completely booted.
b0d623f7
A
1025//******************************************************************************
1026
1027IOReturn IOPMrootDomain::setProperties( OSObject * props_obj )
1028{
1029 IOReturn return_value = kIOReturnSuccess;
1030 OSDictionary *dict = OSDynamicCast(OSDictionary, props_obj);
1031 OSBoolean *b;
1032 OSNumber *n;
6d2010ae 1033 OSDictionary *d;
b0d623f7
A
1034 OSSymbol *type;
1035 OSObject *obj;
1036 unsigned int i;
0c530ab8 1037
6d2010ae
A
1038 const OSSymbol *publish_simulated_battery_string = OSSymbol::withCString("SoftwareSimulatedBatteries");
1039 const OSSymbol *boot_complete_string = OSSymbol::withCString("System Boot Complete");
1040 const OSSymbol *sys_shutdown_string = OSSymbol::withCString("System Shutdown");
1041 const OSSymbol *stall_halt_string = OSSymbol::withCString("StallSystemAtHalt");
1042 const OSSymbol *battery_warning_disabled_string = OSSymbol::withCString("BatteryWarningsDisabled");
1043 const OSSymbol *idle_seconds_string = OSSymbol::withCString("System Idle Seconds");
1044 const OSSymbol *sleepdisabled_string = OSSymbol::withCString("SleepDisabled");
1045 const OSSymbol *ondeck_sleepwake_uuid_string = OSSymbol::withCString(kIOPMSleepWakeUUIDKey);
1046 const OSSymbol *loginwindow_tracepoint_string = OSSymbol::withCString(kIOPMLoginWindowSecurityDebugKey);
1047 const OSSymbol *pmTimelineLogging_string = OSSymbol::withCString(kIOPMTimelineDictionaryKey);
2d21ac55 1048#if HIBERNATION
6d2010ae
A
1049 const OSSymbol *hibernatemode_string = OSSymbol::withCString(kIOHibernateModeKey);
1050 const OSSymbol *hibernatefile_string = OSSymbol::withCString(kIOHibernateFileKey);
1051 const OSSymbol *hibernatefreeratio_string = OSSymbol::withCString(kIOHibernateFreeRatioKey);
1052 const OSSymbol *hibernatefreetime_string = OSSymbol::withCString(kIOHibernateFreeTimeKey);
2d21ac55 1053#endif
6d2010ae
A
1054
1055 if (!dict)
e5568f75
A
1056 {
1057 return_value = kIOReturnBadArgument;
1058 goto exit;
1059 }
4a249263 1060
6d2010ae
A
1061 if ((b = OSDynamicCast(OSBoolean, dict->getObject(publish_simulated_battery_string))))
1062 {
1063 publishResource(publish_simulated_battery_string, kOSBooleanTrue);
1064 }
1065
2d21ac55
A
1066 if ((n = OSDynamicCast(OSNumber, dict->getObject(idle_seconds_string))))
1067 {
1068 setProperty(idle_seconds_string, n);
b0d623f7 1069 idleSeconds = n->unsigned32BitValue();
2d21ac55
A
1070 }
1071
b0d623f7 1072 if (boot_complete_string && dict->getObject(boot_complete_string))
55e303ae 1073 {
b0d623f7 1074 pmPowerStateQueue->submitPowerEvent( kPowerEventSystemBootCompleted );
9bccf70c 1075 }
6d2010ae
A
1076
1077 if( battery_warning_disabled_string && dict->getObject(battery_warning_disabled_string))
2d21ac55 1078 {
6d2010ae 1079 setProperty( battery_warning_disabled_string, dict->getObject(battery_warning_disabled_string));
2d21ac55
A
1080 }
1081
6d2010ae
A
1082 if (pmTimelineLogging_string && (d = OSDynamicCast(OSDictionary, dict->getObject(pmTimelineLogging_string))))
1083 {
1084 if (timeline && timeline->setProperties(d))
1085 {
1086 OSDictionary *tlInfo = timeline->copyInfoDictionary();
1087 if (tlInfo) {
1088 setProperty(kIOPMTimelineDictionaryKey, tlInfo);
1089 tlInfo->release();
1090 }
1091 }
1092 }
1093
1094 if( sys_shutdown_string && (b = OSDynamicCast(OSBoolean, dict->getObject(sys_shutdown_string))))
8f6c56a5 1095 {
b0d623f7 1096 pmPowerStateQueue->submitPowerEvent(kPowerEventSystemShutdown, (void *) b);
8f6c56a5 1097 }
0c530ab8 1098
6d2010ae 1099 if( stall_halt_string && (b = OSDynamicCast(OSBoolean, dict->getObject(stall_halt_string))) )
55e303ae 1100 {
4a249263 1101 setProperty(stall_halt_string, b);
55e303ae 1102 }
91447636 1103
2d21ac55 1104#if HIBERNATION
3a60a9f5 1105 if ( hibernatemode_string
6d2010ae 1106 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatemode_string))))
3a60a9f5 1107 {
0c530ab8 1108 setProperty(hibernatemode_string, n);
3a60a9f5
A
1109 }
1110 if ( hibernatefreeratio_string
6d2010ae 1111 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatefreeratio_string))))
3a60a9f5 1112 {
0c530ab8 1113 setProperty(hibernatefreeratio_string, n);
3a60a9f5
A
1114 }
1115 if ( hibernatefreetime_string
6d2010ae 1116 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatefreetime_string))))
3a60a9f5 1117 {
0c530ab8 1118 setProperty(hibernatefreetime_string, n);
6d2010ae
A
1119 }
1120 OSString *str;
3a60a9f5 1121 if ( hibernatefile_string
6d2010ae 1122 && (str = OSDynamicCast(OSString, dict->getObject(hibernatefile_string))))
8f6c56a5 1123 {
0c530ab8 1124 setProperty(hibernatefile_string, str);
8f6c56a5 1125 }
2d21ac55
A
1126#endif
1127
1128 if( sleepdisabled_string
1129 && (b = OSDynamicCast(OSBoolean, dict->getObject(sleepdisabled_string))) )
1130 {
1131 setProperty(sleepdisabled_string, b);
b0d623f7
A
1132 pmPowerStateQueue->submitPowerEvent(kPowerEventUserDisabledSleep, (void *) b);
1133 }
b0d623f7
A
1134 if (ondeck_sleepwake_uuid_string
1135 && (obj = dict->getObject(ondeck_sleepwake_uuid_string)))
1136 {
6d2010ae
A
1137 if(pmPowerStateQueue) {
1138 obj->retain();
1139 pmPowerStateQueue->submitPowerEvent(kPowerEventQueueSleepWakeUUID, (void *)obj);
b0d623f7
A
1140 }
1141
b0d623f7
A
1142 }
1143
1144 if (loginwindow_tracepoint_string
1145 && (n = OSDynamicCast(OSNumber, dict->getObject(loginwindow_tracepoint_string)))
1146 && pmTracer)
1147 {
1148 pmTracer->traceLoginWindowPhase( n->unsigned8BitValue() );
2d21ac55 1149 }
8f6c56a5 1150
0b4c1975
A
1151 if ((b = OSDynamicCast(OSBoolean, dict->getObject(kIOPMDeepSleepEnabledKey))))
1152 {
1153 setProperty(kIOPMDeepSleepEnabledKey, b);
1154 }
1155 if ((n = OSDynamicCast(OSNumber, dict->getObject(kIOPMDeepSleepDelayKey))))
1156 {
1157 setProperty(kIOPMDeepSleepDelayKey, n);
1158 }
6d2010ae
A
1159 if ((b = OSDynamicCast(OSBoolean, dict->getObject(kIOPMDestroyFVKeyOnStandbyKey))))
1160 {
1161 setProperty(kIOPMDestroyFVKeyOnStandbyKey, b);
1162 }
0b4c1975 1163
0c530ab8
A
1164 // Relay our allowed PM settings onto our registered PM clients
1165 for(i = 0; i < allowedPMSettings->getCount(); i++) {
e5568f75 1166
0c530ab8
A
1167 type = (OSSymbol *)allowedPMSettings->getObject(i);
1168 if(!type) continue;
8ad349bb 1169
0c530ab8
A
1170 obj = dict->getObject(type);
1171 if(!obj) continue;
2d21ac55 1172
6d2010ae
A
1173 if ((gIOPMSettingAutoWakeSecondsKey == type) && ((n = OSDynamicCast(OSNumber, obj))))
1174 {
1175 UInt32 rsecs = n->unsigned32BitValue();
1176 if (!rsecs)
1177 autoWakeStart = autoWakeEnd = 0;
1178 else
1179 {
1180 AbsoluteTime deadline;
1181 clock_interval_to_deadline(rsecs + kAutoWakePostWindow, kSecondScale, &deadline);
1182 autoWakeEnd = AbsoluteTime_to_scalar(&deadline);
1183 if (rsecs > kAutoWakePreWindow)
1184 rsecs -= kAutoWakePreWindow;
1185 else
1186 rsecs = 0;
1187 clock_interval_to_deadline(rsecs, kSecondScale, &deadline);
1188 autoWakeStart = AbsoluteTime_to_scalar(&deadline);
1189 }
1190 }
1191 if (gIOPMSettingDebugWakeRelativeKey == type)
1192 {
1193 if ((n = OSDynamicCast(OSNumber, obj)))
1194 _debugWakeSeconds = n->unsigned32BitValue();
1195 else
1196 _debugWakeSeconds = 0;
1197 }
0c530ab8
A
1198
1199 return_value = setPMSetting(type, obj);
1200
6601e61a
A
1201 if(kIOReturnSuccess != return_value) goto exit;
1202 }
1203
2d21ac55 1204exit:
6d2010ae 1205 if(publish_simulated_battery_string) publish_simulated_battery_string->release();
4a249263 1206 if(boot_complete_string) boot_complete_string->release();
b0d623f7 1207 if(sys_shutdown_string) sys_shutdown_string->release();
4a249263 1208 if(stall_halt_string) stall_halt_string->release();
6d2010ae 1209 if(battery_warning_disabled_string) battery_warning_disabled_string->release();
2d21ac55 1210 if(idle_seconds_string) idle_seconds_string->release();
b0d623f7
A
1211 if(sleepdisabled_string) sleepdisabled_string->release();
1212 if(ondeck_sleepwake_uuid_string) ondeck_sleepwake_uuid_string->release();
0b4c1975 1213 if(loginwindow_tracepoint_string) loginwindow_tracepoint_string->release();
6d2010ae 1214 if(pmTimelineLogging_string) pmTimelineLogging_string->release();
b0d623f7
A
1215#if HIBERNATION
1216 if(hibernatemode_string) hibernatemode_string->release();
1217 if(hibernatefile_string) hibernatefile_string->release();
1218 if(hibernatefreeratio_string) hibernatefreeratio_string->release();
1219 if(hibernatefreetime_string) hibernatefreetime_string->release();
1220#endif
e5568f75 1221 return return_value;
9bccf70c
A
1222}
1223
6d2010ae
A
1224// MARK: -
1225// MARK: Aggressiveness
1c79356b 1226
b0d623f7 1227//******************************************************************************
6d2010ae 1228// setAggressiveness
1c79356b 1229//
6d2010ae 1230// Override IOService::setAggressiveness()
b0d623f7 1231//******************************************************************************
1c79356b 1232
6d2010ae
A
1233IOReturn IOPMrootDomain::setAggressiveness(
1234 unsigned long type,
1235 unsigned long value )
1c79356b 1236{
6d2010ae
A
1237 return setAggressiveness( type, value, 0 );
1238}
d52fe63f 1239
b0d623f7
A
1240/*
1241 * Private setAggressiveness() with an internal options argument.
1242 */
1243IOReturn IOPMrootDomain::setAggressiveness(
1244 unsigned long type,
1245 unsigned long value,
1246 IOOptionBits options )
0b4e3aa0 1247{
b0d623f7
A
1248 AggressivesRequest * entry;
1249 AggressivesRequest * request;
1250 bool found = false;
2d21ac55 1251
6d2010ae
A
1252 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1253 (uint32_t) options, (uint32_t) type, (uint32_t) value);
2d21ac55 1254
b0d623f7
A
1255 request = IONew(AggressivesRequest, 1);
1256 if (!request)
1257 return kIOReturnNoMemory;
1258
1259 memset(request, 0, sizeof(*request));
1260 request->options = options;
1261 request->dataType = kAggressivesRequestTypeRecord;
1262 request->data.record.type = (uint32_t) type;
1263 request->data.record.value = (uint32_t) value;
1264
1265 AGGRESSIVES_LOCK();
1266
1267 // Update disk quick spindown flag used by getAggressiveness().
1268 // Never merge requests with quick spindown flags set.
1269
1270 if (options & kAggressivesOptionQuickSpindownEnable)
1271 gAggressivesState |= kAggressivesStateQuickSpindown;
1272 else if (options & kAggressivesOptionQuickSpindownDisable)
1273 gAggressivesState &= ~kAggressivesStateQuickSpindown;
1274 else
2d21ac55 1275 {
b0d623f7
A
1276 // Coalesce requests with identical aggressives types.
1277 // Deal with callers that calls us too "aggressively".
1278
1279 queue_iterate(&aggressivesQueue, entry, AggressivesRequest *, chain)
1280 {
1281 if ((entry->dataType == kAggressivesRequestTypeRecord) &&
1282 (entry->data.record.type == type) &&
1283 ((entry->options & kAggressivesOptionQuickSpindownMask) == 0))
1284 {
1285 entry->data.record.value = value;
1286 found = true;
1287 break;
1288 }
1289 }
2d21ac55
A
1290 }
1291
b0d623f7
A
1292 if (!found)
1293 {
1294 queue_enter(&aggressivesQueue, request, AggressivesRequest *, chain);
1295 }
0b4e3aa0 1296
b0d623f7
A
1297 AGGRESSIVES_UNLOCK();
1298
1299 if (found)
1300 IODelete(request, AggressivesRequest, 1);
1301
1302 if (options & kAggressivesOptionSynchronous)
1303 handleAggressivesRequests(); // not truly synchronous
1304 else
1305 thread_call_enter(aggressivesThreadCall);
1306
1307 return kIOReturnSuccess;
0b4e3aa0
A
1308}
1309
b0d623f7
A
1310//******************************************************************************
1311// getAggressiveness
1312//
1313// Override IOService::setAggressiveness()
1314// Fetch the aggressiveness factor with the given type.
1315//******************************************************************************
1316
1317IOReturn IOPMrootDomain::getAggressiveness (
1318 unsigned long type,
1319 unsigned long * outLevel )
d52fe63f 1320{
b0d623f7
A
1321 uint32_t value = 0;
1322 int source = 0;
d52fe63f 1323
b0d623f7
A
1324 if (!outLevel)
1325 return kIOReturnBadArgument;
1326
1327 AGGRESSIVES_LOCK();
1328
1329 // Disk quick spindown in effect, report value = 1
1330
1331 if ((gAggressivesState & kAggressivesStateQuickSpindown) &&
1332 (type == kPMMinutesToSpinDown))
1333 {
1334 value = kAggressivesMinValue;
1335 source = 1;
1336 }
1337
1338 // Consult the pending request queue.
1339
1340 if (!source)
1341 {
1342 AggressivesRequest * entry;
1343
1344 queue_iterate(&aggressivesQueue, entry, AggressivesRequest *, chain)
1345 {
1346 if ((entry->dataType == kAggressivesRequestTypeRecord) &&
1347 (entry->data.record.type == type) &&
1348 ((entry->options & kAggressivesOptionQuickSpindownMask) == 0))
1349 {
1350 value = entry->data.record.value;
1351 source = 2;
1352 break;
1353 }
1354 }
1355 }
1356
1357 // Consult the backend records.
1358
1359 if (!source && aggressivesData)
1360 {
1361 AggressivesRecord * record;
1362 int i, count;
1363
1364 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
1365 record = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
1366
1367 for (i = 0; i < count; i++, record++)
1368 {
1369 if (record->type == type)
1370 {
1371 value = record->value;
1372 source = 3;
1373 break;
1374 }
1375 }
1376 }
1377
1378 AGGRESSIVES_UNLOCK();
1379
1380 if (source)
1381 {
6d2010ae
A
1382 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1383 source, (uint32_t) type, value);
b0d623f7
A
1384 *outLevel = (unsigned long) value;
1385 return kIOReturnSuccess;
1386 }
1387 else
1388 {
1389 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type);
1390 *outLevel = 0; // default return = 0, driver may not check for error
1391 return kIOReturnInvalid;
1392 }
d52fe63f
A
1393}
1394
b0d623f7
A
1395//******************************************************************************
1396// joinAggressiveness
1c79356b 1397//
b0d623f7
A
1398// Request from IOService to join future aggressiveness broadcasts.
1399//******************************************************************************
1c79356b 1400
b0d623f7
A
1401IOReturn IOPMrootDomain::joinAggressiveness(
1402 IOService * service )
1c79356b 1403{
b0d623f7
A
1404 AggressivesRequest * request;
1405
1406 if (!service || (service == this))
1407 return kIOReturnBadArgument;
1408
6d2010ae 1409 DLOG("joinAggressiveness %s %p\n", service->getName(), service);
b0d623f7
A
1410
1411 request = IONew(AggressivesRequest, 1);
1412 if (!request)
1413 return kIOReturnNoMemory;
1414
1415 service->retain(); // released by synchronizeAggressives()
1416
1417 memset(request, 0, sizeof(*request));
1418 request->dataType = kAggressivesRequestTypeService;
1419 request->data.service = service;
1420
1421 AGGRESSIVES_LOCK();
1422 queue_enter(&aggressivesQueue, request, AggressivesRequest *, chain);
1423 AGGRESSIVES_UNLOCK();
1424
1425 thread_call_enter(aggressivesThreadCall);
3a60a9f5 1426
1c79356b
A
1427 return kIOReturnSuccess;
1428}
1429
b0d623f7
A
1430//******************************************************************************
1431// handleAggressivesRequests
1432//
1433// Backend thread processes all incoming aggressiveness requests in the queue.
1434//******************************************************************************
1435
1436static void
1437handleAggressivesFunction(
1438 thread_call_param_t param1,
1439 thread_call_param_t param2 )
1440{
1441 if (param1)
1442 {
1443 ((IOPMrootDomain *) param1)->handleAggressivesRequests();
1444 }
1445}
1446
1447void IOPMrootDomain::handleAggressivesRequests( void )
1448{
1449 AggressivesRecord * start;
1450 AggressivesRecord * record;
1451 AggressivesRequest * request;
1452 queue_head_t joinedQueue;
1453 int i, count;
1454 bool broadcast;
1455 bool found;
1456 bool pingSelf = false;
1457
1458 AGGRESSIVES_LOCK();
1459
1460 if ((gAggressivesState & kAggressivesStateBusy) || !aggressivesData ||
1461 queue_empty(&aggressivesQueue))
1462 goto unlock_done;
1463
1464 gAggressivesState |= kAggressivesStateBusy;
1465 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
1466 start = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
1467
1468 do
1469 {
1470 broadcast = false;
1471 queue_init(&joinedQueue);
1472
1473 do
1474 {
1475 // Remove request from the incoming queue in FIFO order.
1476 queue_remove_first(&aggressivesQueue, request, AggressivesRequest *, chain);
1477 switch (request->dataType)
1478 {
1479 case kAggressivesRequestTypeRecord:
1480 // Update existing record if found.
1481 found = false;
1482 for (i = 0, record = start; i < count; i++, record++)
1483 {
1484 if (record->type == request->data.record.type)
1485 {
1486 found = true;
1487
1488 if (request->options & kAggressivesOptionQuickSpindownEnable)
1489 {
1490 if ((record->flags & kAggressivesRecordFlagMinValue) == 0)
1491 {
1492 broadcast = true;
1493 record->flags |= (kAggressivesRecordFlagMinValue |
1494 kAggressivesRecordFlagModified);
6d2010ae 1495 DLOG("disk spindown accelerated, was %u min\n",
b0d623f7
A
1496 record->value);
1497 }
1498 }
1499 else if (request->options & kAggressivesOptionQuickSpindownDisable)
1500 {
1501 if (record->flags & kAggressivesRecordFlagMinValue)
1502 {
1503 broadcast = true;
1504 record->flags |= kAggressivesRecordFlagModified;
1505 record->flags &= ~kAggressivesRecordFlagMinValue;
1506 DLOG("disk spindown restored to %u min\n",
1507 record->value);
1508 }
1509 }
1510 else if (record->value != request->data.record.value)
1511 {
1512 record->value = request->data.record.value;
1513 if ((record->flags & kAggressivesRecordFlagMinValue) == 0)
1514 {
1515 broadcast = true;
1516 record->flags |= kAggressivesRecordFlagModified;
1517 }
1518 }
1519 break;
1520 }
1521 }
1522
1523 // No matching record, append a new record.
1524 if (!found &&
1525 ((request->options & kAggressivesOptionQuickSpindownDisable) == 0))
1526 {
1527 AggressivesRecord newRecord;
1528
1529 newRecord.flags = kAggressivesRecordFlagModified;
1530 newRecord.type = request->data.record.type;
1531 newRecord.value = request->data.record.value;
1532 if (request->options & kAggressivesOptionQuickSpindownEnable)
1533 {
1534 newRecord.flags |= kAggressivesRecordFlagMinValue;
1535 DLOG("disk spindown accelerated\n");
1536 }
1537
1538 aggressivesData->appendBytes(&newRecord, sizeof(newRecord));
1539
1540 // OSData may have switched to another (larger) buffer.
1541 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
1542 start = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
1543 broadcast = true;
1544 }
1545
1546 // Finished processing the request, release it.
1547 IODelete(request, AggressivesRequest, 1);
1548 break;
1549
1550 case kAggressivesRequestTypeService:
1551 // synchronizeAggressives() will free request.
1552 queue_enter(&joinedQueue, request, AggressivesRequest *, chain);
1553 break;
1554
1555 default:
1556 panic("bad aggressives request type %x\n", request->dataType);
1557 break;
1558 }
1559 } while (!queue_empty(&aggressivesQueue));
1560
1561 // Release the lock to perform work, with busy flag set.
1562 if (!queue_empty(&joinedQueue) || broadcast)
1563 {
1564 AGGRESSIVES_UNLOCK();
1565 if (!queue_empty(&joinedQueue))
1566 synchronizeAggressives(&joinedQueue, start, count);
1567 if (broadcast)
1568 broadcastAggressives(start, count);
1569 AGGRESSIVES_LOCK();
1570 }
1571
1572 // Remove the modified flag from all records.
1573 for (i = 0, record = start; i < count; i++, record++)
1574 {
1575 if ((record->flags & kAggressivesRecordFlagModified) &&
1576 ((record->type == kPMMinutesToDim) ||
1577 (record->type == kPMMinutesToSleep)))
1578 pingSelf = true;
1579
1580 record->flags &= ~kAggressivesRecordFlagModified;
1581 }
1582
1583 // Check the incoming queue again since new entries may have been
1584 // added while lock was released above.
1585
1586 } while (!queue_empty(&aggressivesQueue));
1587
1588 gAggressivesState &= ~kAggressivesStateBusy;
1589
1590unlock_done:
1591 AGGRESSIVES_UNLOCK();
1592
1593 // Root domain is interested in system and display sleep slider changes.
1594 // Submit a power event to handle those changes on the PM work loop.
1595
1596 if (pingSelf && pmPowerStateQueue) {
6d2010ae
A
1597 pmPowerStateQueue->submitPowerEvent(
1598 kPowerEventPolicyStimulus,
1599 (void *) kStimulusAggressivenessChanged );
b0d623f7
A
1600 }
1601}
1602
b0d623f7
A
1603//******************************************************************************
1604// synchronizeAggressives
1605//
1606// Push all known aggressiveness records to one or more IOService.
1607//******************************************************************************
1608
1609void IOPMrootDomain::synchronizeAggressives(
1610 queue_head_t * joinedQueue,
1611 const AggressivesRecord * array,
1612 int count )
1613{
1614 IOService * service;
1615 AggressivesRequest * request;
1616 const AggressivesRecord * record;
6d2010ae 1617 IOPMDriverCallEntry callEntry;
b0d623f7
A
1618 uint32_t value;
1619 int i;
1620
1621 while (!queue_empty(joinedQueue))
1622 {
1623 queue_remove_first(joinedQueue, request, AggressivesRequest *, chain);
1624 if (request->dataType == kAggressivesRequestTypeService)
1625 service = request->data.service;
1626 else
1627 service = 0;
1628
1629 IODelete(request, AggressivesRequest, 1);
1630 request = 0;
1631
1632 if (service)
1633 {
6d2010ae 1634 if (service->assertPMDriverCall(&callEntry))
b0d623f7
A
1635 {
1636 for (i = 0, record = array; i < count; i++, record++)
1637 {
1638 value = record->value;
1639 if (record->flags & kAggressivesRecordFlagMinValue)
1640 value = kAggressivesMinValue;
1641
6d2010ae 1642 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
b0d623f7
A
1643 record->type, value, service->getName());
1644 service->setAggressiveness(record->type, value);
1645 }
6d2010ae 1646 service->deassertPMDriverCall(&callEntry);
b0d623f7
A
1647 }
1648 service->release(); // retained by joinAggressiveness()
1649 }
1650 }
1651}
1652
b0d623f7
A
1653//******************************************************************************
1654// broadcastAggressives
1655//
1656// Traverse PM tree and call setAggressiveness() for records that have changed.
1657//******************************************************************************
1658
1659void IOPMrootDomain::broadcastAggressives(
1660 const AggressivesRecord * array,
1661 int count )
1662{
6d2010ae
A
1663 IORegistryIterator * iter;
1664 IORegistryEntry * entry;
1665 IOPowerConnection * connect;
b0d623f7
A
1666 IOService * service;
1667 const AggressivesRecord * record;
6d2010ae 1668 IOPMDriverCallEntry callEntry;
b0d623f7
A
1669 uint32_t value;
1670 int i;
1671
6d2010ae
A
1672 iter = IORegistryIterator::iterateOver(
1673 this, gIOPowerPlane, kIORegistryIterateRecursively);
b0d623f7 1674 if (iter)
6d2010ae 1675 {
b0d623f7
A
1676 do
1677 {
1678 iter->reset();
1679 while ((entry = iter->getNextObject()))
1680 {
1681 connect = OSDynamicCast(IOPowerConnection, entry);
1682 if (!connect || !connect->getReadyFlag())
1683 continue;
1684
1685 if ((service = (IOService *) connect->copyChildEntry(gIOPowerPlane)))
1686 {
6d2010ae 1687 if (service->assertPMDriverCall(&callEntry))
b0d623f7
A
1688 {
1689 for (i = 0, record = array; i < count; i++, record++)
1690 {
1691 if (record->flags & kAggressivesRecordFlagModified)
1692 {
1693 value = record->value;
1694 if (record->flags & kAggressivesRecordFlagMinValue)
1695 value = kAggressivesMinValue;
6d2010ae 1696 _LOG("broadcastAggressives %x = %u to %s\n",
b0d623f7
A
1697 record->type, value, service->getName());
1698 service->setAggressiveness(record->type, value);
1699 }
1700 }
6d2010ae 1701 service->deassertPMDriverCall(&callEntry);
b0d623f7
A
1702 }
1703 service->release();
1704 }
1705 }
1706 }
1707 while (!entry && !iter->isValid());
1708 iter->release();
1709 }
1710}
1711
6d2010ae
A
1712// MARK: -
1713// MARK: System Sleep
b0d623f7
A
1714
1715//******************************************************************************
1716// startIdleSleepTimer
1717//
1718//******************************************************************************
1719
1720void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds )
1721{
1722 AbsoluteTime deadline;
1723
1724 ASSERT_GATED();
1725 if (inSeconds)
1726 {
1727 clock_interval_to_deadline(inSeconds, kSecondScale, &deadline);
1728 thread_call_enter_delayed(extraSleepTimer, deadline);
1729 idleSleepTimerPending = true;
1730 DLOG("idle timer set for %u seconds\n", inSeconds);
1731 }
1732}
1733
b0d623f7
A
1734//******************************************************************************
1735// cancelIdleSleepTimer
1736//
1737//******************************************************************************
1738
1739void IOPMrootDomain::cancelIdleSleepTimer( void )
1740{
1741 ASSERT_GATED();
6d2010ae 1742 if (idleSleepTimerPending)
b0d623f7
A
1743 {
1744 DLOG("idle timer cancelled\n");
1745 thread_call_cancel(extraSleepTimer);
1746 idleSleepTimerPending = false;
1747 }
1748}
1749
b0d623f7
A
1750//******************************************************************************
1751// idleSleepTimerExpired
1752//
1753//******************************************************************************
1754
1755static void idleSleepTimerExpired(
1756 thread_call_param_t us, thread_call_param_t )
1757{
1758 ((IOPMrootDomain *)us)->handleSleepTimerExpiration();
1759}
1760
b0d623f7
A
1761//******************************************************************************
1762// handleSleepTimerExpiration
1763//
1764// The time between the sleep idle timeout and the next longest one has elapsed.
1765// It's time to sleep. Start that by removing the clamp that's holding us awake.
1766//******************************************************************************
1767
1768void IOPMrootDomain::handleSleepTimerExpiration( void )
1769{
1770 if (!getPMworkloop()->inGate())
1771 {
1772 getPMworkloop()->runAction(
1773 OSMemberFunctionCast(IOWorkLoop::Action, this,
1774 &IOPMrootDomain::handleSleepTimerExpiration),
1775 this);
1776 return;
1777 }
1778
1779 AbsoluteTime time;
1780
1781 DLOG("sleep timer expired\n");
1782 ASSERT_GATED();
1783
1784 idleSleepTimerPending = false;
1785
1786 clock_get_uptime(&time);
1787 if ((AbsoluteTime_to_scalar(&time) > autoWakeStart) &&
1788 (AbsoluteTime_to_scalar(&time) < autoWakeEnd))
1789 {
1790 thread_call_enter_delayed(extraSleepTimer, *((AbsoluteTime *) &autoWakeEnd));
1791 return;
1792 }
1793
b0d623f7 1794 setQuickSpinDownTimeout();
6d2010ae 1795 adjustPowerState(true);
b0d623f7
A
1796}
1797
b0d623f7 1798//******************************************************************************
6d2010ae 1799// setQuickSpinDownTimeout
b0d623f7
A
1800//
1801//******************************************************************************
1802
6d2010ae 1803void IOPMrootDomain::setQuickSpinDownTimeout( void )
b0d623f7 1804{
b0d623f7 1805 ASSERT_GATED();
6d2010ae
A
1806 setAggressiveness(
1807 kPMMinutesToSpinDown, 0, kAggressivesOptionQuickSpindownEnable );
1808}
b0d623f7 1809
6d2010ae
A
1810//******************************************************************************
1811// restoreUserSpinDownTimeout
1812//
1813//******************************************************************************
b0d623f7 1814
6d2010ae
A
1815void IOPMrootDomain::restoreUserSpinDownTimeout( void )
1816{
1817 ASSERT_GATED();
1818 setAggressiveness(
1819 kPMMinutesToSpinDown, 0, kAggressivesOptionQuickSpindownDisable );
b0d623f7
A
1820}
1821
b0d623f7 1822//******************************************************************************
1c79356b
A
1823// sleepSystem
1824//
b0d623f7
A
1825//******************************************************************************
1826
2d21ac55 1827/* public */
b0d623f7 1828IOReturn IOPMrootDomain::sleepSystem( void )
1c79356b 1829{
b0d623f7 1830 return sleepSystemOptions(NULL);
2d21ac55
A
1831}
1832
1833/* private */
b0d623f7 1834IOReturn IOPMrootDomain::sleepSystemOptions( OSDictionary *options )
2d21ac55
A
1835{
1836 /* sleepSystem is a public function, and may be called by any kernel driver.
1837 * And that's bad - drivers should sleep the system by calling
1838 * receivePowerNotification() instead. Drivers should not use sleepSystem.
1839 *
1840 * Note that user space app calls to IOPMSleepSystem() will also travel
1841 * this code path and thus be correctly identified as software sleeps.
1842 */
1843
1844 if (options && options->getObject("OSSwitch"))
1845 {
2d21ac55 1846 // Log specific sleep cause for OS Switch hibernation
6d2010ae 1847 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate);
2d21ac55 1848 } else {
0b4c1975 1849 return privateSleepSystem( kIOPMSleepReasonSoftware);
2d21ac55
A
1850 }
1851}
1852
1853/* private */
0b4c1975 1854IOReturn IOPMrootDomain::privateSleepSystem( uint32_t sleepReason )
2d21ac55 1855{
6d2010ae 1856 static const char * IOPMSleepReasons[] = {
0b4c1975
A
1857 "",
1858 kIOPMClamshellSleepKey,
1859 kIOPMPowerButtonSleepKey,
1860 kIOPMSoftwareSleepKey,
1861 kIOPMOSSwitchHibernationKey,
1862 kIOPMIdleSleepKey,
1863 kIOPMLowPowerSleepKey,
1864 kIOPMClamshellSleepKey,
6d2010ae
A
1865 kIOPMThermalEmergencySleepKey,
1866 kIOPMMaintenanceSleepKey
0b4c1975 1867 };
b0d623f7 1868
6d2010ae 1869 PMEventDetails *details;
0c530ab8 1870
6d2010ae 1871 if (!checkSystemCanSleep())
2d21ac55 1872 {
6d2010ae
A
1873 // Record why the system couldn't sleep
1874 details = PMEventDetails::eventDetails(kIOPMEventTypeSleep, NULL,
1875 sleepReason, kIOReturnNotPermitted);
1876
1877 recordAndReleasePMEvent( details );
1878 return kIOReturnNotPermitted;
1879 }
b0d623f7 1880
6d2010ae
A
1881 if (timeline)
1882 timeline->setSleepCycleInProgressFlag(true);
1883
1884 // Time to publish a UUID for the Sleep --> Wake cycle
1885 if(pmPowerStateQueue) {
1886 pmPowerStateQueue->submitPowerEvent(kPowerEventPublishSleepWakeUUID, (void *)true);
0b4e3aa0 1887 }
b0d623f7 1888
6d2010ae
A
1889
1890 // Log the beginning of system sleep.
1891 details = PMEventDetails::eventDetails(kIOPMEventTypeSleep, NULL,
1892 sleepReason, kIOReturnSuccess);
1893
1894 recordAndReleasePMEvent( details );
1895
b0d623f7 1896 // Record sleep cause in IORegistry
0b4c1975 1897 lastSleepReason = sleepReason;
6d2010ae
A
1898 sleepReason -= (kIOPMSleepReasonClamshell - 1);
1899 if (sleepReason && (sleepReason < sizeof(IOPMSleepReasons)/sizeof(IOPMSleepReasons[0]))) {
0b4c1975 1900 setProperty(kRootDomainSleepReasonKey, IOPMSleepReasons[sleepReason]);
b0d623f7
A
1901 }
1902
6d2010ae
A
1903 if (pmPowerStateQueue)
1904 pmPowerStateQueue->submitPowerEvent(
1905 kPowerEventPolicyStimulus,
1906 (void *) kStimulusDemandSystemSleep );
1907
b0d623f7 1908 return kIOReturnSuccess;
0b4e3aa0
A
1909}
1910
6d2010ae
A
1911IOReturn IOPMrootDomain::recordPMEventGated(PMEventDetails *record)
1912{
1913 // If we don't have a place to log to, we can't actually
1914 // log anything. Chances are, the person who is asking us to do
1915 // the PM logging has forgotten to set the right bootflags
1916 if(!timeline)
1917 return kIOReturnSuccess;
0b4e3aa0 1918
6d2010ae
A
1919 if(gIOPMWorkLoop->inGate() == false) {
1920
1921 IOReturn ret = gIOPMWorkLoop->runAction(
1922 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::recordPMEventGated),
1923 (OSObject *)this,
1924 (void *)record);
1925
1926 return ret;
1927 }
1928 else {
1929 // Now that we're guaranteed to be running in gate ...
b0d623f7 1930
6d2010ae
A
1931 // Check the validity of the argument we are given
1932 if(!record)
1933 return kIOReturnBadArgument;
1934
1935 // Record a driver event, or a system event
1936 if(record->eventClassifier == kIOPMEventClassDriverEvent
1937 || record->eventClassifier == kIOPMEventClassSystemEvent)
1938 return this->recordPMEvent(record);
1939
1940 else
1941 return kIOReturnBadArgument;
1942 }
0b4e3aa0
A
1943}
1944
6d2010ae 1945IOReturn IOPMrootDomain::recordAndReleasePMEventGated(PMEventDetails *record)
0b4e3aa0 1946{
6d2010ae 1947 IOReturn ret = kIOReturnBadArgument;
1c79356b 1948
6d2010ae
A
1949 if (record)
1950 {
1951 ret = recordPMEventGated(record);
1952 record->release();
1953 }
1954
1955 return ret;
1956}
1c79356b 1957
b0d623f7 1958//******************************************************************************
1c79356b
A
1959// powerChangeDone
1960//
1961// This overrides powerChangeDone in IOService.
b0d623f7 1962//******************************************************************************
2d21ac55 1963
6d2010ae 1964void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState )
b0d623f7 1965{
6d2010ae
A
1966 PMEventDetails *details;
1967
b0d623f7
A
1968 ASSERT_GATED();
1969 DLOG("PowerChangeDone: %u->%u\n",
6d2010ae
A
1970 (uint32_t) previousPowerState, (uint32_t) getPowerState());
1971
1972 switch ( getPowerState() )
1973 {
1974 case SLEEP_STATE: {
1975 if (previousPowerState != ON_STATE)
1976 break;
1977
1978 details = PMEventDetails::eventDetails(
1979 kIOPMEventTypeSleepDone,
1980 NULL,
1981 NULL,
1982 kIOReturnSuccess);
1983
1984 recordAndReleasePMEvent( details );
2d21ac55 1985
6d2010ae
A
1986 // re-enable this timer for next sleep
1987 cancelIdleSleepTimer();
91447636 1988
6d2010ae
A
1989 clock_sec_t secs;
1990 clock_usec_t microsecs;
1991 clock_get_calendar_microtime(&secs, &microsecs);
1992 logtime(secs);
1993 gIOLastSleepTime.tv_sec = secs;
1994 gIOLastSleepTime.tv_usec = microsecs;
1995 gIOLastWakeTime.tv_sec = 0;
1996 gIOLastWakeTime.tv_usec = 0;
2d21ac55
A
1997
1998#if HIBERNATION
6d2010ae 1999 LOG("System %sSleep\n", gIOHibernateState ? "Safe" : "");
3a60a9f5 2000
6d2010ae 2001 IOHibernateSystemHasSlept();
0b4c1975 2002
6d2010ae 2003 evaluateSystemSleepPolicyFinal();
2d21ac55 2004#else
6d2010ae 2005 LOG("System Sleep\n");
2d21ac55 2006#endif
3a60a9f5 2007
6d2010ae 2008 getPlatform()->sleepKernel();
b0d623f7 2009
6d2010ae
A
2010 // The CPU(s) are off at this point,
2011 // Code will resume execution here upon wake.
9bccf70c 2012
6d2010ae 2013 clock_get_uptime(&systemWakeTime);
91447636 2014
2d21ac55 2015#if HIBERNATION
6d2010ae 2016 IOHibernateSystemWake();
2d21ac55 2017#endif
9bccf70c 2018
6d2010ae
A
2019 // sleep transition complete
2020 gSleepOrShutdownPending = 0;
b0d623f7 2021
6d2010ae
A
2022 // trip the reset of the calendar clock
2023 clock_wakeup_calendar();
b0d623f7 2024
2d21ac55 2025#if HIBERNATION
6d2010ae 2026 LOG("System %sWake\n", gIOHibernateState ? "SafeSleep " : "");
2d21ac55 2027#endif
b0d623f7 2028
6d2010ae
A
2029 // log system wake
2030 getPlatform()->PMLog(kIOPMrootDomainClass, kPMLogSystemWake, 0, 0);
2031 lowBatteryCondition = false;
2032 lastSleepReason = 0;
2033
2034 // And start logging the wake event here
2035 // TODO: Publish the wakeReason string as an integer
2036 details = PMEventDetails::eventDetails(
2037 kIOPMEventTypeWake,
2038 NULL,
2039 0,
2040 kIOReturnSuccess);
2041
2042 recordAndReleasePMEvent( details );
2043
b0d623f7
A
2044
2045#ifndef __LP64__
6d2010ae 2046 systemWake();
b0d623f7
A
2047#endif
2048
b0d623f7 2049#if defined(__i386__) || defined(__x86_64__)
6d2010ae
A
2050 wranglerTickled = false;
2051 graphicsSuppressed = false;
2052 darkWakePostTickle = false;
2053 logGraphicsClamp = true;
2054 logWranglerTickle = true;
2055 sleepTimerMaintenance = false;
2056
2057 OSString * wakeType = OSDynamicCast(
2058 OSString, getProperty(kIOPMRootDomainWakeTypeKey));
2059 OSString * wakeReason = OSDynamicCast(
2060 OSString, getProperty(kIOPMRootDomainWakeReasonKey));
2061
2062 if (wakeType && wakeType->isEqualTo(kIOPMrootDomainWakeTypeLowBattery))
2063 {
2064 lowBatteryCondition = true;
2065 darkWakeMaintenance = true;
2066 darkWakeToSleepASAP = true;
2067 }
2068 else if ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) != 0)
2069 {
2070 OSNumber * hibOptions = OSDynamicCast(
2071 OSNumber, getProperty(kIOHibernateOptionsKey));
2072
2073 if (hibernateAborted ||
2074 ((hibOptions &&
2075 !(hibOptions->unsigned32BitValue() & kIOHibernateOptionDarkWake))) ||
2076 ((_debugWakeSeconds != 0) &&
2077 ((gDarkWakeFlags & kDarkWakeFlagAlarmIsDark) == 0)) ||
2078 (wakeType && (
2079 wakeType->isEqualTo(kIOPMRootDomainWakeTypeUser) ||
2080 wakeType->isEqualTo(kIOPMRootDomainWakeTypeAlarm))))
0b4c1975 2081 {
6d2010ae 2082 wranglerTickled = true;
0b4c1975 2083 }
6d2010ae
A
2084 else
2085 if (wakeType &&
2086 wakeType->isEqualTo(kIOPMRootDomainWakeTypeMaintenance))
0b4c1975 2087 {
6d2010ae
A
2088 darkWakeMaintenance = true;
2089 darkWakeToSleepASAP = true;
0b4c1975 2090 }
6d2010ae
A
2091 else
2092 if (wakeType &&
2093 wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer))
b0d623f7 2094 {
6d2010ae
A
2095 darkWakeMaintenance = true;
2096 darkWakeToSleepASAP = true;
2097 sleepTimerMaintenance = true;
b0d623f7
A
2098 }
2099 else
b0d623f7 2100 {
6d2010ae
A
2101 // Unidentified wake source, resume to full wake if debug
2102 // alarm is pending.
b0d623f7 2103
6d2010ae
A
2104 if (_debugWakeSeconds && (!wakeReason || wakeReason->isEqualTo("")))
2105 wranglerTickled = true;
2106 else
2107 darkWakeToSleepASAP = true;
2108 }
0b4e3aa0 2109 }
6d2010ae 2110 else
55e303ae 2111 {
6d2010ae 2112 // Post a HID tickle immediately - except for maintenance wake.
b0d623f7 2113
6d2010ae
A
2114 if (hibernateAborted || !wakeType ||
2115 !wakeType->isEqualTo(kIOPMRootDomainWakeTypeMaintenance))
0b4c1975 2116 {
6d2010ae 2117 wranglerTickled = true;
0b4c1975
A
2118 }
2119 else
2120 {
6d2010ae
A
2121 darkWakeMaintenance = true;
2122 darkWakeToSleepASAP = true;
0b4c1975 2123 }
b0d623f7
A
2124 }
2125
6d2010ae
A
2126 if (wranglerTickled)
2127 reportUserInput();
2128 else if (!darkWakeMaintenance)
b0d623f7 2129 {
6d2010ae
A
2130 // Early/late tickle for non-maintenance wake.
2131 if (((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
2132 kDarkWakeFlagHIDTickleEarly) ||
2133 ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
2134 kDarkWakeFlagHIDTickleLate))
2135 {
2136 darkWakePostTickle = true;
2137 }
2138 }
2139#else /* !__i386__ && !__x86_64__ */
2140 // stay awake for at least 30 seconds
2141 wranglerTickled = true;
2142 startIdleSleepTimer(30);
2143#endif
2144
2145 changePowerStateToPriv(ON_STATE);
2146 } break;
2147
2148 case ON_STATE: {
2149 bool wasPrevented = childPreventSystemSleep;
2150
2151 details = PMEventDetails::eventDetails(
2152 kIOPMEventTypeWakeDone,
2153 NULL,
2154 0,
2155 kIOReturnSuccess);
2156
2157 recordAndReleasePMEvent( details );
2158
2159 if (previousPowerState != ON_STATE)
2160 _debugWakeSeconds = 0;
2161
2162 // Update childPreventSystemSleep flag using the capability computed
2163 // by IOSevice::rebuildChildClampBits().
2164
2165 childPreventSystemSleep =
2166 ((currentCapability() & kIOPMChildClamp2) != 0);
b0d623f7 2167
6d2010ae
A
2168 if (wasPrevented && !childPreventSystemSleep)
2169 {
2170 evaluatePolicy( kStimulusDarkWakeEvaluate );
b0d623f7 2171 }
6d2010ae 2172 } break;
0b4e3aa0
A
2173 }
2174}
2175
b0d623f7 2176//******************************************************************************
6d2010ae 2177// requestPowerDomainState
0b4e3aa0 2178//
6d2010ae
A
2179// Extend implementation in IOService. Running on PM work loop thread.
2180//
2181// Examine children desires and initiate idle-sleep if all children are idle,
2182// prevent idle and system sleep flags are not set.
b0d623f7
A
2183//******************************************************************************
2184
6d2010ae
A
2185IOReturn IOPMrootDomain::requestPowerDomainState (
2186 IOPMPowerFlags childDesire,
2187 IOPowerConnection * childConnection,
2188 unsigned long specification )
1c79356b 2189{
6d2010ae
A
2190 OSIterator *iter;
2191 OSObject *next;
2192 IOPowerConnection *connection;
2193 IOPMPowerFlags mergedChildDesire = 0;
2194 IOPMPowerFlags editedChildDesire;
2195 IOPMPowerFlags thisDesire;
2196 bool sleepASAP = false;
2197
2198 ASSERT_GATED();
2199
2200 // Disregard disk I/O (anything besides the display wrangler) as a
2201 // factor in preventing idle sleep - based on a runtime setting.
2202
2203 if ((gDarkWakeFlags & kDarkWakeFlagIgnoreDiskIOAlways) &&
2204 (kIOPMPreventIdleSleep & childDesire) &&
2205 (childConnection != wranglerConnection))
55e303ae 2206 {
6d2010ae 2207 childDesire &= ~kIOPMPreventIdleSleep;
1c79356b 2208 }
1c79356b 2209
6d2010ae
A
2210 // Force the child's input power requirement to 0 unless the prevent
2211 // idle-sleep flag is set. Nil input power flags maps to our state 0.
2212 // Our power clamp (deviceDesire) clamps the lowest power state at 2.
1c79356b 2213
6d2010ae
A
2214 editedChildDesire = 0;
2215 if (childDesire & kIOPMPreventIdleSleep)
2216 editedChildDesire |= (kIOPMPowerOn | kIOPMPreventIdleSleep);
2217 if (childDesire & kIOPMPreventSystemSleep)
2218 editedChildDesire |= (kIOPMPowerOn | kIOPMPreventSystemSleep);
b0d623f7 2219
6d2010ae
A
2220 iter = getChildIterator(gIOPowerPlane);
2221 if ( iter )
2222 {
2223 while ( (next = iter->getNextObject()) )
2224 {
2225 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
2226 {
2227 // Ignore child that are in the process of joining.
2228 if (connection->getReadyFlag() == false)
2229 continue;
0c530ab8 2230
6d2010ae
A
2231 // OR in the child's input power requirements.
2232 // Is this connection attached to the child that called
2233 // requestPowerDomainState()?
0c530ab8 2234
6d2010ae
A
2235 if (connection == childConnection)
2236 {
2237 thisDesire = editedChildDesire;
2238 }
2239 else
2240 {
2241 thisDesire = 0;
2242 if (connection->getPreventIdleSleepFlag())
2243 thisDesire |= (kIOPMPowerOn | kIOPMPreventIdleSleep);
2244 if (connection->getPreventSystemSleepFlag())
2245 thisDesire |= (kIOPMPowerOn | kIOPMPreventSystemSleep);
2246 }
0c530ab8 2247
6d2010ae
A
2248 mergedChildDesire |= thisDesire;
2249 if (thisDesire && (kIOLogPMRootDomain & gIOKitDebug))
2250 {
2251 IOService * child =
2252 (IOService *) connection->getChildEntry(gIOPowerPlane);
2253 LOG("child %p, noIdle %d, noSleep %d - %s\n",
2254 child,
2255 ((thisDesire & kIOPMPreventIdleSleep) != 0),
2256 ((thisDesire & kIOPMPreventSystemSleep) != 0),
2257 child ? child->getName() : "?");
2258 }
2259 }
2260 }
2261 iter->release();
0c530ab8 2262 }
b0d623f7 2263
6d2010ae
A
2264 DLOG("mergedChildDesire 0x%lx, extraSleepDelay %ld\n",
2265 mergedChildDesire, extraSleepDelay);
0c530ab8 2266
6d2010ae 2267 if ( !mergedChildDesire && !systemBooting )
0c530ab8 2268 {
6d2010ae 2269 if (!wrangler)
0c530ab8 2270 {
6d2010ae
A
2271 changePowerStateToPriv(ON_STATE);
2272 if (idleSeconds)
2273 {
2274 // stay awake for at least idleSeconds
2275 startIdleSleepTimer(idleSeconds);
2276 }
b0d623f7 2277 }
6d2010ae 2278 else if (!extraSleepDelay && !idleSleepTimerPending && !systemDarkWake)
b0d623f7 2279 {
6d2010ae 2280 sleepASAP = true;
0c530ab8 2281 }
0c530ab8 2282 }
91447636 2283
6d2010ae
A
2284 // Drop our power clamp to SLEEP_STATE when all children became idle,
2285 // and system sleep and display sleep slider values are equal.
0c530ab8 2286
6d2010ae 2287 adjustPowerState(sleepASAP);
0c530ab8 2288
6d2010ae
A
2289 // If our power clamp has already dropped to SLEEP_STATE, and no child
2290 // is keeping us at ON_STATE, then the following will trigger idle sleep.
2d21ac55 2291
6d2010ae
A
2292 return super::requestPowerDomainState(
2293 editedChildDesire, childConnection, specification);
0c530ab8
A
2294}
2295
b0d623f7 2296//******************************************************************************
6d2010ae 2297// tellChangeDown
0c530ab8 2298//
6d2010ae 2299// Override the superclass implementation to send a different message type.
b0d623f7
A
2300//******************************************************************************
2301
6d2010ae 2302bool IOPMrootDomain::tellChangeDown( unsigned long stateNum )
0c530ab8 2303{
6d2010ae
A
2304 DLOG("tellChangeDown %u->%u\n",
2305 (uint32_t) getPowerState(), (uint32_t) stateNum);
0c530ab8 2306
6d2010ae 2307 if (SLEEP_STATE == stateNum)
0c530ab8 2308 {
6d2010ae
A
2309 if (!ignoreTellChangeDown)
2310 tracePoint( kIOPMTracePointSleepApplications );
2311 else
2312 tracePoint( kIOPMTracePointSleepPriorityClients );
0c530ab8 2313 }
6d2010ae
A
2314
2315 if ((SLEEP_STATE == stateNum) && !ignoreTellChangeDown)
0c530ab8 2316 {
6d2010ae
A
2317 userActivityAtSleep = userActivityCount;
2318 hibernateAborted = false;
2319 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep);
0c530ab8 2320
6d2010ae
A
2321 // Direct callout into OSKext so it can disable kext unloads
2322 // during sleep/wake to prevent deadlocks.
2323 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep );
0c530ab8 2324
6d2010ae 2325 IOService::updateConsoleUsers(NULL, kIOMessageSystemWillSleep);
0c530ab8 2326
6d2010ae
A
2327 // Notify platform that sleep has begun
2328 getPlatform()->callPlatformFunction(
2329 sleepMessagePEFunction, false,
2330 (void *)(uintptr_t) kIOMessageSystemWillSleep,
2331 NULL, NULL, NULL);
0c530ab8 2332
6d2010ae
A
2333 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2334 // But tellClientsWithResponse() must be called for both.
2335 ignoreTellChangeDown = true;
0c530ab8 2336 }
5d5c5d0d 2337
6d2010ae
A
2338 return super::tellClientsWithResponse( kIOMessageSystemWillSleep );
2339}
5d5c5d0d 2340
b0d623f7 2341//******************************************************************************
6d2010ae 2342// askChangeDown
0c530ab8 2343//
6d2010ae
A
2344// Override the superclass implementation to send a different message type.
2345// This must be idle sleep since we don't ask during any other power change.
b0d623f7
A
2346//******************************************************************************
2347
6d2010ae 2348bool IOPMrootDomain::askChangeDown( unsigned long stateNum )
55e303ae 2349{
6d2010ae
A
2350 DLOG("askChangeDown %u->%u\n",
2351 (uint32_t) getPowerState(), (uint32_t) stateNum);
0c530ab8 2352
6d2010ae
A
2353 // Don't log for dark wake entry
2354 if (kSystemTransitionSleep == _systemTransitionType)
2355 tracePoint( kIOPMTracePointSleepApplications );
483a1d10 2356
6d2010ae 2357 return super::tellClientsWithResponse( kIOMessageCanSystemSleep );
1c79356b
A
2358}
2359
b0d623f7 2360//******************************************************************************
6d2010ae 2361// askChangeDownDone
0c530ab8 2362//
6d2010ae
A
2363// Called by PM after all apps have responded to kIOMessageCanSystemSleep.
2364// pmconfigd may create a deny sleep assertion before ack'ing.
b0d623f7
A
2365//******************************************************************************
2366
6d2010ae
A
2367void IOPMrootDomain::askChangeDownDone(
2368 IOPMPowerChangeFlags * inOutChangeFlags, bool * cancel )
e5568f75 2369{
6d2010ae
A
2370 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2371 *inOutChangeFlags, *cancel,
2372 _systemTransitionType,
2373 _currentCapability, _pendingCapability);
0c530ab8 2374
6d2010ae
A
2375 if ((false == *cancel) && (kSystemTransitionSleep == _systemTransitionType))
2376 {
2377 // Dark->Sleep transition.
2378 // Check if there are any deny sleep assertions.
2379 // Full->Dark transition is never cancelled.
0c530ab8 2380
6d2010ae
A
2381 if (!checkSystemCanSleep(true))
2382 {
2383 // Cancel dark wake to sleep transition.
2384 // Must re-scan assertions upon entering dark wake.
0c530ab8 2385
6d2010ae
A
2386 *cancel = true;
2387 DLOG("cancel dark->sleep\n");
2388 }
0c530ab8 2389 }
e5568f75
A
2390}
2391
b0d623f7 2392//******************************************************************************
6d2010ae 2393// tellNoChangeDown
0c530ab8 2394//
6d2010ae
A
2395// Notify registered applications and kernel clients that we are not dropping
2396// power.
2397//
2398// We override the superclass implementation so we can send a different message
2399// type to the client or application being notified.
2400//
2401// This must be a vetoed idle sleep, since no other power change can be vetoed.
2402//******************************************************************************
4452a7af 2403
6d2010ae
A
2404void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum )
2405{
2406 DLOG("tellNoChangeDown %u->%u\n",
2407 (uint32_t) getPowerState(), (uint32_t) stateNum);
0c530ab8 2408
6d2010ae
A
2409 if (idleSeconds && !wrangler)
2410 {
2411 // stay awake for at least idleSeconds
2412 startIdleSleepTimer(idleSeconds);
0c530ab8 2413 }
6d2010ae 2414 return tellClients( kIOMessageSystemWillNotSleep );
0c530ab8
A
2415}
2416
b0d623f7 2417//******************************************************************************
6d2010ae 2418// tellChangeUp
1c79356b 2419//
6d2010ae
A
2420// Notify registered applications and kernel clients that we are raising power.
2421//
2422// We override the superclass implementation so we can send a different message
2423// type to the client or application being notified.
b0d623f7
A
2424//******************************************************************************
2425
6d2010ae 2426void IOPMrootDomain::tellChangeUp( unsigned long stateNum )
0c530ab8 2427{
6d2010ae
A
2428 OSData *publishPMStats = NULL;
2429
2430 DLOG("tellChangeUp %u->%u\n",
2431 (uint32_t) getPowerState(), (uint32_t) stateNum);
2432
2433 ignoreTellChangeDown = false;
2434
2435 if ( stateNum == ON_STATE )
2436 {
2437 // Direct callout into OSKext so it can disable kext unloads
2438 // during sleep/wake to prevent deadlocks.
2439 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn );
2440
2441 // Notify platform that sleep was cancelled or resumed.
2442 getPlatform()->callPlatformFunction(
2443 sleepMessagePEFunction, false,
2444 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn,
2445 NULL, NULL, NULL);
2446
2447 if (getPowerState() == ON_STATE)
2448 {
2449 // this is a quick wake from aborted sleep
2450 if (idleSeconds && !wrangler)
2451 {
2452 // stay awake for at least idleSeconds
2453 startIdleSleepTimer(idleSeconds);
2454 }
2455 tellClients( kIOMessageSystemWillPowerOn );
2456 }
2457
2458 tracePoint( kIOPMTracePointWakeApplications );
2459 publishPMStats = OSData::withBytes(&pmStats, sizeof(pmStats));
2460 setProperty(kIOPMSleepStatisticsKey, publishPMStats);
2461 publishPMStats->release();
2462 bzero(&pmStats, sizeof(pmStats));
2463
2464 if (pmStatsAppResponses)
2465 {
2466 setProperty(kIOPMSleepStatisticsAppsKey, pmStatsAppResponses);
2467 pmStatsAppResponses->release();
2468 pmStatsAppResponses = OSArray::withCapacity(5);
2469 }
1c79356b 2470
6d2010ae
A
2471 tellClients( kIOMessageSystemHasPoweredOn );
2472 }
2473}
b0d623f7
A
2474
2475//******************************************************************************
6d2010ae 2476// sysPowerDownHandler
0c530ab8 2477//
6d2010ae 2478// Perform a vfs sync before system sleep.
b0d623f7
A
2479//******************************************************************************
2480
6d2010ae
A
2481IOReturn IOPMrootDomain::sysPowerDownHandler(
2482 void * target, void * refCon,
2483 UInt32 messageType, IOService * service,
2484 void * messageArgs, vm_size_t argSize )
1c79356b 2485{
6d2010ae 2486 IOReturn ret;
0c530ab8 2487
6d2010ae
A
2488 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType));
2489
2490 if (!gRootDomain)
2491 return kIOReturnUnsupported;
2492
2493 if (messageType == kIOMessageSystemCapabilityChange)
55e303ae 2494 {
6d2010ae
A
2495 IOPMSystemCapabilityChangeParameters * params =
2496 (IOPMSystemCapabilityChangeParameters *) messageArgs;
2497
2498 // Interested applications have been notified of an impending power
2499 // change and have acked (when applicable).
2500 // This is our chance to save whatever state we can before powering
2501 // down.
2502 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
2503 // via callout
2504
2505 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
2506 params->fromCapabilities, params->toCapabilities,
2507 params->changeFlags);
2508
2509 if ((params->changeFlags & kIOPMSystemCapabilityWillChange) &&
2510 (params->fromCapabilities & kIOPMSystemCapabilityCPU) &&
2511 (params->toCapabilities & kIOPMSystemCapabilityCPU) == 0)
2512 {
2513 // We will ack within 20 seconds
2514 params->maxWaitForReply = 20 * 1000 * 1000;
2515#if HIBERNATION
2516 gRootDomain->evaluateSystemSleepPolicyEarly();
0c530ab8 2517
6d2010ae
A
2518 // add in time we could spend freeing pages
2519 if (gRootDomain->hibernateMode && !gRootDomain->hibernateDisabled)
2520 {
2521 params->maxWaitForReply = kCapabilityClientMaxWait;
2522 }
2523 DLOG("sysPowerDownHandler timeout %d s\n", (int) (params->maxWaitForReply / 1000 / 1000));
2524#endif
2525
2526 if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending ) )
2527 {
2528 // Purposely delay the ack and hope that shutdown occurs quickly.
2529 // Another option is not to schedule the thread and wait for
2530 // ack timeout...
2531 AbsoluteTime deadline;
2532 clock_interval_to_deadline( 30, kSecondScale, &deadline );
2533 thread_call_enter1_delayed(
2534 gRootDomain->diskSyncCalloutEntry,
2535 (thread_call_param_t) params->notifyRef,
2536 deadline );
2537 }
2538 else
2539 thread_call_enter1(
2540 gRootDomain->diskSyncCalloutEntry,
2541 (thread_call_param_t) params->notifyRef);
2542 }
2543#if HIBERNATION
2544 else
2545 if ((params->changeFlags & kIOPMSystemCapabilityDidChange) &&
2546 (params->toCapabilities & kIOPMSystemCapabilityCPU) &&
2547 (params->fromCapabilities & kIOPMSystemCapabilityCPU) == 0)
2548 {
2549 // We will ack within 110 seconds
2550 params->maxWaitForReply = 110 * 1000 * 1000;
0c530ab8 2551
6d2010ae
A
2552 thread_call_enter1(
2553 gRootDomain->diskSyncCalloutEntry,
2554 (thread_call_param_t) params->notifyRef);
2555 }
2556#endif
2557 ret = kIOReturnSuccess;
0c530ab8
A
2558 }
2559
6d2010ae
A
2560 return ret;
2561}
2562
2563//******************************************************************************
2564// handleQueueSleepWakeUUID
2565//
2566// Called from IOPMrootDomain when we're initiating a sleep,
2567// or indirectly from PM configd when PM decides to clear the UUID.
2568// PM clears the UUID several minutes after successful wake from sleep,
2569// so that we might associate App spindumps with the immediately previous
2570// sleep/wake.
2571//
2572// @param obj has a retain on it. We're responsible for releasing that retain.
2573//******************************************************************************
2574
2575void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject *obj)
2576{
2577 OSString *str = NULL;
2578
2579 if (kOSBooleanFalse == obj)
55e303ae 2580 {
6d2010ae
A
2581 handlePublishSleepWakeUUID(NULL);
2582 }
2583 else if ((str = OSDynamicCast(OSString, obj)))
2584 {
2585 // This branch caches the UUID for an upcoming sleep/wake
2586 if (queuedSleepWakeUUIDString) {
2587 queuedSleepWakeUUIDString->release();
2588 queuedSleepWakeUUIDString = NULL;
0c530ab8 2589 }
6d2010ae
A
2590 queuedSleepWakeUUIDString = str;
2591 queuedSleepWakeUUIDString->retain();
0c530ab8 2592
6d2010ae 2593 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString->getCStringNoCopy());
d52fe63f 2594 }
0c530ab8 2595
6d2010ae
A
2596 if (obj) {
2597 obj->release();
2598 }
2599 return;
2600
2601}
2602//******************************************************************************
2603// handlePublishSleepWakeUUID
2604//
2605// Called from IOPMrootDomain when we're initiating a sleep,
2606// or indirectly from PM configd when PM decides to clear the UUID.
2607// PM clears the UUID several minutes after successful wake from sleep,
2608// so that we might associate App spindumps with the immediately previous
2609// sleep/wake.
2610//******************************************************************************
2611
2612void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish )
2613{
2614 ASSERT_GATED();
2615
2616 /*
2617 * Clear the current UUID
2618 */
2619 if (gSleepWakeUUIDIsSet)
2620 {
2621 DLOG("SleepWake UUID cleared\n");
2622
2623 OSString *UUIDstring = NULL;
2624
2625 if (timeline &&
2626 (UUIDstring = OSDynamicCast(OSString, getProperty(kIOPMSleepWakeUUIDKey))))
2627 {
2628 PMEventDetails *details = PMEventDetails::eventDetails(kIOPMEventTypeUUIDClear,
2629 UUIDstring->getCStringNoCopy(), NULL, 0);
2630 if (details) {
2631 timeline->recordSystemPowerEvent( details );
2632 details->release();
2633 }
2634 timeline->setNumEventsLoggedThisPeriod(0);
2635 }
2636
2637 gSleepWakeUUIDIsSet = false;
2638
2639 removeProperty(kIOPMSleepWakeUUIDKey);
2640 messageClients(kIOPMMessageSleepWakeUUIDChange, kIOPMMessageSleepWakeUUIDCleared);
2641 }
2642
2643 /*
2644 * Optionally, publish a new UUID
2645 */
2646 if (queuedSleepWakeUUIDString && shouldPublish) {
2647
2648 OSString *publishThisUUID = NULL;
2649
2650 publishThisUUID = queuedSleepWakeUUIDString;
2651 publishThisUUID->retain();
2652
2653 if (timeline) {
2654 PMEventDetails *details;
2655 details = PMEventDetails::eventDetails(kIOPMEventTypeUUIDSet,
2656 publishThisUUID->getCStringNoCopy(), NULL, 0);
2657 if (details) {
2658 timeline->recordSystemPowerEvent( details );
2659 details->release();
2660 }
2661 }
2662
2663 if (publishThisUUID)
2664 {
2665 setProperty(kIOPMSleepWakeUUIDKey, publishThisUUID);
2666 publishThisUUID->release();
2667 }
2668
2669 gSleepWakeUUIDIsSet = true;
2670 messageClients(kIOPMMessageSleepWakeUUIDChange, kIOPMMessageSleepWakeUUIDSet);
2671
2672 queuedSleepWakeUUIDString->release();
2673 queuedSleepWakeUUIDString = NULL;
2674 }
2675}
2676
2677//******************************************************************************
2678// changePowerStateTo & changePowerStateToPriv
2679//
2680// Override of these methods for logging purposes.
2681//******************************************************************************
2682
2683IOReturn IOPMrootDomain::changePowerStateTo( unsigned long ordinal )
2684{
2685 return kIOReturnUnsupported; // ignored
2686}
2687
2688IOReturn IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal )
2689{
2690 DLOG("changePowerStateToPriv(%lu)\n", ordinal);
2691
2692 if ((ordinal != ON_STATE) && (ordinal != SLEEP_STATE))
2693 return kIOReturnUnsupported;
0c530ab8 2694
6d2010ae
A
2695 return super::changePowerStateToPriv(ordinal);
2696}
2697
2698//******************************************************************************
2699// activity detect
2700//
2701//******************************************************************************
2702
2703bool IOPMrootDomain::activitySinceSleep(void)
2704{
2705 return (userActivityCount != userActivityAtSleep);
2706}
2707
2708bool IOPMrootDomain::abortHibernation(void)
2709{
2710 bool ret = activitySinceSleep();
0c530ab8 2711
6d2010ae 2712 if (ret && !hibernateAborted)
55e303ae 2713 {
6d2010ae
A
2714 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount, userActivityAtSleep);
2715 hibernateAborted = true;
d52fe63f 2716 }
6d2010ae 2717 return (ret);
0c530ab8
A
2718}
2719
6d2010ae
A
2720extern "C" int
2721hibernate_should_abort(void)
2722{
2723 if (gRootDomain)
2724 return (gRootDomain->abortHibernation());
2725 else
2726 return (0);
2727}
2d21ac55 2728
0c530ab8
A
2729//******************************************************************************
2730// sleepOnClamshellClosed
2731//
2732// contains the logic to determine if the system should sleep when the clamshell
2733// is closed.
2734//******************************************************************************
2735
b0d623f7 2736bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
0c530ab8 2737{
6d2010ae
A
2738 if (!clamshellExists)
2739 return false;
2740
2741 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d\n",
2742 clamshellClosed, clamshellDisabled, desktopMode, acAdaptorConnected);
b0d623f7 2743
6d2010ae 2744 return ( !clamshellDisabled && !(desktopMode && acAdaptorConnected) );
0c530ab8
A
2745}
2746
b0d623f7 2747void IOPMrootDomain::sendClientClamshellNotification( void )
0c530ab8
A
2748{
2749 /* Only broadcast clamshell alert if clamshell exists. */
b0d623f7 2750 if (!clamshellExists)
0c530ab8 2751 return;
b0d623f7 2752
0c530ab8 2753 setProperty(kAppleClamshellStateKey,
6d2010ae 2754 clamshellClosed ? kOSBooleanTrue : kOSBooleanFalse);
0c530ab8
A
2755
2756 setProperty(kAppleClamshellCausesSleepKey,
b0d623f7 2757 shouldSleepOnClamshellClosed() ? kOSBooleanTrue : kOSBooleanFalse);
0c530ab8 2758
2d21ac55 2759 /* Argument to message is a bitfiel of
0c530ab8 2760 * ( kClamshellStateBit | kClamshellSleepBit )
0c530ab8 2761 */
2d21ac55 2762 messageClients(kIOPMMessageClamshellStateChange,
6d2010ae 2763 (void *) ( (clamshellClosed ? kClamshellStateBit : 0)
2d21ac55 2764 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit : 0)) );
0c530ab8
A
2765}
2766
2d21ac55 2767//******************************************************************************
6d2010ae 2768// getSleepSupported
2d21ac55 2769//
6d2010ae 2770// Deprecated
2d21ac55
A
2771//******************************************************************************
2772
6d2010ae 2773IOOptionBits IOPMrootDomain::getSleepSupported( void )
2d21ac55 2774{
6d2010ae
A
2775 return( platformSleepSupport );
2776}
2d21ac55 2777
6d2010ae
A
2778//******************************************************************************
2779// setSleepSupported
2780//
2781// Deprecated
2782//******************************************************************************
2783
2784void IOPMrootDomain::setSleepSupported( IOOptionBits flags )
2785{
2786 DLOG("setSleepSupported(%x)\n", (uint32_t) flags);
2787 OSBitOrAtomic(flags, &platformSleepSupport);
2788}
2789
2790//******************************************************************************
2791// wakeFromDoze
2792//
2793// Deprecated.
2794//******************************************************************************
2795
2796void IOPMrootDomain::wakeFromDoze( void )
2797{
2798 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
2799}
2800
2801// MARK: -
2802// MARK: Features
2803
2804//******************************************************************************
2805// publishFeature
2806//
2807// Adds a new feature to the supported features dictionary
2808//******************************************************************************
2809
2810void IOPMrootDomain::publishFeature( const char * feature )
2811{
2812 publishFeature(feature, kRD_AllPowerSources, NULL);
2813}
2814
2815//******************************************************************************
2816// publishFeature (with supported power source specified)
2817//
2818// Adds a new feature to the supported features dictionary
2819//******************************************************************************
2820
2821void IOPMrootDomain::publishFeature(
2822 const char *feature,
2823 uint32_t supportedWhere,
2824 uint32_t *uniqueFeatureID)
2825{
2826 static uint16_t next_feature_id = 500;
2827
2828 OSNumber *new_feature_data = NULL;
2829 OSNumber *existing_feature = NULL;
2830 OSArray *existing_feature_arr = NULL;
2831 OSObject *osObj = NULL;
2832 uint32_t feature_value = 0;
2833
2834 supportedWhere &= kRD_AllPowerSources; // mask off any craziness!
2835
2836 if(!supportedWhere) {
2837 // Feature isn't supported anywhere!
2838 return;
2839 }
2840
2841 if(next_feature_id > 5000) {
2842 // Far, far too many features!
2843 return;
2844 }
2845
2846 if(featuresDictLock) IOLockLock(featuresDictLock);
2847
2848 OSDictionary *features =
2849 (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
2850
2851 // Create new features dict if necessary
2852 if ( features && OSDynamicCast(OSDictionary, features)) {
2853 features = OSDictionary::withDictionary(features);
2854 } else {
2855 features = OSDictionary::withCapacity(1);
2856 }
2857
2858 // Create OSNumber to track new feature
2859
2860 next_feature_id += 1;
2861 if( uniqueFeatureID ) {
2862 // We don't really mind if the calling kext didn't give us a place
2863 // to stash their unique id. Many kexts don't plan to unload, and thus
2864 // have no need to remove themselves later.
2865 *uniqueFeatureID = next_feature_id;
2866 }
2867
2868 feature_value = (uint32_t)next_feature_id;
2869 feature_value <<= 16;
2870 feature_value += supportedWhere;
2871
2872 new_feature_data = OSNumber::withNumber(
2873 (unsigned long long)feature_value, 32);
2874
2875 // Does features object already exist?
2876 if( (osObj = features->getObject(feature)) )
2877 {
2878 if(( existing_feature = OSDynamicCast(OSNumber, osObj) ))
2879 {
2880 // We need to create an OSArray to hold the now 2 elements.
2881 existing_feature_arr = OSArray::withObjects(
2882 (const OSObject **)&existing_feature, 1, 2);
2883 } else if(( existing_feature_arr = OSDynamicCast(OSArray, osObj) ))
2884 {
2885 // Add object to existing array
2886 existing_feature_arr = OSArray::withArray(
2887 existing_feature_arr,
2888 existing_feature_arr->getCount() + 1);
2889 }
2890
2891 if (existing_feature_arr)
2892 {
2893 existing_feature_arr->setObject(new_feature_data);
2894 features->setObject(feature, existing_feature_arr);
2895 existing_feature_arr->release();
2896 existing_feature_arr = 0;
2897 }
2898 } else {
2899 // The easy case: no previously existing features listed. We simply
2900 // set the OSNumber at key 'feature' and we're on our way.
2901 features->setObject(feature, new_feature_data);
2902 }
2903
2904 new_feature_data->release();
2905
2906 setProperty(kRootDomainSupportedFeatures, features);
2907
2908 features->release();
2909
2910 if(featuresDictLock) IOLockUnlock(featuresDictLock);
2911
2912 // Notify EnergySaver and all those in user space so they might
2913 // re-populate their feature specific UI
2914 if(pmPowerStateQueue) {
2915 pmPowerStateQueue->submitPowerEvent( kPowerEventFeatureChanged );
2916 }
2917}
2918
2919//******************************************************************************
2920// removePublishedFeature
2921//
2922// Removes previously published feature
2923//******************************************************************************
2924
2925IOReturn IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID )
2926{
2927 IOReturn ret = kIOReturnError;
2928 uint32_t feature_value = 0;
2929 uint16_t feature_id = 0;
2930 bool madeAChange = false;
2931
2932 OSSymbol *dictKey = NULL;
2933 OSCollectionIterator *dictIterator = NULL;
2934 OSArray *arrayMember = NULL;
2935 OSNumber *numberMember = NULL;
2936 OSObject *osObj = NULL;
2937 OSNumber *osNum = NULL;
2938 OSArray *arrayMemberCopy;
2939
2940 if(featuresDictLock) IOLockLock(featuresDictLock);
2941
2942 OSDictionary *features =
2943 (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
2944
2945 if ( features && OSDynamicCast(OSDictionary, features) )
2946 {
2947 // Any modifications to the dictionary are made to the copy to prevent
2948 // races & crashes with userland clients. Dictionary updated
2949 // automically later.
2950 features = OSDictionary::withDictionary(features);
2951 } else {
2952 features = NULL;
2953 ret = kIOReturnNotFound;
2954 goto exit;
2955 }
2956
2957 // We iterate 'features' dictionary looking for an entry tagged
2958 // with 'removeFeatureID'. If found, we remove it from our tracking
2959 // structures and notify the OS via a general interest message.
2960
2961 dictIterator = OSCollectionIterator::withCollection(features);
2962 if(!dictIterator) {
2963 goto exit;
2964 }
2965
2966 while( (dictKey = OSDynamicCast(OSSymbol, dictIterator->getNextObject())) )
2967 {
2968 osObj = features->getObject(dictKey);
2969
2970 // Each Feature is either tracked by an OSNumber
2971 if( osObj && (numberMember = OSDynamicCast(OSNumber, osObj)) )
2972 {
2973 feature_value = numberMember->unsigned32BitValue();
2974 feature_id = (uint16_t)(feature_value >> 16);
2975
2976 if( feature_id == (uint16_t)removeFeatureID )
2977 {
2978 // Remove this node
2979 features->removeObject(dictKey);
2980 madeAChange = true;
2981 break;
2982 }
2983
2984 // Or tracked by an OSArray of OSNumbers
2985 } else if( osObj && (arrayMember = OSDynamicCast(OSArray, osObj)) )
2986 {
2987 unsigned int arrayCount = arrayMember->getCount();
2988
2989 for(unsigned int i=0; i<arrayCount; i++)
2990 {
2991 osNum = OSDynamicCast(OSNumber, arrayMember->getObject(i));
2992 if(!osNum) {
2993 continue;
2994 }
2995
2996 feature_value = osNum->unsigned32BitValue();
2997 feature_id = (uint16_t)(feature_value >> 16);
2998
2999 if( feature_id == (uint16_t)removeFeatureID )
3000 {
3001 // Remove this node
3002 if( 1 == arrayCount ) {
3003 // If the array only contains one element, remove
3004 // the whole thing.
3005 features->removeObject(dictKey);
3006 } else {
3007 // Otherwise remove the element from a copy of the array.
3008 arrayMemberCopy = OSArray::withArray(arrayMember);
3009 if (arrayMemberCopy)
3010 {
3011 arrayMemberCopy->removeObject(i);
3012 features->setObject(dictKey, arrayMemberCopy);
3013 arrayMemberCopy->release();
3014 }
3015 }
3016
3017 madeAChange = true;
3018 break;
3019 }
3020 }
3021 }
3022 }
3023
3024 dictIterator->release();
3025
3026 if( madeAChange )
3027 {
3028 ret = kIOReturnSuccess;
3029
3030 setProperty(kRootDomainSupportedFeatures, features);
3031
3032 // Notify EnergySaver and all those in user space so they might
3033 // re-populate their feature specific UI
3034 if(pmPowerStateQueue) {
3035 pmPowerStateQueue->submitPowerEvent( kPowerEventFeatureChanged );
3036 }
3037 } else {
3038 ret = kIOReturnNotFound;
3039 }
3040
3041exit:
3042 if(features) features->release();
3043 if(featuresDictLock) IOLockUnlock(featuresDictLock);
3044 return ret;
3045}
3046
3047//******************************************************************************
3048// setPMSetting (private)
3049//
3050// Internal helper to relay PM settings changes from user space to individual
3051// drivers. Should be called only by IOPMrootDomain::setProperties.
3052//******************************************************************************
3053
3054IOReturn IOPMrootDomain::setPMSetting(
3055 const OSSymbol *type,
3056 OSObject *object )
3057{
3058 PMSettingCallEntry *entries = 0;
3059 OSArray *chosen = 0;
3060 const OSArray *array;
3061 PMSettingObject *pmso;
3062 thread_t thisThread;
3063 int i, j, count, capacity;
3064
3065 if (NULL == type)
3066 return kIOReturnBadArgument;
3067
3068 PMSETTING_LOCK();
3069
3070 // Update settings dict so changes are visible from copyPMSetting().
3071 fPMSettingsDict->setObject(type, object);
3072
3073 // Prep all PMSetting objects with the given 'type' for callout.
3074 array = (const OSArray *) settingsCallbacks->getObject(type);
3075 if (!array || ((capacity = array->getCount()) == 0))
3076 goto unlock_exit;
3077
3078 // Array to retain PMSetting objects targeted for callout.
3079 chosen = OSArray::withCapacity(capacity);
3080 if (!chosen)
3081 goto unlock_exit; // error
3082
3083 entries = IONew(PMSettingCallEntry, capacity);
3084 if (!entries)
3085 goto unlock_exit; // error
3086 memset(entries, 0, sizeof(PMSettingCallEntry) * capacity);
3087
3088 thisThread = current_thread();
3089
3090 for (i = 0, j = 0; i<capacity; i++)
3091 {
3092 pmso = (PMSettingObject *) array->getObject(i);
3093 if (pmso->disabled)
3094 continue;
3095 entries[j].thread = thisThread;
3096 queue_enter(&pmso->calloutQueue, &entries[j], PMSettingCallEntry *, link);
3097 chosen->setObject(pmso);
3098 j++;
3099 }
3100 count = j;
3101 if (!count)
3102 goto unlock_exit;
3103
3104 PMSETTING_UNLOCK();
3105
3106 // Call each pmso in the chosen array.
3107 for (i=0; i<count; i++)
3108 {
3109 pmso = (PMSettingObject *) chosen->getObject(i);
3110 pmso->dispatchPMSetting(type, object);
3111 }
3112
3113 PMSETTING_LOCK();
3114 for (i=0; i<count; i++)
3115 {
3116 pmso = (PMSettingObject *) chosen->getObject(i);
3117 queue_remove(&pmso->calloutQueue, &entries[i], PMSettingCallEntry *, link);
3118 if (pmso->waitThread)
3119 {
3120 PMSETTING_WAKEUP(pmso);
3121 }
3122 }
3123unlock_exit:
3124 PMSETTING_UNLOCK();
3125
3126 if (chosen) chosen->release();
3127 if (entries) IODelete(entries, PMSettingCallEntry, capacity);
3128
3129 return kIOReturnSuccess;
3130}
3131
3132//******************************************************************************
3133// copyPMSetting (public)
3134//
3135// Allows kexts to safely read setting values, without being subscribed to
3136// notifications.
3137//******************************************************************************
3138
3139OSObject * IOPMrootDomain::copyPMSetting(
3140 OSSymbol *whichSetting)
3141{
3142 OSObject *obj = NULL;
3143
3144 if(!whichSetting) return NULL;
3145
3146 PMSETTING_LOCK();
3147 obj = fPMSettingsDict->getObject(whichSetting);
3148 if(obj) {
3149 obj->retain();
3150 }
3151 PMSETTING_UNLOCK();
3152
3153 return obj;
3154}
3155
3156//******************************************************************************
3157// registerPMSettingController (public)
3158//
3159// direct wrapper to registerPMSettingController with uint32_t power source arg
3160//******************************************************************************
3161
3162IOReturn IOPMrootDomain::registerPMSettingController(
3163 const OSSymbol * settings[],
3164 IOPMSettingControllerCallback func,
3165 OSObject *target,
3166 uintptr_t refcon,
3167 OSObject **handle)
3168{
3169 return registerPMSettingController(
3170 settings,
3171 (kIOPMSupportedOnAC | kIOPMSupportedOnBatt | kIOPMSupportedOnUPS),
3172 func, target, refcon, handle);
3173}
3174
3175//******************************************************************************
3176// registerPMSettingController (public)
3177//
3178// Kexts may register for notifications when a particular setting is changed.
3179// A list of settings is available in IOPM.h.
3180// Arguments:
3181// * settings - An OSArray containing OSSymbols. Caller should populate this
3182// array with a list of settings caller wants notifications from.
3183// * func - A C function callback of the type IOPMSettingControllerCallback
3184// * target - caller may provide an OSObject *, which PM will pass as an
3185// target to calls to "func"
3186// * refcon - caller may provide an void *, which PM will pass as an
3187// argument to calls to "func"
3188// * handle - This is a return argument. We will populate this pointer upon
3189// call success. Hold onto this and pass this argument to
3190// IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3191// Returns:
3192// kIOReturnSuccess on success
3193//******************************************************************************
3194
3195IOReturn IOPMrootDomain::registerPMSettingController(
3196 const OSSymbol * settings[],
3197 uint32_t supportedPowerSources,
3198 IOPMSettingControllerCallback func,
3199 OSObject *target,
3200 uintptr_t refcon,
3201 OSObject **handle)
3202{
3203 PMSettingObject *pmso = NULL;
3204 OSObject *pmsh = NULL;
3205 OSArray *list = NULL;
3206 int i;
3207
3208 if (NULL == settings ||
3209 NULL == func ||
3210 NULL == handle)
3211 {
3212 return kIOReturnBadArgument;
3213 }
3214
3215 pmso = PMSettingObject::pmSettingObject(
3216 (IOPMrootDomain *) this, func, target,
3217 refcon, supportedPowerSources, settings, &pmsh);
3218
3219 if (!pmso) {
3220 *handle = NULL;
3221 return kIOReturnInternalError;
3222 }
3223
3224 PMSETTING_LOCK();
3225 for (i=0; settings[i]; i++)
3226 {
3227 list = (OSArray *) settingsCallbacks->getObject(settings[i]);
3228 if (!list) {
3229 // New array of callbacks for this setting
3230 list = OSArray::withCapacity(1);
3231 settingsCallbacks->setObject(settings[i], list);
3232 list->release();
3233 }
3234
3235 // Add caller to the callback list
3236 list->setObject(pmso);
3237 }
3238 PMSETTING_UNLOCK();
3239
3240 // Return handle to the caller, the setting object is private.
3241 *handle = pmsh;
3242
3243 return kIOReturnSuccess;
3244}
3245
3246//******************************************************************************
3247// deregisterPMSettingObject (private)
3248//
3249// Only called from PMSettingObject.
3250//******************************************************************************
3251
3252void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject * pmso )
3253{
3254 thread_t thisThread = current_thread();
3255 PMSettingCallEntry *callEntry;
3256 OSCollectionIterator *iter;
3257 OSSymbol *sym;
3258 OSArray *array;
3259 int index;
3260 bool wait;
3261
3262 PMSETTING_LOCK();
3263
3264 pmso->disabled = true;
3265
3266 // Wait for all callout threads to finish.
3267 do {
3268 wait = false;
3269 queue_iterate(&pmso->calloutQueue, callEntry, PMSettingCallEntry *, link)
3270 {
3271 if (callEntry->thread != thisThread)
3272 {
3273 wait = true;
3274 break;
3275 }
3276 }
3277 if (wait)
3278 {
3279 assert(0 == pmso->waitThread);
3280 pmso->waitThread = thisThread;
3281 PMSETTING_WAIT(pmso);
3282 pmso->waitThread = 0;
3283 }
3284 } while (wait);
3285
3286 // Search each PM settings array in the kernel.
3287 iter = OSCollectionIterator::withCollection(settingsCallbacks);
3288 if (iter)
3289 {
3290 while ((sym = OSDynamicCast(OSSymbol, iter->getNextObject())))
3291 {
3292 array = (OSArray *) settingsCallbacks->getObject(sym);
3293 index = array->getNextIndexOfObject(pmso, 0);
3294 if (-1 != index) {
3295 array->removeObject(index);
3296 }
3297 }
3298 iter->release();
3299 }
3300
3301 PMSETTING_UNLOCK();
3302
3303 pmso->release();
3304}
3305
3306//******************************************************************************
3307// informCPUStateChange
3308//
3309// Call into PM CPU code so that CPU power savings may dynamically adjust for
3310// running on battery, with the lid closed, etc.
3311//
3312// informCPUStateChange is a no-op on non x86 systems
3313// only x86 has explicit support in the IntelCPUPowerManagement kext
3314//******************************************************************************
3315
3316void IOPMrootDomain::informCPUStateChange(
3317 uint32_t type,
3318 uint32_t value )
3319{
3320#if defined(__i386__) || defined(__x86_64__)
3321
3322 pmioctlVariableInfo_t varInfoStruct;
2d21ac55
A
3323 int pmCPUret = 0;
3324 const char *varNameStr = NULL;
3325 int32_t *varIndex = NULL;
3326
3327 if (kInformAC == type) {
3328 varNameStr = kIOPMRootDomainBatPowerCString;
3329 varIndex = &idxPMCPULimitedPower;
3330 } else if (kInformLid == type) {
3331 varNameStr = kIOPMRootDomainLidCloseCString;
3332 varIndex = &idxPMCPUClamshell;
3333 } else {
3334 return;
3335 }
3336
3337 // Set the new value!
3338 // pmCPUControl will assign us a new ID if one doesn't exist yet
3339 bzero(&varInfoStruct, sizeof(pmioctlVariableInfo_t));
3340 varInfoStruct.varID = *varIndex;
3341 varInfoStruct.varType = vBool;
3342 varInfoStruct.varInitValue = value;
3343 varInfoStruct.varCurValue = value;
3344 strncpy( (char *)varInfoStruct.varName,
3345 (const char *)varNameStr,
3346 strlen(varNameStr) + 1 );
3347
3348 // Set!
3349 pmCPUret = pmCPUControl( PMIOCSETVARINFO, (void *)&varInfoStruct );
3350
3351 // pmCPU only assigns numerical id's when a new varName is specified
3352 if ((0 == pmCPUret)
3353 && (*varIndex == kCPUUnknownIndex))
3354 {
3355 // pmCPUControl has assigned us a new variable ID.
3356 // Let's re-read the structure we just SET to learn that ID.
3357 pmCPUret = pmCPUControl( PMIOCGETVARNAMEINFO, (void *)&varInfoStruct );
3358
3359 if (0 == pmCPUret)
3360 {
3361 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
3362 *varIndex = varInfoStruct.varID;
3363 }
3364 }
3365
3366 return;
3367
b0d623f7 3368#endif /* __i386__ || __x86_64__ */
2d21ac55
A
3369}
3370
6d2010ae
A
3371// MARK: -
3372// MARK: Deep Sleep Policy
b0d623f7 3373
0b4c1975
A
3374#if HIBERNATION
3375
3376//******************************************************************************
3377// evaluateSystemSleepPolicy
3378//******************************************************************************
3379
3380struct IOPMSystemSleepPolicyEntry
3381{
3382 uint32_t factorMask;
3383 uint32_t factorBits;
3384 uint32_t sleepFlags;
3385 uint32_t wakeEvents;
3386};
3387
3388struct IOPMSystemSleepPolicyTable
3389{
3390 uint8_t signature[4];
3391 uint16_t version;
3392 uint16_t entryCount;
3393 IOPMSystemSleepPolicyEntry entries[];
3394};
3395
3396enum {
3397 kIOPMSleepFactorSleepTimerWake = 0x00000001,
3398 kIOPMSleepFactorLidOpen = 0x00000002,
3399 kIOPMSleepFactorACPower = 0x00000004,
3400 kIOPMSleepFactorLowBattery = 0x00000008,
3401 kIOPMSleepFactorDeepSleepNoDelay = 0x00000010,
3402 kIOPMSleepFactorDeepSleepDemand = 0x00000020,
3403 kIOPMSleepFactorDeepSleepDisable = 0x00000040,
3404 kIOPMSleepFactorUSBExternalDevice = 0x00000080,
3405 kIOPMSleepFactorBluetoothHIDDevice = 0x00000100,
3406 kIOPMSleepFactorExternalMediaMounted = 0x00000200,
6d2010ae 3407 kIOPMSleepFactorDriverAssertBit5 = 0x00000400, /* Reserved for ThunderBolt */
0b4c1975
A
3408 kIOPMSleepFactorDriverAssertBit6 = 0x00000800,
3409 kIOPMSleepFactorDriverAssertBit7 = 0x00001000
3410};
3411
3412bool IOPMrootDomain::evaluateSystemSleepPolicy( IOPMSystemSleepParameters * p )
3413{
3414 const IOPMSystemSleepPolicyTable * pt;
3415 OSObject * prop = 0;
3416 OSData * policyData;
3417 uint32_t currentFactors;
3418 uint32_t deepSleepDelay = 0;
3419 bool success = false;
3420
3421 if (getProperty(kIOPMDeepSleepEnabledKey) != kOSBooleanTrue)
3422 return false;
3423
3424 getSleepOption(kIOPMDeepSleepDelayKey, &deepSleepDelay);
3425
3426 prop = getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey);
3427 if (!prop)
3428 return false;
3429
3430 policyData = OSDynamicCast(OSData, prop);
3431 if (!policyData ||
3432 (policyData->getLength() < sizeof(IOPMSystemSleepPolicyTable)))
3433 {
3434 goto done;
3435 }
3436
3437 pt = (const IOPMSystemSleepPolicyTable *) policyData->getBytesNoCopy();
3438 if ((pt->signature[0] != 'S') ||
3439 (pt->signature[1] != 'L') ||
3440 (pt->signature[2] != 'P') ||
3441 (pt->signature[3] != 'T') ||
3442 (pt->version != 1) ||
3443 (pt->entryCount == 0))
3444 {
3445 goto done;
3446 }
3447
3448 if ((policyData->getLength() - sizeof(IOPMSystemSleepPolicyTable)) !=
3449 (sizeof(IOPMSystemSleepPolicyEntry) * pt->entryCount))
3450 {
3451 goto done;
3452 }
3453
3454 currentFactors = 0;
3455 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit) !=
3456 kIOPMDriverAssertionLevelOff)
3457 currentFactors |= kIOPMSleepFactorUSBExternalDevice;
3458 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit) !=
3459 kIOPMDriverAssertionLevelOff)
3460 currentFactors |= kIOPMSleepFactorBluetoothHIDDevice;
3461 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit) !=
3462 kIOPMDriverAssertionLevelOff)
3463 currentFactors |= kIOPMSleepFactorExternalMediaMounted;
6d2010ae 3464 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5) != /* AssertionBit5 = Thunderbolt */
0b4c1975
A
3465 kIOPMDriverAssertionLevelOff)
3466 currentFactors |= kIOPMSleepFactorDriverAssertBit5;
0b4c1975
A
3467 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit7) !=
3468 kIOPMDriverAssertionLevelOff)
3469 currentFactors |= kIOPMSleepFactorDriverAssertBit7;
3470 if (0 == deepSleepDelay)
3471 currentFactors |= kIOPMSleepFactorDeepSleepNoDelay;
6d2010ae 3472 if (!clamshellClosed)
0b4c1975
A
3473 currentFactors |= kIOPMSleepFactorLidOpen;
3474 if (acAdaptorConnected)
3475 currentFactors |= kIOPMSleepFactorACPower;
3476 if (lowBatteryCondition)
3477 currentFactors |= kIOPMSleepFactorLowBattery;
3478 if (sleepTimerMaintenance)
3479 currentFactors |= kIOPMSleepFactorSleepTimerWake;
3480
3481 // pmset overrides
3482 if ((hibernateMode & kIOHibernateModeOn) == 0)
3483 currentFactors |= kIOPMSleepFactorDeepSleepDisable;
3484 else if ((hibernateMode & kIOHibernateModeSleep) == 0)
3485 currentFactors |= kIOPMSleepFactorDeepSleepDemand;
3486
3487 DLOG("Sleep policy %u entries, current factors 0x%x\n",
3488 pt->entryCount, currentFactors);
3489
3490 for (uint32_t i = 0; i < pt->entryCount; i++)
3491 {
3492 const IOPMSystemSleepPolicyEntry * policyEntry = &pt->entries[i];
3493
3494 DLOG("factor mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x\n",
3495 policyEntry->factorMask, policyEntry->factorBits,
3496 policyEntry->sleepFlags, policyEntry->wakeEvents);
3497
3498 if ((currentFactors ^ policyEntry->factorBits) & policyEntry->factorMask)
3499 continue; // mismatch, try next
3500
3501 if (p)
3502 {
3503 p->version = 1;
3504 p->sleepFlags = policyEntry->sleepFlags;
3505 p->sleepTimer = 0;
3506 p->wakeEvents = policyEntry->wakeEvents;
3507 if (p->sleepFlags & kIOPMSleepFlagSleepTimerEnable)
3508 {
3509 p->sleepTimer = deepSleepDelay;
3510 }
3511 }
3512
3513 DLOG("matched policy entry %u\n", i);
3514 success = true;
3515 break;
3516 }
3517
3518done:
3519 if (prop)
3520 prop->release();
3521
3522 return success;
3523}
3524
3525void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
3526{
3527 IOPMSystemSleepParameters params;
3528
3529 // Evaluate sleep policy before driver sleep phase.
3530
3531 DLOG("%s\n", __FUNCTION__);
3532 removeProperty(kIOPMSystemSleepParametersKey);
3533
3534 hibernateDisabled = false;
3535 hibernateMode = 0;
3536 getSleepOption(kIOHibernateModeKey, &hibernateMode);
3537
3538 if (!hibernateNoDefeat &&
3539 evaluateSystemSleepPolicy(&params) &&
3540 ((params.sleepFlags & kIOPMSleepFlagHibernate) == 0))
3541 {
3542 hibernateDisabled = true;
3543 }
3544}
3545
3546void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
3547{
3548 IOPMSystemSleepParameters params;
3549 OSData * paramsData;
3550
3551 // Evaluate sleep policy after drivers but before platform sleep.
3552
3553 DLOG("%s\n", __FUNCTION__);
3554
3555 if (evaluateSystemSleepPolicy(&params))
3556 {
3557 if ((hibernateDisabled || hibernateAborted) &&
3558 (params.sleepFlags & kIOPMSleepFlagHibernate))
3559 {
3560 // Should hibernate but unable to or aborted.
3561 // Arm timer for a short sleep and retry or wake fully.
3562
3563 params.sleepFlags &= ~kIOPMSleepFlagHibernate;
3564 params.sleepFlags |= kIOPMSleepFlagSleepTimerEnable;
3565 params.sleepTimer = 1;
3566 hibernateNoDefeat = true;
3567 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d\n",
3568 params.sleepTimer, hibernateDisabled, hibernateAborted);
3569 }
3570 else
3571 hibernateNoDefeat = false;
3572
3573 paramsData = OSData::withBytes(&params, sizeof(params));
3574 if (paramsData)
3575 {
3576 setProperty(kIOPMSystemSleepParametersKey, paramsData);
3577 paramsData->release();
3578 }
3579
3580 if (params.sleepFlags & kIOPMSleepFlagHibernate)
3581 {
3582 // Force hibernate
3583 gIOHibernateMode &= ~kIOHibernateModeSleep;
3584 }
3585 }
3586}
3587
3588bool IOPMrootDomain::getHibernateSettings(
3589 uint32_t * hibernateMode,
3590 uint32_t * hibernateFreeRatio,
3591 uint32_t * hibernateFreeTime )
3592{
3593 bool ok = getSleepOption(kIOHibernateModeKey, hibernateMode);
3594 getSleepOption(kIOHibernateFreeRatioKey, hibernateFreeRatio);
3595 getSleepOption(kIOHibernateFreeTimeKey, hibernateFreeTime);
3596 if (hibernateDisabled)
3597 *hibernateMode = 0;
3598 DLOG("hibernateMode 0x%x\n", *hibernateMode);
3599 return ok;
3600}
3601
3602bool IOPMrootDomain::getSleepOption( const char * key, uint32_t * option )
3603{
3604 OSObject * optionsProp;
3605 OSDictionary * optionsDict;
3606 OSObject * obj = 0;
3607 OSNumber * num;
3608 bool ok = false;
3609
3610 optionsProp = copyProperty(kRootDomainSleepOptionsKey);
3611 optionsDict = OSDynamicCast(OSDictionary, optionsProp);
3612
3613 if (optionsDict)
3614 {
3615 obj = optionsDict->getObject(key);
3616 if (obj) obj->retain();
3617 }
3618 if (!obj)
3619 {
3620 obj = copyProperty(key);
3621 }
3622 if (obj && (num = OSDynamicCast(OSNumber, obj)))
3623 {
3624 *option = num->unsigned32BitValue();
3625 ok = true;
3626 }
3627
6d2010ae
A
3628 if (obj)
3629 obj->release();
3630 if (optionsProp)
3631 optionsProp->release();
3632
3633 return true;
3634}
3635#endif /* HIBERNATION */
3636
3637// MARK: -
3638// MARK: Shutdown and Restart
3639
3640//******************************************************************************
3641// handlePlatformHaltRestart
3642//
3643//******************************************************************************
3644
3645struct HaltRestartApplierContext {
3646 IOPMrootDomain * RootDomain;
3647 unsigned long PowerState;
3648 IOPMPowerFlags PowerFlags;
3649 UInt32 MessageType;
3650 UInt32 Counter;
3651};
3652
3653static void
3654platformHaltRestartApplier( OSObject * object, void * context )
3655{
3656 IOPowerStateChangeNotification notify;
3657 HaltRestartApplierContext * ctx;
3658 AbsoluteTime startTime;
3659 UInt32 deltaTime;
3660
3661 ctx = (HaltRestartApplierContext *) context;
3662
3663 memset(&notify, 0, sizeof(notify));
3664 notify.powerRef = (void *)ctx->Counter;
3665 notify.returnValue = 0;
3666 notify.stateNumber = ctx->PowerState;
3667 notify.stateFlags = ctx->PowerFlags;
3668
3669 clock_get_uptime(&startTime);
3670 ctx->RootDomain->messageClient( ctx->MessageType, object, (void *)&notify );
3671 deltaTime = computeDeltaTimeMS(&startTime);
3672
3673 if ((deltaTime > kPMHaltTimeoutMS) ||
3674 (gIOKitDebug & kIOLogPMRootDomain))
3675 {
3676 _IOServiceInterestNotifier * notifier;
3677 notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
3678
3679 // IOService children of IOPMrootDomain are not instrumented.
3680 // Only IORootParent currently falls under that group.
3681
3682 if (notifier)
3683 {
3684 LOG("%s handler %p took %u ms\n",
3685 (ctx->MessageType == kIOMessageSystemWillPowerOff) ? "PowerOff" :
3686 (ctx->MessageType == kIOMessageSystemPagingOff) ? "PagingOff" : "Restart",
3687 notifier->handler, (uint32_t) deltaTime );
3688 }
3689 }
3690
3691 ctx->Counter++;
3692}
3693
3694void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type )
3695{
3696 HaltRestartApplierContext ctx;
3697 AbsoluteTime startTime;
3698 UInt32 deltaTime;
3699
3700 memset(&ctx, 0, sizeof(ctx));
3701 ctx.RootDomain = this;
3702
3703 clock_get_uptime(&startTime);
3704 switch (pe_type)
3705 {
3706 case kPEHaltCPU:
3707 case kPEUPSDelayHaltCPU:
3708 ctx.PowerState = OFF_STATE;
3709 ctx.MessageType = kIOMessageSystemWillPowerOff;
3710 break;
3711
3712 case kPERestartCPU:
3713 ctx.PowerState = RESTART_STATE;
3714 ctx.MessageType = kIOMessageSystemWillRestart;
3715 break;
3716
3717 case kPEPagingOff:
3718 ctx.PowerState = ON_STATE;
3719 ctx.MessageType = kIOMessageSystemPagingOff;
3720 break;
3721
3722 default:
3723 return;
3724 }
3725
3726 // Notify legacy clients
3727 applyToInterested(gIOPriorityPowerStateInterest, platformHaltRestartApplier, &ctx);
3728
3729 // For normal shutdown, turn off File Server Mode.
3730 if (kPEHaltCPU == pe_type)
3731 {
3732 const OSSymbol * setting = OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey);
3733 OSNumber * num = OSNumber::withNumber((unsigned long long) 0, 32);
3734 if (setting && num)
3735 {
3736 setPMSetting(setting, num);
3737 setting->release();
3738 num->release();
3739 }
3740 }
3741
3742 if (kPEPagingOff != pe_type)
3743 {
3744 // Notify in power tree order
3745 notifySystemShutdown(this, ctx.MessageType);
3746 }
0b4c1975 3747
6d2010ae
A
3748 deltaTime = computeDeltaTimeMS(&startTime);
3749 LOG("%s all drivers took %u ms\n",
3750 (ctx.MessageType == kIOMessageSystemWillPowerOff) ? "PowerOff" :
3751 (ctx.MessageType == kIOMessageSystemPagingOff) ? "PagingOff" : "Restart",
3752 (uint32_t) deltaTime );
0b4c1975 3753}
0b4c1975 3754
b0d623f7 3755//******************************************************************************
6d2010ae 3756// shutdownSystem
b0d623f7 3757//
b0d623f7
A
3758//******************************************************************************
3759
6d2010ae 3760IOReturn IOPMrootDomain::shutdownSystem( void )
b0d623f7 3761{
6d2010ae
A
3762 return kIOReturnUnsupported;
3763}
0b4c1975 3764
6d2010ae
A
3765//******************************************************************************
3766// restartSystem
3767//
3768//******************************************************************************
0b4c1975 3769
6d2010ae
A
3770IOReturn IOPMrootDomain::restartSystem( void )
3771{
3772 return kIOReturnUnsupported;
b0d623f7
A
3773}
3774
6d2010ae
A
3775// MARK: -
3776// MARK: System Capability
b0d623f7 3777
4a3eedf9 3778//******************************************************************************
6d2010ae 3779// tagPowerPlaneService
4a3eedf9 3780//
6d2010ae 3781// Running on PM work loop thread.
4a3eedf9 3782//******************************************************************************
b0d623f7 3783
6d2010ae
A
3784void IOPMrootDomain::tagPowerPlaneService(
3785 IOService * service,
3786 IOPMActions * actions )
4a3eedf9 3787{
6d2010ae
A
3788 uint32_t flags = 0;
3789 bool isDisplayWrangler;
4a3eedf9 3790
6d2010ae
A
3791 memset(actions, 0, sizeof(*actions));
3792 actions->target = this;
4a3eedf9 3793
6d2010ae
A
3794 if (service == this)
3795 {
3796 actions->actionPowerChangeStart =
3797 OSMemberFunctionCast(
3798 IOPMActionPowerChangeStart, this,
3799 &IOPMrootDomain::handleOurPowerChangeStart);
4a3eedf9 3800
6d2010ae
A
3801 actions->actionPowerChangeDone =
3802 OSMemberFunctionCast(
3803 IOPMActionPowerChangeDone, this,
3804 &IOPMrootDomain::handleOurPowerChangeDone);
4a3eedf9 3805
6d2010ae
A
3806 actions->actionPowerChangeOverride =
3807 OSMemberFunctionCast(
3808 IOPMActionPowerChangeOverride, this,
3809 &IOPMrootDomain::overrideOurPowerChange);
3810 return;
3811 }
4a3eedf9 3812
6d2010ae
A
3813#if !NO_KERNEL_HID
3814 isDisplayWrangler = (0 != service->metaCast("IODisplayWrangler"));
3815 if (isDisplayWrangler)
3816 {
3817 wrangler = service;
3818 wranglerConnection = (IOService *) service->getParentEntry(gIOPowerPlane);
3819 }
3820#else
3821 isDisplayWrangler = false;
3822#endif
4a3eedf9 3823
6d2010ae
A
3824#if defined(__i386__) || defined(__x86_64__)
3825 if (isDisplayWrangler)
3826 flags |= kPMActionsFlagIsDisplayWrangler;
3827 if (service->getProperty("IOPMStrictTreeOrder"))
3828 flags |= kPMActionsFlagIsGraphicsDevice;
3829 if (service->getProperty("IOPMUnattendedWakePowerState"))
3830 flags |= kPMActionsFlagIsAudioDevice;
3831#endif
4a3eedf9 3832
6d2010ae
A
3833 // Find the power connection object that is a child of the PCI host
3834 // bridge, and has a graphics/audio device attached below. Mark the
3835 // power branch for delayed child notifications.
4a3eedf9 3836
6d2010ae
A
3837 if (flags)
3838 {
3839 IORegistryEntry * child = service;
3840 IORegistryEntry * parent = child->getParentEntry(gIOPowerPlane);
3841
3842 while (child != this)
3843 {
3844 if ((parent == pciHostBridgeDriver) ||
3845 (parent == this))
3846 {
3847 if (OSDynamicCast(IOPowerConnection, child))
3848 {
3849 IOPowerConnection * conn = (IOPowerConnection *) child;
3850 conn->delayChildNotification = true;
3851 }
3852 break;
3853 }
3854 child = parent;
3855 parent = child->getParentEntry(gIOPowerPlane);
3856 }
4a3eedf9
A
3857 }
3858
6d2010ae
A
3859 if (flags)
3860 {
3861 DLOG("%s tag flags %x\n", service->getName(), flags);
3862 actions->parameter |= flags;
3863 actions->actionPowerChangeOverride =
3864 OSMemberFunctionCast(
3865 IOPMActionPowerChangeOverride, this,
3866 &IOPMrootDomain::overridePowerChangeForUIService);
4a3eedf9 3867
6d2010ae
A
3868 if (flags & kPMActionsFlagIsDisplayWrangler)
3869 {
3870 actions->actionActivityTickle =
3871 OSMemberFunctionCast(
3872 IOPMActionActivityTickle, this,
3873 &IOPMrootDomain::handleActivityTickleForDisplayWrangler);
3874 }
3875 return;
3876 }
4a3eedf9 3877
6d2010ae
A
3878 // Locate the first PCI host bridge for PMTrace.
3879 if (!pciHostBridgeDevice && service->metaCast("IOPCIBridge"))
3880 {
3881 IOService * provider = service->getProvider();
3882 if (OSDynamicCast(IOPlatformDevice, provider) &&
3883 provider->inPlane(gIODTPlane))
3884 {
3885 pciHostBridgeDevice = provider;
3886 pciHostBridgeDriver = service;
3887 DLOG("PMTrace found PCI host bridge %s->%s\n",
3888 provider->getName(), service->getName());
3889 }
3890 }
4a3eedf9 3891
6d2010ae
A
3892 // Tag top-level PCI devices. The order of PMinit() call does not
3893 // change across boots and is used as the PCI bit number.
3894 if (pciHostBridgeDevice && service->metaCast("IOPCIDevice"))
3895 {
3896 // Would prefer to check built-in property, but tagPowerPlaneService()
3897 // is called before pciDevice->registerService().
3898 IORegistryEntry * parent = service->getParentEntry(gIODTPlane);
3899 if ((parent == pciHostBridgeDevice) && service->getProperty("acpi-device"))
3900 {
3901 int bit = pmTracer->recordTopLevelPCIDevice( service );
3902 if (bit >= 0)
3903 {
3904 // Save the assigned bit for fast lookup.
3905 actions->parameter |= (bit & kPMActionsPCIBitNumberMask);
4a3eedf9 3906
6d2010ae
A
3907 actions->actionPowerChangeStart =
3908 OSMemberFunctionCast(
3909 IOPMActionPowerChangeStart, this,
3910 &IOPMrootDomain::handlePowerChangeStartForPCIDevice);
4a3eedf9 3911
6d2010ae
A
3912 actions->actionPowerChangeDone =
3913 OSMemberFunctionCast(
3914 IOPMActionPowerChangeDone, this,
3915 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice);
3916 }
3917 }
3918 }
4a3eedf9
A
3919}
3920
0c530ab8 3921//******************************************************************************
6d2010ae 3922// PM actions for root domain
0c530ab8
A
3923//******************************************************************************
3924
6d2010ae
A
3925void IOPMrootDomain::overrideOurPowerChange(
3926 IOService * service,
3927 IOPMActions * actions,
3928 unsigned long * inOutPowerState,
3929 uint32_t * inOutChangeFlags )
b0d623f7 3930{
6d2010ae
A
3931 uint32_t powerState = (uint32_t) *inOutPowerState;
3932 uint32_t changeFlags = *inOutChangeFlags;
3933 uint32_t currentPowerState = (uint32_t) getPowerState();
3934
3935 if ((currentPowerState == powerState) ||
3936 (changeFlags & kIOPMParentInitiated))
3937 {
3938 // FIXME: cancel any parent change (unexpected)
3939 // Root parent is permanently pegged at max power,
3940 // kIOPMParentInitiated is unexpected.
3941 return;
3942 }
3943
3944 if (powerState < currentPowerState)
3945 {
3946 if ((changeFlags & kIOPMSkipAskPowerDown) == 0)
3947 {
3948 /* Convenient place to run any code at idle sleep time
3949 * IOPMrootDomain initiates an idle sleep here
3950 *
3951 * Set last sleep cause accordingly.
3952 */
3953 pmPowerStateQueue->submitPowerEvent(kPowerEventPublishSleepWakeUUID, (void *)true);
3954
3955 lastSleepReason = kIOPMSleepReasonIdle;
3956 setProperty(kRootDomainSleepReasonKey, kIOPMIdleSleepKey);
3957 }
3958 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics))
3959 {
3960 // Root domain is dropping power state ON->SLEEP.
3961 // If system is in full wake, first drop to dark wake.
3962
3963 darkWakeToSleepASAP = true;
3964
3965 // Drop graphics capability.
3966 // No transition if system is already in dark wake.
3967
3968 _desiredCapability &= ~(
3969 kIOPMSystemCapabilityGraphics |
3970 kIOPMSystemCapabilityAudio );
3971
3972 *inOutPowerState = ON_STATE;
3973 *inOutChangeFlags |= kIOPMSynchronize;
3974
3975 // Revert device desire from SLEEP->ON.
3976 changePowerStateToPriv(ON_STATE);
3977 }
3978 }
b0d623f7
A
3979}
3980
6d2010ae
A
3981void IOPMrootDomain::handleOurPowerChangeStart(
3982 IOService * service,
3983 IOPMActions * actions,
3984 uint32_t powerState,
3985 uint32_t * inOutChangeFlags )
0c530ab8 3986{
6d2010ae
A
3987 uint32_t changeFlags = *inOutChangeFlags;
3988 uint32_t currentPowerState = (uint32_t) getPowerState();
0c530ab8 3989
6d2010ae
A
3990 _systemTransitionType = kSystemTransitionNone;
3991 _systemMessageClientMask = 0;
3992 capabilityLoss = false;
b0d623f7 3993
6d2010ae
A
3994 // 1. Explicit capability change.
3995
3996 if (changeFlags & kIOPMSynchronize)
55e303ae 3997 {
6d2010ae
A
3998 if (powerState == ON_STATE)
3999 {
4000 if (changeFlags & kIOPMSyncNoChildNotify)
4001 _systemTransitionType = kSystemTransitionNewCapClient;
4002 else
4003 _systemTransitionType = kSystemTransitionCapability;
4004 }
d52fe63f 4005 }
0c530ab8 4006
6d2010ae
A
4007 // 2. Going to sleep (cancellation still possible).
4008
4009 else if (powerState < currentPowerState)
4010 _systemTransitionType = kSystemTransitionSleep;
4011
4012 // 3. Woke from (idle or demand) sleep.
4013
4014 else if (!systemBooting &&
4015 (changeFlags & kIOPMSelfInitiated) &&
4016 (powerState > currentPowerState))
55e303ae 4017 {
6d2010ae
A
4018 _systemTransitionType = kSystemTransitionWake;
4019 _desiredCapability = kIOPMSystemCapabilityCPU |
4020 kIOPMSystemCapabilityNetwork;
4021
4022 // Check for early HID events (e.g. LID open)
4023 if (wranglerTickled)
4024 {
4025 _desiredCapability |= (
4026 kIOPMSystemCapabilityGraphics |
4027 kIOPMSystemCapabilityAudio );
4028 }
d52fe63f
A
4029 }
4030
6d2010ae
A
4031 // Update pending wake capability at the beginning of every
4032 // state transition (including synchronize). This will become
4033 // the current capability at the end of the transition.
4034
4035 if (kSystemTransitionSleep == _systemTransitionType)
55e303ae 4036 {
6d2010ae
A
4037 _pendingCapability = 0;
4038 capabilityLoss = true;
d52fe63f 4039 }
6d2010ae 4040 else if (kSystemTransitionNewCapClient != _systemTransitionType)
55e303ae 4041 {
6d2010ae
A
4042 _pendingCapability = _desiredCapability |
4043 kIOPMSystemCapabilityCPU |
4044 kIOPMSystemCapabilityNetwork;
4045
4046 if (_pendingCapability & kIOPMSystemCapabilityGraphics)
4047 _pendingCapability |= kIOPMSystemCapabilityAudio;
4048
4049 if ((kSystemTransitionCapability == _systemTransitionType) &&
4050 (_pendingCapability == _currentCapability))
4051 {
4052 // Cancel the PM state change.
4053 _systemTransitionType = kSystemTransitionNone;
4054 *inOutChangeFlags |= kIOPMNotDone;
4055 }
4056 if (__builtin_popcount(_pendingCapability) <
4057 __builtin_popcount(_currentCapability))
4058 capabilityLoss = true;
4059 if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
4060 rejectWranglerTickle = true;
1c79356b 4061 }
6d2010ae
A
4062
4063 // 1. Capability change.
4064
4065 if (kSystemTransitionCapability == _systemTransitionType)
55e303ae 4066 {
6d2010ae
A
4067 // Dark to Full transition.
4068 if (CAP_GAIN(kIOPMSystemCapabilityGraphics))
4069 {
4070 tracePoint( kIOPMTracePointDarkWakeExit );
4071 wranglerSleepIgnored = false;
4072 sleepTimerMaintenance = false;
4073 hibernateNoDefeat = false;
4074 _systemMessageClientMask = kSystemMessageClientUser;
4075 if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0)
4076 _systemMessageClientMask |= kSystemMessageClientKernel;
4077
4078 tellClients(kIOMessageSystemWillPowerOn);
4079 }
4080
4081 // Full to Dark transition.
4082 if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
4083 {
4084 tracePoint( kIOPMTracePointDarkWakeEntry );
4085 *inOutChangeFlags |= kIOPMSyncTellPowerDown;
4086 _systemMessageClientMask = kSystemMessageClientUser;
4087 }
1c79356b
A
4088 }
4089
6d2010ae
A
4090 // 2. System sleep.
4091
4092 else if (kSystemTransitionSleep == _systemTransitionType)
0c530ab8 4093 {
6d2010ae
A
4094 // Beginning of a system sleep transition.
4095 // Cancellation is still possible.
4096 tracePoint( kIOPMTracePointSleepStarted, lastSleepReason );
0b4c1975 4097
6d2010ae
A
4098 _systemMessageClientMask = kSystemMessageClientAll;
4099 if ((_currentCapability & kIOPMSystemCapabilityGraphics) == 0)
4100 _systemMessageClientMask &= ~kSystemMessageClientApp;
4101 if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0)
4102 _systemMessageClientMask &= ~kSystemMessageClientKernel;
4103
4104 // Optimization to ignore wrangler power down thus skipping
4105 // the disk spindown and arming the idle timer for demand sleep.
4106
4107 if (changeFlags & kIOPMIgnoreChildren)
060df5ea 4108 {
6d2010ae 4109 wranglerSleepIgnored = true;
060df5ea
A
4110 }
4111
6d2010ae
A
4112 logWranglerTickle = false;
4113 }
2d21ac55 4114
6d2010ae 4115 // 3. System wake.
0b4c1975 4116
6d2010ae
A
4117 else if (kSystemTransitionWake == _systemTransitionType)
4118 {
4119 wranglerSleepIgnored = false;
4120
4121 if (_pendingCapability & kIOPMSystemCapabilityGraphics)
4122 {
4123 _systemMessageClientMask = kSystemMessageClientAll;
4124 }
4125 else
4126 {
4127 _systemMessageClientMask = kSystemMessageClientConfigd;
4128 }
4129
4130 tracePoint( kIOPMTracePointWakeWillPowerOnClients );
4131 tellClients(kIOMessageSystemWillPowerOn);
0b4c1975 4132 }
0c530ab8 4133
6d2010ae
A
4134 if ((kSystemTransitionNone != _systemTransitionType) &&
4135 (kSystemTransitionNewCapClient != _systemTransitionType))
0c530ab8 4136 {
6d2010ae
A
4137 _systemStateGeneration++;
4138 systemDarkWake = false;
0c530ab8 4139
6d2010ae
A
4140 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4141 "dcp %x:%x:%x\n",
4142 currentPowerState, powerState, *inOutChangeFlags,
4143 _systemTransitionType, _systemStateGeneration,
4144 _systemMessageClientMask,
4145 _desiredCapability, _currentCapability, _pendingCapability);
4146 }
4147}
2d21ac55 4148
6d2010ae
A
4149void IOPMrootDomain::handleOurPowerChangeDone(
4150 IOService * service,
4151 IOPMActions * actions,
4152 uint32_t powerState,
4153 uint32_t changeFlags )
4154{
4155 if (kSystemTransitionNewCapClient == _systemTransitionType)
4156 {
4157 _systemTransitionType = kSystemTransitionNone;
4158 return;
0c530ab8
A
4159 }
4160
6d2010ae 4161 if (_systemTransitionType != kSystemTransitionNone)
4452a7af 4162 {
6d2010ae 4163 uint32_t currentPowerState = (uint32_t) getPowerState();
0c530ab8 4164
6d2010ae
A
4165 if (changeFlags & kIOPMNotDone)
4166 {
4167 // Power down was cancelled or vetoed.
4168 _pendingCapability = _currentCapability;
4169 lastSleepReason = 0;
0c530ab8 4170
6d2010ae
A
4171 if (((_currentCapability & kIOPMSystemCapabilityGraphics) == 0) &&
4172 (_currentCapability & kIOPMSystemCapabilityCPU))
4173 {
4174 pmPowerStateQueue->submitPowerEvent(
4175 kPowerEventPolicyStimulus,
4176 (void *) kStimulusDarkWakeReentry,
4177 _systemStateGeneration );
4178 }
4179
4180 // Revert device desire to max.
4181 changePowerStateToPriv(ON_STATE);
4182 }
4183 else
4452a7af 4184 {
6d2010ae
A
4185 // Send message on dark wake to full wake promotion.
4186 // tellChangeUp() handles the normal SLEEP->ON case.
4187
4188 if (kSystemTransitionCapability == _systemTransitionType)
4189 {
4190 if (CAP_GAIN(kIOPMSystemCapabilityGraphics))
4191 {
4192 tellClients(kIOMessageSystemHasPoweredOn);
4193#if DARK_TO_FULL_EVALUATE_CLAMSHELL
4194 // Re-evaluate clamshell state ourselves when graphics
4195 // will not get kIOMessageSystemHasPoweredOn.
4196
4197 if (clamshellClosed &&
4198 ((_systemMessageClientMask & kSystemMessageClientKernel) == 0))
4199 {
4200 receivePowerNotification( kLocalEvalClamshellCommand );
4201 }
4202#endif
4203 }
4204 if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
4205 wranglerTickled = false;
4206 }
4207
4208 // Reset state after exiting from dark wake.
4209
4210 if (CAP_GAIN(kIOPMSystemCapabilityGraphics) ||
4211 CAP_LOSS(kIOPMSystemCapabilityCPU))
4212 {
4213 darkWakeMaintenance = false;
4214 darkWakeToSleepASAP = false;
4215 pciCantSleepValid = false;
4216 rejectWranglerTickle = false;
4217 }
4218
4219 // Entered dark mode.
4220
4221 if (((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) &&
4222 (_pendingCapability & kIOPMSystemCapabilityCPU))
4223 {
4224 if (((gDarkWakeFlags & kDarkWakeFlagIgnoreDiskIOInDark) == 0) &&
4225 (kSystemTransitionWake == _systemTransitionType) &&
4226 (_debugWakeSeconds == 0))
4227 {
4228 OSObject * prop = copyProperty(kIOPMRootDomainWakeTypeKey);
4229 if (prop)
4230 {
4231 OSString * wakeType = OSDynamicCast(OSString, prop);
4232 if (wakeType &&
4233 wakeType->isEqualTo(kIOPMRootDomainWakeTypeNetwork))
4234 {
4235 // Woke from network and entered dark wake.
4236 if (darkWakeToSleepASAP)
4237 {
4238 DLOG("cleared darkWakeToSleepASAP\n");
4239 darkWakeToSleepASAP = false;
4240 }
4241 }
4242 prop->release();
4243 }
4244 }
4245
4246 // Queue an evaluation of whether to remain in dark wake,
4247 // and for how long. This serves the purpose of draining
4248 // any assertions from the queue.
4249
4250 pmPowerStateQueue->submitPowerEvent(
4251 kPowerEventPolicyStimulus,
4252 (void *) kStimulusDarkWakeEntry,
4253 _systemStateGeneration );
4254 }
0c530ab8 4255 }
4452a7af 4256
6d2010ae
A
4257 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4258 "dcp %x:%x:%x, dbgtimer %u\n",
4259 currentPowerState, powerState, changeFlags,
4260 _systemTransitionType, _systemStateGeneration,
4261 _systemMessageClientMask,
4262 _desiredCapability, _currentCapability, _pendingCapability,
4263 _debugWakeSeconds);
b0d623f7 4264
6d2010ae 4265 // Update current system capability.
2d21ac55 4266
6d2010ae
A
4267 if (_currentCapability != _pendingCapability)
4268 _currentCapability = _pendingCapability;
0c530ab8 4269
6d2010ae
A
4270 // Update highest system capability.
4271
4272 if (!CAP_CURRENT(kIOPMSystemCapabilityCPU))
4273 _highestCapability = 0; // reset at sleep state
4274 else
4275 _highestCapability |= _currentCapability;
4276
4277 if (darkWakePostTickle &&
4278 (kSystemTransitionWake == _systemTransitionType) &&
4279 (gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
4280 kDarkWakeFlagHIDTickleLate)
0c530ab8 4281 {
6d2010ae
A
4282 darkWakePostTickle = false;
4283 reportUserInput();
4452a7af 4284 }
6d2010ae
A
4285
4286 // Reset tracepoint at completion of capability change,
4287 // completion of wake transition, and aborted sleep transition.
4288
4289 if ((_systemTransitionType == kSystemTransitionCapability) ||
4290 (_systemTransitionType == kSystemTransitionWake) ||
4291 ((_systemTransitionType == kSystemTransitionSleep) &&
4292 (changeFlags & kIOPMNotDone)))
0c530ab8 4293 {
6d2010ae
A
4294 setProperty(kIOPMSystemCapabilitiesKey, _currentCapability, 64);
4295 tracePoint( kIOPMTracePointSystemUp, 0 );
0c530ab8
A
4296 }
4297
6d2010ae
A
4298 _systemTransitionType = kSystemTransitionNone;
4299 _systemMessageClientMask = 0;
0c530ab8 4300
6d2010ae 4301 logGraphicsClamp = false;
0c530ab8 4302 }
6d2010ae 4303}
0c530ab8 4304
6d2010ae
A
4305//******************************************************************************
4306// PM actions for graphics and audio.
4307//******************************************************************************
4308
4309void IOPMrootDomain::overridePowerChangeForUIService(
4310 IOService * service,
4311 IOPMActions * actions,
4312 unsigned long * inOutPowerState,
4313 uint32_t * inOutChangeFlags )
4314{
4315 uint32_t powerState = (uint32_t) *inOutPowerState;
4316 uint32_t changeFlags = (uint32_t) *inOutChangeFlags;
4317
4318 if (kSystemTransitionNone == _systemTransitionType)
4319 {
4320 // Not in midst of a system transition.
4321 // Do not modify power limit enable state.
0c530ab8 4322 }
6d2010ae
A
4323 else if ((actions->parameter & kPMActionsFlagLimitPower) == 0)
4324 {
4325 // Activate power limiter.
0c530ab8 4326
6d2010ae
A
4327 if ((actions->parameter & kPMActionsFlagIsDisplayWrangler) &&
4328 ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0))
4329 {
4330 actions->parameter |= kPMActionsFlagLimitPower;
4331 }
4332 else if ((actions->parameter & kPMActionsFlagIsAudioDevice) &&
4333 ((_pendingCapability & kIOPMSystemCapabilityAudio) == 0))
4334 {
4335 actions->parameter |= kPMActionsFlagLimitPower;
4336 }
4337 else if ((actions->parameter & kPMActionsFlagIsGraphicsDevice) &&
4338 (_systemTransitionType == kSystemTransitionSleep))
4339 {
4340 // For graphics devices, arm the limiter when entering
4341 // system sleep. Not when dropping to dark wake.
4342 actions->parameter |= kPMActionsFlagLimitPower;
4343 }
4344
4345 if (actions->parameter & kPMActionsFlagLimitPower)
4346 {
4347 DLOG("+ plimit %s %p\n",
4348 service->getName(), service);
4349 }
4350 }
4351 else
0c530ab8 4352 {
6d2010ae 4353 // Remove power limit.
0c530ab8 4354
6d2010ae
A
4355 if ((actions->parameter & (
4356 kPMActionsFlagIsDisplayWrangler |
4357 kPMActionsFlagIsGraphicsDevice )) &&
4358 (_pendingCapability & kIOPMSystemCapabilityGraphics))
4359 {
4360 actions->parameter &= ~kPMActionsFlagLimitPower;
4361 }
4362 else if ((actions->parameter & kPMActionsFlagIsAudioDevice) &&
4363 (_pendingCapability & kIOPMSystemCapabilityAudio))
4364 {
4365 actions->parameter &= ~kPMActionsFlagLimitPower;
4366 }
0c530ab8 4367
6d2010ae
A
4368 if ((actions->parameter & kPMActionsFlagLimitPower) == 0)
4369 {
4370 DLOG("- plimit %s %p\n",
4371 service->getName(), service);
4372 }
4452a7af
A
4373 }
4374
7ee9d059
A
4375 if (gRAMDiskImageBoot &&
4376 (actions->parameter & kPMActionsFlagIsDisplayWrangler))
4377 {
4378 // Tag devices subject to power suppression.
4379 *inOutChangeFlags |= kIOPMPowerSuppressed;
4380 }
4381
6d2010ae 4382 if (actions->parameter & kPMActionsFlagLimitPower)
2d21ac55 4383 {
6d2010ae
A
4384 uint32_t maxPowerState = (uint32_t)(-1);
4385
4386 if (changeFlags & (kIOPMDomainDidChange | kIOPMDomainWillChange))
55e303ae 4387 {
6d2010ae
A
4388 // Enforce limit for system power/cap transitions.
4389
4390 maxPowerState = 0;
7ee9d059
A
4391 if ((actions->parameter & kPMActionsFlagIsDisplayWrangler) &&
4392 (!gRAMDiskImageBoot || (service->getPowerState() > 0)))
6d2010ae
A
4393 {
4394 // Forces a 3->1 transition sequence
4395 if (changeFlags & kIOPMDomainWillChange)
4396 maxPowerState = 3;
4397 else
4398 maxPowerState = 1;
4399 }
4400 }
4401 else
4402 {
4403 // Deny all self-initiated changes when power is limited.
4404 // Wrangler tickle should never defeat the limiter.
4405
4406 maxPowerState = service->getPowerState();
4407 }
4408
4409 if (powerState > maxPowerState)
4410 {
4411 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
4412 service->getName(), service, powerState, maxPowerState,
4413 changeFlags);
4414 *inOutPowerState = maxPowerState;
4415
4416 if (darkWakePostTickle &&
4417 (actions->parameter & kPMActionsFlagIsDisplayWrangler) &&
4418 (changeFlags & kIOPMDomainWillChange) &&
4419 ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
4420 kDarkWakeFlagHIDTickleEarly))
4421 {
4422 darkWakePostTickle = false;
4423 reportUserInput();
4424 }
0b4e3aa0 4425 }
6d2010ae
A
4426
4427 if (!graphicsSuppressed && (changeFlags & kIOPMDomainDidChange))
4428 {
4429 if (logGraphicsClamp)
4430 {
4431 AbsoluteTime now;
4432 uint64_t nsec;
4433
4434 clock_get_uptime(&now);
4435 SUB_ABSOLUTETIME(&now, &systemWakeTime);
4436 absolutetime_to_nanoseconds(now, &nsec);
4437 MSG("Graphics suppressed %u ms\n",
4438 ((int)((nsec) / 1000000ULL)));
0c530ab8 4439 }
6d2010ae 4440 graphicsSuppressed = true;
1c79356b 4441 }
0b4e3aa0 4442 }
6d2010ae 4443}
0b4e3aa0 4444
6d2010ae
A
4445void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
4446 IOService * service,
4447 IOPMActions * actions )
4448{
4449 // Warning: Not running in PM work loop context - don't modify state !!!
4450 // Trap tickle directed to IODisplayWrangler while running with graphics
4451 // capability suppressed.
4452
4453 assert(service == wrangler);
4454
4455 if (service == wrangler)
55e303ae 4456 {
6d2010ae
A
4457 bool aborting = ((lastSleepReason == kIOPMSleepReasonIdle)
4458 || (lastSleepReason == kIOPMSleepReasonMaintenance));
4459 if (aborting) {
4460 userActivityCount++;
4461 DLOG("display wrangler tickled1 %d lastSleepReason %d\n", userActivityCount, lastSleepReason);
4462 }
1c79356b
A
4463 }
4464
6d2010ae
A
4465 if (!wranglerTickled && !lowBatteryCondition &&
4466 ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0))
4467 {
4468 DLOG("display wrangler tickled\n");
4469 if (kIOLogPMRootDomain & gIOKitDebug)
4470 OSReportWithBacktrace("Dark wake display tickle");
4471 if (pmPowerStateQueue)
4472 {
4473 pmPowerStateQueue->submitPowerEvent(
4474 kPowerEventPolicyStimulus,
4475 (void *) kStimulusDarkWakeActivityTickle );
0b4e3aa0 4476 }
1c79356b 4477 }
1c79356b
A
4478}
4479
b0d623f7 4480//******************************************************************************
6d2010ae 4481// Approve usage of delayed child notification by PM.
b0d623f7 4482//******************************************************************************
1c79356b 4483
6d2010ae
A
4484bool IOPMrootDomain::shouldDelayChildNotification(
4485 IOService * service )
1c79356b 4486{
6d2010ae
A
4487 if (((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) != 0) &&
4488 !wranglerTickled &&
4489 (kSystemTransitionWake == _systemTransitionType))
4490 {
4491 DLOG("%s: delay child notify\n", service->getName());
4492 return true;
4493 }
4494 return false;
b0d623f7 4495}
0b4e3aa0 4496
b0d623f7 4497//******************************************************************************
6d2010ae 4498// PM actions for PCI device.
b0d623f7
A
4499//******************************************************************************
4500
6d2010ae
A
4501void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
4502 IOService * service,
4503 IOPMActions * actions,
4504 uint32_t powerState,
4505 uint32_t * inOutChangeFlags )
b0d623f7 4506{
6d2010ae
A
4507 pmTracer->tracePCIPowerChange(
4508 PMTraceWorker::kPowerChangeStart,
4509 service, *inOutChangeFlags,
4510 (actions->parameter & kPMActionsPCIBitNumberMask));
0b4e3aa0
A
4511}
4512
6d2010ae
A
4513void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
4514 IOService * service,
4515 IOPMActions * actions,
4516 uint32_t powerState,
4517 uint32_t changeFlags )
4518{
4519 pmTracer->tracePCIPowerChange(
4520 PMTraceWorker::kPowerChangeCompleted,
4521 service, changeFlags,
4522 (actions->parameter & kPMActionsPCIBitNumberMask));
4523}
b0d623f7
A
4524
4525//******************************************************************************
6d2010ae 4526// registerInterest
0b4e3aa0 4527//
6d2010ae 4528// Override IOService::registerInterest() to intercept special clients.
b0d623f7 4529//******************************************************************************
0b4e3aa0 4530
6d2010ae
A
4531IONotifier * IOPMrootDomain::registerInterest(
4532 const OSSymbol * typeOfInterest,
4533 IOServiceInterestHandler handler,
4534 void * target, void * ref )
0b4e3aa0 4535{
6d2010ae
A
4536 IONotifier * notifier;
4537 bool isSystemCapabilityClient;
4538 bool isKernelCapabilityClient;
2d21ac55 4539
6d2010ae
A
4540 isSystemCapabilityClient =
4541 typeOfInterest &&
4542 typeOfInterest->isEqualTo(kIOPMSystemCapabilityInterest);
4543
4544 isKernelCapabilityClient =
4545 typeOfInterest &&
4546 typeOfInterest->isEqualTo(gIOPriorityPowerStateInterest);
b0d623f7 4547
6d2010ae
A
4548 if (isSystemCapabilityClient)
4549 typeOfInterest = gIOAppPowerStateInterest;
4550
4551 notifier = super::registerInterest(typeOfInterest, handler, target, ref);
4552 if (notifier && pmPowerStateQueue)
b0d623f7 4553 {
6d2010ae
A
4554 if (isSystemCapabilityClient)
4555 {
4556 notifier->retain();
4557 if (pmPowerStateQueue->submitPowerEvent(
4558 kPowerEventRegisterSystemCapabilityClient, notifier) == false)
4559 notifier->release();
4560 }
4561
4562 if (isKernelCapabilityClient)
4563 {
4564 notifier->retain();
4565 if (pmPowerStateQueue->submitPowerEvent(
4566 kPowerEventRegisterKernelCapabilityClient, notifier) == false)
4567 notifier->release();
4568 }
b0d623f7 4569 }
55e303ae 4570
6d2010ae
A
4571 return notifier;
4572}
0b4e3aa0 4573
6d2010ae
A
4574//******************************************************************************
4575// systemMessageFilter
4576//
4577//******************************************************************************
0b4e3aa0 4578
6d2010ae
A
4579bool IOPMrootDomain::systemMessageFilter(
4580 void * object, void * arg1, void * arg2, void * arg3 )
4581{
4582 const IOPMInterestContext * context = (const IOPMInterestContext *) arg1;
4583 bool isCapMsg = (context->messageType == kIOMessageSystemCapabilityChange);
4584 bool isCapClient = false;
4585 bool allow = false;
55e303ae 4586
6d2010ae
A
4587 do {
4588 if ((kSystemTransitionNewCapClient == _systemTransitionType) &&
4589 (!isCapMsg || !_joinedCapabilityClients ||
4590 !_joinedCapabilityClients->containsObject((OSObject *) object)))
4591 break;
4592
4593 // Capability change message for app and kernel clients.
4594
4595 if (isCapMsg)
55e303ae 4596 {
6d2010ae
A
4597 if ((context->notifyType == kNotifyPriority) ||
4598 (context->notifyType == kNotifyCapabilityChangePriority))
4599 isCapClient = true;
2d21ac55 4600
6d2010ae
A
4601 if ((context->notifyType == kNotifyCapabilityChangeApps) &&
4602 (object == (void *) systemCapabilityNotifier))
4603 isCapClient = true;
4604 }
2d21ac55 4605
6d2010ae
A
4606 if (isCapClient)
4607 {
4608 IOPMSystemCapabilityChangeParameters * capArgs =
4609 (IOPMSystemCapabilityChangeParameters *) arg2;
2d21ac55 4610
6d2010ae
A
4611 if (kSystemTransitionNewCapClient == _systemTransitionType)
4612 {
4613 capArgs->fromCapabilities = 0;
4614 capArgs->toCapabilities = _currentCapability;
4615 capArgs->changeFlags = 0;
4616 }
4617 else
4618 {
4619 capArgs->fromCapabilities = _currentCapability;
4620 capArgs->toCapabilities = _pendingCapability;
4621
4622 if (context->isPreChange)
4623 capArgs->changeFlags = kIOPMSystemCapabilityWillChange;
2d21ac55 4624 else
6d2010ae
A
4625 capArgs->changeFlags = kIOPMSystemCapabilityDidChange;
4626 }
b0d623f7 4627
6d2010ae
A
4628 // Capability change messages only go to the PM configd plugin.
4629 // Wait for response post-change if capabilitiy is increasing.
4630 // Wait for response pre-change if capability is decreasing.
2d21ac55 4631
6d2010ae
A
4632 if ((context->notifyType == kNotifyCapabilityChangeApps) && arg3 &&
4633 ( (capabilityLoss && context->isPreChange) ||
4634 (!capabilityLoss && !context->isPreChange) ) )
4635 {
4636 // app has not replied yet, wait for it
4637 *((OSObject **) arg3) = kOSBooleanFalse;
0b4e3aa0 4638 }
6d2010ae
A
4639
4640 allow = true;
4641 break;
0b4e3aa0 4642 }
b0d623f7 4643
6d2010ae
A
4644 // Capability client will always see kIOMessageCanSystemSleep,
4645 // even for demand sleep.
b0d623f7 4646
6d2010ae
A
4647 if ((kIOMessageCanSystemSleep == context->messageType) ||
4648 (kIOMessageSystemWillNotSleep == context->messageType))
b0d623f7 4649 {
6d2010ae 4650 if (object == (OSObject *) systemCapabilityNotifier)
b0d623f7 4651 {
6d2010ae
A
4652 allow = true;
4653 break;
4654 }
4655
4656 // Not idle sleep, don't ask apps.
4657 if (context->changeFlags & kIOPMSkipAskPowerDown)
4658 {
4659 break;
b0d623f7
A
4660 }
4661 }
6d2010ae
A
4662
4663 // Reject capability change messages for legacy clients.
4664 // Reject legacy system sleep messages for capability client.
4665
4666 if (isCapMsg || (object == (OSObject *) systemCapabilityNotifier))
b0d623f7 4667 {
6d2010ae 4668 break;
b0d623f7 4669 }
2d21ac55 4670
6d2010ae 4671 // Filter system sleep messages.
0b4e3aa0 4672
6d2010ae
A
4673 if ((context->notifyType == kNotifyApps) &&
4674 (_systemMessageClientMask & kSystemMessageClientApp))
4675 {
4676 allow = true;
4677 }
4678 else if ((context->notifyType == kNotifyPriority) &&
4679 (_systemMessageClientMask & kSystemMessageClientKernel))
4680 {
4681 allow = true;
4682 }
4683 }
4684 while (false);
0b4e3aa0 4685
6d2010ae
A
4686 if (allow && isCapMsg && _joinedCapabilityClients)
4687 {
4688 _joinedCapabilityClients->removeObject((OSObject *) object);
4689 if (_joinedCapabilityClients->getCount() == 0)
4690 {
4691 DLOG("destroyed capability client set %p\n",
4692 _joinedCapabilityClients);
4693 _joinedCapabilityClients->release();
4694 _joinedCapabilityClients = 0;
4695 }
4696 }
1c79356b 4697
6d2010ae 4698 return allow;
1c79356b
A
4699}
4700
b0d623f7 4701//******************************************************************************
6d2010ae 4702// setMaintenanceWakeCalendar
2d21ac55 4703//
b0d623f7 4704//******************************************************************************
2d21ac55 4705
6d2010ae
A
4706IOReturn IOPMrootDomain::setMaintenanceWakeCalendar(
4707 const IOPMCalendarStruct * calendar )
2d21ac55 4708{
6d2010ae
A
4709 OSData * data;
4710 IOReturn ret;
2d21ac55 4711
6d2010ae
A
4712 if (!calendar)
4713 return kIOReturnBadArgument;
4714
4715 data = OSData::withBytesNoCopy((void *) calendar, sizeof(*calendar));
4716 if (!data)
4717 return kIOReturnNoMemory;
4718
4719 ret = setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey, data);
2d21ac55 4720
6d2010ae
A
4721 data->release();
4722 return ret;
4723}
2d21ac55 4724
6d2010ae
A
4725// MARK: -
4726// MARK: Display Wrangler
2d21ac55 4727
6d2010ae
A
4728//******************************************************************************
4729// displayWranglerNotification
4730//
4731// Handle the notification when the IODisplayWrangler changes power state.
4732//******************************************************************************
2d21ac55 4733
6d2010ae
A
4734IOReturn IOPMrootDomain::displayWranglerNotification(
4735 void * target, void * refCon,
4736 UInt32 messageType, IOService * service,
4737 void * messageArgument, vm_size_t argSize )
4738{
4739#if !NO_KERNEL_HID
4740 int displayPowerState;
4741 IOPowerStateChangeNotification * params =
4742 (IOPowerStateChangeNotification *) messageArgument;
2d21ac55 4743
6d2010ae
A
4744 if ((messageType != kIOMessageDeviceWillPowerOff) &&
4745 (messageType != kIOMessageDeviceHasPoweredOn))
4746 return kIOReturnUnsupported;
2d21ac55 4747
6d2010ae
A
4748 ASSERT_GATED();
4749 if (!gRootDomain)
4750 return kIOReturnUnsupported;
2d21ac55 4751
6d2010ae
A
4752 displayPowerState = params->stateNumber;
4753 DLOG("DisplayWrangler message 0x%x, power state %d\n",
4754 (uint32_t) messageType, displayPowerState);
2d21ac55 4755
6d2010ae
A
4756 switch (messageType) {
4757 case kIOMessageDeviceWillPowerOff:
b0d623f7 4758
6d2010ae
A
4759 // Display wrangler has dropped power due to display idle
4760 // or force system sleep.
4761 //
4762 // 4 Display ON
4763 // 3 Display Dim
4764 // 2 Display Sleep
4765 // 1 Not visible to user
4766 // 0 Not visible to user
2d21ac55 4767
6d2010ae
A
4768 if (displayPowerState > 2)
4769 break;
4770
4771 gRootDomain->evaluatePolicy( kStimulusDisplayWranglerSleep );
4772 break;
2d21ac55 4773
6d2010ae 4774 case kIOMessageDeviceHasPoweredOn:
2d21ac55 4775
6d2010ae
A
4776 // Display wrangler has powered on due to user activity
4777 // or wake from sleep.
b0d623f7 4778
6d2010ae
A
4779 if ( 4 != displayPowerState )
4780 break;
2d21ac55 4781
6d2010ae
A
4782 gRootDomain->evaluatePolicy( kStimulusDisplayWranglerWake );
4783 break;
4784 }
4785#endif
4786 return kIOReturnUnsupported;
b0d623f7
A
4787}
4788
6d2010ae
A
4789//*********************************************************************************
4790// displayWranglerMatchPublished
b0d623f7 4791//
6d2010ae
A
4792// Receives a notification when the IODisplayWrangler is published.
4793// When it's published we install a power state change handler.
b0d623f7
A
4794//******************************************************************************
4795
6d2010ae
A
4796bool IOPMrootDomain::displayWranglerMatchPublished(
4797 void * target,
4798 void * refCon,
4799 IOService * newService,
4800 IONotifier * notifier __unused)
b0d623f7 4801{
6d2010ae
A
4802#if !NO_KERNEL_HID
4803 // found the display wrangler, now install a handler
4804 if( !newService->registerInterest( gIOGeneralInterest,
4805 &displayWranglerNotification, target, 0) )
b0d623f7 4806 {
6d2010ae 4807 return false;
b0d623f7
A
4808 }
4809#endif
6d2010ae 4810 return true;
b0d623f7
A
4811}
4812
6d2010ae
A
4813//******************************************************************************
4814// reportUserInput
4815//
4816//******************************************************************************
4817
4818void IOPMrootDomain::reportUserInput( void )
b0d623f7 4819{
6d2010ae
A
4820#if !NO_KERNEL_HID
4821 OSIterator * iter;
b0d623f7 4822
6d2010ae 4823 if(!wrangler)
b0d623f7 4824 {
6d2010ae
A
4825 iter = getMatchingServices(serviceMatching("IODisplayWrangler"));
4826 if(iter)
4827 {
4828 wrangler = (IOService *) iter->getNextObject();
4829 iter->release();
4830 }
b0d623f7
A
4831 }
4832
6d2010ae
A
4833 if(wrangler)
4834 wrangler->activityTickle(0,0);
b0d623f7 4835#endif
2d21ac55
A
4836}
4837
6d2010ae
A
4838// MARK: -
4839// MARK: Battery
2d21ac55 4840
b0d623f7 4841//******************************************************************************
6d2010ae 4842// batteryPublished
1c79356b 4843//
6d2010ae 4844// Notification on battery class IOPowerSource appearance
b0d623f7 4845//******************************************************************************
1c79356b 4846
6d2010ae
A
4847bool IOPMrootDomain::batteryPublished(
4848 void * target,
4849 void * root_domain,
4850 IOService * resourceService,
4851 IONotifier * notifier __unused )
4852{
4853 // rdar://2936060&4435589
4854 // All laptops have dimmable LCD displays
4855 // All laptops have batteries
4856 // So if this machine has a battery, publish the fact that the backlight
4857 // supports dimming.
4858 ((IOPMrootDomain *)root_domain)->publishFeature("DisplayDims");
b0d623f7 4859
6d2010ae
A
4860 return (true);
4861}
b0d623f7 4862
6d2010ae
A
4863// MARK: -
4864// MARK: System PM Policy
0c530ab8 4865
6d2010ae
A
4866//******************************************************************************
4867// checkSystemCanSleep
4868//
4869//******************************************************************************
0b4c1975 4870
6d2010ae
A
4871bool IOPMrootDomain::checkSystemCanSleep( IOOptionBits options )
4872{
4873 int err = 0;
b0d623f7 4874
6d2010ae 4875 // Conditions that prevent idle and demand system sleep.
b0d623f7 4876
6d2010ae
A
4877 do {
4878 if (userDisabledAllSleep)
4879 {
4880 err = 1; // 1. user-space sleep kill switch
4881 break;
4882 }
b0d623f7 4883
6d2010ae
A
4884 if (systemBooting || systemShutdown)
4885 {
4886 err = 2; // 2. restart or shutdown in progress
4887 break;
4888 }
b0d623f7 4889
6d2010ae
A
4890 if (options == 0)
4891 break;
0b4c1975 4892
6d2010ae
A
4893 // Conditions above pegs the system at full wake.
4894 // Conditions below prevent system sleep but does not prevent
4895 // dark wake, and must be called from gated context.
b0d623f7 4896
6d2010ae
A
4897#if !CONFIG_SLEEP
4898 err = 3; // 3. config does not support sleep
4899 break;
b0d623f7 4900#endif
b0d623f7 4901
6d2010ae
A
4902 if (lowBatteryCondition)
4903 {
4904 break; // always sleep on low battery
4905 }
b0d623f7 4906
6d2010ae
A
4907 if (childPreventSystemSleep)
4908 {
4909 err = 4; // 4. child prevent system sleep clamp
b0d623f7 4910 break;
6d2010ae 4911 }
1c79356b 4912
6d2010ae
A
4913 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit ) ==
4914 kIOPMDriverAssertionLevelOn)
4915 {
4916 err = 5; // 5. CPU assertion
4917 break;
4918 }
1c79356b 4919
6d2010ae
A
4920 if (pciCantSleepValid)
4921 {
4922 if (pciCantSleepFlag)
4923 err = 6; // 6. PCI card does not support PM (cached)
4924 break;
4925 }
4926 else if (sleepSupportedPEFunction &&
4927 CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
4928 {
4929 IOReturn ret;
4930 OSBitAndAtomic(~kPCICantSleep, &platformSleepSupport);
4931 ret = getPlatform()->callPlatformFunction(
4932 sleepSupportedPEFunction, false,
4933 NULL, NULL, NULL, NULL);
4934 pciCantSleepValid = true;
4935 pciCantSleepFlag = false;
4936 if ((platformSleepSupport & kPCICantSleep) ||
4937 ((ret != kIOReturnSuccess) && (ret != kIOReturnUnsupported)))
4938 {
4939 err = 6; // 6. PCI card does not support PM
4940 pciCantSleepFlag = true;
4941 break;
4942 }
4943 }
4944 }
4945 while (false);
b0d623f7 4946
6d2010ae
A
4947 if (err)
4948 {
4949 DLOG("System sleep prevented by %d\n", err);
4950 return false;
4951 }
4952 return true;
1c79356b
A
4953}
4954
b0d623f7 4955//******************************************************************************
6d2010ae 4956// adjustPowerState
0b4e3aa0 4957//
6d2010ae
A
4958// Conditions that affect our wake/sleep decision has changed.
4959// If conditions dictate that the system must remain awake, clamp power
4960// state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
4961// is TRUE, then remove the power clamp and allow the power state to drop
4962// to SLEEP_STATE.
b0d623f7 4963//******************************************************************************
1c79356b 4964
6d2010ae 4965void IOPMrootDomain::adjustPowerState( bool sleepASAP )
1c79356b 4966{
6d2010ae
A
4967 DLOG("adjustPowerState ps %u, asap %d, slider %ld\n",
4968 (uint32_t) getPowerState(), sleepASAP, sleepSlider);
b0d623f7 4969
6d2010ae 4970 ASSERT_GATED();
b0d623f7 4971
6d2010ae 4972 if ((sleepSlider == 0) || !checkSystemCanSleep())
2d21ac55 4973 {
6d2010ae
A
4974 changePowerStateToPriv(ON_STATE);
4975 }
4976 else if ( sleepASAP )
4977 {
4978 changePowerStateToPriv(SLEEP_STATE);
2d21ac55 4979 }
1c79356b
A
4980}
4981
b0d623f7 4982//******************************************************************************
6d2010ae 4983// dispatchPowerEvent
1c79356b 4984//
6d2010ae 4985// IOPMPowerStateQueue callback function. Running on PM work loop thread.
b0d623f7 4986//******************************************************************************
1c79356b 4987
6d2010ae
A
4988void IOPMrootDomain::dispatchPowerEvent(
4989 uint32_t event, void * arg0, uint64_t arg1 )
1c79356b 4990{
6d2010ae
A
4991 DLOG("power event %u args %p 0x%llx\n", event, arg0, arg1);
4992 ASSERT_GATED();
b0d623f7 4993
6d2010ae 4994 switch (event)
55e303ae 4995 {
6d2010ae
A
4996 case kPowerEventFeatureChanged:
4997 messageClients(kIOPMMessageFeatureChange, this);
4998 break;
0b4c1975 4999
6d2010ae
A
5000 case kPowerEventReceivedPowerNotification:
5001 handlePowerNotification( (UInt32)(uintptr_t) arg0 );
5002 break;
5003
5004 case kPowerEventSystemBootCompleted:
5005 if (systemBooting)
b0d623f7 5006 {
6d2010ae 5007 systemBooting = false;
b0d623f7 5008
6d2010ae
A
5009 // If lid is closed, re-send lid closed notification
5010 // now that booting is complete.
5011 if ( clamshellClosed )
5012 {
5013 handlePowerNotification(kLocalEvalClamshellCommand);
5014 }
5015 evaluatePolicy( kStimulusAllowSystemSleepChanged );
5016 }
5017 break;
b0d623f7 5018
6d2010ae
A
5019 case kPowerEventSystemShutdown:
5020 if (kOSBooleanTrue == (OSBoolean *) arg0)
5021 {
5022 /* We set systemShutdown = true during shutdown
5023 to prevent sleep at unexpected times while loginwindow is trying
5024 to shutdown apps and while the OS is trying to transition to
5025 complete power of.
5026
5027 Set to true during shutdown, as soon as loginwindow shows
5028 the "shutdown countdown dialog", through individual app
5029 termination, and through black screen kernel shutdown.
5030 */
5031 systemShutdown = true;
5032 } else {
5033 /*
5034 A shutdown was initiated, but then the shutdown
5035 was cancelled, clearing systemShutdown to false here.
5036 */
5037 systemShutdown = false;
5038 }
5039 break;
1c79356b 5040
6d2010ae
A
5041 case kPowerEventUserDisabledSleep:
5042 userDisabledAllSleep = (kOSBooleanTrue == (OSBoolean *) arg0);
5043 break;
b0d623f7 5044
6d2010ae
A
5045 case kPowerEventRegisterSystemCapabilityClient:
5046 if (systemCapabilityNotifier)
5047 {
5048 systemCapabilityNotifier->release();
5049 systemCapabilityNotifier = 0;
5050 }
5051 if (arg0)
5052 {
5053 systemCapabilityNotifier = (IONotifier *) arg0;
5054 systemCapabilityNotifier->retain();
5055 }
5056 /* intentional fall-through */
0b4e3aa0 5057
6d2010ae
A
5058 case kPowerEventRegisterKernelCapabilityClient:
5059 if (!_joinedCapabilityClients)
5060 _joinedCapabilityClients = OSSet::withCapacity(8);
5061 if (arg0)
5062 {
5063 IONotifier * notify = (IONotifier *) arg0;
5064 if (_joinedCapabilityClients)
5065 {
5066 _joinedCapabilityClients->setObject(notify);
5067 synchronizePowerTree( kIOPMSyncNoChildNotify );
5068 }
5069 notify->release();
5070 }
5071 break;
1c79356b 5072
6d2010ae
A
5073 case kPowerEventPolicyStimulus:
5074 if (arg0)
5075 {
5076 int stimulus = (uintptr_t) arg0;
5077 evaluatePolicy( stimulus, (uint32_t) arg1 );
5078 }
5079 break;
0b4e3aa0 5080
6d2010ae
A
5081 case kPowerEventAssertionCreate:
5082 if (pmAssertions) {
5083 pmAssertions->handleCreateAssertion((OSData *)arg0);
5084 }
5085 break;
0b4e3aa0 5086
b0d623f7 5087
6d2010ae
A
5088 case kPowerEventAssertionRelease:
5089 if (pmAssertions) {
5090 pmAssertions->handleReleaseAssertion(arg1);
5091 }
5092 break;
0b4e3aa0 5093
6d2010ae
A
5094 case kPowerEventAssertionSetLevel:
5095 if (pmAssertions) {
5096 pmAssertions->handleSetAssertionLevel(arg1, (IOPMDriverAssertionLevel)(uintptr_t)arg0);
5097 }
5098 break;
5099
5100 case kPowerEventQueueSleepWakeUUID:
5101 handleQueueSleepWakeUUID((OSObject *)arg0);
5102 break;
5103 case kPowerEventPublishSleepWakeUUID:
5104 handlePublishSleepWakeUUID((bool)arg0);
5105 break;
5106 }
0b4e3aa0
A
5107}
5108
b0d623f7 5109//******************************************************************************
6d2010ae
A
5110// systemPowerEventOccurred
5111//
5112// The power controller is notifying us of a hardware-related power management
5113// event that we must handle.
0b4e3aa0 5114//
6d2010ae
A
5115// systemPowerEventOccurred covers the same functionality that
5116// receivePowerNotification does; it simply provides a richer API for conveying
5117// more information.
b0d623f7
A
5118//******************************************************************************
5119
6d2010ae
A
5120IOReturn IOPMrootDomain::systemPowerEventOccurred(
5121 const OSSymbol *event,
5122 uint32_t intValue)
b0d623f7 5123{
6d2010ae
A
5124 IOReturn attempt = kIOReturnSuccess;
5125 OSNumber *newNumber = NULL;
5126
5127 if (!event)
5128 return kIOReturnBadArgument;
5129
5130 newNumber = OSNumber::withNumber(intValue, 8*sizeof(intValue));
5131 if (!newNumber)
5132 return kIOReturnInternalError;
b0d623f7 5133
6d2010ae 5134 attempt = systemPowerEventOccurred(event, (OSObject *)newNumber);
b0d623f7 5135
6d2010ae 5136 newNumber->release();
b0d623f7 5137
6d2010ae 5138 return attempt;
b0d623f7
A
5139}
5140
6d2010ae
A
5141IOReturn IOPMrootDomain::systemPowerEventOccurred(
5142 const OSSymbol *event,
5143 OSObject *value)
b0d623f7 5144{
6d2010ae
A
5145 OSDictionary *thermalsDict = NULL;
5146 bool shouldUpdate = true;
5147
5148 if (!event || !value)
5149 return kIOReturnBadArgument;
b0d623f7 5150
6d2010ae
A
5151 // LOCK
5152 // We reuse featuresDict Lock because it already exists and guards
5153 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
5154 // of stepping on that lock.
5155 if (featuresDictLock) IOLockLock(featuresDictLock);
b0d623f7 5156
6d2010ae
A
5157 thermalsDict = (OSDictionary *)getProperty(kIOPMRootDomainPowerStatusKey);
5158
5159 if (thermalsDict && OSDynamicCast(OSDictionary, thermalsDict)) {
5160 thermalsDict = OSDictionary::withDictionary(thermalsDict);
5161 } else {
5162 thermalsDict = OSDictionary::withCapacity(1);
5163 }
b0d623f7 5164
6d2010ae
A
5165 if (!thermalsDict) {
5166 shouldUpdate = false;
5167 goto exit;
b0d623f7
A
5168 }
5169
6d2010ae 5170 thermalsDict->setObject (event, value);
b0d623f7 5171
6d2010ae 5172 setProperty (kIOPMRootDomainPowerStatusKey, thermalsDict);
0b4c1975 5173
6d2010ae 5174 thermalsDict->release();
0b4c1975 5175
6d2010ae
A
5176exit:
5177 // UNLOCK
5178 if (featuresDictLock) IOLockUnlock(featuresDictLock);
0b4c1975 5179
6d2010ae
A
5180 if (shouldUpdate)
5181 messageClients (kIOPMMessageSystemPowerEventOccurred, (void *)NULL);
0b4c1975 5182
6d2010ae 5183 return kIOReturnSuccess;
0b4c1975 5184}
b0d623f7
A
5185
5186//******************************************************************************
6d2010ae 5187// receivePowerNotification
b0d623f7 5188//
6d2010ae
A
5189// The power controller is notifying us of a hardware-related power management
5190// event that we must handle. This may be a result of an 'environment' interrupt
5191// from the power mgt micro.
b0d623f7
A
5192//******************************************************************************
5193
6d2010ae 5194IOReturn IOPMrootDomain::receivePowerNotification( UInt32 msg )
b0d623f7 5195{
6d2010ae
A
5196 pmPowerStateQueue->submitPowerEvent(
5197 kPowerEventReceivedPowerNotification, (void *) msg );
5198 return kIOReturnSuccess;
b0d623f7
A
5199}
5200
6d2010ae
A
5201void IOPMrootDomain::handlePowerNotification( UInt32 msg )
5202{
5203 bool eval_clamshell = false;
b0d623f7 5204
6d2010ae 5205 ASSERT_GATED();
b0d623f7 5206
6d2010ae
A
5207 /*
5208 * Local (IOPMrootDomain only) eval clamshell command
5209 */
5210 if (msg & kLocalEvalClamshellCommand)
5211 {
5212 eval_clamshell = true;
5213 }
b0d623f7 5214
6d2010ae
A
5215 /*
5216 * Overtemp
5217 */
5218 if (msg & kIOPMOverTemp)
b0d623f7 5219 {
6d2010ae
A
5220 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
5221 privateSleepSystem (kIOPMSleepReasonThermalEmergency);
b0d623f7
A
5222 }
5223
6d2010ae
A
5224 /*
5225 * Sleep Now!
5226 */
5227 if (msg & kIOPMSleepNow)
b0d623f7 5228 {
6d2010ae
A
5229 privateSleepSystem (kIOPMSleepReasonSoftware);
5230 }
5231
5232 /*
5233 * Power Emergency
5234 */
5235 if (msg & kIOPMPowerEmergency)
5236 {
5237 lowBatteryCondition = true;
5238 privateSleepSystem (kIOPMSleepReasonLowPower);
b0d623f7
A
5239 }
5240
6d2010ae
A
5241 /*
5242 * Clamshell OPEN
5243 */
5244 if (msg & kIOPMClamshellOpened)
b0d623f7 5245 {
6d2010ae
A
5246 // Received clamshel open message from clamshell controlling driver
5247 // Update our internal state and tell general interest clients
5248 clamshellClosed = false;
5249 clamshellExists = true;
5250
5251 if (msg & kIOPMSetValue)
b0d623f7 5252 {
6d2010ae
A
5253 reportUserInput();
5254 }
b0d623f7 5255
6d2010ae
A
5256 // Tell PMCPU
5257 informCPUStateChange(kInformLid, 0);
b0d623f7 5258
6d2010ae
A
5259 // Tell general interest clients
5260 sendClientClamshellNotification();
b0d623f7 5261
6d2010ae
A
5262 bool aborting = ((lastSleepReason == kIOPMSleepReasonClamshell)
5263 || (lastSleepReason == kIOPMSleepReasonIdle)
0b4c1975
A
5264 || (lastSleepReason == kIOPMSleepReasonMaintenance));
5265 if (aborting) userActivityCount++;
6d2010ae
A
5266 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount, lastSleepReason);
5267 }
b0d623f7 5268
6d2010ae
A
5269 /*
5270 * Clamshell CLOSED
5271 * Send the clamshell interest notification since the lid is closing.
5272 */
5273 if (msg & kIOPMClamshellClosed)
b0d623f7 5274 {
6d2010ae
A
5275 // Received clamshel open message from clamshell controlling driver
5276 // Update our internal state and tell general interest clients
5277 clamshellClosed = true;
5278 clamshellExists = true;
b0d623f7 5279
6d2010ae
A
5280 // Tell PMCPU
5281 informCPUStateChange(kInformLid, 1);
b0d623f7 5282
6d2010ae
A
5283 // Tell general interest clients
5284 sendClientClamshellNotification();
5285
5286 // And set eval_clamshell = so we can attempt
5287 eval_clamshell = true;
5288 }
b0d623f7 5289
6d2010ae
A
5290 /*
5291 * Set Desktop mode (sent from graphics)
5292 *
5293 * -> reevaluate lid state
5294 */
5295 if (msg & kIOPMSetDesktopMode)
5296 {
5297 desktopMode = (0 != (msg & kIOPMSetValue));
5298 msg &= ~(kIOPMSetDesktopMode | kIOPMSetValue);
b0d623f7 5299
6d2010ae 5300 sendClientClamshellNotification();
b0d623f7 5301
6d2010ae
A
5302 // Re-evaluate the lid state
5303 if( clamshellClosed )
b0d623f7 5304 {
6d2010ae 5305 eval_clamshell = true;
b0d623f7 5306 }
6d2010ae
A
5307 }
5308
5309 /*
5310 * AC Adaptor connected
5311 *
5312 * -> reevaluate lid state
5313 */
5314 if (msg & kIOPMSetACAdaptorConnected)
5315 {
5316 acAdaptorConnected = (0 != (msg & kIOPMSetValue));
5317 msg &= ~(kIOPMSetACAdaptorConnected | kIOPMSetValue);
b0d623f7 5318
6d2010ae
A
5319 // Tell CPU PM
5320 informCPUStateChange(kInformAC, !acAdaptorConnected);
b0d623f7 5321
6d2010ae
A
5322 // Tell BSD if AC is connected
5323 // 0 == external power source; 1 == on battery
5324 post_sys_powersource(acAdaptorConnected ? 0:1);
b0d623f7 5325
6d2010ae
A
5326 sendClientClamshellNotification();
5327
5328 // Re-evaluate the lid state
5329 if( clamshellClosed )
d1ecb069 5330 {
6d2010ae 5331 eval_clamshell = true;
d1ecb069 5332 }
b0d623f7
A
5333 }
5334
6d2010ae
A
5335 /*
5336 * Enable Clamshell (external display disappear)
5337 *
5338 * -> reevaluate lid state
5339 */
5340 if (msg & kIOPMEnableClamshell)
b0d623f7 5341 {
6d2010ae
A
5342 // Re-evaluate the lid state
5343 // System should sleep on external display disappearance
5344 // in lid closed operation.
5345 if( clamshellClosed && (true == clamshellDisabled) )
5346 {
5347 eval_clamshell = true;
5348 }
b0d623f7 5349
6d2010ae 5350 clamshellDisabled = false;
b0d623f7 5351
6d2010ae 5352 sendClientClamshellNotification();
b0d623f7 5353 }
6d2010ae
A
5354
5355 /*
5356 * Disable Clamshell (external display appeared)
5357 * We don't bother re-evaluating clamshell state. If the system is awake,
5358 * the lid is probably open.
5359 */
5360 if (msg & kIOPMDisableClamshell)
5361 {
5362 clamshellDisabled = true;
b0d623f7 5363
6d2010ae
A
5364 sendClientClamshellNotification();
5365 }
b0d623f7 5366
6d2010ae
A
5367 /*
5368 * Evaluate clamshell and SLEEP if appropiate
5369 */
5370 if ( eval_clamshell && shouldSleepOnClamshellClosed() )
b0d623f7 5371 {
b0d623f7 5372
b0d623f7 5373
6d2010ae
A
5374 // SLEEP!
5375 privateSleepSystem (kIOPMSleepReasonClamshell);
b0d623f7 5376 }
6d2010ae 5377 else if ( eval_clamshell )
b0d623f7 5378 {
6d2010ae
A
5379 evaluatePolicy(kStimulusDarkWakeEvaluate);
5380 }
b0d623f7 5381
6d2010ae
A
5382 /*
5383 * Power Button
5384 */
5385 if (msg & kIOPMPowerButton)
5386 {
5387 if (!wranglerAsleep)
b0d623f7 5388 {
6d2010ae
A
5389 OSString *pbs = OSString::withCString("DisablePowerButtonSleep");
5390 // Check that power button sleep is enabled
5391 if( pbs ) {
5392 if( kOSBooleanTrue != getProperty(pbs))
5393 privateSleepSystem (kIOPMSleepReasonPowerButton);
b0d623f7
A
5394 }
5395 }
5396 else
6d2010ae 5397 reportUserInput();
b0d623f7 5398 }
0b4e3aa0
A
5399}
5400
b0d623f7 5401//******************************************************************************
6d2010ae 5402// evaluatePolicy
0b4e3aa0 5403//
6d2010ae 5404// Evaluate root-domain policy in response to external changes.
b0d623f7 5405//******************************************************************************
0b4e3aa0 5406
6d2010ae 5407void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
0b4e3aa0 5408{
6d2010ae
A
5409 union {
5410 struct {
5411 int idleSleepEnabled : 1;
5412 int idleSleepDisabled : 1;
5413 int displaySleep : 1;
5414 int sleepDelayChanged : 1;
5415 int evaluateDarkWake : 1;
5416 } bit;
5417 uint32_t u32;
5418 } flags;
5419
5420 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
fa4905b1 5421
6d2010ae
A
5422 ASSERT_GATED();
5423 flags.u32 = 0;
b0d623f7 5424
6d2010ae 5425 switch (stimulus)
b0d623f7 5426 {
6d2010ae
A
5427 case kStimulusDisplayWranglerSleep:
5428 if (!wranglerAsleep)
b0d623f7 5429 {
6d2010ae
A
5430 wranglerAsleep = true;
5431 clock_get_uptime(&wranglerSleepTime);
5432 flags.bit.displaySleep = true;
b0d623f7 5433 }
6d2010ae 5434 break;
b0d623f7 5435
6d2010ae
A
5436 case kStimulusDisplayWranglerWake:
5437 wranglerAsleep = false;
5438 flags.bit.idleSleepDisabled = true;
5439 break;
0b4e3aa0 5440
6d2010ae
A
5441 case kStimulusAggressivenessChanged:
5442 {
5443 unsigned long minutesToIdleSleep = 0;
5444 unsigned long minutesToDisplayDim = 0;
5445 unsigned long minutesDelta = 0;
0b4e3aa0 5446
6d2010ae
A
5447 // Fetch latest display and system sleep slider values.
5448 getAggressiveness(kPMMinutesToSleep, &minutesToIdleSleep);
5449 getAggressiveness(kPMMinutesToDim, &minutesToDisplayDim);
5450 DLOG("aggressiveness changed: system %u->%u, display %u\n",
5451 (uint32_t) sleepSlider,
5452 (uint32_t) minutesToIdleSleep,
5453 (uint32_t) minutesToDisplayDim);
b0d623f7 5454
6d2010ae
A
5455 DLOG("idle time -> %ld secs (ena %d)\n",
5456 idleSeconds, (minutesToIdleSleep != 0));
2d21ac55 5457
6d2010ae
A
5458 if (0x7fffffff == minutesToIdleSleep)
5459 minutesToIdleSleep = idleSeconds;
b0d623f7 5460
6d2010ae
A
5461 // How long to wait before sleeping the system once
5462 // the displays turns off is indicated by 'extraSleepDelay'.
b0d623f7 5463
6d2010ae
A
5464 if ( minutesToIdleSleep > minutesToDisplayDim )
5465 minutesDelta = minutesToIdleSleep - minutesToDisplayDim;
2d21ac55 5466
6d2010ae
A
5467 if ((sleepSlider == 0) && (minutesToIdleSleep != 0))
5468 flags.bit.idleSleepEnabled = true;
2d21ac55 5469
6d2010ae
A
5470 if ((sleepSlider != 0) && (minutesToIdleSleep == 0))
5471 flags.bit.idleSleepDisabled = true;
5472
5473 if ((minutesDelta != extraSleepDelay) &&
5474 !flags.bit.idleSleepEnabled && !flags.bit.idleSleepDisabled)
5475 flags.bit.sleepDelayChanged = true;
2d21ac55 5476
6d2010ae
A
5477 if (systemDarkWake && !darkWakeToSleepASAP &&
5478 (flags.bit.idleSleepEnabled || flags.bit.idleSleepDisabled))
b0d623f7 5479 {
6d2010ae
A
5480 // Reconsider decision to remain in dark wake
5481 flags.bit.evaluateDarkWake = true;
b0d623f7 5482 }
2d21ac55 5483
6d2010ae
A
5484 sleepSlider = minutesToIdleSleep;
5485 extraSleepDelay = minutesDelta;
5486 } break;
0b4e3aa0 5487
6d2010ae
A
5488 case kStimulusDemandSystemSleep:
5489 changePowerStateWithOverrideTo( SLEEP_STATE );
2d21ac55 5490 break;
0b4e3aa0 5491
6d2010ae
A
5492 case kStimulusAllowSystemSleepChanged:
5493 // FIXME: de-compose to change flags.
5494 adjustPowerState();
5495 break;
2d21ac55 5496
6d2010ae
A
5497 case kStimulusDarkWakeActivityTickle:
5498 if (false == wranglerTickled)
5499 {
5500 uint32_t options = 0;
5501 IOService * pciRoot = 0;
0b4e3aa0 5502
6d2010ae
A
5503 if (rejectWranglerTickle)
5504 {
5505 DLOG("rejected tickle, type %u capability %x:%x\n",
5506 _systemTransitionType,
5507 _currentCapability, _pendingCapability);
5508 break;
5509 }
5510
5511 _desiredCapability |=
5512 (kIOPMSystemCapabilityGraphics |
5513 kIOPMSystemCapabilityAudio);
5514
5515 if ((kSystemTransitionWake == _systemTransitionType) &&
5516 !(_pendingCapability & kIOPMSystemCapabilityGraphics) &&
5517 !graphicsSuppressed)
5518 {
5519 DLOG("Promoting to full wake\n");
5520
5521 // Elevate to full wake while waking up to dark wake.
5522 // PM will hold off notifying the graphics subsystem about
5523 // system wake as late as possible, so if a HID event does
5524 // arrive, we can turn on graphics on this wake cycle, and
5525 // not have to wait till the following cycle. That latency
5526 // can be huge on some systems. However, once any graphics
5527 // suppression has taken effect, it is too late. All other
5528 // graphics devices must be similarly suppressed. But the
5529 // delay till the following cycle should be very short.
5530
5531 _pendingCapability |=
5532 (kIOPMSystemCapabilityGraphics |
5533 kIOPMSystemCapabilityAudio);
5534
5535 // Immediately bring up audio and graphics.
5536 pciRoot = pciHostBridgeDriver;
5537
5538 // Notify clients about full wake.
5539 _systemMessageClientMask = kSystemMessageClientAll;
5540 tellClients(kIOMessageSystemWillPowerOn);
5541 }
0b4e3aa0 5542
6d2010ae
A
5543 // Unsafe to cancel once graphics was powered.
5544 // If system woke from dark wake, the return to sleep can
5545 // be cancelled. But "awake -> dark -> sleep" transition
5546 // cannot be cancelled.
5547
5548 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics)) {
5549 options |= kIOPMSyncCancelPowerDown;
5550 }
0b4e3aa0 5551
6d2010ae
A
5552 synchronizePowerTree( options, pciRoot );
5553 wranglerTickled = true;
5554 // IOGraphics doesn't lit the display even though graphics
5555 // is enanbled in kIOMessageSystemCapabilityChange message(radar 9502104)
5556 // So, do an explicit activity tickle
5557 if(wrangler)
5558 wrangler->activityTickle(0,0);
0b4e3aa0 5559
6d2010ae
A
5560 if (logWranglerTickle)
5561 {
5562 AbsoluteTime now;
5563 uint64_t nsec;
5564
5565 clock_get_uptime(&now);
5566 SUB_ABSOLUTETIME(&now, &systemWakeTime);
5567 absolutetime_to_nanoseconds(now, &nsec);
5568 MSG("HID tickle %u ms\n",
5569 ((int)((nsec) / 1000000ULL)));
5570 logWranglerTickle = false;
5571 }
5572 }
0b4e3aa0
A
5573 break;
5574
6d2010ae
A
5575 case kStimulusDarkWakeEntry:
5576 case kStimulusDarkWakeReentry:
5577 // Any system transitions since the last dark wake transition
5578 // will invalid the stimulus.
0b4e3aa0 5579
6d2010ae
A
5580 if (arg == _systemStateGeneration)
5581 {
5582 DLOG("dark wake entry\n");
5583 systemDarkWake = true;
5584 wranglerAsleep = true;
5585 clock_get_uptime(&wranglerSleepTime);
0b4e3aa0 5586
6d2010ae
A
5587 // Always accelerate disk spindown while in dark wake,
5588 // even if system does not support/allow sleep.
0b4e3aa0 5589
6d2010ae
A
5590 cancelIdleSleepTimer();
5591 setQuickSpinDownTimeout();
5592 flags.bit.evaluateDarkWake = true;
5593 }
5594 break;
b0d623f7 5595
6d2010ae
A
5596 case kStimulusDarkWakeEvaluate:
5597 if (systemDarkWake)
5598 {
5599 flags.bit.evaluateDarkWake = true;
5600 }
5601#if !DARK_TO_FULL_EVALUATE_CLAMSHELL
5602 else
5603 {
5604 // Not through kLocalEvalClamshellCommand to avoid loop.
5605 if (clamshellClosed && shouldSleepOnClamshellClosed() &&
5606 checkSystemCanSleep(true))
5607 {
5608 privateSleepSystem( kIOPMSleepReasonClamshell );
5609 }
5610 }
2d21ac55 5611#endif
6d2010ae 5612 break;
1c79356b 5613
6d2010ae 5614 } /* switch(stimulus) */
b0d623f7 5615
6d2010ae
A
5616 if (flags.bit.evaluateDarkWake && !wranglerTickled)
5617 {
5618 if (darkWakeToSleepASAP ||
5619 (clamshellClosed && !(desktopMode && acAdaptorConnected)))
5620 {
5621 // System currently in dark wake, and no children and
5622 // assertion prevent system sleep.
0c530ab8 5623
6d2010ae
A
5624 if (checkSystemCanSleep(true))
5625 {
5626 if (lowBatteryCondition)
5627 {
5628 lastSleepReason = kIOPMSleepReasonLowPower;
5629 setProperty(kRootDomainSleepReasonKey, kIOPMLowPowerSleepKey);
5630 }
5631 else if (darkWakeMaintenance)
5632 {
5633 lastSleepReason = kIOPMSleepReasonMaintenance;
5634 setProperty(kRootDomainSleepReasonKey, kIOPMMaintenanceSleepKey);
5635 }
5636 changePowerStateWithOverrideTo( SLEEP_STATE );
5637 }
5638 else
5639 {
5640 // Parked in dark wake, a tickle will return to full wake
5641 rejectWranglerTickle = false;
5642 }
5643 } else // non-maintenance (network) dark wake
5644 {
5645 if (checkSystemCanSleep(true))
5646 {
5647 // Release power clamp, and wait for children idle.
5648 adjustPowerState(true);
5649 }
5650 else
5651 {
5652 changePowerStateToPriv(ON_STATE);
5653 }
5654 rejectWranglerTickle = false;
5655 }
5656 }
0c530ab8 5657
6d2010ae
A
5658 if (systemDarkWake)
5659 {
5660 // The rest are irrelevant while system is in dark wake.
5661 flags.u32 = 0;
5662 }
483a1d10 5663
6d2010ae
A
5664 if (flags.bit.displaySleep || flags.bit.sleepDelayChanged)
5665 {
5666 bool cancelQuickSpindown = false;
b0d623f7 5667
6d2010ae
A
5668 if (flags.bit.sleepDelayChanged)
5669 {
5670 DLOG("extra sleep timer changed\n");
5671 cancelIdleSleepTimer();
5672 cancelQuickSpindown = true;
5673 }
5674 else
5675 {
5676 DLOG("display sleep\n");
5677 }
0b4e3aa0 5678
6d2010ae
A
5679 if (wranglerAsleep && !wranglerSleepIgnored)
5680 {
5681 if ( extraSleepDelay )
5682 {
5683 // Start a timer here if the System Sleep timer is greater
5684 // than the Display Sleep timer.
b0d623f7 5685
6d2010ae
A
5686 startIdleSleepTimer(gRootDomain->extraSleepDelay * 60);
5687 }
5688 else if ( sleepSlider )
5689 {
5690 // Accelerate disk spindown if system sleep and display sleep
5691 // sliders are set to the same value (e.g. both set to 5 min),
5692 // and display is about to go dark. Check the system sleep is
5693 // not set to never sleep. Disk sleep setting is ignored.
5694
5695 setQuickSpinDownTimeout();
5696 cancelQuickSpindown = false;
5697 }
5698 }
5699
5700 if (cancelQuickSpindown)
5701 restoreUserSpinDownTimeout();
5702 }
b0d623f7 5703
6d2010ae 5704 if (flags.bit.idleSleepEnabled)
0c530ab8 5705 {
6d2010ae
A
5706 DLOG("idle sleep timer enabled\n");
5707 if (!wrangler)
55e303ae 5708 {
6d2010ae
A
5709 changePowerStateToPriv(ON_STATE);
5710 if (idleSeconds)
5711 {
5712 startIdleSleepTimer( idleSeconds );
5713 }
5714 }
5715 else
5716 {
5717 // Start idle sleep timer if wrangler went to sleep
5718 // while system sleep was disabled. Disk spindown is
5719 // accelerated upon timer expiration.
5720
5721 if (wranglerAsleep)
5722 {
5723 AbsoluteTime now;
5724 uint64_t nanos;
5725 uint32_t minutesSinceDisplaySleep = 0;
5726 uint32_t sleepDelay;
5727
5728 clock_get_uptime(&now);
5729 if (CMP_ABSOLUTETIME(&now, &wranglerSleepTime) > 0)
5730 {
5731 SUB_ABSOLUTETIME(&now, &wranglerSleepTime);
5732 absolutetime_to_nanoseconds(now, &nanos);
5733 minutesSinceDisplaySleep = nanos / (60000000000ULL);
5734 }
5735
5736 if (extraSleepDelay > minutesSinceDisplaySleep)
5737 {
5738 sleepDelay = extraSleepDelay - minutesSinceDisplaySleep;
5739 }
5740 else
5741 {
5742 sleepDelay = 1; // 1 min
5743 }
b0d623f7 5744
6d2010ae
A
5745 startIdleSleepTimer(sleepDelay * 60);
5746 DLOG("display slept %u min, set idle timer to %u min\n",
5747 minutesSinceDisplaySleep, sleepDelay);
5748 }
0c530ab8
A
5749 }
5750 }
6d2010ae
A
5751
5752 if (flags.bit.idleSleepDisabled)
5753 {
5754 DLOG("idle sleep timer disabled\n");
5755 cancelIdleSleepTimer();
5756 restoreUserSpinDownTimeout();
5757 adjustPowerState();
5758 }
0c530ab8
A
5759}
5760
6d2010ae
A
5761// MARK: -
5762// MARK: Statistics
5763
5764//******************************************************************************
5765// pmStats
5766//
5767//******************************************************************************
5768
b0d623f7
A
5769void IOPMrootDomain::pmStatsRecordEvent(
5770 int eventIndex,
5771 AbsoluteTime timestamp)
5772{
5773 bool starting = eventIndex & kIOPMStatsEventStartFlag ? true:false;
5774 bool stopping = eventIndex & kIOPMStatsEventStopFlag ? true:false;
5775 uint64_t delta;
5776 uint64_t nsec;
5777
5778 eventIndex &= ~(kIOPMStatsEventStartFlag | kIOPMStatsEventStopFlag);
5779
5780 absolutetime_to_nanoseconds(timestamp, &nsec);
5781
5782 switch (eventIndex) {
5783 case kIOPMStatsHibernateImageWrite:
5784 if (starting)
5785 pmStats.hibWrite.start = nsec;
5786 else if (stopping)
5787 pmStats.hibWrite.stop = nsec;
5788
5789 if (stopping) {
5790 delta = pmStats.hibWrite.stop - pmStats.hibWrite.start;
5791 IOLog("PMStats: Hibernate write took %qd ms\n", delta/1000000ULL);
5792 }
5793 break;
5794 case kIOPMStatsHibernateImageRead:
5795 if (starting)
5796 pmStats.hibRead.start = nsec;
5797 else if (stopping)
5798 pmStats.hibRead.stop = nsec;
5799
5800 if (stopping) {
5801 delta = pmStats.hibRead.stop - pmStats.hibRead.start;
5802 IOLog("PMStats: Hibernate read took %qd ms\n", delta/1000000ULL);
5803 }
5804 break;
5805 }
5806}
5807
5808/*
5809 * Appends a record of the application response to
5810 * IOPMrootDomain::pmStatsAppResponses
5811 */
5812void IOPMrootDomain::pmStatsRecordApplicationResponse(
5813 const OSSymbol *response,
5814 const char *name,
5815 int messageType,
5816 uint32_t delay_ms,
5817 int app_pid)
5818{
5819 OSDictionary *responseDescription = NULL;
5820 OSNumber *delayNum = NULL;
5821 OSNumber *pidNum = NULL;
5822 OSNumber *msgNum = NULL;
5823 const OSSymbol *appname;
5824 const OSSymbol *entryName;
5825 OSObject *entryType;
5826 int i;
5827
5828 if (!pmStatsAppResponses || pmStatsAppResponses->getCount() > 50)
5829 return;
5830
5831 i = 0;
5832 while ((responseDescription = (OSDictionary *) pmStatsAppResponses->getObject(i++)))
5833 {
5834 entryType = responseDescription->getObject(_statsResponseTypeKey);
5835 entryName = (OSSymbol *) responseDescription->getObject(_statsNameKey);
5836 if (entryName && (entryType == response) && entryName->isEqualTo(name))
5837 {
5838 OSNumber * entryValue;
5839 entryValue = (OSNumber *) responseDescription->getObject(_statsTimeMSKey);
5840 if (entryValue && (entryValue->unsigned32BitValue() < delay_ms))
5841 entryValue->setValue(delay_ms);
5842 return;
5843 }
5844 }
5845
5846 responseDescription = OSDictionary::withCapacity(5);
5847 if (responseDescription)
5848 {
5849 if (response) {
5850 responseDescription->setObject(_statsResponseTypeKey, response);
5851 }
5852
5853 if (messageType != 0) {
5854 msgNum = OSNumber::withNumber(messageType, 32);
5855 if (msgNum) {
5856 responseDescription->setObject(_statsMessageTypeKey, msgNum);
5857 msgNum->release();
5858 }
5859 }
5860
5861 if (name && (strlen(name) > 0))
5862 {
5863 appname = OSSymbol::withCString(name);
5864 if (appname) {
5865 responseDescription->setObject(_statsNameKey, appname);
5866 appname->release();
5867 }
5868 }
5869
5870 if (app_pid != -1) {
5871 pidNum = OSNumber::withNumber(app_pid, 32);
5872 if (pidNum) {
5873 responseDescription->setObject(_statsPIDKey, pidNum);
5874 pidNum->release();
5875 }
5876 }
5877
5878 delayNum = OSNumber::withNumber(delay_ms, 32);
5879 if (delayNum) {
5880 responseDescription->setObject(_statsTimeMSKey, delayNum);
5881 delayNum->release();
5882 }
5883
5884 if (pmStatsAppResponses) {
5885 pmStatsAppResponses->setObject(responseDescription);
5886 }
5887
5888 responseDescription->release();
5889 }
5890 return;
5891}
5892
6d2010ae
A
5893// MARK: -
5894// MARK: PMTraceWorker
b0d623f7
A
5895
5896//******************************************************************************
5897// TracePoint support
5898//
5899//******************************************************************************
5900
5901#define kIOPMRegisterNVRAMTracePointHandlerKey \
5902 "IOPMRegisterNVRAMTracePointHandler"
5903
5904IOReturn IOPMrootDomain::callPlatformFunction(
5905 const OSSymbol * functionName,
5906 bool waitForFunction,
5907 void * param1, void * param2,
5908 void * param3, void * param4 )
5909{
5910 if (pmTracer && functionName &&
5911 functionName->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey) &&
5912 !pmTracer->tracePointHandler && !pmTracer->tracePointTarget)
5913 {
5914 uint32_t tracePointPhases, tracePointPCI;
5915 uint64_t statusCode;
5916
5917 pmTracer->tracePointHandler = (IOPMTracePointHandler) param1;
5918 pmTracer->tracePointTarget = (void *) param2;
5919 tracePointPCI = (uint32_t)(uintptr_t) param3;
5920 tracePointPhases = (uint32_t)(uintptr_t) param4;
5921 statusCode = (((uint64_t)tracePointPCI) << 32) | tracePointPhases;
5922 if ((tracePointPhases >> 24) != kIOPMTracePointSystemUp)
5923 {
6d2010ae 5924 MSG("Sleep failure code 0x%08x 0x%08x\n",
b0d623f7
A
5925 tracePointPCI, tracePointPhases);
5926 }
5927 setProperty(kIOPMSleepWakeFailureCodeKey, statusCode, 64);
5928 pmTracer->tracePointHandler( pmTracer->tracePointTarget, 0, 0 );
5929
5930 return kIOReturnSuccess;
5931 }
5932
5933 return super::callPlatformFunction(
5934 functionName, waitForFunction, param1, param2, param3, param4);
5935}
5936
5937void IOPMrootDomain::tracePoint( uint8_t point )
5938{
6d2010ae
A
5939 if (!systemBooting)
5940 pmTracer->tracePoint(point);
5941}
5942
5943void IOPMrootDomain::tracePoint( uint8_t point, uint8_t data )
5944{
5945 if (!systemBooting)
5946 pmTracer->tracePoint(point, data);
5947}
5948
5949void IOPMrootDomain::traceDetail( uint32_t detail )
5950{
5951 if (!systemBooting)
5952 pmTracer->traceDetail( detail );
b0d623f7
A
5953}
5954
5955//******************************************************************************
5956// PMTraceWorker Class
5957//
5958//******************************************************************************
5959
5960#undef super
5961#define super OSObject
5962OSDefineMetaClassAndStructors(PMTraceWorker, OSObject)
5963
5964#define kPMBestGuessPCIDevicesCount 25
5965#define kPMMaxRTCBitfieldSize 32
5966
5967PMTraceWorker *PMTraceWorker::tracer(IOPMrootDomain *owner)
5968{
5969 PMTraceWorker *me;
5970
5971 me = OSTypeAlloc( PMTraceWorker );
5972 if (!me || !me->init())
5973 {
5974 return NULL;
5975 }
5976
5977 DLOG("PMTraceWorker %p\n", me);
5978
5979 // Note that we cannot instantiate the PCI device -> bit mappings here, since
5980 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
5981 // this dictionary lazily.
5982 me->owner = owner;
5983 me->pciDeviceBitMappings = NULL;
5984 me->pciMappingLock = IOLockAlloc();
5985 me->tracePhase = kIOPMTracePointSystemUp;
5986 me->loginWindowPhase = 0;
6d2010ae 5987 me->traceData32 = 0;
b0d623f7
A
5988 return me;
5989}
5990
5991void PMTraceWorker::RTC_TRACE(void)
5992{
5993 if (tracePointHandler && tracePointTarget)
5994 {
5995 uint32_t wordA;
5996
6d2010ae
A
5997 wordA = (tracePhase << 24) | (loginWindowPhase << 16) |
5998 (traceData8 << 8);
b0d623f7 5999
6d2010ae
A
6000 tracePointHandler( tracePointTarget, traceData32, wordA );
6001 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32, wordA);
b0d623f7
A
6002 }
6003}
6004
6005int PMTraceWorker::recordTopLevelPCIDevice(IOService * pciDevice)
6006{
6007 const OSSymbol * deviceName;
6008 int index = -1;
6009
6010 IOLockLock(pciMappingLock);
6011
6012 if (!pciDeviceBitMappings)
6013 {
6014 pciDeviceBitMappings = OSArray::withCapacity(kPMBestGuessPCIDevicesCount);
6015 if (!pciDeviceBitMappings)
6016 goto exit;
6017 }
6018
6019 // Check for bitmask overflow.
6020 if (pciDeviceBitMappings->getCount() >= kPMMaxRTCBitfieldSize)
6021 goto exit;
6022
6023 if ((deviceName = pciDevice->copyName()) &&
6024 (pciDeviceBitMappings->getNextIndexOfObject(deviceName, 0) == (unsigned int)-1) &&
6025 pciDeviceBitMappings->setObject(deviceName))
6026 {
6027 index = pciDeviceBitMappings->getCount() - 1;
6d2010ae 6028 _LOG("PMTrace PCI array: set object %s => %d\n",
b0d623f7
A
6029 deviceName->getCStringNoCopy(), index);
6030 }
6031 if (deviceName)
6032 deviceName->release();
6033 if (!addedToRegistry && (index >= 0))
6034 addedToRegistry = owner->setProperty("PCITopLevel", this);
6035
6036exit:
6037 IOLockUnlock(pciMappingLock);
6038 return index;
6039}
6040
6041bool PMTraceWorker::serialize(OSSerialize *s) const
6042{
6043 bool ok = false;
6044 if (pciDeviceBitMappings)
6045 {
6046 IOLockLock(pciMappingLock);
6047 ok = pciDeviceBitMappings->serialize(s);
6048 IOLockUnlock(pciMappingLock);
6049 }
6050 return ok;
6051}
6052
6053void PMTraceWorker::tracePoint(uint8_t phase)
6054{
6d2010ae
A
6055 // clear trace detail when phase begins
6056 if (tracePhase != phase)
6057 traceData32 = 0;
6058
6059 tracePhase = phase;
6060
6061 DLOG("trace point 0x%02x\n", tracePhase);
6062 RTC_TRACE();
6063}
6064
6065void PMTraceWorker::tracePoint(uint8_t phase, uint8_t data8)
6066{
6067 // clear trace detail when phase begins
6068 if (tracePhase != phase)
6069 traceData32 = 0;
6070
b0d623f7 6071 tracePhase = phase;
6d2010ae
A
6072 traceData8 = data8;
6073
6074 DLOG("trace point 0x%02x 0x%02x\n", tracePhase, traceData8);
6075 RTC_TRACE();
6076}
6077
6078void PMTraceWorker::traceDetail(uint32_t detail)
6079{
6080 if (kIOPMTracePointSleepPriorityClients != tracePhase)
6081 return;
6082
6083 traceData32 = detail;
6084 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase, traceData32);
b0d623f7 6085
b0d623f7
A
6086 RTC_TRACE();
6087}
6088
6089void PMTraceWorker::traceLoginWindowPhase(uint8_t phase)
6090{
6091 loginWindowPhase = phase;
6092
6d2010ae 6093 DLOG("loginwindow tracepoint 0x%02x\n", loginWindowPhase);
b0d623f7
A
6094 RTC_TRACE();
6095}
6096
6097void PMTraceWorker::tracePCIPowerChange(
6098 change_t type, IOService *service, uint32_t changeFlags, uint32_t bitNum)
6099{
6100 uint32_t bitMask;
6101 uint32_t expectedFlag;
6102
6103 // Ignore PCI changes outside of system sleep/wake.
6d2010ae
A
6104 if ((kIOPMTracePointSleepPowerPlaneDrivers != tracePhase) &&
6105 (kIOPMTracePointWakePowerPlaneDrivers != tracePhase))
b0d623f7
A
6106 return;
6107
6108 // Only record the WillChange transition when going to sleep,
6109 // and the DidChange on the way up.
6110 changeFlags &= (kIOPMDomainWillChange | kIOPMDomainDidChange);
6d2010ae 6111 expectedFlag = (kIOPMTracePointSleepPowerPlaneDrivers == tracePhase) ?
b0d623f7
A
6112 kIOPMDomainWillChange : kIOPMDomainDidChange;
6113 if (changeFlags != expectedFlag)
6114 return;
6115
6116 // Mark this device off in our bitfield
6117 if (bitNum < kPMMaxRTCBitfieldSize)
6118 {
6119 bitMask = (1 << bitNum);
6120
6121 if (kPowerChangeStart == type)
6122 {
6d2010ae
A
6123 traceData32 |= bitMask;
6124 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
6125 service->getName(), bitNum, bitMask, traceData32);
b0d623f7
A
6126 }
6127 else
6128 {
6d2010ae
A
6129 traceData32 &= ~bitMask;
6130 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
6131 service->getName(), bitNum, bitMask, traceData32);
b0d623f7
A
6132 }
6133
6d2010ae 6134 RTC_TRACE();
b0d623f7
A
6135 }
6136}
6137
6d2010ae
A
6138// MARK: -
6139// MARK: PMHaltWorker
b0d623f7
A
6140
6141//******************************************************************************
2d21ac55
A
6142// PMHaltWorker Class
6143//
b0d623f7 6144//******************************************************************************
2d21ac55
A
6145
6146static unsigned int gPMHaltBusyCount;
6147static unsigned int gPMHaltIdleCount;
6148static int gPMHaltDepth;
6149static unsigned long gPMHaltEvent;
6150static IOLock * gPMHaltLock = 0;
6151static OSArray * gPMHaltArray = 0;
6152static const OSSymbol * gPMHaltClientAcknowledgeKey = 0;
6153
6154PMHaltWorker * PMHaltWorker::worker( void )
6155{
6156 PMHaltWorker * me;
6157 IOThread thread;
6158
6159 do {
6160 me = OSTypeAlloc( PMHaltWorker );
6161 if (!me || !me->init())
6162 break;
6163
6164 me->lock = IOLockAlloc();
6165 if (!me->lock)
6166 break;
6167
b0d623f7 6168 DLOG("PMHaltWorker %p\n", me);
2d21ac55 6169 me->retain(); // thread holds extra retain
b0d623f7 6170 if (KERN_SUCCESS != kernel_thread_start(&PMHaltWorker::main, (void *) me, &thread))
2d21ac55
A
6171 {
6172 me->release();
6173 break;
6174 }
b0d623f7 6175 thread_deallocate(thread);
2d21ac55
A
6176 return me;
6177
6178 } while (false);
6179
6180 if (me) me->release();
6181 return 0;
6182}
6183
6184void PMHaltWorker::free( void )
6185{
b0d623f7 6186 DLOG("PMHaltWorker free %p\n", this);
2d21ac55
A
6187 if (lock)
6188 {
6189 IOLockFree(lock);
6190 lock = 0;
6191 }
6192 return OSObject::free();
6193}
6194
b0d623f7 6195void PMHaltWorker::main( void * arg, wait_result_t waitResult )
2d21ac55
A
6196{
6197 PMHaltWorker * me = (PMHaltWorker *) arg;
6198
6199 IOLockLock( gPMHaltLock );
6200 gPMHaltBusyCount++;
6201 me->depth = gPMHaltDepth;
6202 IOLockUnlock( gPMHaltLock );
6203
6204 while (me->depth >= 0)
6205 {
6206 PMHaltWorker::work( me );
6207
6208 IOLockLock( gPMHaltLock );
6209 if (++gPMHaltIdleCount >= gPMHaltBusyCount)
6210 {
6211 // This is the last thread to finish work on this level,
6212 // inform everyone to start working on next lower level.
6213 gPMHaltDepth--;
6214 me->depth = gPMHaltDepth;
6215 gPMHaltIdleCount = 0;
6216 thread_wakeup((event_t) &gPMHaltIdleCount);
6217 }
6218 else
6219 {
6220 // One or more threads are still working on this level,
6221 // this thread must wait.
6222 me->depth = gPMHaltDepth - 1;
6223 do {
6224 IOLockSleep(gPMHaltLock, &gPMHaltIdleCount, THREAD_UNINT);
6225 } while (me->depth != gPMHaltDepth);
6226 }
6227 IOLockUnlock( gPMHaltLock );
6228 }
6229
6230 // No more work to do, terminate thread
b0d623f7 6231 DLOG("All done for worker: %p (visits = %u)\n", me, me->visits);
2d21ac55
A
6232 thread_wakeup( &gPMHaltDepth );
6233 me->release();
6234}
6235
6236void PMHaltWorker::work( PMHaltWorker * me )
6237{
6238 IOService * service;
6239 OSSet * inner;
6240 AbsoluteTime startTime;
6241 UInt32 deltaTime;
6242 bool timeout;
6243
6244 while (true)
6245 {
6246 service = 0;
6247 timeout = false;
6248
6249 // Claim an unit of work from the shared pool
6250 IOLockLock( gPMHaltLock );
6251 inner = (OSSet *)gPMHaltArray->getObject(me->depth);
6252 if (inner)
6253 {
6254 service = (IOService *)inner->getAnyObject();
6255 if (service)
6256 {
6257 service->retain();
6258 inner->removeObject(service);
6259 }
6260 }
6261 IOLockUnlock( gPMHaltLock );
6262 if (!service)
6263 break; // no more work at this depth
6264
6265 clock_get_uptime(&startTime);
6266
6267 if (!service->isInactive() &&
6268 service->setProperty(gPMHaltClientAcknowledgeKey, me))
6269 {
6270 IOLockLock(me->lock);
6271 me->startTime = startTime;
6272 me->service = service;
6273 me->timeout = false;
6274 IOLockUnlock(me->lock);
6275
6276 service->systemWillShutdown( gPMHaltEvent );
6277
6278 // Wait for driver acknowledgement
6279 IOLockLock(me->lock);
6280 while (service->getProperty(gPMHaltClientAcknowledgeKey))
6281 {
6282 IOLockSleep(me->lock, me, THREAD_UNINT);
6283 }
6284 me->service = 0;
6285 timeout = me->timeout;
6286 IOLockUnlock(me->lock);
6287 }
6288
6289 deltaTime = computeDeltaTimeMS(&startTime);
6290 if ((deltaTime > kPMHaltTimeoutMS) || timeout ||
6d2010ae 6291 (gIOKitDebug & kIOLogPMRootDomain))
2d21ac55 6292 {
6d2010ae 6293 LOG("%s driver %s (%p) took %u ms\n",
2d21ac55
A
6294 (gPMHaltEvent == kIOMessageSystemWillPowerOff) ?
6295 "PowerOff" : "Restart",
6296 service->getName(), service,
b0d623f7 6297 (uint32_t) deltaTime );
2d21ac55
A
6298 }
6299
6300 service->release();
6301 me->visits++;
6302 }
6303}
6304
6305void PMHaltWorker::checkTimeout( PMHaltWorker * me, AbsoluteTime * now )
6306{
6307 UInt64 nano;
6308 AbsoluteTime startTime;
6309 AbsoluteTime endTime;
6310
6311 endTime = *now;
6312
6313 IOLockLock(me->lock);
6314 if (me->service && !me->timeout)
6315 {
6316 startTime = me->startTime;
6317 nano = 0;
6318 if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0)
6319 {
6320 SUB_ABSOLUTETIME(&endTime, &startTime);
6321 absolutetime_to_nanoseconds(endTime, &nano);
6322 }
6323 if (nano > 3000000000ULL)
6324 {
6325 me->timeout = true;
6d2010ae 6326 MSG("%s still waiting on %s\n",
2d21ac55
A
6327 (gPMHaltEvent == kIOMessageSystemWillPowerOff) ?
6328 "PowerOff" : "Restart",
6329 me->service->getName());
6330 }
6331 }
6332 IOLockUnlock(me->lock);
6333}
6334
b0d623f7
A
6335
6336//******************************************************************************
2d21ac55
A
6337// acknowledgeSystemWillShutdown
6338//
6339// Acknowledgement from drivers that they have prepared for shutdown/restart.
b0d623f7 6340//******************************************************************************
2d21ac55
A
6341
6342void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService * from )
6343{
6344 PMHaltWorker * worker;
6345 OSObject * prop;
6346
6347 if (!from)
6348 return;
6349
b0d623f7 6350 //DLOG("%s acknowledged\n", from->getName());
2d21ac55
A
6351 prop = from->copyProperty( gPMHaltClientAcknowledgeKey );
6352 if (prop)
6353 {
6354 worker = (PMHaltWorker *) prop;
6355 IOLockLock(worker->lock);
6356 from->removeProperty( gPMHaltClientAcknowledgeKey );
6357 thread_wakeup((event_t) worker);
6358 IOLockUnlock(worker->lock);
6359 worker->release();
6360 }
6361 else
6362 {
b0d623f7 6363 DLOG("%s acknowledged without worker property\n",
2d21ac55
A
6364 from->getName());
6365 }
6366}
6367
b0d623f7
A
6368
6369//******************************************************************************
2d21ac55
A
6370// notifySystemShutdown
6371//
6372// Notify all objects in PM tree that system will shutdown or restart
b0d623f7 6373//******************************************************************************
2d21ac55
A
6374
6375static void
6376notifySystemShutdown( IOService * root, unsigned long event )
6377{
6378#define PLACEHOLDER ((OSSet *)gPMHaltArray)
6379 IORegistryIterator * iter;
6380 IORegistryEntry * entry;
6381 IOService * node;
6382 OSSet * inner;
6383 PMHaltWorker * workers[kPMHaltMaxWorkers];
6384 AbsoluteTime deadline;
6385 unsigned int totalNodes = 0;
6386 unsigned int depth;
6387 unsigned int rootDepth;
6388 unsigned int numWorkers;
6389 unsigned int count;
6390 int waitResult;
6391 void * baseFunc;
6392 bool ok;
6393
b0d623f7 6394 DLOG("%s event = %lx\n", __FUNCTION__, event);
2d21ac55
A
6395
6396 baseFunc = OSMemberFunctionCast(void *, root, &IOService::systemWillShutdown);
6397
6398 // Iterate the entire PM tree starting from root
6399
6400 rootDepth = root->getDepth( gIOPowerPlane );
6401 if (!rootDepth) goto done;
6402
6403 // debug - for repeated test runs
6404 while (PMHaltWorker::metaClass->getInstanceCount())
6405 IOSleep(1);
6406
6407 if (!gPMHaltArray)
6408 {
6409 gPMHaltArray = OSArray::withCapacity(40);
6410 if (!gPMHaltArray) goto done;
6411 }
6412 else // debug
6413 gPMHaltArray->flushCollection();
6414
6415 if (!gPMHaltLock)
6416 {
6417 gPMHaltLock = IOLockAlloc();
6418 if (!gPMHaltLock) goto done;
6419 }
6420
6421 if (!gPMHaltClientAcknowledgeKey)
6422 {
6423 gPMHaltClientAcknowledgeKey =
6424 OSSymbol::withCStringNoCopy("PMShutdown");
6425 if (!gPMHaltClientAcknowledgeKey) goto done;
6426 }
6427
6428 gPMHaltEvent = event;
6429
6430 // Depth-first walk of PM plane
6431
6432 iter = IORegistryIterator::iterateOver(
6433 root, gIOPowerPlane, kIORegistryIterateRecursively);
6434
6435 if (iter)
6436 {
6437 while ((entry = iter->getNextObject()))
6438 {
6439 node = OSDynamicCast(IOService, entry);
6440 if (!node)
6441 continue;
6442
6443 if (baseFunc ==
6444 OSMemberFunctionCast(void *, node, &IOService::systemWillShutdown))
6445 continue;
6446
6447 depth = node->getDepth( gIOPowerPlane );
6448 if (depth <= rootDepth)
6449 continue;
6450
6451 ok = false;
6452
6453 // adjust to zero based depth
6454 depth -= (rootDepth + 1);
6455
6456 // gPMHaltArray is an array of containers, each container
6457 // refers to nodes with the same depth.
6458
6459 count = gPMHaltArray->getCount();
6460 while (depth >= count)
6461 {
6462 // expand array and insert placeholders
6463 gPMHaltArray->setObject(PLACEHOLDER);
6464 count++;
6465 }
6466 count = gPMHaltArray->getCount();
6467 if (depth < count)
6468 {
6469 inner = (OSSet *)gPMHaltArray->getObject(depth);
6470 if (inner == PLACEHOLDER)
6471 {
6472 inner = OSSet::withCapacity(40);
6473 if (inner)
6474 {
6475 gPMHaltArray->replaceObject(depth, inner);
6476 inner->release();
6477 }
6478 }
6479
6480 // PM nodes that appear more than once in the tree will have
6481 // the same depth, OSSet will refuse to add the node twice.
6482 if (inner)
6483 ok = inner->setObject(node);
6484 }
6485 if (!ok)
b0d623f7 6486 DLOG("Skipped PM node %s\n", node->getName());
2d21ac55
A
6487 }
6488 iter->release();
6489 }
6490
6491 // debug only
6492 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); i++)
6493 {
6494 count = 0;
6495 if (inner != PLACEHOLDER)
6496 count = inner->getCount();
b0d623f7 6497 DLOG("Nodes at depth %u = %u\n", i, count);
2d21ac55
A
6498 }
6499
6500 // strip placeholders (not all depths are populated)
6501 numWorkers = 0;
6502 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); )
6503 {
6504 if (inner == PLACEHOLDER)
6505 {
6506 gPMHaltArray->removeObject(i);
6507 continue;
6508 }
6509 count = inner->getCount();
6510 if (count > numWorkers)
6511 numWorkers = count;
6512 totalNodes += count;
6513 i++;
6514 }
6515
6516 if (gPMHaltArray->getCount() == 0 || !numWorkers)
6517 goto done;
6518
6519 gPMHaltBusyCount = 0;
6520 gPMHaltIdleCount = 0;
6521 gPMHaltDepth = gPMHaltArray->getCount() - 1;
6522
6523 // Create multiple workers (and threads)
6524
6525 if (numWorkers > kPMHaltMaxWorkers)
6526 numWorkers = kPMHaltMaxWorkers;
6527
b0d623f7 6528 DLOG("PM nodes = %u, maxDepth = %u, workers = %u\n",
2d21ac55
A
6529 totalNodes, gPMHaltArray->getCount(), numWorkers);
6530
6531 for (unsigned int i = 0; i < numWorkers; i++)
6532 workers[i] = PMHaltWorker::worker();
6533
6534 // Wait for workers to exhaust all available work
6535
6536 IOLockLock(gPMHaltLock);
6537 while (gPMHaltDepth >= 0)
6538 {
6539 clock_interval_to_deadline(1000, kMillisecondScale, &deadline);
6540
6541 waitResult = IOLockSleepDeadline(
6542 gPMHaltLock, &gPMHaltDepth, deadline, THREAD_UNINT);
6543 if (THREAD_TIMED_OUT == waitResult)
6544 {
6545 AbsoluteTime now;
6546 clock_get_uptime(&now);
6547
6548 IOLockUnlock(gPMHaltLock);
6549 for (unsigned int i = 0 ; i < numWorkers; i++)
6550 {
6551 if (workers[i])
6552 PMHaltWorker::checkTimeout(workers[i], &now);
6553 }
6554 IOLockLock(gPMHaltLock);
6555 }
6556 }
6557 IOLockUnlock(gPMHaltLock);
6558
6d2010ae
A
6559 // Release all workers
6560
6561 for (unsigned int i = 0; i < numWorkers; i++)
6562 {
6563 if (workers[i])
6564 workers[i]->release();
6565 // worker also retained by it's own thread
6566 }
6567
6568done:
6569 DLOG("%s done\n", __FUNCTION__);
6570 return;
6571}
6572
6573//*********************************************************************************
6574// Sleep/Wake logging
6575//
6576//*********************************************************************************
6577
6578IOMemoryDescriptor *IOPMrootDomain::getPMTraceMemoryDescriptor(void)
6579{
6580 if (timeline)
6581 return timeline->getPMTraceMemoryDescriptor();
6582 else
6583 return NULL;
6584}
6585
6586// Forwards external reports of detailed events to IOPMTimeline
6587IOReturn IOPMrootDomain::recordPMEvent(PMEventDetails *details)
6588{
6589 if (timeline && details) {
6590
6591 IOReturn rc;
6592
6593 // Record a detailed driver power change event, or...
6594 if(details->eventClassifier == kIOPMEventClassDriverEvent) {
6595 rc = timeline->recordDetailedPowerEvent( details );
6596 }
6597
6598 // Record a system power management event
6599 else if(details->eventClassifier == kIOPMEventClassSystemEvent) {
6600 rc = timeline->recordSystemPowerEvent( details );
6601 }
6602 else {
6603 return kIOReturnBadArgument;
6604 }
6605
6606 // If we get to record this message, then we've reached the
6607 // end of another successful Sleep --> Wake cycle
6608 // At this point, we pat ourselves in the back and allow
6609 // our Sleep --> Wake UUID to be published
6610 if(details->eventType == kIOPMEventTypeWakeDone) {
6611 timeline->setSleepCycleInProgressFlag(false);
6612 }
6613
6614/*
6615 // Check if its time to clear the timeline buffer
6616 if(getProperty(kIOPMSleepWakeUUIDKey)
6617 && timeline->isSleepCycleInProgress() == false
6618 && timeline->getNumEventsLoggedThisPeriod() > 500) {
6619
6620 // Clear the old UUID
6621 if(pmPowerStateQueue) {
6622 pmPowerStateQueue->submitPowerEvent(kPowerEventPublishSleepWakeUUID, (void *)false );
6623 }
6624 }
6625*/
6626 return rc;
6627 }
6628 else
6629 return kIOReturnNotReady;
6630}
6631
6632IOReturn IOPMrootDomain::recordAndReleasePMEvent(PMEventDetails *details)
6633{
6634 IOReturn ret = kIOReturnBadArgument;
2d21ac55 6635
6d2010ae
A
6636 if (details)
6637 {
6638 ret = recordPMEvent(details);
6639 details->release();
6640 }
2d21ac55 6641
6d2010ae 6642 return ret;
2d21ac55
A
6643}
6644
0b4c1975
A
6645/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6646
6647IOPMDriverAssertionID IOPMrootDomain::createPMAssertion(
6648 IOPMDriverAssertionType whichAssertionBits,
6649 IOPMDriverAssertionLevel assertionLevel,
6650 IOService *ownerService,
6651 const char *ownerDescription)
6652{
6653 IOReturn ret;
6654 IOPMDriverAssertionID newAssertion;
6655
6656 if (!pmAssertions)
6657 return 0;
6658
6659 ret = pmAssertions->createAssertion(whichAssertionBits, assertionLevel, ownerService, ownerDescription, &newAssertion);
6660
6661 if (kIOReturnSuccess == ret)
6662 return newAssertion;
6663 else
6664 return 0;
6665}
6666
6667IOReturn IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion)
6668{
6669 if (!pmAssertions)
6670 return kIOReturnInternalError;
6671
6672 return pmAssertions->releaseAssertion(releaseAssertion);
6673}
6674
6675IOReturn IOPMrootDomain::setPMAssertionLevel(
6676 IOPMDriverAssertionID assertionID,
6677 IOPMDriverAssertionLevel assertionLevel)
6678{
6679 return pmAssertions->setAssertionLevel(assertionID, assertionLevel);
6680}
6681
6682IOPMDriverAssertionLevel IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion)
6683{
6684 IOPMDriverAssertionType sysLevels;
6685
6686 if (!pmAssertions || whichAssertion == 0)
6687 return kIOPMDriverAssertionLevelOff;
6688
6689 sysLevels = pmAssertions->getActivatedAssertions();
6690
6691 // Check that every bit set in argument 'whichAssertion' is asserted
6692 // in the aggregate bits.
6693 if ((sysLevels & whichAssertion) == whichAssertion)
6694 return kIOPMDriverAssertionLevelOn;
6695 else
6696 return kIOPMDriverAssertionLevelOff;
6697}
6698
6699IOReturn IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels)
6700{
6701 if (!pmAssertions)
6702 return kIOReturnNotFound;
6703
6704 return pmAssertions->setUserAssertionLevels(inLevels);
6705}
6706
6707bool IOPMrootDomain::serializeProperties( OSSerialize * s ) const
6708{
6709 if (pmAssertions)
6710 {
6711 pmAssertions->publishProperties();
6712 }
6713 return( IOService::serializeProperties(s) );
6714}
2d21ac55 6715
0c530ab8
A
6716/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6717
6d2010ae
A
6718// MARK: -
6719// MARK: PMSettingHandle
0c530ab8 6720
6d2010ae 6721OSDefineMetaClassAndStructors( PMSettingHandle, OSObject )
0c530ab8 6722
6d2010ae 6723void PMSettingHandle::free( void )
0c530ab8 6724{
6d2010ae
A
6725 if (pmso)
6726 {
6727 pmso->clientHandleFreed();
6728 pmso->release();
6729 pmso = 0;
6730 }
6731
6732 OSObject::free();
0c530ab8
A
6733}
6734
6d2010ae
A
6735// MARK: -
6736// MARK: PMSettingObject
6737
6738#undef super
6739#define super OSObject
6740OSDefineMetaClassAndFinalStructors( PMSettingObject, OSObject )
6741
0c530ab8
A
6742/*
6743 * Static constructor/initializer for PMSettingObject
6744 */
6745PMSettingObject *PMSettingObject::pmSettingObject(
6746 IOPMrootDomain *parent_arg,
6747 IOPMSettingControllerCallback handler_arg,
6748 OSObject *target_arg,
6749 uintptr_t refcon_arg,
6750 uint32_t supportedPowerSources,
6d2010ae
A
6751 const OSSymbol * settings[],
6752 OSObject **handle_obj)
0c530ab8 6753{
6d2010ae
A
6754 uint32_t settingCount = 0;
6755 PMSettingObject *pmso = 0;
6756 PMSettingHandle *pmsh = 0;
0c530ab8 6757
6d2010ae
A
6758 if ( !parent_arg || !handler_arg || !settings || !handle_obj )
6759 return NULL;
0c530ab8 6760
6d2010ae
A
6761 // count OSSymbol entries in NULL terminated settings array
6762 while (settings[settingCount]) {
6763 settingCount++;
0c530ab8 6764 }
6d2010ae
A
6765 if (0 == settingCount)
6766 return NULL;
0c530ab8
A
6767
6768 pmso = new PMSettingObject;
6d2010ae
A
6769 if (!pmso || !pmso->init())
6770 goto fail;
6771
6772 pmsh = new PMSettingHandle;
6773 if (!pmsh || !pmsh->init())
6774 goto fail;
6775
6776 queue_init(&pmso->calloutQueue);
6777 pmso->parent = parent_arg;
6778 pmso->func = handler_arg;
6779 pmso->target = target_arg;
6780 pmso->refcon = refcon_arg;
6781 pmso->settingCount = settingCount;
6782
6783 pmso->retain(); // handle holds a retain on pmso
6784 pmsh->pmso = pmso;
6785 pmso->pmsh = pmsh;
6786
6787 pmso->publishedFeatureID = (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount);
6788 if (pmso->publishedFeatureID) {
6789 for (unsigned int i=0; i<settingCount; i++) {
0c530ab8
A
6790 // Since there is now at least one listener to this setting, publish
6791 // PM root domain support for it.
6d2010ae 6792 parent_arg->publishFeature( settings[i]->getCStringNoCopy(),
0c530ab8
A
6793 supportedPowerSources, &pmso->publishedFeatureID[i] );
6794 }
6795 }
6d2010ae
A
6796
6797 *handle_obj = pmsh;
0c530ab8 6798 return pmso;
6d2010ae
A
6799
6800fail:
6801 if (pmso) pmso->release();
6802 if (pmsh) pmsh->release();
6803 return NULL;
0c530ab8
A
6804}
6805
6d2010ae 6806void PMSettingObject::free( void )
0c530ab8 6807{
6d2010ae
A
6808 if (publishedFeatureID) {
6809 for (uint32_t i=0; i<settingCount; i++) {
6810 if (publishedFeatureID[i]) {
0c530ab8 6811 parent->removePublishedFeature( publishedFeatureID[i] );
0b4e3aa0
A
6812 }
6813 }
6d2010ae
A
6814
6815 IOFree(publishedFeatureID, sizeof(uint32_t) * settingCount);
6816 }
6817
6818 super::free();
6819}
6820
6821void PMSettingObject::dispatchPMSetting( const OSSymbol * type, OSObject * object )
6822{
6823 (*func)(target, type, object, refcon);
6824}
6825
6826void PMSettingObject::clientHandleFreed( void )
6827{
6828 parent->deregisterPMSettingObject(this);
6829}
6830
6831// MARK: -
6832// MARK: IOPMTimeline
6833
6834#undef super
6835#define super OSObject
6836
6837//*********************************************************************************
6838//*********************************************************************************
6839//*********************************************************************************
6840
6841IOPMTimeline *IOPMTimeline::timeline(IOPMrootDomain *root_domain)
6842{
6843 IOPMTimeline *myself;
6844
6845 if (!root_domain)
6846 return NULL;
0c530ab8 6847
6d2010ae
A
6848 myself = new IOPMTimeline;
6849
6850 if (myself) {
6851 myself->owner = root_domain;
6852 myself->init();
0b4e3aa0 6853 }
6d2010ae
A
6854
6855 return myself;
6856}
6857
6858bool IOPMTimeline::init(void)
6859{
6860 if (!super::init()) {
6861 return false;
6862 }
6863
6864 logLock = IOLockAlloc();
0c530ab8 6865
6d2010ae
A
6866 // Fresh timeline, no events logged yet
6867 this->numEventsLoggedThisPeriod = 0;
6868 this->sleepCycleInProgress = false;
6869
6870 //this->setEventsRecordingLevel(1); // TODO
6871 this->setEventsTrackedCount(kIOPMDefaultSystemEventsTracked);
6872
6873 return true;
6874}
6875
6876void IOPMTimeline::free(void)
6877{
6878 if (pmTraceMemoryDescriptor) {
6879 pmTraceMemoryDescriptor->release();
6880 pmTraceMemoryDescriptor = NULL;
6881 }
6882
6883 IOLockFree(logLock);
6884
6885 super::free();
6886}
6887
6888IOMemoryDescriptor *IOPMTimeline::getPMTraceMemoryDescriptor()
6889{
6890 return pmTraceMemoryDescriptor;
6891}
6892
6893//*********************************************************************************
6894//*********************************************************************************
6895//*********************************************************************************
6896
6897bool IOPMTimeline::setProperties(OSDictionary *d)
6898{
6899 OSNumber *n = NULL;
6900 OSBoolean *b = NULL;
6901 bool changed = false;
6902
6903 /* Changes size of detailed events buffer */
6904 n = (OSNumber *)d->getObject(kIOPMTimelineSystemNumberTrackedKey);
6905 if (OSDynamicCast(OSNumber, n))
0c530ab8 6906 {
6d2010ae
A
6907 changed = true;
6908 this->setEventsTrackedCount(n->unsigned32BitValue());
6909 }
6910
6911
6912 /* enables or disables system events */
6913 b = (OSBoolean *)d->getObject(kIOPMTimelineEnabledKey);
6914 if (b)
6915 {
6916 changed = true;
6917 this->setEventsRecordingLevel((int)(kOSBooleanTrue == b));
6918 }
6919
6920 return changed;
6921}
6922
6923//*********************************************************************************
6924//*********************************************************************************
6925//*********************************************************************************
6926
6927OSDictionary *IOPMTimeline::copyInfoDictionary(void)
6928{
6929 OSDictionary *out = OSDictionary::withCapacity(3);
6930 OSNumber *n = NULL;
6931
6932 if (!out || !hdr)
6933 return NULL;
6934
6935 n = OSNumber::withNumber(hdr->sizeEntries, 32);
6936 out->setObject(kIOPMTimelineSystemNumberTrackedKey, n);
6937 n->release();
6938
6939 n = OSNumber::withNumber(hdr->sizeBytes, 32);
6940 out->setObject(kIOPMTimelineSystemBufferSizeKey, n);
6941 n->release();
6942
6943 // bool
6944 out->setObject(kIOPMTimelineEnabledKey, eventsRecordingLevel ? kOSBooleanTrue : kOSBooleanFalse);
6945
6946 return out;
6947}
6948
6949//*********************************************************************************
6950//*********************************************************************************
6951//*********************************************************************************
6952
6953/* IOPMTimeline::recordSystemPowerEvent()
6954 *
6955 * Expected "type" arguments are listed in IOPMPrivate.h under enum "SystemEventTypes"
6956 * Type arguments include "system events", and "Intermediate events"
6957 *
6958 * - System Events have paired "start" and "stop" events.
6959 * - A start event shall be followed by a stop event.
6960 * - Any number of Intermediate Events may fall between the
6961 * start and stop events.
6962 * - Intermediate events are meaningless outside the bounds of a system event's
6963 * start & stoup routines.
6964 * - It's invalid to record a Start event without a following Stop event; e.g. two
6965 * Start events without an intervenining Stop event is invalid.
6966 *
6967 * Buffer invariants
6968 * - The first recorded system event shall be preceded by an entry with type == 0
6969 * - IOPMTimeline may choose not to record intermediate events while there's not
6970 * a system event in process.
6971 */
6972IOReturn IOPMTimeline::recordSystemPowerEvent( PMEventDetails *details )
6973{
6974 static bool wakeDonePending = true;
6975 IOPMSystemEventRecord *record_to = NULL;
6976 OSString *swUUIDKey = NULL;
6977 uint32_t useIndex = 0;
6978
6979 if (!details)
6980 return kIOReturnBadArgument;
6981
6982 if (!traceBuffer)
6983 return kIOReturnNotReady;
6984
6985 if (details->eventType == kIOPMEventTypeWakeDone)
6986 {
6987 if(!wakeDonePending)
6988 return kIOReturnBadArgument;
6989 }
6990
6991 IOLockLock(logLock);
0c530ab8 6992
6d2010ae
A
6993 if (details->eventType == kIOPMEventTypeWake) {
6994 wakeDonePending = true;
6995 } else if (details->eventType == kIOPMEventTypeWakeDone) {
6996 wakeDonePending = false;
0c530ab8 6997 }
6d2010ae
A
6998
6999 systemState = details->eventType;
7000
7001 useIndex = _atomicIndexIncrement(&hdr->index, hdr->sizeEntries);
0c530ab8 7002
6d2010ae
A
7003 // The entry immediately after the latest entry (and thus
7004 // immediately before the first entry) shall have a type 0.
7005 if (useIndex + 1 >= hdr->sizeEntries) {
7006 traceBuffer[useIndex + 1].eventType = 0;
7007 } else {
7008 traceBuffer[0].eventType = 0;
7009 }
0c530ab8 7010
6d2010ae
A
7011 record_to = &traceBuffer[useIndex];
7012 bzero(record_to, sizeof(IOPMSystemEventRecord));
7013
7014 /*****/
7015 record_to->eventType = details->eventType;
7016 record_to->eventReason = details->reason;
7017 record_to->eventResult = details->result;
7018 pmEventTimeStamp(&record_to->timestamp);
7019
7020 // If caller doesn't provide a UUID, we'll use the UUID that's posted
7021 // on IOPMrootDomain under key kIOPMSleepWakeUUIDKey
7022 if (!details->uuid) {
7023 swUUIDKey = OSDynamicCast(OSString, owner->copyProperty(kIOPMSleepWakeUUIDKey));
7024
7025 if (swUUIDKey)
7026 details->uuid = swUUIDKey->getCStringNoCopy();
7027 }
7028
7029 if (details->uuid)
7030 strncpy(record_to->uuid, details->uuid, kMaxPMStringLength);
7031
7032 if (swUUIDKey)
7033 swUUIDKey->release();
7034
7035 numEventsLoggedThisPeriod++;
7036 /*****/
7037
7038 IOLockUnlock(logLock);
7039
7040 return kIOReturnSuccess;
7041
7042}
7043
7044//*********************************************************************************
7045//*********************************************************************************
7046//*********************************************************************************
7047
7048IOReturn IOPMTimeline::recordDetailedPowerEvent( PMEventDetails *details )
7049{
7050 IOPMSystemEventRecord *record_to = NULL;
7051 uint32_t useIndex;
7052
7053 if (!details->eventType || !details->ownerName)
7054 return kIOReturnBadArgument;
7055
7056 IOLockLock(logLock);
7057
7058 useIndex = _atomicIndexIncrement(&hdr->index, hdr->sizeEntries);
7059
7060 record_to = (IOPMSystemEventRecord *)&traceBuffer[useIndex];
7061 bzero(record_to, sizeof(IOPMSystemEventRecord));
7062
7063 /*****/
7064 record_to->eventType = details->eventType;
7065 if (details->ownerName && (strlen(details->ownerName) > 1)) {
7066 strlcpy( record_to->ownerName,
7067 details->ownerName,
7068 sizeof(record_to->ownerName));
7069 }
7070
7071 record_to->ownerDisambiguateID = details->ownerUnique;
7072
7073 if (details->interestName && (strlen(details->interestName) > 1)) {
7074 strlcpy(record_to->interestName,
7075 details->interestName,
7076 sizeof(record_to->interestName));
7077 }
7078
7079 record_to->oldState = details->oldState;
7080 record_to->newState = details->newState;
7081 record_to->eventResult = details->result;
7082 record_to->elapsedTimeUS = details->elapsedTimeUS;
7083 pmEventTimeStamp(&record_to->timestamp);
7084
7085 numEventsLoggedThisPeriod++;
7086 /*****/
7087
7088 IOLockUnlock(logLock);
7089 return kIOReturnSuccess;
7090}
7091
7092uint32_t IOPMTimeline::getNumEventsLoggedThisPeriod() {
7093 return this->numEventsLoggedThisPeriod;
7094}
7095
7096void IOPMTimeline::setNumEventsLoggedThisPeriod(uint32_t newCount) {
7097 this->numEventsLoggedThisPeriod = newCount;
7098}
7099
7100bool IOPMTimeline::isSleepCycleInProgress() {
7101 return this->sleepCycleInProgress;
7102}
7103
7104void IOPMTimeline::setSleepCycleInProgressFlag(bool flag) {
7105 this->sleepCycleInProgress = flag;
7106}
7107//*********************************************************************************
7108//*********************************************************************************
7109//*********************************************************************************
7110
7111void IOPMTimeline::setEventsTrackedCount(uint32_t newTracked)
7112{
7113 size_t make_buf_size = 0;
7114
7115 make_buf_size = sizeof(IOPMTraceBufferHeader) + (newTracked * sizeof(IOPMSystemEventRecord));
7116
7117 IOLockLock(logLock);
7118
7119 if (pmTraceMemoryDescriptor) {
7120 pmTraceMemoryDescriptor->release();
7121 pmTraceMemoryDescriptor = NULL;
7122 }
7123
7124 hdr = NULL;
7125 traceBuffer = NULL;
7126
7127 if (0 == newTracked)
7128 {
7129 IOLog("IOPMrootDomain -> erased buffer.\n");
7130 goto exit;
7131 }
7132
7133 pmTraceMemoryDescriptor = IOBufferMemoryDescriptor::withOptions(
7134 kIOMemoryKernelUserShared | kIODirectionIn, make_buf_size);
7135
7136 if (!pmTraceMemoryDescriptor)
7137 {
7138 IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns NULL\n", (int)make_buf_size);
7139 goto exit;
7140 }
7141
7142 pmTraceMemoryDescriptor->prepare(kIODirectionIn);
7143
7144 // Header occupies the first sizeof(IOPMTraceBufferHeader) bytes
7145 hdr = (IOPMTraceBufferHeader *)pmTraceMemoryDescriptor->getBytesNoCopy();
7146
7147 // Recorded events occupy the remaining bulk of the buffer
7148 traceBuffer = (IOPMSystemEventRecord *)((uint8_t *)hdr + sizeof(IOPMTraceBufferHeader));
7149
7150 bzero(hdr, make_buf_size);
7151
7152 hdr->sizeBytes = make_buf_size;
7153 hdr->sizeEntries = newTracked;
7154
7155 IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns bufferMB with address 0x%08x\n", (int)make_buf_size, (unsigned int)(uintptr_t)traceBuffer);
7156
7157exit:
7158 IOLockUnlock(logLock);
7159}
7160
7161//*********************************************************************************
7162//*********************************************************************************
7163//*********************************************************************************
7164
7165void IOPMTimeline::setEventsRecordingLevel(uint32_t eventsTrackedBits)
7166{
7167
7168 // TODO
7169
7170 return;
7171
0c530ab8
A
7172}
7173
6d2010ae
A
7174/* static helper to IOPMTimeline
7175 */
7176uint32_t IOPMTimeline::_atomicIndexIncrement(uint32_t *index, uint32_t limit)
7177{
7178 uint32_t was_index;
7179 uint32_t inc_index;
7180
7181 if(!index)
7182 return NULL;
7183
7184 do {
7185 was_index = *index;
7186 inc_index = (was_index+1)%limit;
7187 } while (!OSCompareAndSwap(was_index, inc_index, index));
0c530ab8 7188
6d2010ae 7189 return inc_index;
0b4e3aa0 7190}
1c79356b 7191
0b4c1975
A
7192// MARK: -
7193// MARK: PMAssertionsTracker
7194
7195//*********************************************************************************
7196//*********************************************************************************
7197//*********************************************************************************
7198// class PMAssertionsTracker Implementation
7199
7200#define kAssertUniqueIDStart 500
7201
7202PMAssertionsTracker *PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain *rootDomain )
7203{
7204 PMAssertionsTracker *myself;
7205
7206 myself = new PMAssertionsTracker;
7207
7208 if (myself) {
7209 myself->init();
7210 myself->owner = rootDomain;
7211 myself->issuingUniqueID = kAssertUniqueIDStart;
7212 myself->assertionsArray = OSArray::withCapacity(5);
7213 myself->assertionsKernel = 0;
7214 myself->assertionsUser = 0;
7215 myself->assertionsCombined = 0;
7216 myself->assertionsArrayLock = IOLockAlloc();
7217 myself->tabulateProducerCount = myself->tabulateConsumerCount = 0;
7218
7219 if (!myself->assertionsArray || !myself->assertionsArrayLock)
7220 myself = NULL;
7221 }
7222
7223 return myself;
7224}
7225
7226/* tabulate
7227 * - Update assertionsKernel to reflect the state of all
7228 * assertions in the kernel.
7229 * - Update assertionsCombined to reflect both kernel & user space.
7230 */
7231void PMAssertionsTracker::tabulate(void)
7232{
7233 int i;
7234 int count;
7235 PMAssertStruct *_a = NULL;
7236 OSData *_d = NULL;
7237
7238 IOPMDriverAssertionType oldKernel = assertionsKernel;
7239 IOPMDriverAssertionType oldCombined = assertionsCombined;
7240
7241 ASSERT_GATED();
7242
7243 assertionsKernel = 0;
7244 assertionsCombined = 0;
7245
7246 if (!assertionsArray)
7247 return;
7248
7249 if ((count = assertionsArray->getCount()))
7250 {
7251 for (i=0; i<count; i++)
7252 {
7253 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
7254 if (_d)
7255 {
7256 _a = (PMAssertStruct *)_d->getBytesNoCopy();
7257 if (_a && (kIOPMDriverAssertionLevelOn == _a->level))
7258 assertionsKernel |= _a->assertionBits;
7259 }
7260 }
7261 }
7262
7263 tabulateProducerCount++;
7264 assertionsCombined = assertionsKernel | assertionsUser;
7265
7266 if ((assertionsKernel != oldKernel) ||
7267 (assertionsCombined != oldCombined))
6d2010ae
A
7268 {
7269 owner->messageClients(kIOPMMessageDriverAssertionsChanged);
7270
7271 if (((assertionsCombined & kIOPMDriverAssertionPreventDisplaySleepBit) != 0)
7272 && ((oldCombined & kIOPMDriverAssertionPreventDisplaySleepBit) == 0))
7273 {
7274 /* We react to a new PreventDisplaySleep assertion by waking the display
7275 * with an activityTickle
7276 */
7277 owner->evaluatePolicy(kStimulusDarkWakeActivityTickle);
7278 } else {
7279 owner->evaluatePolicy(kStimulusDarkWakeEvaluate);
7280 }
0b4c1975
A
7281 }
7282}
7283
7284void PMAssertionsTracker::publishProperties( void )
7285{
7286 OSArray *assertionsSummary = NULL;
7287
7288 if (tabulateConsumerCount != tabulateProducerCount)
7289 {
7290 IOLockLock(assertionsArrayLock);
7291
7292 tabulateConsumerCount = tabulateProducerCount;
7293
7294 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
7295 */
7296 assertionsSummary = copyAssertionsArray();
7297 if (assertionsSummary)
7298 {
7299 owner->setProperty(kIOPMAssertionsDriverDetailedKey, assertionsSummary);
7300 assertionsSummary->release();
7301 }
7302 else
7303 {
7304 owner->removeProperty(kIOPMAssertionsDriverDetailedKey);
7305 }
7306
7307 /* Publish the IOPMrootDomain property "DriverPMAssertions"
7308 */
7309 owner->setProperty(kIOPMAssertionsDriverKey, assertionsKernel, 64);
7310
7311 IOLockUnlock(assertionsArrayLock);
7312 }
7313}
7314
7315PMAssertionsTracker::PMAssertStruct *PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id, int *index)
7316{
7317 PMAssertStruct *_a = NULL;
7318 OSData *_d = NULL;
7319 int found = -1;
7320 int count = 0;
7321 int i = 0;
7322
7323 if (assertionsArray
7324 && (count = assertionsArray->getCount()))
7325 {
7326 for (i=0; i<count; i++)
7327 {
7328 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
7329 if (_d)
7330 {
7331 _a = (PMAssertStruct *)_d->getBytesNoCopy();
7332 if (_a && (_id == _a->id)) {
7333 found = i;
7334 break;
7335 }
7336 }
7337 }
7338 }
7339
7340 if (-1 == found) {
7341 return NULL;
7342 } else {
7343 if (index)
7344 *index = found;
7345 return _a;
7346 }
7347}
7348
7349/* PMAssertionsTracker::handleCreateAssertion
7350 * Perform assertion work on the PM workloop. Do not call directly.
7351 */
7352IOReturn PMAssertionsTracker::handleCreateAssertion(OSData *newAssertion)
7353{
7354 ASSERT_GATED();
7355
7356 if (newAssertion)
7357 {
7358 IOLockLock(assertionsArrayLock);
7359 assertionsArray->setObject(newAssertion);
7360 IOLockUnlock(assertionsArrayLock);
7361 newAssertion->release();
7362
7363 tabulate();
7364 }
7365 return kIOReturnSuccess;
7366}
7367
7368/* PMAssertionsTracker::createAssertion
7369 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
7370 * appropiate.
7371 */
7372IOReturn PMAssertionsTracker::createAssertion(
7373 IOPMDriverAssertionType which,
7374 IOPMDriverAssertionLevel level,
7375 IOService *serviceID,
7376 const char *whoItIs,
7377 IOPMDriverAssertionID *outID)
7378{
7379 OSData *dataStore = NULL;
7380 PMAssertStruct track;
7381
7382 // Warning: trillions and trillions of created assertions may overflow the unique ID.
0b4c1975 7383 track.id = OSIncrementAtomic64((SInt64*) &issuingUniqueID);
0b4c1975
A
7384 track.level = level;
7385 track.assertionBits = which;
7386 track.ownerString = whoItIs ? OSSymbol::withCString(whoItIs) : 0;
7387 track.ownerService = serviceID;
7388 track.modifiedTime = 0;
7389 pmEventTimeStamp(&track.createdTime);
6d2010ae 7390
0b4c1975
A
7391 dataStore = OSData::withBytes(&track, sizeof(PMAssertStruct));
7392 if (!dataStore)
7393 {
7394 if (track.ownerString)
7395 track.ownerString->release();
7396 return kIOReturnNoMemory;
7397 }
7398
7399 *outID = track.id;
7400
7401 if (owner && owner->pmPowerStateQueue) {
7402 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionCreate, (void *)dataStore);
7403 }
7404
7405 return kIOReturnSuccess;
7406}
1c79356b 7407
0b4c1975
A
7408/* PMAssertionsTracker::handleReleaseAssertion
7409 * Runs in PM workloop. Do not call directly.
7410 */
7411IOReturn PMAssertionsTracker::handleReleaseAssertion(
7412 IOPMDriverAssertionID _id)
7413{
7414 ASSERT_GATED();
7415
7416 int index;
7417 PMAssertStruct *assertStruct = detailsForID(_id, &index);
7418
7419 if (!assertStruct)
7420 return kIOReturnNotFound;
7421
7422 IOLockLock(assertionsArrayLock);
7423 if (assertStruct->ownerString)
7424 assertStruct->ownerString->release();
7425
7426 assertionsArray->removeObject(index);
7427 IOLockUnlock(assertionsArrayLock);
7428
7429 tabulate();
7430 return kIOReturnSuccess;
7431}
7432
7433/* PMAssertionsTracker::releaseAssertion
7434 * Releases an assertion and affects system behavior if appropiate.
7435 * Actual work happens on PM workloop.
7436 */
7437IOReturn PMAssertionsTracker::releaseAssertion(
7438 IOPMDriverAssertionID _id)
7439{
7440 if (owner && owner->pmPowerStateQueue) {
7441 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionRelease, 0, _id);
7442 }
7443 return kIOReturnSuccess;
7444}
7445
7446/* PMAssertionsTracker::handleSetAssertionLevel
7447 * Runs in PM workloop. Do not call directly.
7448 */
7449IOReturn PMAssertionsTracker::handleSetAssertionLevel(
7450 IOPMDriverAssertionID _id,
7451 IOPMDriverAssertionLevel _level)
7452{
7453 PMAssertStruct *assertStruct = detailsForID(_id, NULL);
7454
7455 ASSERT_GATED();
7456
7457 if (!assertStruct) {
7458 return kIOReturnNotFound;
7459 }
7460
7461 IOLockLock(assertionsArrayLock);
7462 pmEventTimeStamp(&assertStruct->modifiedTime);
7463 assertStruct->level = _level;
7464 IOLockUnlock(assertionsArrayLock);
7465
7466 tabulate();
7467 return kIOReturnSuccess;
7468}
7469
7470/* PMAssertionsTracker::setAssertionLevel
7471 */
7472IOReturn PMAssertionsTracker::setAssertionLevel(
7473 IOPMDriverAssertionID _id,
7474 IOPMDriverAssertionLevel _level)
7475{
7476 if (owner && owner->pmPowerStateQueue) {
7477 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionSetLevel,
7478 (void *)_level, _id);
7479 }
7480
7481 return kIOReturnSuccess;
7482}
7483
7484IOReturn PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0)
7485{
7486 IOPMDriverAssertionType new_user_levels = *(IOPMDriverAssertionType *) arg0;
7487
7488 ASSERT_GATED();
7489
7490 if (new_user_levels != assertionsUser)
7491 {
7492 assertionsUser = new_user_levels;
7493 DLOG("assertionsUser 0x%llx\n", assertionsUser);
7494 }
7495
7496 tabulate();
7497 return kIOReturnSuccess;
7498}
7499
7500IOReturn PMAssertionsTracker::setUserAssertionLevels(
7501 IOPMDriverAssertionType new_user_levels)
7502{
7503 if (gIOPMWorkLoop) {
7504 gIOPMWorkLoop->runAction(
7505 OSMemberFunctionCast(
7506 IOWorkLoop::Action,
7507 this,
7508 &PMAssertionsTracker::handleSetUserAssertionLevels),
7509 this,
7510 (void *) &new_user_levels, 0, 0, 0);
7511 }
7512
7513 return kIOReturnSuccess;
7514}
7515
7516
7517OSArray *PMAssertionsTracker::copyAssertionsArray(void)
7518{
7519 int count;
7520 int i;
7521 OSArray *outArray = NULL;
7522
7523 if (!assertionsArray ||
7524 (0 == (count = assertionsArray->getCount())) ||
7525 (NULL == (outArray = OSArray::withCapacity(count))))
7526 {
7527 goto exit;
7528 }
7529
7530 for (i=0; i<count; i++)
7531 {
7532 PMAssertStruct *_a = NULL;
7533 OSData *_d = NULL;
7534 OSDictionary *details = NULL;
7535
7536 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
7537 if (_d && (_a = (PMAssertStruct *)_d->getBytesNoCopy()))
7538 {
7539 OSNumber *_n = NULL;
7540
7541 details = OSDictionary::withCapacity(7);
7542 if (!details)
7543 continue;
7544
7545 outArray->setObject(details);
7546 details->release();
7547
7548 _n = OSNumber::withNumber(_a->id, 64);
7549 if (_n) {
7550 details->setObject(kIOPMDriverAssertionIDKey, _n);
7551 _n->release();
7552 }
7553 _n = OSNumber::withNumber(_a->createdTime, 64);
7554 if (_n) {
7555 details->setObject(kIOPMDriverAssertionCreatedTimeKey, _n);
7556 _n->release();
7557 }
7558 _n = OSNumber::withNumber(_a->modifiedTime, 64);
7559 if (_n) {
7560 details->setObject(kIOPMDriverAssertionModifiedTimeKey, _n);
7561 _n->release();
7562 }
7563 _n = OSNumber::withNumber((uintptr_t)_a->ownerService, 64);
7564 if (_n) {
7565 details->setObject(kIOPMDriverAssertionOwnerServiceKey, _n);
7566 _n->release();
7567 }
7568 _n = OSNumber::withNumber(_a->level, 64);
7569 if (_n) {
7570 details->setObject(kIOPMDriverAssertionLevelKey, _n);
7571 _n->release();
7572 }
7573 _n = OSNumber::withNumber(_a->assertionBits, 64);
7574 if (_n) {
7575 details->setObject(kIOPMDriverAssertionAssertedKey, _n);
7576 _n->release();
7577 }
7578
7579 if (_a->ownerString) {
7580 details->setObject(kIOPMDriverAssertionOwnerStringKey, _a->ownerString);
7581 }
7582 }
7583 }
7584
7585exit:
7586 return outArray;
7587}
7588
7589IOPMDriverAssertionType PMAssertionsTracker::getActivatedAssertions(void)
7590{
7591 return assertionsCombined;
7592}
7593
7594IOPMDriverAssertionLevel PMAssertionsTracker::getAssertionLevel(
7595 IOPMDriverAssertionType type)
7596{
7597 if (type && ((type & assertionsKernel) == assertionsKernel))
7598 {
7599 return kIOPMDriverAssertionLevelOn;
7600 } else {
7601 return kIOPMDriverAssertionLevelOff;
7602 }
7603}
7604
7605//*********************************************************************************
7606//*********************************************************************************
7607//*********************************************************************************
7608
6d2010ae 7609
0b4c1975
A
7610static void pmEventTimeStamp(uint64_t *recordTS)
7611{
7612 clock_sec_t tsec;
7613 clock_usec_t tusec;
7614
7615 if (!recordTS)
7616 return;
7617
7618 // We assume tsec fits into 32 bits; 32 bits holds enough
7619 // seconds for 136 years since the epoch in 1970.
7620 clock_get_calendar_microtime(&tsec, &tusec);
7621
7622
7623 // Pack the sec & microsec calendar time into a uint64_t, for fun.
7624 *recordTS = 0;
7625 *recordTS |= (uint32_t)tusec;
7626 *recordTS |= ((uint64_t)tsec << 32);
7627
7628 return;
7629}
0c530ab8 7630
6d2010ae
A
7631// MARK: -
7632// MARK: IORootParent
1c79356b 7633
6d2010ae 7634/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1c79356b 7635
b0d623f7 7636OSDefineMetaClassAndFinalStructors(IORootParent, IOService)
1c79356b 7637
6d2010ae
A
7638// The reason that root domain needs a root parent is to facilitate demand
7639// sleep, since a power change from the root parent cannot be vetoed.
7640//
7641// The above statement is no longer true since root domain now performs
7642// demand sleep using overrides. But root parent remains to avoid changing
7643// the power tree stacking. Root parent is parked at the max power state.
7644
1c79356b 7645
6d2010ae 7646static IOPMPowerState patriarchPowerStates[2] =
b0d623f7 7647{
6d2010ae
A
7648 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0},
7649 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0},
1c79356b
A
7650};
7651
6d2010ae
A
7652void IORootParent::initialize( void )
7653{
7654}
7655
b0d623f7 7656bool IORootParent::start( IOService * nub )
1c79356b 7657{
6d2010ae 7658 IOService::start(nub);
b0d623f7 7659 attachToParent( getRegistryRoot(), gIOPowerPlane );
1c79356b 7660 PMinit();
6d2010ae
A
7661 registerPowerDriver(this, patriarchPowerStates, 2);
7662 makeUsable();
1c79356b
A
7663 return true;
7664}
7665
b0d623f7 7666void IORootParent::shutDownSystem( void )
1c79356b 7667{
0b4e3aa0
A
7668}
7669
b0d623f7 7670void IORootParent::restartSystem( void )
0b4e3aa0 7671{
1c79356b
A
7672}
7673
b0d623f7 7674void IORootParent::sleepSystem( void )
1c79356b 7675{
0b4e3aa0
A
7676}
7677
b0d623f7 7678void IORootParent::dozeSystem( void )
0b4e3aa0 7679{
0b4e3aa0
A
7680}
7681
b0d623f7 7682void IORootParent::sleepToDoze( void )
0b4e3aa0 7683{
1c79356b
A
7684}
7685
b0d623f7 7686void IORootParent::wakeSystem( void )
1c79356b 7687{
1c79356b 7688}
6d2010ae
A
7689
7690OSObject * IORootParent::copyProperty( const char * aKey) const
7691{
7692 return (IOService::copyProperty(aKey));
7693}
7694