]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOPMrootDomain.cpp
60f3ec07acc147928283d3e90242a4711cbf4b79
[apple/xnu.git] / iokit / Kernel / IOPMrootDomain.cpp
1 /*
2 * Copyright (c) 1998-2008 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
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
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 #include <libkern/c++/OSKext.h>
29 #include <libkern/c++/OSMetaClass.h>
30 #include <libkern/OSAtomic.h>
31 #include <libkern/OSDebug.h>
32 #include <IOKit/IOWorkLoop.h>
33 #include <IOKit/IOCommandGate.h>
34 #include <IOKit/IOPlatformExpert.h>
35 #include <IOKit/IOKitDebug.h>
36 #include <IOKit/IOTimeStamp.h>
37 #include <IOKit/pwr_mgt/IOPMlog.h>
38 #include <IOKit/pwr_mgt/RootDomain.h>
39 #include <IOKit/pwr_mgt/IOPMPrivate.h>
40 #include <IOKit/IODeviceTreeSupport.h>
41 #include <IOKit/IOMessage.h>
42 #include <IOKit/IOReturn.h>
43 #include "RootDomainUserClient.h"
44 #include "IOKit/pwr_mgt/IOPowerConnection.h"
45 #include "IOPMPowerStateQueue.h"
46 #include <IOKit/IOCatalogue.h>
47 #if HIBERNATION
48 #include <IOKit/IOHibernatePrivate.h>
49 #endif
50 #include <sys/syslog.h>
51 #include <sys/sysctl.h>
52 #include <sys/time.h>
53 #include "IOServicePrivate.h" // _IOServiceInterestNotifier
54 #include "IOServicePMPrivate.h"
55
56 __BEGIN_DECLS
57 #include <mach/shared_region.h>
58 __END_DECLS
59
60 #if defined(__i386__) || defined(__x86_64__)
61 __BEGIN_DECLS
62 #include "IOPMrootDomainInternal.h"
63 __END_DECLS
64 #endif
65
66 #define kIOPMrootDomainClass "IOPMrootDomain"
67 #define LOG_PREFIX "PMRD: "
68
69 #define MSG(x...) \
70 do { kprintf(LOG_PREFIX x); IOLog(x); } while (false)
71
72 #define LOG(x...) \
73 do { kprintf(LOG_PREFIX x); } while (false)
74
75 #define DLOG(x...) do { \
76 if (kIOLogPMRootDomain & gIOKitDebug) \
77 kprintf(LOG_PREFIX x); } while (false)
78
79 #define _LOG(x...)
80
81 #define CHECK_THREAD_CONTEXT
82 #ifdef CHECK_THREAD_CONTEXT
83 static IOWorkLoop * gIOPMWorkLoop = 0;
84 #define ASSERT_GATED() \
85 do { \
86 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
87 panic("RootDomain: not inside PM gate"); \
88 } \
89 } while(false)
90 #else
91 #define ASSERT_GATED()
92 #endif /* CHECK_THREAD_CONTEXT */
93
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
113 // Event types for IOPMPowerStateQueue::submitPowerEvent()
114 enum {
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.
132 enum {
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
142 };
143
144 extern "C" {
145 IOReturn OSKextSystemSleepOrWake( UInt32 );
146 }
147
148 static void idleSleepTimerExpired( thread_call_param_t, thread_call_param_t );
149 static void notifySystemShutdown( IOService * root, unsigned long event );
150 static void handleAggressivesFunction( thread_call_param_t, thread_call_param_t );
151 static void pmEventTimeStamp(uint64_t *recordTS);
152
153 // "IOPMSetSleepSupported" callPlatformFunction name
154 static const OSSymbol *sleepSupportedPEFunction = NULL;
155 static const OSSymbol *sleepMessagePEFunction = NULL;
156
157 #define kIOSleepSupportedKey "IOSleepSupported"
158 #define kIOPMSystemCapabilitiesKey "System Capabilities"
159
160 #define kRD_AllPowerSources (kIOPMSupportedOnAC \
161 | kIOPMSupportedOnBatt \
162 | kIOPMSupportedOnUPS)
163
164 enum
165 {
166 // not idle around autowake time, secs
167 kAutoWakePreWindow = 45,
168 kAutoWakePostWindow = 15
169 };
170
171 #define kLocalEvalClamshellCommand (1 << 15)
172
173 enum {
174 OFF_STATE = 0,
175 RESTART_STATE = 1,
176 SLEEP_STATE = 2,
177 ON_STATE = 3,
178 NUM_POWER_STATES
179 };
180
181 #define ON_POWER kIOPMPowerOn
182 #define RESTART_POWER kIOPMRestart
183 #define SLEEP_POWER kIOPMAuxPowerOn
184
185 static 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},
190 {1, kIOPMPowerOn, kIOPMPowerOn, ON_POWER, 0,0,0,0,0,0,0,0}
191 };
192
193 #define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
194 #define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer"
195 #define kIOPMrootDomainWakeTypeLowBattery "LowBattery"
196 #define kIOPMRootDomainWakeTypeUser "User"
197 #define kIOPMRootDomainWakeTypeAlarm "Alarm"
198 #define kIOPMRootDomainWakeTypeNetwork "Network"
199
200 // Special interest that entitles the interested client from receiving
201 // all system messages. Only used by powerd.
202 //
203 #define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest"
204
205 /*
206 * Aggressiveness
207 */
208 #define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
209 #define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
210
211 #define kAggressivesMinValue 1
212
213 enum {
214 kAggressivesStateBusy = 0x01,
215 kAggressivesStateQuickSpindown = 0x02
216 };
217
218 struct AggressivesRecord {
219 uint32_t flags;
220 uint32_t type;
221 uint32_t value;
222 };
223
224 struct 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
234 enum {
235 kAggressivesRequestTypeService = 1,
236 kAggressivesRequestTypeRecord
237 };
238
239 enum {
240 kAggressivesOptionSynchronous = 0x00000001,
241 kAggressivesOptionQuickSpindownEnable = 0x00000100,
242 kAggressivesOptionQuickSpindownDisable = 0x00000200,
243 kAggressivesOptionQuickSpindownMask = 0x00000300
244 };
245
246 enum {
247 kAggressivesRecordFlagModified = 0x00000001,
248 kAggressivesRecordFlagMinValue = 0x00000002
249 };
250
251 // gDarkWakeFlags
252 enum {
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
261 };
262
263 static IOPMrootDomain * gRootDomain;
264 static IONotifier * gSysPowerDownNotifier = 0;
265 static UInt32 gSleepOrShutdownPending = 0;
266 static UInt32 gWillShutdown = 0;
267 static UInt32 gPagingOff = 0;
268 static UInt32 gSleepWakeUUIDIsSet = false;
269 static uint32_t gAggressivesState = 0;
270 static uint32_t gDarkWakeFlags = kDarkWakeFlagHIDTickleNone;
271 static bool gRAMDiskImageBoot = false;
272
273 struct timeval gIOLastSleepTime;
274 struct timeval gIOLastWakeTime;
275
276 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
277 #define kCPUUnknownIndex 9999999
278 enum {
279 kInformAC = 0,
280 kInformLid = 1,
281 kInformableCount = 2
282 };
283
284 const OSSymbol *gIOPMStatsApplicationResponseTimedOut;
285 const OSSymbol *gIOPMStatsApplicationResponseCancel;
286 const OSSymbol *gIOPMStatsApplicationResponseSlow;
287
288 /*
289 * PMSettingHandle
290 * Opaque handle passed to clients of registerPMSettingController()
291 */
292 class PMSettingHandle : public OSObject
293 {
294 OSDeclareFinalStructors( PMSettingHandle )
295 friend class PMSettingObject;
296
297 private:
298 PMSettingObject *pmso;
299 void free(void);
300 };
301
302 /*
303 * PMSettingObject
304 * Internal object to track each PM setting controller
305 */
306 class PMSettingObject : public OSObject
307 {
308 OSDeclareFinalStructors( PMSettingObject )
309 friend class IOPMrootDomain;
310
311 private:
312 queue_head_t calloutQueue;
313 thread_t waitThread;
314 IOPMrootDomain *parent;
315 PMSettingHandle *pmsh;
316 IOPMSettingControllerCallback func;
317 OSObject *target;
318 uintptr_t refcon;
319 uint32_t *publishedFeatureID;
320 uint32_t settingCount;
321 bool disabled;
322
323 void free(void);
324
325 public:
326 static PMSettingObject *pmSettingObject(
327 IOPMrootDomain *parent_arg,
328 IOPMSettingControllerCallback handler_arg,
329 OSObject *target_arg,
330 uintptr_t refcon_arg,
331 uint32_t supportedPowerSources,
332 const OSSymbol *settings[],
333 OSObject **handle_obj);
334
335 void dispatchPMSetting(const OSSymbol *type, OSObject *object);
336 void clientHandleFreed(void);
337 };
338
339 struct PMSettingCallEntry {
340 queue_chain_t link;
341 thread_t thread;
342 };
343
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)
348
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 */
358 class IOPMTimeline : public OSObject
359 {
360 OSDeclareDefaultStructors( IOPMTimeline );
361
362 public:
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);
378 private:
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
415 OSDefineMetaClassAndStructors( 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
424 typedef void (*IOPMTracePointHandler)(
425 void * target, uint32_t code, uint32_t data );
426
427 class PMTraceWorker : public OSObject
428 {
429 OSDeclareDefaultStructors(PMTraceWorker)
430 public:
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;
445 private:
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;
455 };
456
457 /*
458 * PMAssertionsTracker
459 * Tracks kernel and user space PM assertions
460 */
461 class PMAssertionsTracker : public OSObject
462 {
463 OSDeclareFinalStructors(PMAssertionsTracker)
464 public:
465 static PMAssertionsTracker *pmAssertionsTracker( IOPMrootDomain * );
466
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
482 private:
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;
492
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;
502 IOPMDriverAssertionID issuingUniqueID __attribute__((aligned(8))); /* aligned for atomic access */
503 IOPMDriverAssertionType assertionsKernel;
504 IOPMDriverAssertionType assertionsUser;
505 IOPMDriverAssertionType assertionsCombined;
506 };
507
508 OSDefineMetaClassAndFinalStructors(PMAssertionsTracker, OSObject);
509
510 /*
511 * PMHaltWorker
512 * Internal helper object for Shutdown/Restart notifications.
513 */
514 #define kPMHaltMaxWorkers 8
515 #define kPMHaltTimeoutMS 100
516
517 class PMHaltWorker : public OSObject
518 {
519 OSDeclareFinalStructors( PMHaltWorker )
520
521 public:
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 );
530 static void main( void * arg, wait_result_t waitResult );
531 static void work( PMHaltWorker * me );
532 static void checkTimeout( PMHaltWorker * me, AbsoluteTime * now );
533 virtual void free( void );
534 };
535
536 OSDefineMetaClassAndFinalStructors( PMHaltWorker, OSObject )
537
538
539 #define super IOService
540 OSDefineMetaClassAndFinalStructors(IOPMrootDomain, IOService)
541
542 static 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
555 extern "C"
556 {
557 IONotifier * registerSleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
558 {
559 return gRootDomain->registerInterest( gIOGeneralInterest, handler, self, ref );
560 }
561
562 IONotifier * registerPrioritySleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
563 {
564 return gRootDomain->registerInterest( gIOPriorityPowerStateInterest, handler, self, ref );
565 }
566
567 IOReturn acknowledgeSleepWakeNotification(void * PMrefcon)
568 {
569 return gRootDomain->allowPowerChange ( (unsigned long)PMrefcon );
570 }
571
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
587 void IOSystemShutdownNotification(void)
588 {
589 IOPMRootDomainWillShutdown();
590 if (OSCompareAndSwap(0, 1, &gPagingOff))
591 {
592 #if !CONFIG_EMBEDDED
593 gRootDomain->handlePlatformHaltRestart(kPEPagingOff);
594 #endif
595 }
596 }
597
598 int sync_internal(void);
599 }
600
601 /*
602 A device is always in the highest power state which satisfies its driver,
603 its policy-maker, and any power children it has, but within the constraint
604 of the power state provided by its parent. The driver expresses its desire by
605 calling changePowerStateTo(), the policy-maker expresses its desire by calling
606 changePowerStateToPriv(), and the children express their desires by calling
607 requestPowerDomainState().
608
609 The Root Power Domain owns the policy for idle and demand sleep for the system.
610 It is a power-managed IOService just like the others in the system.
611 It implements several power states which map to what we see as Sleep and On.
612
613 The sleep policy is as follows:
614 1. Sleep is prevented if the case is open so that nobody will think the machine
615 is off and plug/unplug cards.
616 2. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
617 3. System cannot Sleep if some object in the tree is in a power state marked
618 kIOPMPreventSystemSleep.
619
620 These three conditions are enforced using the "driver clamp" by calling
621 changePowerStateTo(). For example, if the case is opened,
622 changePowerStateTo(ON_STATE) is called to hold the system on regardless
623 of the desires of the children of the root or the state of the other clamp.
624
625 Demand Sleep is initiated by pressing the front panel power button, closing
626 the clamshell, or selecting the menu item. In this case the root's parent
627 actually initiates the power state change so that the root domain has no
628 choice and does not give applications the opportunity to veto the change.
629
630 Idle Sleep occurs if no objects in the tree are in a state marked
631 kIOPMPreventIdleSleep. When this is true, the root's children are not holding
632 the root on, so it sets the "policy-maker clamp" by calling
633 changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
634 This timer is set for the difference between the sleep timeout slider and the
635 display dim timeout slider. When the timer expires, it releases its clamp and
636 now nothing is holding it awake, so it falls asleep.
637
638 Demand sleep is prevented when the system is booting. When preferences are
639 transmitted by the loginwindow at the end of boot, a flag is cleared,
640 and this allows subsequent Demand Sleep.
641 */
642
643 //******************************************************************************
644
645 IOPMrootDomain * IOPMrootDomain::construct( void )
646 {
647 IOPMrootDomain *root;
648
649 root = new IOPMrootDomain;
650 if( root)
651 root->init();
652
653 return( root );
654 }
655
656 //******************************************************************************
657
658 static void disk_sync_callout( thread_call_param_t p0, thread_call_param_t p1 )
659 {
660 IOService * rootDomain = (IOService *) p0;
661 uint32_t notifyRef = (uint32_t)(uintptr_t) p1;
662 uint32_t powerState = rootDomain->getPowerState();
663
664 DLOG("disk_sync_callout ps=%u\n", powerState);
665
666 if (ON_STATE == powerState)
667 {
668 #if HIBERNATION
669 IOHibernateSystemSleep();
670 #endif
671 sync_internal();
672 }
673 #if HIBERNATION
674 else
675 {
676 IOHibernateSystemPostWake();
677 }
678 #endif
679
680 rootDomain->allowPowerChange(notifyRef);
681 DLOG("disk_sync_callout finish\n");
682 }
683
684 //******************************************************************************
685
686 static UInt32 computeDeltaTimeMS( const AbsoluteTime * startTime )
687 {
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 }
697
698 return (UInt32)(nano / 1000000ULL);
699 }
700
701 //******************************************************************************
702
703 static int
704 sysctl_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
724 static SYSCTL_PROC(_kern, OID_AUTO, sleeptime,
725 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
726 &gIOLastSleepTime, 0, sysctl_sleepwaketime, "S,timeval", "");
727
728 static SYSCTL_PROC(_kern, OID_AUTO, waketime,
729 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
730 &gIOLastWakeTime, 0, sysctl_sleepwaketime, "S,timeval", "");
731
732
733 static int
734 sysctl_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)) {
741 IOPMRootDomainWillShutdown();
742 } else
743 error = EINVAL;
744 }
745 return(error);
746 }
747
748 static SYSCTL_PROC(_kern, OID_AUTO, willshutdown,
749 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
750 0, 0, sysctl_willshutdown, "I", "");
751
752 #if !CONFIG_EMBEDDED
753
754 static int
755 sysctl_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
769 static int
770 sysctl_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
784 static SYSCTL_PROC(_kern, OID_AUTO, progressmeterenable,
785 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
786 0, 0, sysctl_progressmeterenable, "I", "");
787
788 static SYSCTL_PROC(_kern, OID_AUTO, progressmeter,
789 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
790 0, 0, sysctl_progressmeter, "I", "");
791
792 #endif
793
794 static SYSCTL_INT(_debug, OID_AUTO, darkwake, CTLFLAG_RW, &gDarkWakeFlags, 0, "");
795
796 static const OSSymbol * gIOPMSettingAutoWakeSecondsKey;
797 static const OSSymbol * gIOPMSettingDebugWakeRelativeKey;
798 static const OSSymbol * gIOPMSettingMaintenanceWakeCalendarKey;
799
800 //******************************************************************************
801 // start
802 //
803 //******************************************************************************
804
805 #define kRootDomainSettingsCount 16
806
807 bool IOPMrootDomain::start( IOService * nub )
808 {
809 OSIterator *psIterator;
810 OSDictionary *tmpDict;
811 IORootParent * patriarch;
812
813 super::start(nub);
814
815 gRootDomain = this;
816 gIOPMSettingAutoWakeSecondsKey = OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey);
817 gIOPMSettingDebugWakeRelativeKey = OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey);
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");
826 sleepMessagePEFunction = OSSymbol::withCString("IOPMSystemSleepMessage");
827
828 const OSSymbol *settingsArr[kRootDomainSettingsCount] =
829 {
830 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey),
831 gIOPMSettingAutoWakeSecondsKey,
832 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey),
833 OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey),
834 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey),
835 gIOPMSettingDebugWakeRelativeKey,
836 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey),
837 OSSymbol::withCString(kIOPMSettingWakeOnRingKey),
838 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey),
839 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey),
840 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey),
841 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey),
842 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey),
843 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey),
844 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey),
845 OSSymbol::withCString(kIOPMStateConsoleShutdown)
846 };
847
848 PE_parse_boot_argn("darkwake", &gDarkWakeFlags, sizeof(gDarkWakeFlags));
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 }
860
861 queue_init(&aggressivesQueue);
862 aggressivesThreadCall = thread_call_allocate(handleAggressivesFunction, this);
863 aggressivesData = OSData::withCapacity(
864 sizeof(AggressivesRecord) * (kPMLastAggressivenessType + 4));
865
866 featuresDictLock = IOLockAlloc();
867 settingsCtrlLock = IOLockAlloc();
868 setPMRootDomain(this);
869
870 extraSleepTimer = thread_call_allocate(
871 idleSleepTimerExpired,
872 (thread_call_param_t) this);
873
874 diskSyncCalloutEntry = thread_call_allocate(
875 &disk_sync_callout,
876 (thread_call_param_t) this);
877
878 setProperty(kIOSleepSupportedKey, true);
879
880 bzero(&pmStats, sizeof(pmStats));
881
882 pmTracer = PMTraceWorker::tracer(this);
883
884 pmAssertions = PMAssertionsTracker::pmAssertionsTracker(this);
885
886 userDisabledAllSleep = false;
887 systemBooting = true;
888 sleepSlider = 0;
889 idleSleepTimerPending = false;
890 wrangler = NULL;
891 clamshellClosed = false;
892 clamshellExists = false;
893 clamshellDisabled = true;
894 acAdaptorConnected = true;
895
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
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);
914
915 idxPMCPUClamshell = kCPUUnknownIndex;
916 idxPMCPULimitedPower = kCPUUnknownIndex;
917
918 tmpDict = OSDictionary::withCapacity(1);
919 setProperty(kRootDomainSupportedFeatures, tmpDict);
920 tmpDict->release();
921
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);
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));
940 getPMworkloop()->addEventSource(pmPowerStateQueue);
941 #ifdef CHECK_THREAD_CONTEXT
942 gIOPMWorkLoop = getPMworkloop();
943 #endif
944
945 // create our power parent
946 patriarch = new IORootParent;
947 patriarch->init();
948 patriarch->attach(this);
949 patriarch->start(this);
950 patriarch->addPowerChild(this);
951
952 registerPowerDriver(this, ourPowerStates, NUM_POWER_STATES);
953 changePowerStateToPriv(ON_STATE);
954
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
970 // install power change handler
971 gSysPowerDownNotifier = registerPrioritySleepWakeInterest( &sysPowerDownHandler, this, 0);
972
973 #if !NO_KERNEL_HID
974 // Register for a notification when IODisplayWrangler is published
975 if ((tmpDict = serviceMatching("IODisplayWrangler")))
976 {
977 _displayWranglerNotifier = addMatchingNotification(
978 gIOPublishNotification, tmpDict,
979 (IOServiceMatchingNotificationHandler) &displayWranglerMatchPublished,
980 this, 0);
981 tmpDict->release();
982 }
983 #endif
984
985 const OSSymbol *ucClassName = OSSymbol::withCStringNoCopy("RootDomainUserClient");
986 setProperty(gIOUserClientClassKey, (OSObject *) ucClassName);
987 ucClassName->release();
988
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() )
994 {
995 // There's at least one battery on the system, so we publish
996 // 'DisplayDims' support for the LCD.
997 publishFeature("DisplayDims");
998 }
999 if(psIterator) {
1000 psIterator->release();
1001 }
1002
1003 sysctl_register_oid(&sysctl__kern_sleeptime);
1004 sysctl_register_oid(&sysctl__kern_waketime);
1005 sysctl_register_oid(&sysctl__kern_willshutdown);
1006 #if !CONFIG_EMBEDDED
1007 sysctl_register_oid(&sysctl__kern_progressmeterenable);
1008 sysctl_register_oid(&sysctl__kern_progressmeter);
1009 #endif /* !CONFIG_EMBEDDED */
1010
1011 #if HIBERNATION
1012 IOHibernateSystemInit(this);
1013 #endif
1014
1015 registerService(); // let clients find us
1016
1017 return true;
1018 }
1019
1020 //******************************************************************************
1021 // setProperties
1022 //
1023 // Receive a setProperty call
1024 // The "System Boot" property means the system is completely booted.
1025 //******************************************************************************
1026
1027 IOReturn IOPMrootDomain::setProperties( OSObject * props_obj )
1028 {
1029 IOReturn return_value = kIOReturnSuccess;
1030 OSDictionary *dict = OSDynamicCast(OSDictionary, props_obj);
1031 OSBoolean *b;
1032 OSNumber *n;
1033 OSDictionary *d;
1034 OSSymbol *type;
1035 OSObject *obj;
1036 unsigned int i;
1037
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);
1048 #if HIBERNATION
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);
1053 #endif
1054
1055 if (!dict)
1056 {
1057 return_value = kIOReturnBadArgument;
1058 goto exit;
1059 }
1060
1061 if ((b = OSDynamicCast(OSBoolean, dict->getObject(publish_simulated_battery_string))))
1062 {
1063 publishResource(publish_simulated_battery_string, kOSBooleanTrue);
1064 }
1065
1066 if ((n = OSDynamicCast(OSNumber, dict->getObject(idle_seconds_string))))
1067 {
1068 setProperty(idle_seconds_string, n);
1069 idleSeconds = n->unsigned32BitValue();
1070 }
1071
1072 if (boot_complete_string && dict->getObject(boot_complete_string))
1073 {
1074 pmPowerStateQueue->submitPowerEvent( kPowerEventSystemBootCompleted );
1075 }
1076
1077 if( battery_warning_disabled_string && dict->getObject(battery_warning_disabled_string))
1078 {
1079 setProperty( battery_warning_disabled_string, dict->getObject(battery_warning_disabled_string));
1080 }
1081
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))))
1095 {
1096 pmPowerStateQueue->submitPowerEvent(kPowerEventSystemShutdown, (void *) b);
1097 }
1098
1099 if( stall_halt_string && (b = OSDynamicCast(OSBoolean, dict->getObject(stall_halt_string))) )
1100 {
1101 setProperty(stall_halt_string, b);
1102 }
1103
1104 #if HIBERNATION
1105 if ( hibernatemode_string
1106 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatemode_string))))
1107 {
1108 setProperty(hibernatemode_string, n);
1109 }
1110 if ( hibernatefreeratio_string
1111 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatefreeratio_string))))
1112 {
1113 setProperty(hibernatefreeratio_string, n);
1114 }
1115 if ( hibernatefreetime_string
1116 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatefreetime_string))))
1117 {
1118 setProperty(hibernatefreetime_string, n);
1119 }
1120 OSString *str;
1121 if ( hibernatefile_string
1122 && (str = OSDynamicCast(OSString, dict->getObject(hibernatefile_string))))
1123 {
1124 setProperty(hibernatefile_string, str);
1125 }
1126 #endif
1127
1128 if( sleepdisabled_string
1129 && (b = OSDynamicCast(OSBoolean, dict->getObject(sleepdisabled_string))) )
1130 {
1131 setProperty(sleepdisabled_string, b);
1132 pmPowerStateQueue->submitPowerEvent(kPowerEventUserDisabledSleep, (void *) b);
1133 }
1134 if (ondeck_sleepwake_uuid_string
1135 && (obj = dict->getObject(ondeck_sleepwake_uuid_string)))
1136 {
1137 if(pmPowerStateQueue) {
1138 obj->retain();
1139 pmPowerStateQueue->submitPowerEvent(kPowerEventQueueSleepWakeUUID, (void *)obj);
1140 }
1141
1142 }
1143
1144 if (loginwindow_tracepoint_string
1145 && (n = OSDynamicCast(OSNumber, dict->getObject(loginwindow_tracepoint_string)))
1146 && pmTracer)
1147 {
1148 pmTracer->traceLoginWindowPhase( n->unsigned8BitValue() );
1149 }
1150
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 }
1159 if ((b = OSDynamicCast(OSBoolean, dict->getObject(kIOPMDestroyFVKeyOnStandbyKey))))
1160 {
1161 setProperty(kIOPMDestroyFVKeyOnStandbyKey, b);
1162 }
1163
1164 // Relay our allowed PM settings onto our registered PM clients
1165 for(i = 0; i < allowedPMSettings->getCount(); i++) {
1166
1167 type = (OSSymbol *)allowedPMSettings->getObject(i);
1168 if(!type) continue;
1169
1170 obj = dict->getObject(type);
1171 if(!obj) continue;
1172
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 }
1198
1199 return_value = setPMSetting(type, obj);
1200
1201 if(kIOReturnSuccess != return_value) goto exit;
1202 }
1203
1204 exit:
1205 if(publish_simulated_battery_string) publish_simulated_battery_string->release();
1206 if(boot_complete_string) boot_complete_string->release();
1207 if(sys_shutdown_string) sys_shutdown_string->release();
1208 if(stall_halt_string) stall_halt_string->release();
1209 if(battery_warning_disabled_string) battery_warning_disabled_string->release();
1210 if(idle_seconds_string) idle_seconds_string->release();
1211 if(sleepdisabled_string) sleepdisabled_string->release();
1212 if(ondeck_sleepwake_uuid_string) ondeck_sleepwake_uuid_string->release();
1213 if(loginwindow_tracepoint_string) loginwindow_tracepoint_string->release();
1214 if(pmTimelineLogging_string) pmTimelineLogging_string->release();
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
1221 return return_value;
1222 }
1223
1224 // MARK: -
1225 // MARK: Aggressiveness
1226
1227 //******************************************************************************
1228 // setAggressiveness
1229 //
1230 // Override IOService::setAggressiveness()
1231 //******************************************************************************
1232
1233 IOReturn IOPMrootDomain::setAggressiveness(
1234 unsigned long type,
1235 unsigned long value )
1236 {
1237 return setAggressiveness( type, value, 0 );
1238 }
1239
1240 /*
1241 * Private setAggressiveness() with an internal options argument.
1242 */
1243 IOReturn IOPMrootDomain::setAggressiveness(
1244 unsigned long type,
1245 unsigned long value,
1246 IOOptionBits options )
1247 {
1248 AggressivesRequest * entry;
1249 AggressivesRequest * request;
1250 bool found = false;
1251
1252 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1253 (uint32_t) options, (uint32_t) type, (uint32_t) value);
1254
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
1275 {
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 }
1290 }
1291
1292 if (!found)
1293 {
1294 queue_enter(&aggressivesQueue, request, AggressivesRequest *, chain);
1295 }
1296
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;
1308 }
1309
1310 //******************************************************************************
1311 // getAggressiveness
1312 //
1313 // Override IOService::setAggressiveness()
1314 // Fetch the aggressiveness factor with the given type.
1315 //******************************************************************************
1316
1317 IOReturn IOPMrootDomain::getAggressiveness (
1318 unsigned long type,
1319 unsigned long * outLevel )
1320 {
1321 uint32_t value = 0;
1322 int source = 0;
1323
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 {
1382 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1383 source, (uint32_t) type, value);
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 }
1393 }
1394
1395 //******************************************************************************
1396 // joinAggressiveness
1397 //
1398 // Request from IOService to join future aggressiveness broadcasts.
1399 //******************************************************************************
1400
1401 IOReturn IOPMrootDomain::joinAggressiveness(
1402 IOService * service )
1403 {
1404 AggressivesRequest * request;
1405
1406 if (!service || (service == this))
1407 return kIOReturnBadArgument;
1408
1409 DLOG("joinAggressiveness %s %p\n", service->getName(), service);
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);
1426
1427 return kIOReturnSuccess;
1428 }
1429
1430 //******************************************************************************
1431 // handleAggressivesRequests
1432 //
1433 // Backend thread processes all incoming aggressiveness requests in the queue.
1434 //******************************************************************************
1435
1436 static void
1437 handleAggressivesFunction(
1438 thread_call_param_t param1,
1439 thread_call_param_t param2 )
1440 {
1441 if (param1)
1442 {
1443 ((IOPMrootDomain *) param1)->handleAggressivesRequests();
1444 }
1445 }
1446
1447 void 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);
1495 DLOG("disk spindown accelerated, was %u min\n",
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
1590 unlock_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) {
1597 pmPowerStateQueue->submitPowerEvent(
1598 kPowerEventPolicyStimulus,
1599 (void *) kStimulusAggressivenessChanged );
1600 }
1601 }
1602
1603 //******************************************************************************
1604 // synchronizeAggressives
1605 //
1606 // Push all known aggressiveness records to one or more IOService.
1607 //******************************************************************************
1608
1609 void 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;
1617 IOPMDriverCallEntry callEntry;
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 {
1634 if (service->assertPMDriverCall(&callEntry))
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
1642 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
1643 record->type, value, service->getName());
1644 service->setAggressiveness(record->type, value);
1645 }
1646 service->deassertPMDriverCall(&callEntry);
1647 }
1648 service->release(); // retained by joinAggressiveness()
1649 }
1650 }
1651 }
1652
1653 //******************************************************************************
1654 // broadcastAggressives
1655 //
1656 // Traverse PM tree and call setAggressiveness() for records that have changed.
1657 //******************************************************************************
1658
1659 void IOPMrootDomain::broadcastAggressives(
1660 const AggressivesRecord * array,
1661 int count )
1662 {
1663 IORegistryIterator * iter;
1664 IORegistryEntry * entry;
1665 IOPowerConnection * connect;
1666 IOService * service;
1667 const AggressivesRecord * record;
1668 IOPMDriverCallEntry callEntry;
1669 uint32_t value;
1670 int i;
1671
1672 iter = IORegistryIterator::iterateOver(
1673 this, gIOPowerPlane, kIORegistryIterateRecursively);
1674 if (iter)
1675 {
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 {
1687 if (service->assertPMDriverCall(&callEntry))
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;
1696 _LOG("broadcastAggressives %x = %u to %s\n",
1697 record->type, value, service->getName());
1698 service->setAggressiveness(record->type, value);
1699 }
1700 }
1701 service->deassertPMDriverCall(&callEntry);
1702 }
1703 service->release();
1704 }
1705 }
1706 }
1707 while (!entry && !iter->isValid());
1708 iter->release();
1709 }
1710 }
1711
1712 // MARK: -
1713 // MARK: System Sleep
1714
1715 //******************************************************************************
1716 // startIdleSleepTimer
1717 //
1718 //******************************************************************************
1719
1720 void 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
1734 //******************************************************************************
1735 // cancelIdleSleepTimer
1736 //
1737 //******************************************************************************
1738
1739 void IOPMrootDomain::cancelIdleSleepTimer( void )
1740 {
1741 ASSERT_GATED();
1742 if (idleSleepTimerPending)
1743 {
1744 DLOG("idle timer cancelled\n");
1745 thread_call_cancel(extraSleepTimer);
1746 idleSleepTimerPending = false;
1747 }
1748 }
1749
1750 //******************************************************************************
1751 // idleSleepTimerExpired
1752 //
1753 //******************************************************************************
1754
1755 static void idleSleepTimerExpired(
1756 thread_call_param_t us, thread_call_param_t )
1757 {
1758 ((IOPMrootDomain *)us)->handleSleepTimerExpiration();
1759 }
1760
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
1768 void 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
1794 setQuickSpinDownTimeout();
1795 adjustPowerState(true);
1796 }
1797
1798 //******************************************************************************
1799 // setQuickSpinDownTimeout
1800 //
1801 //******************************************************************************
1802
1803 void IOPMrootDomain::setQuickSpinDownTimeout( void )
1804 {
1805 ASSERT_GATED();
1806 setAggressiveness(
1807 kPMMinutesToSpinDown, 0, kAggressivesOptionQuickSpindownEnable );
1808 }
1809
1810 //******************************************************************************
1811 // restoreUserSpinDownTimeout
1812 //
1813 //******************************************************************************
1814
1815 void IOPMrootDomain::restoreUserSpinDownTimeout( void )
1816 {
1817 ASSERT_GATED();
1818 setAggressiveness(
1819 kPMMinutesToSpinDown, 0, kAggressivesOptionQuickSpindownDisable );
1820 }
1821
1822 //******************************************************************************
1823 // sleepSystem
1824 //
1825 //******************************************************************************
1826
1827 /* public */
1828 IOReturn IOPMrootDomain::sleepSystem( void )
1829 {
1830 return sleepSystemOptions(NULL);
1831 }
1832
1833 /* private */
1834 IOReturn IOPMrootDomain::sleepSystemOptions( OSDictionary *options )
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 {
1846 // Log specific sleep cause for OS Switch hibernation
1847 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate);
1848 } else {
1849 return privateSleepSystem( kIOPMSleepReasonSoftware);
1850 }
1851 }
1852
1853 /* private */
1854 IOReturn IOPMrootDomain::privateSleepSystem( uint32_t sleepReason )
1855 {
1856 static const char * IOPMSleepReasons[] = {
1857 "",
1858 kIOPMClamshellSleepKey,
1859 kIOPMPowerButtonSleepKey,
1860 kIOPMSoftwareSleepKey,
1861 kIOPMOSSwitchHibernationKey,
1862 kIOPMIdleSleepKey,
1863 kIOPMLowPowerSleepKey,
1864 kIOPMClamshellSleepKey,
1865 kIOPMThermalEmergencySleepKey,
1866 kIOPMMaintenanceSleepKey
1867 };
1868
1869 PMEventDetails *details;
1870
1871 if (!checkSystemCanSleep())
1872 {
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 }
1880
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);
1887 }
1888
1889
1890 // Log the beginning of system sleep.
1891 details = PMEventDetails::eventDetails(kIOPMEventTypeSleep, NULL,
1892 sleepReason, kIOReturnSuccess);
1893
1894 recordAndReleasePMEvent( details );
1895
1896 // Record sleep cause in IORegistry
1897 lastSleepReason = sleepReason;
1898 sleepReason -= (kIOPMSleepReasonClamshell - 1);
1899 if (sleepReason && (sleepReason < sizeof(IOPMSleepReasons)/sizeof(IOPMSleepReasons[0]))) {
1900 setProperty(kRootDomainSleepReasonKey, IOPMSleepReasons[sleepReason]);
1901 }
1902
1903 if (pmPowerStateQueue)
1904 pmPowerStateQueue->submitPowerEvent(
1905 kPowerEventPolicyStimulus,
1906 (void *) kStimulusDemandSystemSleep );
1907
1908 return kIOReturnSuccess;
1909 }
1910
1911 IOReturn 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;
1918
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 ...
1930
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 }
1943 }
1944
1945 IOReturn IOPMrootDomain::recordAndReleasePMEventGated(PMEventDetails *record)
1946 {
1947 IOReturn ret = kIOReturnBadArgument;
1948
1949 if (record)
1950 {
1951 ret = recordPMEventGated(record);
1952 record->release();
1953 }
1954
1955 return ret;
1956 }
1957
1958 //******************************************************************************
1959 // powerChangeDone
1960 //
1961 // This overrides powerChangeDone in IOService.
1962 //******************************************************************************
1963
1964 void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState )
1965 {
1966 PMEventDetails *details;
1967
1968 ASSERT_GATED();
1969 DLOG("PowerChangeDone: %u->%u\n",
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 );
1985
1986 // re-enable this timer for next sleep
1987 cancelIdleSleepTimer();
1988
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;
1997
1998 #if HIBERNATION
1999 LOG("System %sSleep\n", gIOHibernateState ? "Safe" : "");
2000
2001 IOHibernateSystemHasSlept();
2002
2003 evaluateSystemSleepPolicyFinal();
2004 #else
2005 LOG("System Sleep\n");
2006 #endif
2007
2008 getPlatform()->sleepKernel();
2009
2010 // The CPU(s) are off at this point,
2011 // Code will resume execution here upon wake.
2012
2013 clock_get_uptime(&systemWakeTime);
2014
2015 #if HIBERNATION
2016 IOHibernateSystemWake();
2017 #endif
2018
2019 // sleep transition complete
2020 gSleepOrShutdownPending = 0;
2021
2022 // trip the reset of the calendar clock
2023 clock_wakeup_calendar();
2024
2025 #if HIBERNATION
2026 LOG("System %sWake\n", gIOHibernateState ? "SafeSleep " : "");
2027 #endif
2028
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
2044
2045 #ifndef __LP64__
2046 systemWake();
2047 #endif
2048
2049 #if defined(__i386__) || defined(__x86_64__)
2050 wranglerTickled = false;
2051 graphicsSuppressed = false;
2052 darkWakePostTickle = false;
2053 logGraphicsClamp = true;
2054 logWranglerTickle = true;
2055 sleepTimerMaintenance = false;
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))))
2081 {
2082 wranglerTickled = true;
2083 }
2084 else
2085 if (wakeType &&
2086 wakeType->isEqualTo(kIOPMRootDomainWakeTypeMaintenance))
2087 {
2088 darkWakeMaintenance = true;
2089 darkWakeToSleepASAP = true;
2090 }
2091 else
2092 if (wakeType &&
2093 wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer))
2094 {
2095 darkWakeMaintenance = true;
2096 darkWakeToSleepASAP = true;
2097 sleepTimerMaintenance = true;
2098 }
2099 else
2100 {
2101 // Unidentified wake source, resume to full wake if debug
2102 // alarm is pending.
2103
2104 if (_debugWakeSeconds && (!wakeReason || wakeReason->isEqualTo("")))
2105 wranglerTickled = true;
2106 else
2107 darkWakeToSleepASAP = true;
2108 }
2109 }
2110 else
2111 {
2112 // Post a HID tickle immediately - except for maintenance wake.
2113
2114 if (hibernateAborted || !wakeType ||
2115 !wakeType->isEqualTo(kIOPMRootDomainWakeTypeMaintenance))
2116 {
2117 wranglerTickled = true;
2118 }
2119 else
2120 {
2121 darkWakeMaintenance = true;
2122 darkWakeToSleepASAP = true;
2123 }
2124 }
2125
2126 if (wranglerTickled)
2127 reportUserInput();
2128 else if (!darkWakeMaintenance)
2129 {
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);
2167
2168 if (wasPrevented && !childPreventSystemSleep)
2169 {
2170 evaluatePolicy( kStimulusDarkWakeEvaluate );
2171 }
2172 } break;
2173 }
2174 }
2175
2176 //******************************************************************************
2177 // requestPowerDomainState
2178 //
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.
2183 //******************************************************************************
2184
2185 IOReturn IOPMrootDomain::requestPowerDomainState (
2186 IOPMPowerFlags childDesire,
2187 IOPowerConnection * childConnection,
2188 unsigned long specification )
2189 {
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))
2206 {
2207 childDesire &= ~kIOPMPreventIdleSleep;
2208 }
2209
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.
2213
2214 editedChildDesire = 0;
2215 if (childDesire & kIOPMPreventIdleSleep)
2216 editedChildDesire |= (kIOPMPowerOn | kIOPMPreventIdleSleep);
2217 if (childDesire & kIOPMPreventSystemSleep)
2218 editedChildDesire |= (kIOPMPowerOn | kIOPMPreventSystemSleep);
2219
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;
2230
2231 // OR in the child's input power requirements.
2232 // Is this connection attached to the child that called
2233 // requestPowerDomainState()?
2234
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 }
2247
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();
2262 }
2263
2264 DLOG("mergedChildDesire 0x%lx, extraSleepDelay %ld\n",
2265 mergedChildDesire, extraSleepDelay);
2266
2267 if ( !mergedChildDesire && !systemBooting )
2268 {
2269 if (!wrangler)
2270 {
2271 changePowerStateToPriv(ON_STATE);
2272 if (idleSeconds)
2273 {
2274 // stay awake for at least idleSeconds
2275 startIdleSleepTimer(idleSeconds);
2276 }
2277 }
2278 else if (!extraSleepDelay && !idleSleepTimerPending && !systemDarkWake)
2279 {
2280 sleepASAP = true;
2281 }
2282 }
2283
2284 // Drop our power clamp to SLEEP_STATE when all children became idle,
2285 // and system sleep and display sleep slider values are equal.
2286
2287 adjustPowerState(sleepASAP);
2288
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.
2291
2292 return super::requestPowerDomainState(
2293 editedChildDesire, childConnection, specification);
2294 }
2295
2296 //******************************************************************************
2297 // tellChangeDown
2298 //
2299 // Override the superclass implementation to send a different message type.
2300 //******************************************************************************
2301
2302 bool IOPMrootDomain::tellChangeDown( unsigned long stateNum )
2303 {
2304 DLOG("tellChangeDown %u->%u\n",
2305 (uint32_t) getPowerState(), (uint32_t) stateNum);
2306
2307 if (SLEEP_STATE == stateNum)
2308 {
2309 if (!ignoreTellChangeDown)
2310 tracePoint( kIOPMTracePointSleepApplications );
2311 else
2312 tracePoint( kIOPMTracePointSleepPriorityClients );
2313 }
2314
2315 if ((SLEEP_STATE == stateNum) && !ignoreTellChangeDown)
2316 {
2317 userActivityAtSleep = userActivityCount;
2318 hibernateAborted = false;
2319 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep);
2320
2321 // Direct callout into OSKext so it can disable kext unloads
2322 // during sleep/wake to prevent deadlocks.
2323 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep );
2324
2325 IOService::updateConsoleUsers(NULL, kIOMessageSystemWillSleep);
2326
2327 // Notify platform that sleep has begun
2328 getPlatform()->callPlatformFunction(
2329 sleepMessagePEFunction, false,
2330 (void *)(uintptr_t) kIOMessageSystemWillSleep,
2331 NULL, NULL, NULL);
2332
2333 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2334 // But tellClientsWithResponse() must be called for both.
2335 ignoreTellChangeDown = true;
2336 }
2337
2338 return super::tellClientsWithResponse( kIOMessageSystemWillSleep );
2339 }
2340
2341 //******************************************************************************
2342 // askChangeDown
2343 //
2344 // Override the superclass implementation to send a different message type.
2345 // This must be idle sleep since we don't ask during any other power change.
2346 //******************************************************************************
2347
2348 bool IOPMrootDomain::askChangeDown( unsigned long stateNum )
2349 {
2350 DLOG("askChangeDown %u->%u\n",
2351 (uint32_t) getPowerState(), (uint32_t) stateNum);
2352
2353 // Don't log for dark wake entry
2354 if (kSystemTransitionSleep == _systemTransitionType)
2355 tracePoint( kIOPMTracePointSleepApplications );
2356
2357 return super::tellClientsWithResponse( kIOMessageCanSystemSleep );
2358 }
2359
2360 //******************************************************************************
2361 // askChangeDownDone
2362 //
2363 // Called by PM after all apps have responded to kIOMessageCanSystemSleep.
2364 // pmconfigd may create a deny sleep assertion before ack'ing.
2365 //******************************************************************************
2366
2367 void IOPMrootDomain::askChangeDownDone(
2368 IOPMPowerChangeFlags * inOutChangeFlags, bool * cancel )
2369 {
2370 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2371 *inOutChangeFlags, *cancel,
2372 _systemTransitionType,
2373 _currentCapability, _pendingCapability);
2374
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.
2380
2381 if (!checkSystemCanSleep(true))
2382 {
2383 // Cancel dark wake to sleep transition.
2384 // Must re-scan assertions upon entering dark wake.
2385
2386 *cancel = true;
2387 DLOG("cancel dark->sleep\n");
2388 }
2389 }
2390 }
2391
2392 //******************************************************************************
2393 // tellNoChangeDown
2394 //
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 //******************************************************************************
2403
2404 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum )
2405 {
2406 DLOG("tellNoChangeDown %u->%u\n",
2407 (uint32_t) getPowerState(), (uint32_t) stateNum);
2408
2409 if (idleSeconds && !wrangler)
2410 {
2411 // stay awake for at least idleSeconds
2412 startIdleSleepTimer(idleSeconds);
2413 }
2414 return tellClients( kIOMessageSystemWillNotSleep );
2415 }
2416
2417 //******************************************************************************
2418 // tellChangeUp
2419 //
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.
2424 //******************************************************************************
2425
2426 void IOPMrootDomain::tellChangeUp( unsigned long stateNum )
2427 {
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 }
2470
2471 tellClients( kIOMessageSystemHasPoweredOn );
2472 }
2473 }
2474
2475 //******************************************************************************
2476 // sysPowerDownHandler
2477 //
2478 // Perform a vfs sync before system sleep.
2479 //******************************************************************************
2480
2481 IOReturn IOPMrootDomain::sysPowerDownHandler(
2482 void * target, void * refCon,
2483 UInt32 messageType, IOService * service,
2484 void * messageArgs, vm_size_t argSize )
2485 {
2486 IOReturn ret;
2487
2488 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType));
2489
2490 if (!gRootDomain)
2491 return kIOReturnUnsupported;
2492
2493 if (messageType == kIOMessageSystemCapabilityChange)
2494 {
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();
2517
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;
2551
2552 thread_call_enter1(
2553 gRootDomain->diskSyncCalloutEntry,
2554 (thread_call_param_t) params->notifyRef);
2555 }
2556 #endif
2557 ret = kIOReturnSuccess;
2558 }
2559
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
2575 void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject *obj)
2576 {
2577 OSString *str = NULL;
2578
2579 if (kOSBooleanFalse == obj)
2580 {
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;
2589 }
2590 queuedSleepWakeUUIDString = str;
2591 queuedSleepWakeUUIDString->retain();
2592
2593 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString->getCStringNoCopy());
2594 }
2595
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
2612 void 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
2683 IOReturn IOPMrootDomain::changePowerStateTo( unsigned long ordinal )
2684 {
2685 return kIOReturnUnsupported; // ignored
2686 }
2687
2688 IOReturn IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal )
2689 {
2690 DLOG("changePowerStateToPriv(%lu)\n", ordinal);
2691
2692 if ((ordinal != ON_STATE) && (ordinal != SLEEP_STATE))
2693 return kIOReturnUnsupported;
2694
2695 return super::changePowerStateToPriv(ordinal);
2696 }
2697
2698 //******************************************************************************
2699 // activity detect
2700 //
2701 //******************************************************************************
2702
2703 bool IOPMrootDomain::activitySinceSleep(void)
2704 {
2705 return (userActivityCount != userActivityAtSleep);
2706 }
2707
2708 bool IOPMrootDomain::abortHibernation(void)
2709 {
2710 bool ret = activitySinceSleep();
2711
2712 if (ret && !hibernateAborted)
2713 {
2714 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount, userActivityAtSleep);
2715 hibernateAborted = true;
2716 }
2717 return (ret);
2718 }
2719
2720 extern "C" int
2721 hibernate_should_abort(void)
2722 {
2723 if (gRootDomain)
2724 return (gRootDomain->abortHibernation());
2725 else
2726 return (0);
2727 }
2728
2729 //******************************************************************************
2730 // sleepOnClamshellClosed
2731 //
2732 // contains the logic to determine if the system should sleep when the clamshell
2733 // is closed.
2734 //******************************************************************************
2735
2736 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
2737 {
2738 if (!clamshellExists)
2739 return false;
2740
2741 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d\n",
2742 clamshellClosed, clamshellDisabled, desktopMode, acAdaptorConnected);
2743
2744 return ( !clamshellDisabled && !(desktopMode && acAdaptorConnected) );
2745 }
2746
2747 void IOPMrootDomain::sendClientClamshellNotification( void )
2748 {
2749 /* Only broadcast clamshell alert if clamshell exists. */
2750 if (!clamshellExists)
2751 return;
2752
2753 setProperty(kAppleClamshellStateKey,
2754 clamshellClosed ? kOSBooleanTrue : kOSBooleanFalse);
2755
2756 setProperty(kAppleClamshellCausesSleepKey,
2757 shouldSleepOnClamshellClosed() ? kOSBooleanTrue : kOSBooleanFalse);
2758
2759 /* Argument to message is a bitfiel of
2760 * ( kClamshellStateBit | kClamshellSleepBit )
2761 */
2762 messageClients(kIOPMMessageClamshellStateChange,
2763 (void *) ( (clamshellClosed ? kClamshellStateBit : 0)
2764 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit : 0)) );
2765 }
2766
2767 //******************************************************************************
2768 // getSleepSupported
2769 //
2770 // Deprecated
2771 //******************************************************************************
2772
2773 IOOptionBits IOPMrootDomain::getSleepSupported( void )
2774 {
2775 return( platformSleepSupport );
2776 }
2777
2778 //******************************************************************************
2779 // setSleepSupported
2780 //
2781 // Deprecated
2782 //******************************************************************************
2783
2784 void 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
2796 void 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
2810 void 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
2821 void 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
2925 IOReturn 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
3041 exit:
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
3054 IOReturn 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 }
3123 unlock_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
3139 OSObject * 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
3162 IOReturn 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
3195 IOReturn 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
3252 void 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
3316 void IOPMrootDomain::informCPUStateChange(
3317 uint32_t type,
3318 uint32_t value )
3319 {
3320 #if defined(__i386__) || defined(__x86_64__)
3321
3322 pmioctlVariableInfo_t varInfoStruct;
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
3368 #endif /* __i386__ || __x86_64__ */
3369 }
3370
3371 // MARK: -
3372 // MARK: Deep Sleep Policy
3373
3374 #if HIBERNATION
3375
3376 //******************************************************************************
3377 // evaluateSystemSleepPolicy
3378 //******************************************************************************
3379
3380 struct IOPMSystemSleepPolicyEntry
3381 {
3382 uint32_t factorMask;
3383 uint32_t factorBits;
3384 uint32_t sleepFlags;
3385 uint32_t wakeEvents;
3386 };
3387
3388 struct IOPMSystemSleepPolicyTable
3389 {
3390 uint8_t signature[4];
3391 uint16_t version;
3392 uint16_t entryCount;
3393 IOPMSystemSleepPolicyEntry entries[];
3394 };
3395
3396 enum {
3397 kIOPMSleepFactorSleepTimerWake = 0x00000001,
3398 kIOPMSleepFactorLidOpen = 0x00000002,
3399 kIOPMSleepFactorACPower = 0x00000004,
3400 kIOPMSleepFactorLowBattery = 0x00000008,
3401 kIOPMSleepFactorDeepSleepNoDelay = 0x00000010,
3402 kIOPMSleepFactorDeepSleepDemand = 0x00000020,
3403 kIOPMSleepFactorDeepSleepDisable = 0x00000040,
3404 kIOPMSleepFactorUSBExternalDevice = 0x00000080,
3405 kIOPMSleepFactorBluetoothHIDDevice = 0x00000100,
3406 kIOPMSleepFactorExternalMediaMounted = 0x00000200,
3407 kIOPMSleepFactorDriverAssertBit5 = 0x00000400, /* Reserved for ThunderBolt */
3408 kIOPMSleepFactorDriverAssertBit6 = 0x00000800,
3409 kIOPMSleepFactorDriverAssertBit7 = 0x00001000
3410 };
3411
3412 bool 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;
3464 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5) != /* AssertionBit5 = Thunderbolt */
3465 kIOPMDriverAssertionLevelOff)
3466 currentFactors |= kIOPMSleepFactorDriverAssertBit5;
3467 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit7) !=
3468 kIOPMDriverAssertionLevelOff)
3469 currentFactors |= kIOPMSleepFactorDriverAssertBit7;
3470 if (0 == deepSleepDelay)
3471 currentFactors |= kIOPMSleepFactorDeepSleepNoDelay;
3472 if (!clamshellClosed)
3473 currentFactors |= kIOPMSleepFactorLidOpen;
3474 if (acAdaptorConnected)
3475 currentFactors |= kIOPMSleepFactorACPower;
3476 if (lowBatteryCondition)
3477 currentFactors |= kIOPMSleepFactorLowBattery;
3478 if (sleepTimerMaintenance)
3479 currentFactors |= kIOPMSleepFactorSleepTimerWake;
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
3518 done:
3519 if (prop)
3520 prop->release();
3521
3522 return success;
3523 }
3524
3525 void 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
3546 void 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
3588 bool 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
3602 bool 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
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
3645 struct HaltRestartApplierContext {
3646 IOPMrootDomain * RootDomain;
3647 unsigned long PowerState;
3648 IOPMPowerFlags PowerFlags;
3649 UInt32 MessageType;
3650 UInt32 Counter;
3651 };
3652
3653 static void
3654 platformHaltRestartApplier( 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
3694 void 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 IOService::updateConsoleUsers(NULL, kIOMessageSystemPagingOff);
3721 break;
3722
3723 default:
3724 return;
3725 }
3726
3727 // Notify legacy clients
3728 applyToInterested(gIOPriorityPowerStateInterest, platformHaltRestartApplier, &ctx);
3729
3730 // For normal shutdown, turn off File Server Mode.
3731 if (kPEHaltCPU == pe_type)
3732 {
3733 const OSSymbol * setting = OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey);
3734 OSNumber * num = OSNumber::withNumber((unsigned long long) 0, 32);
3735 if (setting && num)
3736 {
3737 setPMSetting(setting, num);
3738 setting->release();
3739 num->release();
3740 }
3741 }
3742
3743 if (kPEPagingOff != pe_type)
3744 {
3745 // Notify in power tree order
3746 notifySystemShutdown(this, ctx.MessageType);
3747 }
3748
3749 deltaTime = computeDeltaTimeMS(&startTime);
3750 LOG("%s all drivers took %u ms\n",
3751 (ctx.MessageType == kIOMessageSystemWillPowerOff) ? "PowerOff" :
3752 (ctx.MessageType == kIOMessageSystemPagingOff) ? "PagingOff" : "Restart",
3753 (uint32_t) deltaTime );
3754 }
3755
3756 //******************************************************************************
3757 // shutdownSystem
3758 //
3759 //******************************************************************************
3760
3761 IOReturn IOPMrootDomain::shutdownSystem( void )
3762 {
3763 return kIOReturnUnsupported;
3764 }
3765
3766 //******************************************************************************
3767 // restartSystem
3768 //
3769 //******************************************************************************
3770
3771 IOReturn IOPMrootDomain::restartSystem( void )
3772 {
3773 return kIOReturnUnsupported;
3774 }
3775
3776 // MARK: -
3777 // MARK: System Capability
3778
3779 //******************************************************************************
3780 // tagPowerPlaneService
3781 //
3782 // Running on PM work loop thread.
3783 //******************************************************************************
3784
3785 void IOPMrootDomain::tagPowerPlaneService(
3786 IOService * service,
3787 IOPMActions * actions )
3788 {
3789 uint32_t flags = 0;
3790 bool isDisplayWrangler;
3791
3792 memset(actions, 0, sizeof(*actions));
3793 actions->target = this;
3794
3795 if (service == this)
3796 {
3797 actions->actionPowerChangeStart =
3798 OSMemberFunctionCast(
3799 IOPMActionPowerChangeStart, this,
3800 &IOPMrootDomain::handleOurPowerChangeStart);
3801
3802 actions->actionPowerChangeDone =
3803 OSMemberFunctionCast(
3804 IOPMActionPowerChangeDone, this,
3805 &IOPMrootDomain::handleOurPowerChangeDone);
3806
3807 actions->actionPowerChangeOverride =
3808 OSMemberFunctionCast(
3809 IOPMActionPowerChangeOverride, this,
3810 &IOPMrootDomain::overrideOurPowerChange);
3811 return;
3812 }
3813
3814 #if !NO_KERNEL_HID
3815 isDisplayWrangler = (0 != service->metaCast("IODisplayWrangler"));
3816 if (isDisplayWrangler)
3817 {
3818 wrangler = service;
3819 wranglerConnection = (IOService *) service->getParentEntry(gIOPowerPlane);
3820 }
3821 #else
3822 isDisplayWrangler = false;
3823 #endif
3824
3825 #if defined(__i386__) || defined(__x86_64__)
3826 if (isDisplayWrangler)
3827 flags |= kPMActionsFlagIsDisplayWrangler;
3828 if (service->getProperty("IOPMStrictTreeOrder"))
3829 flags |= kPMActionsFlagIsGraphicsDevice;
3830 if (service->getProperty("IOPMUnattendedWakePowerState"))
3831 flags |= kPMActionsFlagIsAudioDevice;
3832 #endif
3833
3834 // Find the power connection object that is a child of the PCI host
3835 // bridge, and has a graphics/audio device attached below. Mark the
3836 // power branch for delayed child notifications.
3837
3838 if (flags)
3839 {
3840 IORegistryEntry * child = service;
3841 IORegistryEntry * parent = child->getParentEntry(gIOPowerPlane);
3842
3843 while (child != this)
3844 {
3845 if ((parent == pciHostBridgeDriver) ||
3846 (parent == this))
3847 {
3848 if (OSDynamicCast(IOPowerConnection, child))
3849 {
3850 IOPowerConnection * conn = (IOPowerConnection *) child;
3851 conn->delayChildNotification = true;
3852 }
3853 break;
3854 }
3855 child = parent;
3856 parent = child->getParentEntry(gIOPowerPlane);
3857 }
3858 }
3859
3860 if (flags)
3861 {
3862 DLOG("%s tag flags %x\n", service->getName(), flags);
3863 actions->parameter |= flags;
3864 actions->actionPowerChangeOverride =
3865 OSMemberFunctionCast(
3866 IOPMActionPowerChangeOverride, this,
3867 &IOPMrootDomain::overridePowerChangeForUIService);
3868
3869 if (flags & kPMActionsFlagIsDisplayWrangler)
3870 {
3871 actions->actionActivityTickle =
3872 OSMemberFunctionCast(
3873 IOPMActionActivityTickle, this,
3874 &IOPMrootDomain::handleActivityTickleForDisplayWrangler);
3875 }
3876 return;
3877 }
3878
3879 // Locate the first PCI host bridge for PMTrace.
3880 if (!pciHostBridgeDevice && service->metaCast("IOPCIBridge"))
3881 {
3882 IOService * provider = service->getProvider();
3883 if (OSDynamicCast(IOPlatformDevice, provider) &&
3884 provider->inPlane(gIODTPlane))
3885 {
3886 pciHostBridgeDevice = provider;
3887 pciHostBridgeDriver = service;
3888 DLOG("PMTrace found PCI host bridge %s->%s\n",
3889 provider->getName(), service->getName());
3890 }
3891 }
3892
3893 // Tag top-level PCI devices. The order of PMinit() call does not
3894 // change across boots and is used as the PCI bit number.
3895 if (pciHostBridgeDevice && service->metaCast("IOPCIDevice"))
3896 {
3897 // Would prefer to check built-in property, but tagPowerPlaneService()
3898 // is called before pciDevice->registerService().
3899 IORegistryEntry * parent = service->getParentEntry(gIODTPlane);
3900 if ((parent == pciHostBridgeDevice) && service->getProperty("acpi-device"))
3901 {
3902 int bit = pmTracer->recordTopLevelPCIDevice( service );
3903 if (bit >= 0)
3904 {
3905 // Save the assigned bit for fast lookup.
3906 actions->parameter |= (bit & kPMActionsPCIBitNumberMask);
3907
3908 actions->actionPowerChangeStart =
3909 OSMemberFunctionCast(
3910 IOPMActionPowerChangeStart, this,
3911 &IOPMrootDomain::handlePowerChangeStartForPCIDevice);
3912
3913 actions->actionPowerChangeDone =
3914 OSMemberFunctionCast(
3915 IOPMActionPowerChangeDone, this,
3916 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice);
3917 }
3918 }
3919 }
3920 }
3921
3922 //******************************************************************************
3923 // PM actions for root domain
3924 //******************************************************************************
3925
3926 void IOPMrootDomain::overrideOurPowerChange(
3927 IOService * service,
3928 IOPMActions * actions,
3929 unsigned long * inOutPowerState,
3930 uint32_t * inOutChangeFlags )
3931 {
3932 uint32_t powerState = (uint32_t) *inOutPowerState;
3933 uint32_t changeFlags = *inOutChangeFlags;
3934 uint32_t currentPowerState = (uint32_t) getPowerState();
3935
3936 if ((currentPowerState == powerState) ||
3937 (changeFlags & kIOPMParentInitiated))
3938 {
3939 // FIXME: cancel any parent change (unexpected)
3940 // Root parent is permanently pegged at max power,
3941 // kIOPMParentInitiated is unexpected.
3942 return;
3943 }
3944
3945 if (powerState < currentPowerState)
3946 {
3947 if ((changeFlags & kIOPMSkipAskPowerDown) == 0)
3948 {
3949 /* Convenient place to run any code at idle sleep time
3950 * IOPMrootDomain initiates an idle sleep here
3951 *
3952 * Set last sleep cause accordingly.
3953 */
3954 pmPowerStateQueue->submitPowerEvent(kPowerEventPublishSleepWakeUUID, (void *)true);
3955
3956 lastSleepReason = kIOPMSleepReasonIdle;
3957 setProperty(kRootDomainSleepReasonKey, kIOPMIdleSleepKey);
3958 }
3959 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics))
3960 {
3961 // Root domain is dropping power state ON->SLEEP.
3962 // If system is in full wake, first drop to dark wake.
3963
3964 darkWakeToSleepASAP = true;
3965
3966 // Drop graphics capability.
3967 // No transition if system is already in dark wake.
3968
3969 _desiredCapability &= ~(
3970 kIOPMSystemCapabilityGraphics |
3971 kIOPMSystemCapabilityAudio );
3972
3973 *inOutPowerState = ON_STATE;
3974 *inOutChangeFlags |= kIOPMSynchronize;
3975
3976 // Revert device desire from SLEEP->ON.
3977 changePowerStateToPriv(ON_STATE);
3978 }
3979 }
3980 }
3981
3982 void IOPMrootDomain::handleOurPowerChangeStart(
3983 IOService * service,
3984 IOPMActions * actions,
3985 uint32_t powerState,
3986 uint32_t * inOutChangeFlags )
3987 {
3988 uint32_t changeFlags = *inOutChangeFlags;
3989 uint32_t currentPowerState = (uint32_t) getPowerState();
3990
3991 _systemTransitionType = kSystemTransitionNone;
3992 _systemMessageClientMask = 0;
3993 capabilityLoss = false;
3994
3995 // 1. Explicit capability change.
3996
3997 if (changeFlags & kIOPMSynchronize)
3998 {
3999 if (powerState == ON_STATE)
4000 {
4001 if (changeFlags & kIOPMSyncNoChildNotify)
4002 _systemTransitionType = kSystemTransitionNewCapClient;
4003 else
4004 _systemTransitionType = kSystemTransitionCapability;
4005 }
4006 }
4007
4008 // 2. Going to sleep (cancellation still possible).
4009
4010 else if (powerState < currentPowerState)
4011 _systemTransitionType = kSystemTransitionSleep;
4012
4013 // 3. Woke from (idle or demand) sleep.
4014
4015 else if (!systemBooting &&
4016 (changeFlags & kIOPMSelfInitiated) &&
4017 (powerState > currentPowerState))
4018 {
4019 _systemTransitionType = kSystemTransitionWake;
4020 _desiredCapability = kIOPMSystemCapabilityCPU |
4021 kIOPMSystemCapabilityNetwork;
4022
4023 // Check for early HID events (e.g. LID open)
4024 if (wranglerTickled)
4025 {
4026 _desiredCapability |= (
4027 kIOPMSystemCapabilityGraphics |
4028 kIOPMSystemCapabilityAudio );
4029 }
4030 }
4031
4032 // Update pending wake capability at the beginning of every
4033 // state transition (including synchronize). This will become
4034 // the current capability at the end of the transition.
4035
4036 if (kSystemTransitionSleep == _systemTransitionType)
4037 {
4038 _pendingCapability = 0;
4039 capabilityLoss = true;
4040 }
4041 else if (kSystemTransitionNewCapClient != _systemTransitionType)
4042 {
4043 _pendingCapability = _desiredCapability |
4044 kIOPMSystemCapabilityCPU |
4045 kIOPMSystemCapabilityNetwork;
4046
4047 if (_pendingCapability & kIOPMSystemCapabilityGraphics)
4048 _pendingCapability |= kIOPMSystemCapabilityAudio;
4049
4050 if ((kSystemTransitionCapability == _systemTransitionType) &&
4051 (_pendingCapability == _currentCapability))
4052 {
4053 // Cancel the PM state change.
4054 _systemTransitionType = kSystemTransitionNone;
4055 *inOutChangeFlags |= kIOPMNotDone;
4056 }
4057 if (__builtin_popcount(_pendingCapability) <
4058 __builtin_popcount(_currentCapability))
4059 capabilityLoss = true;
4060 if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
4061 rejectWranglerTickle = true;
4062 }
4063
4064 // 1. Capability change.
4065
4066 if (kSystemTransitionCapability == _systemTransitionType)
4067 {
4068 // Dark to Full transition.
4069 if (CAP_GAIN(kIOPMSystemCapabilityGraphics))
4070 {
4071 tracePoint( kIOPMTracePointDarkWakeExit );
4072 wranglerSleepIgnored = false;
4073 sleepTimerMaintenance = false;
4074 hibernateNoDefeat = false;
4075 _systemMessageClientMask = kSystemMessageClientUser;
4076 if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0)
4077 _systemMessageClientMask |= kSystemMessageClientKernel;
4078
4079 tellClients(kIOMessageSystemWillPowerOn);
4080 }
4081
4082 // Full to Dark transition.
4083 if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
4084 {
4085 tracePoint( kIOPMTracePointDarkWakeEntry );
4086 *inOutChangeFlags |= kIOPMSyncTellPowerDown;
4087 _systemMessageClientMask = kSystemMessageClientUser;
4088 }
4089 }
4090
4091 // 2. System sleep.
4092
4093 else if (kSystemTransitionSleep == _systemTransitionType)
4094 {
4095 // Beginning of a system sleep transition.
4096 // Cancellation is still possible.
4097 tracePoint( kIOPMTracePointSleepStarted, lastSleepReason );
4098
4099 _systemMessageClientMask = kSystemMessageClientAll;
4100 if ((_currentCapability & kIOPMSystemCapabilityGraphics) == 0)
4101 _systemMessageClientMask &= ~kSystemMessageClientApp;
4102 if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0)
4103 _systemMessageClientMask &= ~kSystemMessageClientKernel;
4104
4105 // Optimization to ignore wrangler power down thus skipping
4106 // the disk spindown and arming the idle timer for demand sleep.
4107
4108 if (changeFlags & kIOPMIgnoreChildren)
4109 {
4110 wranglerSleepIgnored = true;
4111 }
4112
4113 logWranglerTickle = false;
4114 }
4115
4116 // 3. System wake.
4117
4118 else if (kSystemTransitionWake == _systemTransitionType)
4119 {
4120 wranglerSleepIgnored = false;
4121
4122 if (_pendingCapability & kIOPMSystemCapabilityGraphics)
4123 {
4124 _systemMessageClientMask = kSystemMessageClientAll;
4125 }
4126 else
4127 {
4128 _systemMessageClientMask = kSystemMessageClientConfigd;
4129 }
4130
4131 tracePoint( kIOPMTracePointWakeWillPowerOnClients );
4132 tellClients(kIOMessageSystemWillPowerOn);
4133 }
4134
4135 if ((kSystemTransitionNone != _systemTransitionType) &&
4136 (kSystemTransitionNewCapClient != _systemTransitionType))
4137 {
4138 _systemStateGeneration++;
4139 systemDarkWake = false;
4140
4141 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4142 "dcp %x:%x:%x\n",
4143 currentPowerState, powerState, *inOutChangeFlags,
4144 _systemTransitionType, _systemStateGeneration,
4145 _systemMessageClientMask,
4146 _desiredCapability, _currentCapability, _pendingCapability);
4147 }
4148 }
4149
4150 void IOPMrootDomain::handleOurPowerChangeDone(
4151 IOService * service,
4152 IOPMActions * actions,
4153 uint32_t powerState,
4154 uint32_t changeFlags )
4155 {
4156 if (kSystemTransitionNewCapClient == _systemTransitionType)
4157 {
4158 _systemTransitionType = kSystemTransitionNone;
4159 return;
4160 }
4161
4162 if (_systemTransitionType != kSystemTransitionNone)
4163 {
4164 uint32_t currentPowerState = (uint32_t) getPowerState();
4165
4166 if (changeFlags & kIOPMNotDone)
4167 {
4168 // Power down was cancelled or vetoed.
4169 _pendingCapability = _currentCapability;
4170 lastSleepReason = 0;
4171
4172 if (((_currentCapability & kIOPMSystemCapabilityGraphics) == 0) &&
4173 (_currentCapability & kIOPMSystemCapabilityCPU))
4174 {
4175 pmPowerStateQueue->submitPowerEvent(
4176 kPowerEventPolicyStimulus,
4177 (void *) kStimulusDarkWakeReentry,
4178 _systemStateGeneration );
4179 }
4180
4181 // Revert device desire to max.
4182 changePowerStateToPriv(ON_STATE);
4183 }
4184 else
4185 {
4186 // Send message on dark wake to full wake promotion.
4187 // tellChangeUp() handles the normal SLEEP->ON case.
4188
4189 if (kSystemTransitionCapability == _systemTransitionType)
4190 {
4191 if (CAP_GAIN(kIOPMSystemCapabilityGraphics))
4192 {
4193 tellClients(kIOMessageSystemHasPoweredOn);
4194 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
4195 // Re-evaluate clamshell state ourselves when graphics
4196 // will not get kIOMessageSystemHasPoweredOn.
4197
4198 if (clamshellClosed &&
4199 ((_systemMessageClientMask & kSystemMessageClientKernel) == 0))
4200 {
4201 receivePowerNotification( kLocalEvalClamshellCommand );
4202 }
4203 #endif
4204 }
4205 if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
4206 wranglerTickled = false;
4207 }
4208
4209 // Reset state after exiting from dark wake.
4210
4211 if (CAP_GAIN(kIOPMSystemCapabilityGraphics) ||
4212 CAP_LOSS(kIOPMSystemCapabilityCPU))
4213 {
4214 darkWakeMaintenance = false;
4215 darkWakeToSleepASAP = false;
4216 pciCantSleepValid = false;
4217 rejectWranglerTickle = false;
4218 }
4219
4220 // Entered dark mode.
4221
4222 if (((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) &&
4223 (_pendingCapability & kIOPMSystemCapabilityCPU))
4224 {
4225 if (((gDarkWakeFlags & kDarkWakeFlagIgnoreDiskIOInDark) == 0) &&
4226 (kSystemTransitionWake == _systemTransitionType) &&
4227 (_debugWakeSeconds == 0))
4228 {
4229 OSObject * prop = copyProperty(kIOPMRootDomainWakeTypeKey);
4230 if (prop)
4231 {
4232 OSString * wakeType = OSDynamicCast(OSString, prop);
4233 if (wakeType &&
4234 wakeType->isEqualTo(kIOPMRootDomainWakeTypeNetwork))
4235 {
4236 // Woke from network and entered dark wake.
4237 if (darkWakeToSleepASAP)
4238 {
4239 DLOG("cleared darkWakeToSleepASAP\n");
4240 darkWakeToSleepASAP = false;
4241 }
4242 }
4243 prop->release();
4244 }
4245 }
4246
4247 // Queue an evaluation of whether to remain in dark wake,
4248 // and for how long. This serves the purpose of draining
4249 // any assertions from the queue.
4250
4251 pmPowerStateQueue->submitPowerEvent(
4252 kPowerEventPolicyStimulus,
4253 (void *) kStimulusDarkWakeEntry,
4254 _systemStateGeneration );
4255 }
4256 }
4257
4258 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4259 "dcp %x:%x:%x, dbgtimer %u\n",
4260 currentPowerState, powerState, changeFlags,
4261 _systemTransitionType, _systemStateGeneration,
4262 _systemMessageClientMask,
4263 _desiredCapability, _currentCapability, _pendingCapability,
4264 _debugWakeSeconds);
4265
4266 // Update current system capability.
4267
4268 if (_currentCapability != _pendingCapability)
4269 _currentCapability = _pendingCapability;
4270
4271 // Update highest system capability.
4272
4273 if (!CAP_CURRENT(kIOPMSystemCapabilityCPU))
4274 _highestCapability = 0; // reset at sleep state
4275 else
4276 _highestCapability |= _currentCapability;
4277
4278 if (darkWakePostTickle &&
4279 (kSystemTransitionWake == _systemTransitionType) &&
4280 (gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
4281 kDarkWakeFlagHIDTickleLate)
4282 {
4283 darkWakePostTickle = false;
4284 reportUserInput();
4285 }
4286
4287 // Reset tracepoint at completion of capability change,
4288 // completion of wake transition, and aborted sleep transition.
4289
4290 if ((_systemTransitionType == kSystemTransitionCapability) ||
4291 (_systemTransitionType == kSystemTransitionWake) ||
4292 ((_systemTransitionType == kSystemTransitionSleep) &&
4293 (changeFlags & kIOPMNotDone)))
4294 {
4295 setProperty(kIOPMSystemCapabilitiesKey, _currentCapability, 64);
4296 tracePoint( kIOPMTracePointSystemUp, 0 );
4297 }
4298
4299 _systemTransitionType = kSystemTransitionNone;
4300 _systemMessageClientMask = 0;
4301
4302 logGraphicsClamp = false;
4303 }
4304 }
4305
4306 //******************************************************************************
4307 // PM actions for graphics and audio.
4308 //******************************************************************************
4309
4310 void IOPMrootDomain::overridePowerChangeForUIService(
4311 IOService * service,
4312 IOPMActions * actions,
4313 unsigned long * inOutPowerState,
4314 uint32_t * inOutChangeFlags )
4315 {
4316 uint32_t powerState = (uint32_t) *inOutPowerState;
4317 uint32_t changeFlags = (uint32_t) *inOutChangeFlags;
4318
4319 if (kSystemTransitionNone == _systemTransitionType)
4320 {
4321 // Not in midst of a system transition.
4322 // Do not modify power limit enable state.
4323 }
4324 else if ((actions->parameter & kPMActionsFlagLimitPower) == 0)
4325 {
4326 // Activate power limiter.
4327
4328 if ((actions->parameter & kPMActionsFlagIsDisplayWrangler) &&
4329 ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0))
4330 {
4331 actions->parameter |= kPMActionsFlagLimitPower;
4332 }
4333 else if ((actions->parameter & kPMActionsFlagIsAudioDevice) &&
4334 ((_pendingCapability & kIOPMSystemCapabilityAudio) == 0))
4335 {
4336 actions->parameter |= kPMActionsFlagLimitPower;
4337 }
4338 else if ((actions->parameter & kPMActionsFlagIsGraphicsDevice) &&
4339 (_systemTransitionType == kSystemTransitionSleep))
4340 {
4341 // For graphics devices, arm the limiter when entering
4342 // system sleep. Not when dropping to dark wake.
4343 actions->parameter |= kPMActionsFlagLimitPower;
4344 }
4345
4346 if (actions->parameter & kPMActionsFlagLimitPower)
4347 {
4348 DLOG("+ plimit %s %p\n",
4349 service->getName(), service);
4350 }
4351 }
4352 else
4353 {
4354 // Remove power limit.
4355
4356 if ((actions->parameter & (
4357 kPMActionsFlagIsDisplayWrangler |
4358 kPMActionsFlagIsGraphicsDevice )) &&
4359 (_pendingCapability & kIOPMSystemCapabilityGraphics))
4360 {
4361 actions->parameter &= ~kPMActionsFlagLimitPower;
4362 }
4363 else if ((actions->parameter & kPMActionsFlagIsAudioDevice) &&
4364 (_pendingCapability & kIOPMSystemCapabilityAudio))
4365 {
4366 actions->parameter &= ~kPMActionsFlagLimitPower;
4367 }
4368
4369 if ((actions->parameter & kPMActionsFlagLimitPower) == 0)
4370 {
4371 DLOG("- plimit %s %p\n",
4372 service->getName(), service);
4373 }
4374 }
4375
4376 if (gRAMDiskImageBoot &&
4377 (actions->parameter & kPMActionsFlagIsDisplayWrangler))
4378 {
4379 // Tag devices subject to power suppression.
4380 *inOutChangeFlags |= kIOPMPowerSuppressed;
4381 }
4382
4383 if (actions->parameter & kPMActionsFlagLimitPower)
4384 {
4385 uint32_t maxPowerState = (uint32_t)(-1);
4386
4387 if (changeFlags & (kIOPMDomainDidChange | kIOPMDomainWillChange))
4388 {
4389 // Enforce limit for system power/cap transitions.
4390
4391 maxPowerState = 0;
4392 if ((actions->parameter & kPMActionsFlagIsDisplayWrangler) &&
4393 (!gRAMDiskImageBoot || (service->getPowerState() > 0)))
4394 {
4395 // Forces a 3->1 transition sequence
4396 if (changeFlags & kIOPMDomainWillChange)
4397 maxPowerState = 3;
4398 else
4399 maxPowerState = 1;
4400 }
4401 }
4402 else
4403 {
4404 // Deny all self-initiated changes when power is limited.
4405 // Wrangler tickle should never defeat the limiter.
4406
4407 maxPowerState = service->getPowerState();
4408 }
4409
4410 if (powerState > maxPowerState)
4411 {
4412 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
4413 service->getName(), service, powerState, maxPowerState,
4414 changeFlags);
4415 *inOutPowerState = maxPowerState;
4416
4417 if (darkWakePostTickle &&
4418 (actions->parameter & kPMActionsFlagIsDisplayWrangler) &&
4419 (changeFlags & kIOPMDomainWillChange) &&
4420 ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
4421 kDarkWakeFlagHIDTickleEarly))
4422 {
4423 darkWakePostTickle = false;
4424 reportUserInput();
4425 }
4426 }
4427
4428 if (!graphicsSuppressed && (changeFlags & kIOPMDomainDidChange))
4429 {
4430 if (logGraphicsClamp)
4431 {
4432 AbsoluteTime now;
4433 uint64_t nsec;
4434
4435 clock_get_uptime(&now);
4436 SUB_ABSOLUTETIME(&now, &systemWakeTime);
4437 absolutetime_to_nanoseconds(now, &nsec);
4438 MSG("Graphics suppressed %u ms\n",
4439 ((int)((nsec) / 1000000ULL)));
4440 }
4441 graphicsSuppressed = true;
4442 }
4443 }
4444 }
4445
4446 void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
4447 IOService * service,
4448 IOPMActions * actions )
4449 {
4450 // Warning: Not running in PM work loop context - don't modify state !!!
4451 // Trap tickle directed to IODisplayWrangler while running with graphics
4452 // capability suppressed.
4453
4454 assert(service == wrangler);
4455
4456 if (service == wrangler)
4457 {
4458 bool aborting = ((lastSleepReason == kIOPMSleepReasonIdle)
4459 || (lastSleepReason == kIOPMSleepReasonMaintenance));
4460 if (aborting) {
4461 userActivityCount++;
4462 DLOG("display wrangler tickled1 %d lastSleepReason %d\n", userActivityCount, lastSleepReason);
4463 }
4464 }
4465
4466 if (!wranglerTickled && !lowBatteryCondition &&
4467 ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0))
4468 {
4469 DLOG("display wrangler tickled\n");
4470 if (kIOLogPMRootDomain & gIOKitDebug)
4471 OSReportWithBacktrace("Dark wake display tickle");
4472 if (pmPowerStateQueue)
4473 {
4474 pmPowerStateQueue->submitPowerEvent(
4475 kPowerEventPolicyStimulus,
4476 (void *) kStimulusDarkWakeActivityTickle );
4477 }
4478 }
4479 }
4480
4481 //******************************************************************************
4482 // Approve usage of delayed child notification by PM.
4483 //******************************************************************************
4484
4485 bool IOPMrootDomain::shouldDelayChildNotification(
4486 IOService * service )
4487 {
4488 if (((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) != 0) &&
4489 !wranglerTickled &&
4490 (kSystemTransitionWake == _systemTransitionType))
4491 {
4492 DLOG("%s: delay child notify\n", service->getName());
4493 return true;
4494 }
4495 return false;
4496 }
4497
4498 //******************************************************************************
4499 // PM actions for PCI device.
4500 //******************************************************************************
4501
4502 void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
4503 IOService * service,
4504 IOPMActions * actions,
4505 uint32_t powerState,
4506 uint32_t * inOutChangeFlags )
4507 {
4508 pmTracer->tracePCIPowerChange(
4509 PMTraceWorker::kPowerChangeStart,
4510 service, *inOutChangeFlags,
4511 (actions->parameter & kPMActionsPCIBitNumberMask));
4512 }
4513
4514 void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
4515 IOService * service,
4516 IOPMActions * actions,
4517 uint32_t powerState,
4518 uint32_t changeFlags )
4519 {
4520 pmTracer->tracePCIPowerChange(
4521 PMTraceWorker::kPowerChangeCompleted,
4522 service, changeFlags,
4523 (actions->parameter & kPMActionsPCIBitNumberMask));
4524 }
4525
4526 //******************************************************************************
4527 // registerInterest
4528 //
4529 // Override IOService::registerInterest() to intercept special clients.
4530 //******************************************************************************
4531
4532 IONotifier * IOPMrootDomain::registerInterest(
4533 const OSSymbol * typeOfInterest,
4534 IOServiceInterestHandler handler,
4535 void * target, void * ref )
4536 {
4537 IONotifier * notifier;
4538 bool isSystemCapabilityClient;
4539 bool isKernelCapabilityClient;
4540
4541 isSystemCapabilityClient =
4542 typeOfInterest &&
4543 typeOfInterest->isEqualTo(kIOPMSystemCapabilityInterest);
4544
4545 isKernelCapabilityClient =
4546 typeOfInterest &&
4547 typeOfInterest->isEqualTo(gIOPriorityPowerStateInterest);
4548
4549 if (isSystemCapabilityClient)
4550 typeOfInterest = gIOAppPowerStateInterest;
4551
4552 notifier = super::registerInterest(typeOfInterest, handler, target, ref);
4553 if (notifier && pmPowerStateQueue)
4554 {
4555 if (isSystemCapabilityClient)
4556 {
4557 notifier->retain();
4558 if (pmPowerStateQueue->submitPowerEvent(
4559 kPowerEventRegisterSystemCapabilityClient, notifier) == false)
4560 notifier->release();
4561 }
4562
4563 if (isKernelCapabilityClient)
4564 {
4565 notifier->retain();
4566 if (pmPowerStateQueue->submitPowerEvent(
4567 kPowerEventRegisterKernelCapabilityClient, notifier) == false)
4568 notifier->release();
4569 }
4570 }
4571
4572 return notifier;
4573 }
4574
4575 //******************************************************************************
4576 // systemMessageFilter
4577 //
4578 //******************************************************************************
4579
4580 bool IOPMrootDomain::systemMessageFilter(
4581 void * object, void * arg1, void * arg2, void * arg3 )
4582 {
4583 const IOPMInterestContext * context = (const IOPMInterestContext *) arg1;
4584 bool isCapMsg = (context->messageType == kIOMessageSystemCapabilityChange);
4585 bool isCapClient = false;
4586 bool allow = false;
4587
4588 do {
4589 if ((kSystemTransitionNewCapClient == _systemTransitionType) &&
4590 (!isCapMsg || !_joinedCapabilityClients ||
4591 !_joinedCapabilityClients->containsObject((OSObject *) object)))
4592 break;
4593
4594 // Capability change message for app and kernel clients.
4595
4596 if (isCapMsg)
4597 {
4598 if ((context->notifyType == kNotifyPriority) ||
4599 (context->notifyType == kNotifyCapabilityChangePriority))
4600 isCapClient = true;
4601
4602 if ((context->notifyType == kNotifyCapabilityChangeApps) &&
4603 (object == (void *) systemCapabilityNotifier))
4604 isCapClient = true;
4605 }
4606
4607 if (isCapClient)
4608 {
4609 IOPMSystemCapabilityChangeParameters * capArgs =
4610 (IOPMSystemCapabilityChangeParameters *) arg2;
4611
4612 if (kSystemTransitionNewCapClient == _systemTransitionType)
4613 {
4614 capArgs->fromCapabilities = 0;
4615 capArgs->toCapabilities = _currentCapability;
4616 capArgs->changeFlags = 0;
4617 }
4618 else
4619 {
4620 capArgs->fromCapabilities = _currentCapability;
4621 capArgs->toCapabilities = _pendingCapability;
4622
4623 if (context->isPreChange)
4624 capArgs->changeFlags = kIOPMSystemCapabilityWillChange;
4625 else
4626 capArgs->changeFlags = kIOPMSystemCapabilityDidChange;
4627 }
4628
4629 // Capability change messages only go to the PM configd plugin.
4630 // Wait for response post-change if capabilitiy is increasing.
4631 // Wait for response pre-change if capability is decreasing.
4632
4633 if ((context->notifyType == kNotifyCapabilityChangeApps) && arg3 &&
4634 ( (capabilityLoss && context->isPreChange) ||
4635 (!capabilityLoss && !context->isPreChange) ) )
4636 {
4637 // app has not replied yet, wait for it
4638 *((OSObject **) arg3) = kOSBooleanFalse;
4639 }
4640
4641 allow = true;
4642 break;
4643 }
4644
4645 // Capability client will always see kIOMessageCanSystemSleep,
4646 // even for demand sleep.
4647
4648 if ((kIOMessageCanSystemSleep == context->messageType) ||
4649 (kIOMessageSystemWillNotSleep == context->messageType))
4650 {
4651 if (object == (OSObject *) systemCapabilityNotifier)
4652 {
4653 allow = true;
4654 break;
4655 }
4656
4657 // Not idle sleep, don't ask apps.
4658 if (context->changeFlags & kIOPMSkipAskPowerDown)
4659 {
4660 break;
4661 }
4662 }
4663
4664 // Reject capability change messages for legacy clients.
4665 // Reject legacy system sleep messages for capability client.
4666
4667 if (isCapMsg || (object == (OSObject *) systemCapabilityNotifier))
4668 {
4669 break;
4670 }
4671
4672 // Filter system sleep messages.
4673
4674 if ((context->notifyType == kNotifyApps) &&
4675 (_systemMessageClientMask & kSystemMessageClientApp))
4676 {
4677 allow = true;
4678 }
4679 else if ((context->notifyType == kNotifyPriority) &&
4680 (_systemMessageClientMask & kSystemMessageClientKernel))
4681 {
4682 allow = true;
4683 }
4684 }
4685 while (false);
4686
4687 if (allow && isCapMsg && _joinedCapabilityClients)
4688 {
4689 _joinedCapabilityClients->removeObject((OSObject *) object);
4690 if (_joinedCapabilityClients->getCount() == 0)
4691 {
4692 DLOG("destroyed capability client set %p\n",
4693 _joinedCapabilityClients);
4694 _joinedCapabilityClients->release();
4695 _joinedCapabilityClients = 0;
4696 }
4697 }
4698
4699 return allow;
4700 }
4701
4702 //******************************************************************************
4703 // setMaintenanceWakeCalendar
4704 //
4705 //******************************************************************************
4706
4707 IOReturn IOPMrootDomain::setMaintenanceWakeCalendar(
4708 const IOPMCalendarStruct * calendar )
4709 {
4710 OSData * data;
4711 IOReturn ret;
4712
4713 if (!calendar)
4714 return kIOReturnBadArgument;
4715
4716 data = OSData::withBytesNoCopy((void *) calendar, sizeof(*calendar));
4717 if (!data)
4718 return kIOReturnNoMemory;
4719
4720 ret = setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey, data);
4721
4722 data->release();
4723 return ret;
4724 }
4725
4726 // MARK: -
4727 // MARK: Display Wrangler
4728
4729 //******************************************************************************
4730 // displayWranglerNotification
4731 //
4732 // Handle the notification when the IODisplayWrangler changes power state.
4733 //******************************************************************************
4734
4735 IOReturn IOPMrootDomain::displayWranglerNotification(
4736 void * target, void * refCon,
4737 UInt32 messageType, IOService * service,
4738 void * messageArgument, vm_size_t argSize )
4739 {
4740 #if !NO_KERNEL_HID
4741 int displayPowerState;
4742 IOPowerStateChangeNotification * params =
4743 (IOPowerStateChangeNotification *) messageArgument;
4744
4745 if ((messageType != kIOMessageDeviceWillPowerOff) &&
4746 (messageType != kIOMessageDeviceHasPoweredOn))
4747 return kIOReturnUnsupported;
4748
4749 ASSERT_GATED();
4750 if (!gRootDomain)
4751 return kIOReturnUnsupported;
4752
4753 displayPowerState = params->stateNumber;
4754 DLOG("DisplayWrangler message 0x%x, power state %d\n",
4755 (uint32_t) messageType, displayPowerState);
4756
4757 switch (messageType) {
4758 case kIOMessageDeviceWillPowerOff:
4759
4760 // Display wrangler has dropped power due to display idle
4761 // or force system sleep.
4762 //
4763 // 4 Display ON
4764 // 3 Display Dim
4765 // 2 Display Sleep
4766 // 1 Not visible to user
4767 // 0 Not visible to user
4768
4769 if (displayPowerState > 2)
4770 break;
4771
4772 gRootDomain->evaluatePolicy( kStimulusDisplayWranglerSleep );
4773 break;
4774
4775 case kIOMessageDeviceHasPoweredOn:
4776
4777 // Display wrangler has powered on due to user activity
4778 // or wake from sleep.
4779
4780 if ( 4 != displayPowerState )
4781 break;
4782
4783 gRootDomain->evaluatePolicy( kStimulusDisplayWranglerWake );
4784 break;
4785 }
4786 #endif
4787 return kIOReturnUnsupported;
4788 }
4789
4790 //*********************************************************************************
4791 // displayWranglerMatchPublished
4792 //
4793 // Receives a notification when the IODisplayWrangler is published.
4794 // When it's published we install a power state change handler.
4795 //******************************************************************************
4796
4797 bool IOPMrootDomain::displayWranglerMatchPublished(
4798 void * target,
4799 void * refCon,
4800 IOService * newService,
4801 IONotifier * notifier __unused)
4802 {
4803 #if !NO_KERNEL_HID
4804 // found the display wrangler, now install a handler
4805 if( !newService->registerInterest( gIOGeneralInterest,
4806 &displayWranglerNotification, target, 0) )
4807 {
4808 return false;
4809 }
4810 #endif
4811 return true;
4812 }
4813
4814 //******************************************************************************
4815 // reportUserInput
4816 //
4817 //******************************************************************************
4818
4819 void IOPMrootDomain::reportUserInput( void )
4820 {
4821 #if !NO_KERNEL_HID
4822 OSIterator * iter;
4823
4824 if(!wrangler)
4825 {
4826 iter = getMatchingServices(serviceMatching("IODisplayWrangler"));
4827 if(iter)
4828 {
4829 wrangler = (IOService *) iter->getNextObject();
4830 iter->release();
4831 }
4832 }
4833
4834 if(wrangler)
4835 wrangler->activityTickle(0,0);
4836 #endif
4837 }
4838
4839 // MARK: -
4840 // MARK: Battery
4841
4842 //******************************************************************************
4843 // batteryPublished
4844 //
4845 // Notification on battery class IOPowerSource appearance
4846 //******************************************************************************
4847
4848 bool IOPMrootDomain::batteryPublished(
4849 void * target,
4850 void * root_domain,
4851 IOService * resourceService,
4852 IONotifier * notifier __unused )
4853 {
4854 // rdar://2936060&4435589
4855 // All laptops have dimmable LCD displays
4856 // All laptops have batteries
4857 // So if this machine has a battery, publish the fact that the backlight
4858 // supports dimming.
4859 ((IOPMrootDomain *)root_domain)->publishFeature("DisplayDims");
4860
4861 return (true);
4862 }
4863
4864 // MARK: -
4865 // MARK: System PM Policy
4866
4867 //******************************************************************************
4868 // checkSystemCanSleep
4869 //
4870 //******************************************************************************
4871
4872 bool IOPMrootDomain::checkSystemCanSleep( IOOptionBits options )
4873 {
4874 int err = 0;
4875
4876 // Conditions that prevent idle and demand system sleep.
4877
4878 do {
4879 if (userDisabledAllSleep)
4880 {
4881 err = 1; // 1. user-space sleep kill switch
4882 break;
4883 }
4884
4885 if (systemBooting || systemShutdown)
4886 {
4887 err = 2; // 2. restart or shutdown in progress
4888 break;
4889 }
4890
4891 if (options == 0)
4892 break;
4893
4894 // Conditions above pegs the system at full wake.
4895 // Conditions below prevent system sleep but does not prevent
4896 // dark wake, and must be called from gated context.
4897
4898 #if !CONFIG_SLEEP
4899 err = 3; // 3. config does not support sleep
4900 break;
4901 #endif
4902
4903 if (lowBatteryCondition)
4904 {
4905 break; // always sleep on low battery
4906 }
4907
4908 if (childPreventSystemSleep)
4909 {
4910 err = 4; // 4. child prevent system sleep clamp
4911 break;
4912 }
4913
4914 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit ) ==
4915 kIOPMDriverAssertionLevelOn)
4916 {
4917 err = 5; // 5. CPU assertion
4918 break;
4919 }
4920
4921 if (pciCantSleepValid)
4922 {
4923 if (pciCantSleepFlag)
4924 err = 6; // 6. PCI card does not support PM (cached)
4925 break;
4926 }
4927 else if (sleepSupportedPEFunction &&
4928 CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
4929 {
4930 IOReturn ret;
4931 OSBitAndAtomic(~kPCICantSleep, &platformSleepSupport);
4932 ret = getPlatform()->callPlatformFunction(
4933 sleepSupportedPEFunction, false,
4934 NULL, NULL, NULL, NULL);
4935 pciCantSleepValid = true;
4936 pciCantSleepFlag = false;
4937 if ((platformSleepSupport & kPCICantSleep) ||
4938 ((ret != kIOReturnSuccess) && (ret != kIOReturnUnsupported)))
4939 {
4940 err = 6; // 6. PCI card does not support PM
4941 pciCantSleepFlag = true;
4942 break;
4943 }
4944 }
4945 }
4946 while (false);
4947
4948 if (err)
4949 {
4950 DLOG("System sleep prevented by %d\n", err);
4951 return false;
4952 }
4953 return true;
4954 }
4955
4956 //******************************************************************************
4957 // adjustPowerState
4958 //
4959 // Conditions that affect our wake/sleep decision has changed.
4960 // If conditions dictate that the system must remain awake, clamp power
4961 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
4962 // is TRUE, then remove the power clamp and allow the power state to drop
4963 // to SLEEP_STATE.
4964 //******************************************************************************
4965
4966 void IOPMrootDomain::adjustPowerState( bool sleepASAP )
4967 {
4968 DLOG("adjustPowerState ps %u, asap %d, slider %ld\n",
4969 (uint32_t) getPowerState(), sleepASAP, sleepSlider);
4970
4971 ASSERT_GATED();
4972
4973 if ((sleepSlider == 0) || !checkSystemCanSleep())
4974 {
4975 changePowerStateToPriv(ON_STATE);
4976 }
4977 else if ( sleepASAP )
4978 {
4979 changePowerStateToPriv(SLEEP_STATE);
4980 }
4981 }
4982
4983 //******************************************************************************
4984 // dispatchPowerEvent
4985 //
4986 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
4987 //******************************************************************************
4988
4989 void IOPMrootDomain::dispatchPowerEvent(
4990 uint32_t event, void * arg0, uint64_t arg1 )
4991 {
4992 DLOG("power event %u args %p 0x%llx\n", event, arg0, arg1);
4993 ASSERT_GATED();
4994
4995 switch (event)
4996 {
4997 case kPowerEventFeatureChanged:
4998 messageClients(kIOPMMessageFeatureChange, this);
4999 break;
5000
5001 case kPowerEventReceivedPowerNotification:
5002 handlePowerNotification( (UInt32)(uintptr_t) arg0 );
5003 break;
5004
5005 case kPowerEventSystemBootCompleted:
5006 if (systemBooting)
5007 {
5008 systemBooting = false;
5009
5010 // If lid is closed, re-send lid closed notification
5011 // now that booting is complete.
5012 if ( clamshellClosed )
5013 {
5014 handlePowerNotification(kLocalEvalClamshellCommand);
5015 }
5016 evaluatePolicy( kStimulusAllowSystemSleepChanged );
5017 }
5018 break;
5019
5020 case kPowerEventSystemShutdown:
5021 if (kOSBooleanTrue == (OSBoolean *) arg0)
5022 {
5023 /* We set systemShutdown = true during shutdown
5024 to prevent sleep at unexpected times while loginwindow is trying
5025 to shutdown apps and while the OS is trying to transition to
5026 complete power of.
5027
5028 Set to true during shutdown, as soon as loginwindow shows
5029 the "shutdown countdown dialog", through individual app
5030 termination, and through black screen kernel shutdown.
5031 */
5032 systemShutdown = true;
5033 } else {
5034 /*
5035 A shutdown was initiated, but then the shutdown
5036 was cancelled, clearing systemShutdown to false here.
5037 */
5038 systemShutdown = false;
5039 }
5040 break;
5041
5042 case kPowerEventUserDisabledSleep:
5043 userDisabledAllSleep = (kOSBooleanTrue == (OSBoolean *) arg0);
5044 break;
5045
5046 case kPowerEventRegisterSystemCapabilityClient:
5047 if (systemCapabilityNotifier)
5048 {
5049 systemCapabilityNotifier->release();
5050 systemCapabilityNotifier = 0;
5051 }
5052 if (arg0)
5053 {
5054 systemCapabilityNotifier = (IONotifier *) arg0;
5055 systemCapabilityNotifier->retain();
5056 }
5057 /* intentional fall-through */
5058
5059 case kPowerEventRegisterKernelCapabilityClient:
5060 if (!_joinedCapabilityClients)
5061 _joinedCapabilityClients = OSSet::withCapacity(8);
5062 if (arg0)
5063 {
5064 IONotifier * notify = (IONotifier *) arg0;
5065 if (_joinedCapabilityClients)
5066 {
5067 _joinedCapabilityClients->setObject(notify);
5068 synchronizePowerTree( kIOPMSyncNoChildNotify );
5069 }
5070 notify->release();
5071 }
5072 break;
5073
5074 case kPowerEventPolicyStimulus:
5075 if (arg0)
5076 {
5077 int stimulus = (uintptr_t) arg0;
5078 evaluatePolicy( stimulus, (uint32_t) arg1 );
5079 }
5080 break;
5081
5082 case kPowerEventAssertionCreate:
5083 if (pmAssertions) {
5084 pmAssertions->handleCreateAssertion((OSData *)arg0);
5085 }
5086 break;
5087
5088
5089 case kPowerEventAssertionRelease:
5090 if (pmAssertions) {
5091 pmAssertions->handleReleaseAssertion(arg1);
5092 }
5093 break;
5094
5095 case kPowerEventAssertionSetLevel:
5096 if (pmAssertions) {
5097 pmAssertions->handleSetAssertionLevel(arg1, (IOPMDriverAssertionLevel)(uintptr_t)arg0);
5098 }
5099 break;
5100
5101 case kPowerEventQueueSleepWakeUUID:
5102 handleQueueSleepWakeUUID((OSObject *)arg0);
5103 break;
5104 case kPowerEventPublishSleepWakeUUID:
5105 handlePublishSleepWakeUUID((bool)arg0);
5106 break;
5107 }
5108 }
5109
5110 //******************************************************************************
5111 // systemPowerEventOccurred
5112 //
5113 // The power controller is notifying us of a hardware-related power management
5114 // event that we must handle.
5115 //
5116 // systemPowerEventOccurred covers the same functionality that
5117 // receivePowerNotification does; it simply provides a richer API for conveying
5118 // more information.
5119 //******************************************************************************
5120
5121 IOReturn IOPMrootDomain::systemPowerEventOccurred(
5122 const OSSymbol *event,
5123 uint32_t intValue)
5124 {
5125 IOReturn attempt = kIOReturnSuccess;
5126 OSNumber *newNumber = NULL;
5127
5128 if (!event)
5129 return kIOReturnBadArgument;
5130
5131 newNumber = OSNumber::withNumber(intValue, 8*sizeof(intValue));
5132 if (!newNumber)
5133 return kIOReturnInternalError;
5134
5135 attempt = systemPowerEventOccurred(event, (OSObject *)newNumber);
5136
5137 newNumber->release();
5138
5139 return attempt;
5140 }
5141
5142 IOReturn IOPMrootDomain::systemPowerEventOccurred(
5143 const OSSymbol *event,
5144 OSObject *value)
5145 {
5146 OSDictionary *thermalsDict = NULL;
5147 bool shouldUpdate = true;
5148
5149 if (!event || !value)
5150 return kIOReturnBadArgument;
5151
5152 // LOCK
5153 // We reuse featuresDict Lock because it already exists and guards
5154 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
5155 // of stepping on that lock.
5156 if (featuresDictLock) IOLockLock(featuresDictLock);
5157
5158 thermalsDict = (OSDictionary *)getProperty(kIOPMRootDomainPowerStatusKey);
5159
5160 if (thermalsDict && OSDynamicCast(OSDictionary, thermalsDict)) {
5161 thermalsDict = OSDictionary::withDictionary(thermalsDict);
5162 } else {
5163 thermalsDict = OSDictionary::withCapacity(1);
5164 }
5165
5166 if (!thermalsDict) {
5167 shouldUpdate = false;
5168 goto exit;
5169 }
5170
5171 thermalsDict->setObject (event, value);
5172
5173 setProperty (kIOPMRootDomainPowerStatusKey, thermalsDict);
5174
5175 thermalsDict->release();
5176
5177 exit:
5178 // UNLOCK
5179 if (featuresDictLock) IOLockUnlock(featuresDictLock);
5180
5181 if (shouldUpdate)
5182 messageClients (kIOPMMessageSystemPowerEventOccurred, (void *)NULL);
5183
5184 return kIOReturnSuccess;
5185 }
5186
5187 //******************************************************************************
5188 // receivePowerNotification
5189 //
5190 // The power controller is notifying us of a hardware-related power management
5191 // event that we must handle. This may be a result of an 'environment' interrupt
5192 // from the power mgt micro.
5193 //******************************************************************************
5194
5195 IOReturn IOPMrootDomain::receivePowerNotification( UInt32 msg )
5196 {
5197 pmPowerStateQueue->submitPowerEvent(
5198 kPowerEventReceivedPowerNotification, (void *) msg );
5199 return kIOReturnSuccess;
5200 }
5201
5202 void IOPMrootDomain::handlePowerNotification( UInt32 msg )
5203 {
5204 bool eval_clamshell = false;
5205
5206 ASSERT_GATED();
5207
5208 /*
5209 * Local (IOPMrootDomain only) eval clamshell command
5210 */
5211 if (msg & kLocalEvalClamshellCommand)
5212 {
5213 eval_clamshell = true;
5214 }
5215
5216 /*
5217 * Overtemp
5218 */
5219 if (msg & kIOPMOverTemp)
5220 {
5221 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
5222 privateSleepSystem (kIOPMSleepReasonThermalEmergency);
5223 }
5224
5225 /*
5226 * Sleep Now!
5227 */
5228 if (msg & kIOPMSleepNow)
5229 {
5230 privateSleepSystem (kIOPMSleepReasonSoftware);
5231 }
5232
5233 /*
5234 * Power Emergency
5235 */
5236 if (msg & kIOPMPowerEmergency)
5237 {
5238 lowBatteryCondition = true;
5239 privateSleepSystem (kIOPMSleepReasonLowPower);
5240 }
5241
5242 /*
5243 * Clamshell OPEN
5244 */
5245 if (msg & kIOPMClamshellOpened)
5246 {
5247 // Received clamshel open message from clamshell controlling driver
5248 // Update our internal state and tell general interest clients
5249 clamshellClosed = false;
5250 clamshellExists = true;
5251
5252 if (msg & kIOPMSetValue)
5253 {
5254 reportUserInput();
5255 }
5256
5257 // Tell PMCPU
5258 informCPUStateChange(kInformLid, 0);
5259
5260 // Tell general interest clients
5261 sendClientClamshellNotification();
5262
5263 bool aborting = ((lastSleepReason == kIOPMSleepReasonClamshell)
5264 || (lastSleepReason == kIOPMSleepReasonIdle)
5265 || (lastSleepReason == kIOPMSleepReasonMaintenance));
5266 if (aborting) userActivityCount++;
5267 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount, lastSleepReason);
5268 }
5269
5270 /*
5271 * Clamshell CLOSED
5272 * Send the clamshell interest notification since the lid is closing.
5273 */
5274 if (msg & kIOPMClamshellClosed)
5275 {
5276 // Received clamshel open message from clamshell controlling driver
5277 // Update our internal state and tell general interest clients
5278 clamshellClosed = true;
5279 clamshellExists = true;
5280
5281 // Tell PMCPU
5282 informCPUStateChange(kInformLid, 1);
5283
5284 // Tell general interest clients
5285 sendClientClamshellNotification();
5286
5287 // And set eval_clamshell = so we can attempt
5288 eval_clamshell = true;
5289 }
5290
5291 /*
5292 * Set Desktop mode (sent from graphics)
5293 *
5294 * -> reevaluate lid state
5295 */
5296 if (msg & kIOPMSetDesktopMode)
5297 {
5298 desktopMode = (0 != (msg & kIOPMSetValue));
5299 msg &= ~(kIOPMSetDesktopMode | kIOPMSetValue);
5300
5301 sendClientClamshellNotification();
5302
5303 // Re-evaluate the lid state
5304 if( clamshellClosed )
5305 {
5306 eval_clamshell = true;
5307 }
5308 }
5309
5310 /*
5311 * AC Adaptor connected
5312 *
5313 * -> reevaluate lid state
5314 */
5315 if (msg & kIOPMSetACAdaptorConnected)
5316 {
5317 acAdaptorConnected = (0 != (msg & kIOPMSetValue));
5318 msg &= ~(kIOPMSetACAdaptorConnected | kIOPMSetValue);
5319
5320 // Tell CPU PM
5321 informCPUStateChange(kInformAC, !acAdaptorConnected);
5322
5323 // Tell BSD if AC is connected
5324 // 0 == external power source; 1 == on battery
5325 post_sys_powersource(acAdaptorConnected ? 0:1);
5326
5327 sendClientClamshellNotification();
5328
5329 // Re-evaluate the lid state
5330 if( clamshellClosed )
5331 {
5332 eval_clamshell = true;
5333 }
5334 }
5335
5336 /*
5337 * Enable Clamshell (external display disappear)
5338 *
5339 * -> reevaluate lid state
5340 */
5341 if (msg & kIOPMEnableClamshell)
5342 {
5343 // Re-evaluate the lid state
5344 // System should sleep on external display disappearance
5345 // in lid closed operation.
5346 if( clamshellClosed && (true == clamshellDisabled) )
5347 {
5348 eval_clamshell = true;
5349 }
5350
5351 clamshellDisabled = false;
5352
5353 sendClientClamshellNotification();
5354 }
5355
5356 /*
5357 * Disable Clamshell (external display appeared)
5358 * We don't bother re-evaluating clamshell state. If the system is awake,
5359 * the lid is probably open.
5360 */
5361 if (msg & kIOPMDisableClamshell)
5362 {
5363 clamshellDisabled = true;
5364
5365 sendClientClamshellNotification();
5366 }
5367
5368 /*
5369 * Evaluate clamshell and SLEEP if appropiate
5370 */
5371 if ( eval_clamshell && shouldSleepOnClamshellClosed() )
5372 {
5373
5374
5375 // SLEEP!
5376 privateSleepSystem (kIOPMSleepReasonClamshell);
5377 }
5378 else if ( eval_clamshell )
5379 {
5380 evaluatePolicy(kStimulusDarkWakeEvaluate);
5381 }
5382
5383 /*
5384 * Power Button
5385 */
5386 if (msg & kIOPMPowerButton)
5387 {
5388 if (!wranglerAsleep)
5389 {
5390 OSString *pbs = OSString::withCString("DisablePowerButtonSleep");
5391 // Check that power button sleep is enabled
5392 if( pbs ) {
5393 if( kOSBooleanTrue != getProperty(pbs))
5394 privateSleepSystem (kIOPMSleepReasonPowerButton);
5395 }
5396 }
5397 else
5398 reportUserInput();
5399 }
5400 }
5401
5402 //******************************************************************************
5403 // evaluatePolicy
5404 //
5405 // Evaluate root-domain policy in response to external changes.
5406 //******************************************************************************
5407
5408 void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
5409 {
5410 union {
5411 struct {
5412 int idleSleepEnabled : 1;
5413 int idleSleepDisabled : 1;
5414 int displaySleep : 1;
5415 int sleepDelayChanged : 1;
5416 int evaluateDarkWake : 1;
5417 } bit;
5418 uint32_t u32;
5419 } flags;
5420
5421 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
5422
5423 ASSERT_GATED();
5424 flags.u32 = 0;
5425
5426 switch (stimulus)
5427 {
5428 case kStimulusDisplayWranglerSleep:
5429 if (!wranglerAsleep)
5430 {
5431 wranglerAsleep = true;
5432 clock_get_uptime(&wranglerSleepTime);
5433 flags.bit.displaySleep = true;
5434 }
5435 break;
5436
5437 case kStimulusDisplayWranglerWake:
5438 wranglerAsleep = false;
5439 flags.bit.idleSleepDisabled = true;
5440 break;
5441
5442 case kStimulusAggressivenessChanged:
5443 {
5444 unsigned long minutesToIdleSleep = 0;
5445 unsigned long minutesToDisplayDim = 0;
5446 unsigned long minutesDelta = 0;
5447
5448 // Fetch latest display and system sleep slider values.
5449 getAggressiveness(kPMMinutesToSleep, &minutesToIdleSleep);
5450 getAggressiveness(kPMMinutesToDim, &minutesToDisplayDim);
5451 DLOG("aggressiveness changed: system %u->%u, display %u\n",
5452 (uint32_t) sleepSlider,
5453 (uint32_t) minutesToIdleSleep,
5454 (uint32_t) minutesToDisplayDim);
5455
5456 DLOG("idle time -> %ld secs (ena %d)\n",
5457 idleSeconds, (minutesToIdleSleep != 0));
5458
5459 if (0x7fffffff == minutesToIdleSleep)
5460 minutesToIdleSleep = idleSeconds;
5461
5462 // How long to wait before sleeping the system once
5463 // the displays turns off is indicated by 'extraSleepDelay'.
5464
5465 if ( minutesToIdleSleep > minutesToDisplayDim )
5466 minutesDelta = minutesToIdleSleep - minutesToDisplayDim;
5467
5468 if ((sleepSlider == 0) && (minutesToIdleSleep != 0))
5469 flags.bit.idleSleepEnabled = true;
5470
5471 if ((sleepSlider != 0) && (minutesToIdleSleep == 0))
5472 flags.bit.idleSleepDisabled = true;
5473
5474 if ((minutesDelta != extraSleepDelay) &&
5475 !flags.bit.idleSleepEnabled && !flags.bit.idleSleepDisabled)
5476 flags.bit.sleepDelayChanged = true;
5477
5478 if (systemDarkWake && !darkWakeToSleepASAP &&
5479 (flags.bit.idleSleepEnabled || flags.bit.idleSleepDisabled))
5480 {
5481 // Reconsider decision to remain in dark wake
5482 flags.bit.evaluateDarkWake = true;
5483 }
5484
5485 sleepSlider = minutesToIdleSleep;
5486 extraSleepDelay = minutesDelta;
5487 } break;
5488
5489 case kStimulusDemandSystemSleep:
5490 changePowerStateWithOverrideTo( SLEEP_STATE );
5491 break;
5492
5493 case kStimulusAllowSystemSleepChanged:
5494 // FIXME: de-compose to change flags.
5495 adjustPowerState();
5496 break;
5497
5498 case kStimulusDarkWakeActivityTickle:
5499 if (false == wranglerTickled)
5500 {
5501 uint32_t options = 0;
5502 IOService * pciRoot = 0;
5503
5504 if (rejectWranglerTickle)
5505 {
5506 DLOG("rejected tickle, type %u capability %x:%x\n",
5507 _systemTransitionType,
5508 _currentCapability, _pendingCapability);
5509 break;
5510 }
5511
5512 _desiredCapability |=
5513 (kIOPMSystemCapabilityGraphics |
5514 kIOPMSystemCapabilityAudio);
5515
5516 if ((kSystemTransitionWake == _systemTransitionType) &&
5517 !(_pendingCapability & kIOPMSystemCapabilityGraphics) &&
5518 !graphicsSuppressed)
5519 {
5520 DLOG("Promoting to full wake\n");
5521
5522 // Elevate to full wake while waking up to dark wake.
5523 // PM will hold off notifying the graphics subsystem about
5524 // system wake as late as possible, so if a HID event does
5525 // arrive, we can turn on graphics on this wake cycle, and
5526 // not have to wait till the following cycle. That latency
5527 // can be huge on some systems. However, once any graphics
5528 // suppression has taken effect, it is too late. All other
5529 // graphics devices must be similarly suppressed. But the
5530 // delay till the following cycle should be very short.
5531
5532 _pendingCapability |=
5533 (kIOPMSystemCapabilityGraphics |
5534 kIOPMSystemCapabilityAudio);
5535
5536 // Immediately bring up audio and graphics.
5537 pciRoot = pciHostBridgeDriver;
5538
5539 // Notify clients about full wake.
5540 _systemMessageClientMask = kSystemMessageClientAll;
5541 tellClients(kIOMessageSystemWillPowerOn);
5542 }
5543
5544 // Unsafe to cancel once graphics was powered.
5545 // If system woke from dark wake, the return to sleep can
5546 // be cancelled. But "awake -> dark -> sleep" transition
5547 // cannot be cancelled.
5548
5549 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics)) {
5550 options |= kIOPMSyncCancelPowerDown;
5551 }
5552
5553 synchronizePowerTree( options, pciRoot );
5554 wranglerTickled = true;
5555 // IOGraphics doesn't lit the display even though graphics
5556 // is enanbled in kIOMessageSystemCapabilityChange message(radar 9502104)
5557 // So, do an explicit activity tickle
5558 if(wrangler)
5559 wrangler->activityTickle(0,0);
5560
5561 if (logWranglerTickle)
5562 {
5563 AbsoluteTime now;
5564 uint64_t nsec;
5565
5566 clock_get_uptime(&now);
5567 SUB_ABSOLUTETIME(&now, &systemWakeTime);
5568 absolutetime_to_nanoseconds(now, &nsec);
5569 MSG("HID tickle %u ms\n",
5570 ((int)((nsec) / 1000000ULL)));
5571 logWranglerTickle = false;
5572 }
5573 }
5574 break;
5575
5576 case kStimulusDarkWakeEntry:
5577 case kStimulusDarkWakeReentry:
5578 // Any system transitions since the last dark wake transition
5579 // will invalid the stimulus.
5580
5581 if (arg == _systemStateGeneration)
5582 {
5583 DLOG("dark wake entry\n");
5584 systemDarkWake = true;
5585 wranglerAsleep = true;
5586 clock_get_uptime(&wranglerSleepTime);
5587
5588 // Always accelerate disk spindown while in dark wake,
5589 // even if system does not support/allow sleep.
5590
5591 cancelIdleSleepTimer();
5592 setQuickSpinDownTimeout();
5593 flags.bit.evaluateDarkWake = true;
5594 }
5595 break;
5596
5597 case kStimulusDarkWakeEvaluate:
5598 if (systemDarkWake)
5599 {
5600 flags.bit.evaluateDarkWake = true;
5601 }
5602 #if !DARK_TO_FULL_EVALUATE_CLAMSHELL
5603 else
5604 {
5605 // Not through kLocalEvalClamshellCommand to avoid loop.
5606 if (clamshellClosed && shouldSleepOnClamshellClosed() &&
5607 checkSystemCanSleep(true))
5608 {
5609 privateSleepSystem( kIOPMSleepReasonClamshell );
5610 }
5611 }
5612 #endif
5613 break;
5614
5615 } /* switch(stimulus) */
5616
5617 if (flags.bit.evaluateDarkWake && !wranglerTickled)
5618 {
5619 if (darkWakeToSleepASAP ||
5620 (clamshellClosed && !(desktopMode && acAdaptorConnected)))
5621 {
5622 // System currently in dark wake, and no children and
5623 // assertion prevent system sleep.
5624
5625 if (checkSystemCanSleep(true))
5626 {
5627 if (lowBatteryCondition)
5628 {
5629 lastSleepReason = kIOPMSleepReasonLowPower;
5630 setProperty(kRootDomainSleepReasonKey, kIOPMLowPowerSleepKey);
5631 }
5632 else if (darkWakeMaintenance)
5633 {
5634 lastSleepReason = kIOPMSleepReasonMaintenance;
5635 setProperty(kRootDomainSleepReasonKey, kIOPMMaintenanceSleepKey);
5636 }
5637 changePowerStateWithOverrideTo( SLEEP_STATE );
5638 }
5639 else
5640 {
5641 // Parked in dark wake, a tickle will return to full wake
5642 rejectWranglerTickle = false;
5643 }
5644 } else // non-maintenance (network) dark wake
5645 {
5646 if (checkSystemCanSleep(true))
5647 {
5648 // Release power clamp, and wait for children idle.
5649 adjustPowerState(true);
5650 }
5651 else
5652 {
5653 changePowerStateToPriv(ON_STATE);
5654 }
5655 rejectWranglerTickle = false;
5656 }
5657 }
5658
5659 if (systemDarkWake)
5660 {
5661 // The rest are irrelevant while system is in dark wake.
5662 flags.u32 = 0;
5663 }
5664
5665 if (flags.bit.displaySleep || flags.bit.sleepDelayChanged)
5666 {
5667 bool cancelQuickSpindown = false;
5668
5669 if (flags.bit.sleepDelayChanged)
5670 {
5671 DLOG("extra sleep timer changed\n");
5672 cancelIdleSleepTimer();
5673 cancelQuickSpindown = true;
5674 }
5675 else
5676 {
5677 DLOG("display sleep\n");
5678 }
5679
5680 if (wranglerAsleep && !wranglerSleepIgnored)
5681 {
5682 if ( extraSleepDelay )
5683 {
5684 // Start a timer here if the System Sleep timer is greater
5685 // than the Display Sleep timer.
5686
5687 startIdleSleepTimer(gRootDomain->extraSleepDelay * 60);
5688 }
5689 else if ( sleepSlider )
5690 {
5691 // Accelerate disk spindown if system sleep and display sleep
5692 // sliders are set to the same value (e.g. both set to 5 min),
5693 // and display is about to go dark. Check the system sleep is
5694 // not set to never sleep. Disk sleep setting is ignored.
5695
5696 setQuickSpinDownTimeout();
5697 cancelQuickSpindown = false;
5698 }
5699 }
5700
5701 if (cancelQuickSpindown)
5702 restoreUserSpinDownTimeout();
5703 }
5704
5705 if (flags.bit.idleSleepEnabled)
5706 {
5707 DLOG("idle sleep timer enabled\n");
5708 if (!wrangler)
5709 {
5710 changePowerStateToPriv(ON_STATE);
5711 if (idleSeconds)
5712 {
5713 startIdleSleepTimer( idleSeconds );
5714 }
5715 }
5716 else
5717 {
5718 // Start idle sleep timer if wrangler went to sleep
5719 // while system sleep was disabled. Disk spindown is
5720 // accelerated upon timer expiration.
5721
5722 if (wranglerAsleep)
5723 {
5724 AbsoluteTime now;
5725 uint64_t nanos;
5726 uint32_t minutesSinceDisplaySleep = 0;
5727 uint32_t sleepDelay;
5728
5729 clock_get_uptime(&now);
5730 if (CMP_ABSOLUTETIME(&now, &wranglerSleepTime) > 0)
5731 {
5732 SUB_ABSOLUTETIME(&now, &wranglerSleepTime);
5733 absolutetime_to_nanoseconds(now, &nanos);
5734 minutesSinceDisplaySleep = nanos / (60000000000ULL);
5735 }
5736
5737 if (extraSleepDelay > minutesSinceDisplaySleep)
5738 {
5739 sleepDelay = extraSleepDelay - minutesSinceDisplaySleep;
5740 }
5741 else
5742 {
5743 sleepDelay = 1; // 1 min
5744 }
5745
5746 startIdleSleepTimer(sleepDelay * 60);
5747 DLOG("display slept %u min, set idle timer to %u min\n",
5748 minutesSinceDisplaySleep, sleepDelay);
5749 }
5750 }
5751 }
5752
5753 if (flags.bit.idleSleepDisabled)
5754 {
5755 DLOG("idle sleep timer disabled\n");
5756 cancelIdleSleepTimer();
5757 restoreUserSpinDownTimeout();
5758 adjustPowerState();
5759 }
5760 }
5761
5762 // MARK: -
5763 // MARK: Statistics
5764
5765 //******************************************************************************
5766 // pmStats
5767 //
5768 //******************************************************************************
5769
5770 void IOPMrootDomain::pmStatsRecordEvent(
5771 int eventIndex,
5772 AbsoluteTime timestamp)
5773 {
5774 bool starting = eventIndex & kIOPMStatsEventStartFlag ? true:false;
5775 bool stopping = eventIndex & kIOPMStatsEventStopFlag ? true:false;
5776 uint64_t delta;
5777 uint64_t nsec;
5778
5779 eventIndex &= ~(kIOPMStatsEventStartFlag | kIOPMStatsEventStopFlag);
5780
5781 absolutetime_to_nanoseconds(timestamp, &nsec);
5782
5783 switch (eventIndex) {
5784 case kIOPMStatsHibernateImageWrite:
5785 if (starting)
5786 pmStats.hibWrite.start = nsec;
5787 else if (stopping)
5788 pmStats.hibWrite.stop = nsec;
5789
5790 if (stopping) {
5791 delta = pmStats.hibWrite.stop - pmStats.hibWrite.start;
5792 IOLog("PMStats: Hibernate write took %qd ms\n", delta/1000000ULL);
5793 }
5794 break;
5795 case kIOPMStatsHibernateImageRead:
5796 if (starting)
5797 pmStats.hibRead.start = nsec;
5798 else if (stopping)
5799 pmStats.hibRead.stop = nsec;
5800
5801 if (stopping) {
5802 delta = pmStats.hibRead.stop - pmStats.hibRead.start;
5803 IOLog("PMStats: Hibernate read took %qd ms\n", delta/1000000ULL);
5804 }
5805 break;
5806 }
5807 }
5808
5809 /*
5810 * Appends a record of the application response to
5811 * IOPMrootDomain::pmStatsAppResponses
5812 */
5813 void IOPMrootDomain::pmStatsRecordApplicationResponse(
5814 const OSSymbol *response,
5815 const char *name,
5816 int messageType,
5817 uint32_t delay_ms,
5818 int app_pid)
5819 {
5820 OSDictionary *responseDescription = NULL;
5821 OSNumber *delayNum = NULL;
5822 OSNumber *pidNum = NULL;
5823 OSNumber *msgNum = NULL;
5824 const OSSymbol *appname;
5825 const OSSymbol *entryName;
5826 OSObject *entryType;
5827 int i;
5828
5829 if (!pmStatsAppResponses || pmStatsAppResponses->getCount() > 50)
5830 return;
5831
5832 i = 0;
5833 while ((responseDescription = (OSDictionary *) pmStatsAppResponses->getObject(i++)))
5834 {
5835 entryType = responseDescription->getObject(_statsResponseTypeKey);
5836 entryName = (OSSymbol *) responseDescription->getObject(_statsNameKey);
5837 if (entryName && (entryType == response) && entryName->isEqualTo(name))
5838 {
5839 OSNumber * entryValue;
5840 entryValue = (OSNumber *) responseDescription->getObject(_statsTimeMSKey);
5841 if (entryValue && (entryValue->unsigned32BitValue() < delay_ms))
5842 entryValue->setValue(delay_ms);
5843 return;
5844 }
5845 }
5846
5847 responseDescription = OSDictionary::withCapacity(5);
5848 if (responseDescription)
5849 {
5850 if (response) {
5851 responseDescription->setObject(_statsResponseTypeKey, response);
5852 }
5853
5854 if (messageType != 0) {
5855 msgNum = OSNumber::withNumber(messageType, 32);
5856 if (msgNum) {
5857 responseDescription->setObject(_statsMessageTypeKey, msgNum);
5858 msgNum->release();
5859 }
5860 }
5861
5862 if (name && (strlen(name) > 0))
5863 {
5864 appname = OSSymbol::withCString(name);
5865 if (appname) {
5866 responseDescription->setObject(_statsNameKey, appname);
5867 appname->release();
5868 }
5869 }
5870
5871 if (app_pid != -1) {
5872 pidNum = OSNumber::withNumber(app_pid, 32);
5873 if (pidNum) {
5874 responseDescription->setObject(_statsPIDKey, pidNum);
5875 pidNum->release();
5876 }
5877 }
5878
5879 delayNum = OSNumber::withNumber(delay_ms, 32);
5880 if (delayNum) {
5881 responseDescription->setObject(_statsTimeMSKey, delayNum);
5882 delayNum->release();
5883 }
5884
5885 if (pmStatsAppResponses) {
5886 pmStatsAppResponses->setObject(responseDescription);
5887 }
5888
5889 responseDescription->release();
5890 }
5891 return;
5892 }
5893
5894 // MARK: -
5895 // MARK: PMTraceWorker
5896
5897 //******************************************************************************
5898 // TracePoint support
5899 //
5900 //******************************************************************************
5901
5902 #define kIOPMRegisterNVRAMTracePointHandlerKey \
5903 "IOPMRegisterNVRAMTracePointHandler"
5904
5905 IOReturn IOPMrootDomain::callPlatformFunction(
5906 const OSSymbol * functionName,
5907 bool waitForFunction,
5908 void * param1, void * param2,
5909 void * param3, void * param4 )
5910 {
5911 if (pmTracer && functionName &&
5912 functionName->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey) &&
5913 !pmTracer->tracePointHandler && !pmTracer->tracePointTarget)
5914 {
5915 uint32_t tracePointPhases, tracePointPCI;
5916 uint64_t statusCode;
5917
5918 pmTracer->tracePointHandler = (IOPMTracePointHandler) param1;
5919 pmTracer->tracePointTarget = (void *) param2;
5920 tracePointPCI = (uint32_t)(uintptr_t) param3;
5921 tracePointPhases = (uint32_t)(uintptr_t) param4;
5922 statusCode = (((uint64_t)tracePointPCI) << 32) | tracePointPhases;
5923 if ((tracePointPhases >> 24) != kIOPMTracePointSystemUp)
5924 {
5925 MSG("Sleep failure code 0x%08x 0x%08x\n",
5926 tracePointPCI, tracePointPhases);
5927 }
5928 setProperty(kIOPMSleepWakeFailureCodeKey, statusCode, 64);
5929 pmTracer->tracePointHandler( pmTracer->tracePointTarget, 0, 0 );
5930
5931 return kIOReturnSuccess;
5932 }
5933
5934 return super::callPlatformFunction(
5935 functionName, waitForFunction, param1, param2, param3, param4);
5936 }
5937
5938 void IOPMrootDomain::tracePoint( uint8_t point )
5939 {
5940 if (!systemBooting)
5941 pmTracer->tracePoint(point);
5942 }
5943
5944 void IOPMrootDomain::tracePoint( uint8_t point, uint8_t data )
5945 {
5946 if (!systemBooting)
5947 pmTracer->tracePoint(point, data);
5948 }
5949
5950 void IOPMrootDomain::traceDetail( uint32_t detail )
5951 {
5952 if (!systemBooting)
5953 pmTracer->traceDetail( detail );
5954 }
5955
5956 //******************************************************************************
5957 // PMTraceWorker Class
5958 //
5959 //******************************************************************************
5960
5961 #undef super
5962 #define super OSObject
5963 OSDefineMetaClassAndStructors(PMTraceWorker, OSObject)
5964
5965 #define kPMBestGuessPCIDevicesCount 25
5966 #define kPMMaxRTCBitfieldSize 32
5967
5968 PMTraceWorker *PMTraceWorker::tracer(IOPMrootDomain *owner)
5969 {
5970 PMTraceWorker *me;
5971
5972 me = OSTypeAlloc( PMTraceWorker );
5973 if (!me || !me->init())
5974 {
5975 return NULL;
5976 }
5977
5978 DLOG("PMTraceWorker %p\n", me);
5979
5980 // Note that we cannot instantiate the PCI device -> bit mappings here, since
5981 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
5982 // this dictionary lazily.
5983 me->owner = owner;
5984 me->pciDeviceBitMappings = NULL;
5985 me->pciMappingLock = IOLockAlloc();
5986 me->tracePhase = kIOPMTracePointSystemUp;
5987 me->loginWindowPhase = 0;
5988 me->traceData32 = 0;
5989 return me;
5990 }
5991
5992 void PMTraceWorker::RTC_TRACE(void)
5993 {
5994 if (tracePointHandler && tracePointTarget)
5995 {
5996 uint32_t wordA;
5997
5998 wordA = (tracePhase << 24) | (loginWindowPhase << 16) |
5999 (traceData8 << 8);
6000
6001 tracePointHandler( tracePointTarget, traceData32, wordA );
6002 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32, wordA);
6003 }
6004 }
6005
6006 int PMTraceWorker::recordTopLevelPCIDevice(IOService * pciDevice)
6007 {
6008 const OSSymbol * deviceName;
6009 int index = -1;
6010
6011 IOLockLock(pciMappingLock);
6012
6013 if (!pciDeviceBitMappings)
6014 {
6015 pciDeviceBitMappings = OSArray::withCapacity(kPMBestGuessPCIDevicesCount);
6016 if (!pciDeviceBitMappings)
6017 goto exit;
6018 }
6019
6020 // Check for bitmask overflow.
6021 if (pciDeviceBitMappings->getCount() >= kPMMaxRTCBitfieldSize)
6022 goto exit;
6023
6024 if ((deviceName = pciDevice->copyName()) &&
6025 (pciDeviceBitMappings->getNextIndexOfObject(deviceName, 0) == (unsigned int)-1) &&
6026 pciDeviceBitMappings->setObject(deviceName))
6027 {
6028 index = pciDeviceBitMappings->getCount() - 1;
6029 _LOG("PMTrace PCI array: set object %s => %d\n",
6030 deviceName->getCStringNoCopy(), index);
6031 }
6032 if (deviceName)
6033 deviceName->release();
6034 if (!addedToRegistry && (index >= 0))
6035 addedToRegistry = owner->setProperty("PCITopLevel", this);
6036
6037 exit:
6038 IOLockUnlock(pciMappingLock);
6039 return index;
6040 }
6041
6042 bool PMTraceWorker::serialize(OSSerialize *s) const
6043 {
6044 bool ok = false;
6045 if (pciDeviceBitMappings)
6046 {
6047 IOLockLock(pciMappingLock);
6048 ok = pciDeviceBitMappings->serialize(s);
6049 IOLockUnlock(pciMappingLock);
6050 }
6051 return ok;
6052 }
6053
6054 void PMTraceWorker::tracePoint(uint8_t phase)
6055 {
6056 // clear trace detail when phase begins
6057 if (tracePhase != phase)
6058 traceData32 = 0;
6059
6060 tracePhase = phase;
6061
6062 DLOG("trace point 0x%02x\n", tracePhase);
6063 RTC_TRACE();
6064 }
6065
6066 void PMTraceWorker::tracePoint(uint8_t phase, uint8_t data8)
6067 {
6068 // clear trace detail when phase begins
6069 if (tracePhase != phase)
6070 traceData32 = 0;
6071
6072 tracePhase = phase;
6073 traceData8 = data8;
6074
6075 DLOG("trace point 0x%02x 0x%02x\n", tracePhase, traceData8);
6076 RTC_TRACE();
6077 }
6078
6079 void PMTraceWorker::traceDetail(uint32_t detail)
6080 {
6081 if (kIOPMTracePointSleepPriorityClients != tracePhase)
6082 return;
6083
6084 traceData32 = detail;
6085 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase, traceData32);
6086
6087 RTC_TRACE();
6088 }
6089
6090 void PMTraceWorker::traceLoginWindowPhase(uint8_t phase)
6091 {
6092 loginWindowPhase = phase;
6093
6094 DLOG("loginwindow tracepoint 0x%02x\n", loginWindowPhase);
6095 RTC_TRACE();
6096 }
6097
6098 void PMTraceWorker::tracePCIPowerChange(
6099 change_t type, IOService *service, uint32_t changeFlags, uint32_t bitNum)
6100 {
6101 uint32_t bitMask;
6102 uint32_t expectedFlag;
6103
6104 // Ignore PCI changes outside of system sleep/wake.
6105 if ((kIOPMTracePointSleepPowerPlaneDrivers != tracePhase) &&
6106 (kIOPMTracePointWakePowerPlaneDrivers != tracePhase))
6107 return;
6108
6109 // Only record the WillChange transition when going to sleep,
6110 // and the DidChange on the way up.
6111 changeFlags &= (kIOPMDomainWillChange | kIOPMDomainDidChange);
6112 expectedFlag = (kIOPMTracePointSleepPowerPlaneDrivers == tracePhase) ?
6113 kIOPMDomainWillChange : kIOPMDomainDidChange;
6114 if (changeFlags != expectedFlag)
6115 return;
6116
6117 // Mark this device off in our bitfield
6118 if (bitNum < kPMMaxRTCBitfieldSize)
6119 {
6120 bitMask = (1 << bitNum);
6121
6122 if (kPowerChangeStart == type)
6123 {
6124 traceData32 |= bitMask;
6125 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
6126 service->getName(), bitNum, bitMask, traceData32);
6127 }
6128 else
6129 {
6130 traceData32 &= ~bitMask;
6131 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
6132 service->getName(), bitNum, bitMask, traceData32);
6133 }
6134
6135 RTC_TRACE();
6136 }
6137 }
6138
6139 // MARK: -
6140 // MARK: PMHaltWorker
6141
6142 //******************************************************************************
6143 // PMHaltWorker Class
6144 //
6145 //******************************************************************************
6146
6147 static unsigned int gPMHaltBusyCount;
6148 static unsigned int gPMHaltIdleCount;
6149 static int gPMHaltDepth;
6150 static unsigned long gPMHaltEvent;
6151 static IOLock * gPMHaltLock = 0;
6152 static OSArray * gPMHaltArray = 0;
6153 static const OSSymbol * gPMHaltClientAcknowledgeKey = 0;
6154
6155 PMHaltWorker * PMHaltWorker::worker( void )
6156 {
6157 PMHaltWorker * me;
6158 IOThread thread;
6159
6160 do {
6161 me = OSTypeAlloc( PMHaltWorker );
6162 if (!me || !me->init())
6163 break;
6164
6165 me->lock = IOLockAlloc();
6166 if (!me->lock)
6167 break;
6168
6169 DLOG("PMHaltWorker %p\n", me);
6170 me->retain(); // thread holds extra retain
6171 if (KERN_SUCCESS != kernel_thread_start(&PMHaltWorker::main, (void *) me, &thread))
6172 {
6173 me->release();
6174 break;
6175 }
6176 thread_deallocate(thread);
6177 return me;
6178
6179 } while (false);
6180
6181 if (me) me->release();
6182 return 0;
6183 }
6184
6185 void PMHaltWorker::free( void )
6186 {
6187 DLOG("PMHaltWorker free %p\n", this);
6188 if (lock)
6189 {
6190 IOLockFree(lock);
6191 lock = 0;
6192 }
6193 return OSObject::free();
6194 }
6195
6196 void PMHaltWorker::main( void * arg, wait_result_t waitResult )
6197 {
6198 PMHaltWorker * me = (PMHaltWorker *) arg;
6199
6200 IOLockLock( gPMHaltLock );
6201 gPMHaltBusyCount++;
6202 me->depth = gPMHaltDepth;
6203 IOLockUnlock( gPMHaltLock );
6204
6205 while (me->depth >= 0)
6206 {
6207 PMHaltWorker::work( me );
6208
6209 IOLockLock( gPMHaltLock );
6210 if (++gPMHaltIdleCount >= gPMHaltBusyCount)
6211 {
6212 // This is the last thread to finish work on this level,
6213 // inform everyone to start working on next lower level.
6214 gPMHaltDepth--;
6215 me->depth = gPMHaltDepth;
6216 gPMHaltIdleCount = 0;
6217 thread_wakeup((event_t) &gPMHaltIdleCount);
6218 }
6219 else
6220 {
6221 // One or more threads are still working on this level,
6222 // this thread must wait.
6223 me->depth = gPMHaltDepth - 1;
6224 do {
6225 IOLockSleep(gPMHaltLock, &gPMHaltIdleCount, THREAD_UNINT);
6226 } while (me->depth != gPMHaltDepth);
6227 }
6228 IOLockUnlock( gPMHaltLock );
6229 }
6230
6231 // No more work to do, terminate thread
6232 DLOG("All done for worker: %p (visits = %u)\n", me, me->visits);
6233 thread_wakeup( &gPMHaltDepth );
6234 me->release();
6235 }
6236
6237 void PMHaltWorker::work( PMHaltWorker * me )
6238 {
6239 IOService * service;
6240 OSSet * inner;
6241 AbsoluteTime startTime;
6242 UInt32 deltaTime;
6243 bool timeout;
6244
6245 while (true)
6246 {
6247 service = 0;
6248 timeout = false;
6249
6250 // Claim an unit of work from the shared pool
6251 IOLockLock( gPMHaltLock );
6252 inner = (OSSet *)gPMHaltArray->getObject(me->depth);
6253 if (inner)
6254 {
6255 service = (IOService *)inner->getAnyObject();
6256 if (service)
6257 {
6258 service->retain();
6259 inner->removeObject(service);
6260 }
6261 }
6262 IOLockUnlock( gPMHaltLock );
6263 if (!service)
6264 break; // no more work at this depth
6265
6266 clock_get_uptime(&startTime);
6267
6268 if (!service->isInactive() &&
6269 service->setProperty(gPMHaltClientAcknowledgeKey, me))
6270 {
6271 IOLockLock(me->lock);
6272 me->startTime = startTime;
6273 me->service = service;
6274 me->timeout = false;
6275 IOLockUnlock(me->lock);
6276
6277 service->systemWillShutdown( gPMHaltEvent );
6278
6279 // Wait for driver acknowledgement
6280 IOLockLock(me->lock);
6281 while (service->getProperty(gPMHaltClientAcknowledgeKey))
6282 {
6283 IOLockSleep(me->lock, me, THREAD_UNINT);
6284 }
6285 me->service = 0;
6286 timeout = me->timeout;
6287 IOLockUnlock(me->lock);
6288 }
6289
6290 deltaTime = computeDeltaTimeMS(&startTime);
6291 if ((deltaTime > kPMHaltTimeoutMS) || timeout ||
6292 (gIOKitDebug & kIOLogPMRootDomain))
6293 {
6294 LOG("%s driver %s (%p) took %u ms\n",
6295 (gPMHaltEvent == kIOMessageSystemWillPowerOff) ?
6296 "PowerOff" : "Restart",
6297 service->getName(), service,
6298 (uint32_t) deltaTime );
6299 }
6300
6301 service->release();
6302 me->visits++;
6303 }
6304 }
6305
6306 void PMHaltWorker::checkTimeout( PMHaltWorker * me, AbsoluteTime * now )
6307 {
6308 UInt64 nano;
6309 AbsoluteTime startTime;
6310 AbsoluteTime endTime;
6311
6312 endTime = *now;
6313
6314 IOLockLock(me->lock);
6315 if (me->service && !me->timeout)
6316 {
6317 startTime = me->startTime;
6318 nano = 0;
6319 if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0)
6320 {
6321 SUB_ABSOLUTETIME(&endTime, &startTime);
6322 absolutetime_to_nanoseconds(endTime, &nano);
6323 }
6324 if (nano > 3000000000ULL)
6325 {
6326 me->timeout = true;
6327 MSG("%s still waiting on %s\n",
6328 (gPMHaltEvent == kIOMessageSystemWillPowerOff) ?
6329 "PowerOff" : "Restart",
6330 me->service->getName());
6331 }
6332 }
6333 IOLockUnlock(me->lock);
6334 }
6335
6336
6337 //******************************************************************************
6338 // acknowledgeSystemWillShutdown
6339 //
6340 // Acknowledgement from drivers that they have prepared for shutdown/restart.
6341 //******************************************************************************
6342
6343 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService * from )
6344 {
6345 PMHaltWorker * worker;
6346 OSObject * prop;
6347
6348 if (!from)
6349 return;
6350
6351 //DLOG("%s acknowledged\n", from->getName());
6352 prop = from->copyProperty( gPMHaltClientAcknowledgeKey );
6353 if (prop)
6354 {
6355 worker = (PMHaltWorker *) prop;
6356 IOLockLock(worker->lock);
6357 from->removeProperty( gPMHaltClientAcknowledgeKey );
6358 thread_wakeup((event_t) worker);
6359 IOLockUnlock(worker->lock);
6360 worker->release();
6361 }
6362 else
6363 {
6364 DLOG("%s acknowledged without worker property\n",
6365 from->getName());
6366 }
6367 }
6368
6369
6370 //******************************************************************************
6371 // notifySystemShutdown
6372 //
6373 // Notify all objects in PM tree that system will shutdown or restart
6374 //******************************************************************************
6375
6376 static void
6377 notifySystemShutdown( IOService * root, unsigned long event )
6378 {
6379 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
6380 IORegistryIterator * iter;
6381 IORegistryEntry * entry;
6382 IOService * node;
6383 OSSet * inner;
6384 PMHaltWorker * workers[kPMHaltMaxWorkers];
6385 AbsoluteTime deadline;
6386 unsigned int totalNodes = 0;
6387 unsigned int depth;
6388 unsigned int rootDepth;
6389 unsigned int numWorkers;
6390 unsigned int count;
6391 int waitResult;
6392 void * baseFunc;
6393 bool ok;
6394
6395 DLOG("%s event = %lx\n", __FUNCTION__, event);
6396
6397 baseFunc = OSMemberFunctionCast(void *, root, &IOService::systemWillShutdown);
6398
6399 // Iterate the entire PM tree starting from root
6400
6401 rootDepth = root->getDepth( gIOPowerPlane );
6402 if (!rootDepth) goto done;
6403
6404 // debug - for repeated test runs
6405 while (PMHaltWorker::metaClass->getInstanceCount())
6406 IOSleep(1);
6407
6408 if (!gPMHaltArray)
6409 {
6410 gPMHaltArray = OSArray::withCapacity(40);
6411 if (!gPMHaltArray) goto done;
6412 }
6413 else // debug
6414 gPMHaltArray->flushCollection();
6415
6416 if (!gPMHaltLock)
6417 {
6418 gPMHaltLock = IOLockAlloc();
6419 if (!gPMHaltLock) goto done;
6420 }
6421
6422 if (!gPMHaltClientAcknowledgeKey)
6423 {
6424 gPMHaltClientAcknowledgeKey =
6425 OSSymbol::withCStringNoCopy("PMShutdown");
6426 if (!gPMHaltClientAcknowledgeKey) goto done;
6427 }
6428
6429 gPMHaltEvent = event;
6430
6431 // Depth-first walk of PM plane
6432
6433 iter = IORegistryIterator::iterateOver(
6434 root, gIOPowerPlane, kIORegistryIterateRecursively);
6435
6436 if (iter)
6437 {
6438 while ((entry = iter->getNextObject()))
6439 {
6440 node = OSDynamicCast(IOService, entry);
6441 if (!node)
6442 continue;
6443
6444 if (baseFunc ==
6445 OSMemberFunctionCast(void *, node, &IOService::systemWillShutdown))
6446 continue;
6447
6448 depth = node->getDepth( gIOPowerPlane );
6449 if (depth <= rootDepth)
6450 continue;
6451
6452 ok = false;
6453
6454 // adjust to zero based depth
6455 depth -= (rootDepth + 1);
6456
6457 // gPMHaltArray is an array of containers, each container
6458 // refers to nodes with the same depth.
6459
6460 count = gPMHaltArray->getCount();
6461 while (depth >= count)
6462 {
6463 // expand array and insert placeholders
6464 gPMHaltArray->setObject(PLACEHOLDER);
6465 count++;
6466 }
6467 count = gPMHaltArray->getCount();
6468 if (depth < count)
6469 {
6470 inner = (OSSet *)gPMHaltArray->getObject(depth);
6471 if (inner == PLACEHOLDER)
6472 {
6473 inner = OSSet::withCapacity(40);
6474 if (inner)
6475 {
6476 gPMHaltArray->replaceObject(depth, inner);
6477 inner->release();
6478 }
6479 }
6480
6481 // PM nodes that appear more than once in the tree will have
6482 // the same depth, OSSet will refuse to add the node twice.
6483 if (inner)
6484 ok = inner->setObject(node);
6485 }
6486 if (!ok)
6487 DLOG("Skipped PM node %s\n", node->getName());
6488 }
6489 iter->release();
6490 }
6491
6492 // debug only
6493 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); i++)
6494 {
6495 count = 0;
6496 if (inner != PLACEHOLDER)
6497 count = inner->getCount();
6498 DLOG("Nodes at depth %u = %u\n", i, count);
6499 }
6500
6501 // strip placeholders (not all depths are populated)
6502 numWorkers = 0;
6503 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); )
6504 {
6505 if (inner == PLACEHOLDER)
6506 {
6507 gPMHaltArray->removeObject(i);
6508 continue;
6509 }
6510 count = inner->getCount();
6511 if (count > numWorkers)
6512 numWorkers = count;
6513 totalNodes += count;
6514 i++;
6515 }
6516
6517 if (gPMHaltArray->getCount() == 0 || !numWorkers)
6518 goto done;
6519
6520 gPMHaltBusyCount = 0;
6521 gPMHaltIdleCount = 0;
6522 gPMHaltDepth = gPMHaltArray->getCount() - 1;
6523
6524 // Create multiple workers (and threads)
6525
6526 if (numWorkers > kPMHaltMaxWorkers)
6527 numWorkers = kPMHaltMaxWorkers;
6528
6529 DLOG("PM nodes = %u, maxDepth = %u, workers = %u\n",
6530 totalNodes, gPMHaltArray->getCount(), numWorkers);
6531
6532 for (unsigned int i = 0; i < numWorkers; i++)
6533 workers[i] = PMHaltWorker::worker();
6534
6535 // Wait for workers to exhaust all available work
6536
6537 IOLockLock(gPMHaltLock);
6538 while (gPMHaltDepth >= 0)
6539 {
6540 clock_interval_to_deadline(1000, kMillisecondScale, &deadline);
6541
6542 waitResult = IOLockSleepDeadline(
6543 gPMHaltLock, &gPMHaltDepth, deadline, THREAD_UNINT);
6544 if (THREAD_TIMED_OUT == waitResult)
6545 {
6546 AbsoluteTime now;
6547 clock_get_uptime(&now);
6548
6549 IOLockUnlock(gPMHaltLock);
6550 for (unsigned int i = 0 ; i < numWorkers; i++)
6551 {
6552 if (workers[i])
6553 PMHaltWorker::checkTimeout(workers[i], &now);
6554 }
6555 IOLockLock(gPMHaltLock);
6556 }
6557 }
6558 IOLockUnlock(gPMHaltLock);
6559
6560 // Release all workers
6561
6562 for (unsigned int i = 0; i < numWorkers; i++)
6563 {
6564 if (workers[i])
6565 workers[i]->release();
6566 // worker also retained by it's own thread
6567 }
6568
6569 done:
6570 DLOG("%s done\n", __FUNCTION__);
6571 return;
6572 }
6573
6574 //*********************************************************************************
6575 // Sleep/Wake logging
6576 //
6577 //*********************************************************************************
6578
6579 IOMemoryDescriptor *IOPMrootDomain::getPMTraceMemoryDescriptor(void)
6580 {
6581 if (timeline)
6582 return timeline->getPMTraceMemoryDescriptor();
6583 else
6584 return NULL;
6585 }
6586
6587 // Forwards external reports of detailed events to IOPMTimeline
6588 IOReturn IOPMrootDomain::recordPMEvent(PMEventDetails *details)
6589 {
6590 if (timeline && details) {
6591
6592 IOReturn rc;
6593
6594 // Record a detailed driver power change event, or...
6595 if(details->eventClassifier == kIOPMEventClassDriverEvent) {
6596 rc = timeline->recordDetailedPowerEvent( details );
6597 }
6598
6599 // Record a system power management event
6600 else if(details->eventClassifier == kIOPMEventClassSystemEvent) {
6601 rc = timeline->recordSystemPowerEvent( details );
6602 }
6603 else {
6604 return kIOReturnBadArgument;
6605 }
6606
6607 // If we get to record this message, then we've reached the
6608 // end of another successful Sleep --> Wake cycle
6609 // At this point, we pat ourselves in the back and allow
6610 // our Sleep --> Wake UUID to be published
6611 if(details->eventType == kIOPMEventTypeWakeDone) {
6612 timeline->setSleepCycleInProgressFlag(false);
6613 }
6614
6615 /*
6616 // Check if its time to clear the timeline buffer
6617 if(getProperty(kIOPMSleepWakeUUIDKey)
6618 && timeline->isSleepCycleInProgress() == false
6619 && timeline->getNumEventsLoggedThisPeriod() > 500) {
6620
6621 // Clear the old UUID
6622 if(pmPowerStateQueue) {
6623 pmPowerStateQueue->submitPowerEvent(kPowerEventPublishSleepWakeUUID, (void *)false );
6624 }
6625 }
6626 */
6627 return rc;
6628 }
6629 else
6630 return kIOReturnNotReady;
6631 }
6632
6633 IOReturn IOPMrootDomain::recordAndReleasePMEvent(PMEventDetails *details)
6634 {
6635 IOReturn ret = kIOReturnBadArgument;
6636
6637 if (details)
6638 {
6639 ret = recordPMEvent(details);
6640 details->release();
6641 }
6642
6643 return ret;
6644 }
6645
6646 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6647
6648 IOPMDriverAssertionID IOPMrootDomain::createPMAssertion(
6649 IOPMDriverAssertionType whichAssertionBits,
6650 IOPMDriverAssertionLevel assertionLevel,
6651 IOService *ownerService,
6652 const char *ownerDescription)
6653 {
6654 IOReturn ret;
6655 IOPMDriverAssertionID newAssertion;
6656
6657 if (!pmAssertions)
6658 return 0;
6659
6660 ret = pmAssertions->createAssertion(whichAssertionBits, assertionLevel, ownerService, ownerDescription, &newAssertion);
6661
6662 if (kIOReturnSuccess == ret)
6663 return newAssertion;
6664 else
6665 return 0;
6666 }
6667
6668 IOReturn IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion)
6669 {
6670 if (!pmAssertions)
6671 return kIOReturnInternalError;
6672
6673 return pmAssertions->releaseAssertion(releaseAssertion);
6674 }
6675
6676 IOReturn IOPMrootDomain::setPMAssertionLevel(
6677 IOPMDriverAssertionID assertionID,
6678 IOPMDriverAssertionLevel assertionLevel)
6679 {
6680 return pmAssertions->setAssertionLevel(assertionID, assertionLevel);
6681 }
6682
6683 IOPMDriverAssertionLevel IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion)
6684 {
6685 IOPMDriverAssertionType sysLevels;
6686
6687 if (!pmAssertions || whichAssertion == 0)
6688 return kIOPMDriverAssertionLevelOff;
6689
6690 sysLevels = pmAssertions->getActivatedAssertions();
6691
6692 // Check that every bit set in argument 'whichAssertion' is asserted
6693 // in the aggregate bits.
6694 if ((sysLevels & whichAssertion) == whichAssertion)
6695 return kIOPMDriverAssertionLevelOn;
6696 else
6697 return kIOPMDriverAssertionLevelOff;
6698 }
6699
6700 IOReturn IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels)
6701 {
6702 if (!pmAssertions)
6703 return kIOReturnNotFound;
6704
6705 return pmAssertions->setUserAssertionLevels(inLevels);
6706 }
6707
6708 bool IOPMrootDomain::serializeProperties( OSSerialize * s ) const
6709 {
6710 if (pmAssertions)
6711 {
6712 pmAssertions->publishProperties();
6713 }
6714 return( IOService::serializeProperties(s) );
6715 }
6716
6717 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6718
6719 // MARK: -
6720 // MARK: PMSettingHandle
6721
6722 OSDefineMetaClassAndStructors( PMSettingHandle, OSObject )
6723
6724 void PMSettingHandle::free( void )
6725 {
6726 if (pmso)
6727 {
6728 pmso->clientHandleFreed();
6729 pmso->release();
6730 pmso = 0;
6731 }
6732
6733 OSObject::free();
6734 }
6735
6736 // MARK: -
6737 // MARK: PMSettingObject
6738
6739 #undef super
6740 #define super OSObject
6741 OSDefineMetaClassAndFinalStructors( PMSettingObject, OSObject )
6742
6743 /*
6744 * Static constructor/initializer for PMSettingObject
6745 */
6746 PMSettingObject *PMSettingObject::pmSettingObject(
6747 IOPMrootDomain *parent_arg,
6748 IOPMSettingControllerCallback handler_arg,
6749 OSObject *target_arg,
6750 uintptr_t refcon_arg,
6751 uint32_t supportedPowerSources,
6752 const OSSymbol * settings[],
6753 OSObject **handle_obj)
6754 {
6755 uint32_t settingCount = 0;
6756 PMSettingObject *pmso = 0;
6757 PMSettingHandle *pmsh = 0;
6758
6759 if ( !parent_arg || !handler_arg || !settings || !handle_obj )
6760 return NULL;
6761
6762 // count OSSymbol entries in NULL terminated settings array
6763 while (settings[settingCount]) {
6764 settingCount++;
6765 }
6766 if (0 == settingCount)
6767 return NULL;
6768
6769 pmso = new PMSettingObject;
6770 if (!pmso || !pmso->init())
6771 goto fail;
6772
6773 pmsh = new PMSettingHandle;
6774 if (!pmsh || !pmsh->init())
6775 goto fail;
6776
6777 queue_init(&pmso->calloutQueue);
6778 pmso->parent = parent_arg;
6779 pmso->func = handler_arg;
6780 pmso->target = target_arg;
6781 pmso->refcon = refcon_arg;
6782 pmso->settingCount = settingCount;
6783
6784 pmso->retain(); // handle holds a retain on pmso
6785 pmsh->pmso = pmso;
6786 pmso->pmsh = pmsh;
6787
6788 pmso->publishedFeatureID = (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount);
6789 if (pmso->publishedFeatureID) {
6790 for (unsigned int i=0; i<settingCount; i++) {
6791 // Since there is now at least one listener to this setting, publish
6792 // PM root domain support for it.
6793 parent_arg->publishFeature( settings[i]->getCStringNoCopy(),
6794 supportedPowerSources, &pmso->publishedFeatureID[i] );
6795 }
6796 }
6797
6798 *handle_obj = pmsh;
6799 return pmso;
6800
6801 fail:
6802 if (pmso) pmso->release();
6803 if (pmsh) pmsh->release();
6804 return NULL;
6805 }
6806
6807 void PMSettingObject::free( void )
6808 {
6809 if (publishedFeatureID) {
6810 for (uint32_t i=0; i<settingCount; i++) {
6811 if (publishedFeatureID[i]) {
6812 parent->removePublishedFeature( publishedFeatureID[i] );
6813 }
6814 }
6815
6816 IOFree(publishedFeatureID, sizeof(uint32_t) * settingCount);
6817 }
6818
6819 super::free();
6820 }
6821
6822 void PMSettingObject::dispatchPMSetting( const OSSymbol * type, OSObject * object )
6823 {
6824 (*func)(target, type, object, refcon);
6825 }
6826
6827 void PMSettingObject::clientHandleFreed( void )
6828 {
6829 parent->deregisterPMSettingObject(this);
6830 }
6831
6832 // MARK: -
6833 // MARK: IOPMTimeline
6834
6835 #undef super
6836 #define super OSObject
6837
6838 //*********************************************************************************
6839 //*********************************************************************************
6840 //*********************************************************************************
6841
6842 IOPMTimeline *IOPMTimeline::timeline(IOPMrootDomain *root_domain)
6843 {
6844 IOPMTimeline *myself;
6845
6846 if (!root_domain)
6847 return NULL;
6848
6849 myself = new IOPMTimeline;
6850
6851 if (myself) {
6852 myself->owner = root_domain;
6853 myself->init();
6854 }
6855
6856 return myself;
6857 }
6858
6859 bool IOPMTimeline::init(void)
6860 {
6861 if (!super::init()) {
6862 return false;
6863 }
6864
6865 logLock = IOLockAlloc();
6866
6867 // Fresh timeline, no events logged yet
6868 this->numEventsLoggedThisPeriod = 0;
6869 this->sleepCycleInProgress = false;
6870
6871 //this->setEventsRecordingLevel(1); // TODO
6872 this->setEventsTrackedCount(kIOPMDefaultSystemEventsTracked);
6873
6874 return true;
6875 }
6876
6877 void IOPMTimeline::free(void)
6878 {
6879 if (pmTraceMemoryDescriptor) {
6880 pmTraceMemoryDescriptor->release();
6881 pmTraceMemoryDescriptor = NULL;
6882 }
6883
6884 IOLockFree(logLock);
6885
6886 super::free();
6887 }
6888
6889 IOMemoryDescriptor *IOPMTimeline::getPMTraceMemoryDescriptor()
6890 {
6891 return pmTraceMemoryDescriptor;
6892 }
6893
6894 //*********************************************************************************
6895 //*********************************************************************************
6896 //*********************************************************************************
6897
6898 bool IOPMTimeline::setProperties(OSDictionary *d)
6899 {
6900 OSNumber *n = NULL;
6901 OSBoolean *b = NULL;
6902 bool changed = false;
6903
6904 /* Changes size of detailed events buffer */
6905 n = (OSNumber *)d->getObject(kIOPMTimelineSystemNumberTrackedKey);
6906 if (OSDynamicCast(OSNumber, n))
6907 {
6908 changed = true;
6909 this->setEventsTrackedCount(n->unsigned32BitValue());
6910 }
6911
6912
6913 /* enables or disables system events */
6914 b = (OSBoolean *)d->getObject(kIOPMTimelineEnabledKey);
6915 if (b)
6916 {
6917 changed = true;
6918 this->setEventsRecordingLevel((int)(kOSBooleanTrue == b));
6919 }
6920
6921 return changed;
6922 }
6923
6924 //*********************************************************************************
6925 //*********************************************************************************
6926 //*********************************************************************************
6927
6928 OSDictionary *IOPMTimeline::copyInfoDictionary(void)
6929 {
6930 OSDictionary *out = OSDictionary::withCapacity(3);
6931 OSNumber *n = NULL;
6932
6933 if (!out || !hdr)
6934 return NULL;
6935
6936 n = OSNumber::withNumber(hdr->sizeEntries, 32);
6937 out->setObject(kIOPMTimelineSystemNumberTrackedKey, n);
6938 n->release();
6939
6940 n = OSNumber::withNumber(hdr->sizeBytes, 32);
6941 out->setObject(kIOPMTimelineSystemBufferSizeKey, n);
6942 n->release();
6943
6944 // bool
6945 out->setObject(kIOPMTimelineEnabledKey, eventsRecordingLevel ? kOSBooleanTrue : kOSBooleanFalse);
6946
6947 return out;
6948 }
6949
6950 //*********************************************************************************
6951 //*********************************************************************************
6952 //*********************************************************************************
6953
6954 /* IOPMTimeline::recordSystemPowerEvent()
6955 *
6956 * Expected "type" arguments are listed in IOPMPrivate.h under enum "SystemEventTypes"
6957 * Type arguments include "system events", and "Intermediate events"
6958 *
6959 * - System Events have paired "start" and "stop" events.
6960 * - A start event shall be followed by a stop event.
6961 * - Any number of Intermediate Events may fall between the
6962 * start and stop events.
6963 * - Intermediate events are meaningless outside the bounds of a system event's
6964 * start & stoup routines.
6965 * - It's invalid to record a Start event without a following Stop event; e.g. two
6966 * Start events without an intervenining Stop event is invalid.
6967 *
6968 * Buffer invariants
6969 * - The first recorded system event shall be preceded by an entry with type == 0
6970 * - IOPMTimeline may choose not to record intermediate events while there's not
6971 * a system event in process.
6972 */
6973 IOReturn IOPMTimeline::recordSystemPowerEvent( PMEventDetails *details )
6974 {
6975 static bool wakeDonePending = true;
6976 IOPMSystemEventRecord *record_to = NULL;
6977 OSString *swUUIDKey = NULL;
6978 uint32_t useIndex = 0;
6979
6980 if (!details)
6981 return kIOReturnBadArgument;
6982
6983 if (!traceBuffer)
6984 return kIOReturnNotReady;
6985
6986 if (details->eventType == kIOPMEventTypeWakeDone)
6987 {
6988 if(!wakeDonePending)
6989 return kIOReturnBadArgument;
6990 }
6991
6992 IOLockLock(logLock);
6993
6994 if (details->eventType == kIOPMEventTypeWake) {
6995 wakeDonePending = true;
6996 } else if (details->eventType == kIOPMEventTypeWakeDone) {
6997 wakeDonePending = false;
6998 }
6999
7000 systemState = details->eventType;
7001
7002 useIndex = _atomicIndexIncrement(&hdr->index, hdr->sizeEntries);
7003
7004 // The entry immediately after the latest entry (and thus
7005 // immediately before the first entry) shall have a type 0.
7006 if (useIndex + 1 >= hdr->sizeEntries) {
7007 traceBuffer[useIndex + 1].eventType = 0;
7008 } else {
7009 traceBuffer[0].eventType = 0;
7010 }
7011
7012 record_to = &traceBuffer[useIndex];
7013 bzero(record_to, sizeof(IOPMSystemEventRecord));
7014
7015 /*****/
7016 record_to->eventType = details->eventType;
7017 record_to->eventReason = details->reason;
7018 record_to->eventResult = details->result;
7019 pmEventTimeStamp(&record_to->timestamp);
7020
7021 // If caller doesn't provide a UUID, we'll use the UUID that's posted
7022 // on IOPMrootDomain under key kIOPMSleepWakeUUIDKey
7023 if (!details->uuid) {
7024 swUUIDKey = OSDynamicCast(OSString, owner->copyProperty(kIOPMSleepWakeUUIDKey));
7025
7026 if (swUUIDKey)
7027 details->uuid = swUUIDKey->getCStringNoCopy();
7028 }
7029
7030 if (details->uuid)
7031 strncpy(record_to->uuid, details->uuid, kMaxPMStringLength);
7032
7033 if (swUUIDKey)
7034 swUUIDKey->release();
7035
7036 numEventsLoggedThisPeriod++;
7037 /*****/
7038
7039 IOLockUnlock(logLock);
7040
7041 return kIOReturnSuccess;
7042
7043 }
7044
7045 //*********************************************************************************
7046 //*********************************************************************************
7047 //*********************************************************************************
7048
7049 IOReturn IOPMTimeline::recordDetailedPowerEvent( PMEventDetails *details )
7050 {
7051 IOPMSystemEventRecord *record_to = NULL;
7052 uint32_t useIndex;
7053
7054 if (!details->eventType || !details->ownerName)
7055 return kIOReturnBadArgument;
7056
7057 IOLockLock(logLock);
7058
7059 useIndex = _atomicIndexIncrement(&hdr->index, hdr->sizeEntries);
7060
7061 record_to = (IOPMSystemEventRecord *)&traceBuffer[useIndex];
7062 bzero(record_to, sizeof(IOPMSystemEventRecord));
7063
7064 /*****/
7065 record_to->eventType = details->eventType;
7066 if (details->ownerName && (strlen(details->ownerName) > 1)) {
7067 strlcpy( record_to->ownerName,
7068 details->ownerName,
7069 sizeof(record_to->ownerName));
7070 }
7071
7072 record_to->ownerDisambiguateID = details->ownerUnique;
7073
7074 if (details->interestName && (strlen(details->interestName) > 1)) {
7075 strlcpy(record_to->interestName,
7076 details->interestName,
7077 sizeof(record_to->interestName));
7078 }
7079
7080 record_to->oldState = details->oldState;
7081 record_to->newState = details->newState;
7082 record_to->eventResult = details->result;
7083 record_to->elapsedTimeUS = details->elapsedTimeUS;
7084 pmEventTimeStamp(&record_to->timestamp);
7085
7086 numEventsLoggedThisPeriod++;
7087 /*****/
7088
7089 IOLockUnlock(logLock);
7090 return kIOReturnSuccess;
7091 }
7092
7093 uint32_t IOPMTimeline::getNumEventsLoggedThisPeriod() {
7094 return this->numEventsLoggedThisPeriod;
7095 }
7096
7097 void IOPMTimeline::setNumEventsLoggedThisPeriod(uint32_t newCount) {
7098 this->numEventsLoggedThisPeriod = newCount;
7099 }
7100
7101 bool IOPMTimeline::isSleepCycleInProgress() {
7102 return this->sleepCycleInProgress;
7103 }
7104
7105 void IOPMTimeline::setSleepCycleInProgressFlag(bool flag) {
7106 this->sleepCycleInProgress = flag;
7107 }
7108 //*********************************************************************************
7109 //*********************************************************************************
7110 //*********************************************************************************
7111
7112 void IOPMTimeline::setEventsTrackedCount(uint32_t newTracked)
7113 {
7114 size_t make_buf_size = 0;
7115
7116 make_buf_size = sizeof(IOPMTraceBufferHeader) + (newTracked * sizeof(IOPMSystemEventRecord));
7117
7118 IOLockLock(logLock);
7119
7120 if (pmTraceMemoryDescriptor) {
7121 pmTraceMemoryDescriptor->release();
7122 pmTraceMemoryDescriptor = NULL;
7123 }
7124
7125 hdr = NULL;
7126 traceBuffer = NULL;
7127
7128 if (0 == newTracked)
7129 {
7130 IOLog("IOPMrootDomain -> erased buffer.\n");
7131 goto exit;
7132 }
7133
7134 pmTraceMemoryDescriptor = IOBufferMemoryDescriptor::withOptions(
7135 kIOMemoryKernelUserShared | kIODirectionIn, make_buf_size);
7136
7137 if (!pmTraceMemoryDescriptor)
7138 {
7139 IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns NULL\n", (int)make_buf_size);
7140 goto exit;
7141 }
7142
7143 pmTraceMemoryDescriptor->prepare(kIODirectionIn);
7144
7145 // Header occupies the first sizeof(IOPMTraceBufferHeader) bytes
7146 hdr = (IOPMTraceBufferHeader *)pmTraceMemoryDescriptor->getBytesNoCopy();
7147
7148 // Recorded events occupy the remaining bulk of the buffer
7149 traceBuffer = (IOPMSystemEventRecord *)((uint8_t *)hdr + sizeof(IOPMTraceBufferHeader));
7150
7151 bzero(hdr, make_buf_size);
7152
7153 hdr->sizeBytes = make_buf_size;
7154 hdr->sizeEntries = newTracked;
7155
7156 IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns bufferMB with address 0x%08x\n", (int)make_buf_size, (unsigned int)(uintptr_t)traceBuffer);
7157
7158 exit:
7159 IOLockUnlock(logLock);
7160 }
7161
7162 //*********************************************************************************
7163 //*********************************************************************************
7164 //*********************************************************************************
7165
7166 void IOPMTimeline::setEventsRecordingLevel(uint32_t eventsTrackedBits)
7167 {
7168
7169 // TODO
7170
7171 return;
7172
7173 }
7174
7175 /* static helper to IOPMTimeline
7176 */
7177 uint32_t IOPMTimeline::_atomicIndexIncrement(uint32_t *index, uint32_t limit)
7178 {
7179 uint32_t was_index;
7180 uint32_t inc_index;
7181
7182 if(!index)
7183 return NULL;
7184
7185 do {
7186 was_index = *index;
7187 inc_index = (was_index+1)%limit;
7188 } while (!OSCompareAndSwap(was_index, inc_index, index));
7189
7190 return inc_index;
7191 }
7192
7193 // MARK: -
7194 // MARK: PMAssertionsTracker
7195
7196 //*********************************************************************************
7197 //*********************************************************************************
7198 //*********************************************************************************
7199 // class PMAssertionsTracker Implementation
7200
7201 #define kAssertUniqueIDStart 500
7202
7203 PMAssertionsTracker *PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain *rootDomain )
7204 {
7205 PMAssertionsTracker *myself;
7206
7207 myself = new PMAssertionsTracker;
7208
7209 if (myself) {
7210 myself->init();
7211 myself->owner = rootDomain;
7212 myself->issuingUniqueID = kAssertUniqueIDStart;
7213 myself->assertionsArray = OSArray::withCapacity(5);
7214 myself->assertionsKernel = 0;
7215 myself->assertionsUser = 0;
7216 myself->assertionsCombined = 0;
7217 myself->assertionsArrayLock = IOLockAlloc();
7218 myself->tabulateProducerCount = myself->tabulateConsumerCount = 0;
7219
7220 if (!myself->assertionsArray || !myself->assertionsArrayLock)
7221 myself = NULL;
7222 }
7223
7224 return myself;
7225 }
7226
7227 /* tabulate
7228 * - Update assertionsKernel to reflect the state of all
7229 * assertions in the kernel.
7230 * - Update assertionsCombined to reflect both kernel & user space.
7231 */
7232 void PMAssertionsTracker::tabulate(void)
7233 {
7234 int i;
7235 int count;
7236 PMAssertStruct *_a = NULL;
7237 OSData *_d = NULL;
7238
7239 IOPMDriverAssertionType oldKernel = assertionsKernel;
7240 IOPMDriverAssertionType oldCombined = assertionsCombined;
7241
7242 ASSERT_GATED();
7243
7244 assertionsKernel = 0;
7245 assertionsCombined = 0;
7246
7247 if (!assertionsArray)
7248 return;
7249
7250 if ((count = assertionsArray->getCount()))
7251 {
7252 for (i=0; i<count; i++)
7253 {
7254 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
7255 if (_d)
7256 {
7257 _a = (PMAssertStruct *)_d->getBytesNoCopy();
7258 if (_a && (kIOPMDriverAssertionLevelOn == _a->level))
7259 assertionsKernel |= _a->assertionBits;
7260 }
7261 }
7262 }
7263
7264 tabulateProducerCount++;
7265 assertionsCombined = assertionsKernel | assertionsUser;
7266
7267 if ((assertionsKernel != oldKernel) ||
7268 (assertionsCombined != oldCombined))
7269 {
7270 owner->messageClients(kIOPMMessageDriverAssertionsChanged);
7271
7272 if (((assertionsCombined & kIOPMDriverAssertionPreventDisplaySleepBit) != 0)
7273 && ((oldCombined & kIOPMDriverAssertionPreventDisplaySleepBit) == 0))
7274 {
7275 /* We react to a new PreventDisplaySleep assertion by waking the display
7276 * with an activityTickle
7277 */
7278 owner->evaluatePolicy(kStimulusDarkWakeActivityTickle);
7279 } else {
7280 owner->evaluatePolicy(kStimulusDarkWakeEvaluate);
7281 }
7282 }
7283 }
7284
7285 void PMAssertionsTracker::publishProperties( void )
7286 {
7287 OSArray *assertionsSummary = NULL;
7288
7289 if (tabulateConsumerCount != tabulateProducerCount)
7290 {
7291 IOLockLock(assertionsArrayLock);
7292
7293 tabulateConsumerCount = tabulateProducerCount;
7294
7295 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
7296 */
7297 assertionsSummary = copyAssertionsArray();
7298 if (assertionsSummary)
7299 {
7300 owner->setProperty(kIOPMAssertionsDriverDetailedKey, assertionsSummary);
7301 assertionsSummary->release();
7302 }
7303 else
7304 {
7305 owner->removeProperty(kIOPMAssertionsDriverDetailedKey);
7306 }
7307
7308 /* Publish the IOPMrootDomain property "DriverPMAssertions"
7309 */
7310 owner->setProperty(kIOPMAssertionsDriverKey, assertionsKernel, 64);
7311
7312 IOLockUnlock(assertionsArrayLock);
7313 }
7314 }
7315
7316 PMAssertionsTracker::PMAssertStruct *PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id, int *index)
7317 {
7318 PMAssertStruct *_a = NULL;
7319 OSData *_d = NULL;
7320 int found = -1;
7321 int count = 0;
7322 int i = 0;
7323
7324 if (assertionsArray
7325 && (count = assertionsArray->getCount()))
7326 {
7327 for (i=0; i<count; i++)
7328 {
7329 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
7330 if (_d)
7331 {
7332 _a = (PMAssertStruct *)_d->getBytesNoCopy();
7333 if (_a && (_id == _a->id)) {
7334 found = i;
7335 break;
7336 }
7337 }
7338 }
7339 }
7340
7341 if (-1 == found) {
7342 return NULL;
7343 } else {
7344 if (index)
7345 *index = found;
7346 return _a;
7347 }
7348 }
7349
7350 /* PMAssertionsTracker::handleCreateAssertion
7351 * Perform assertion work on the PM workloop. Do not call directly.
7352 */
7353 IOReturn PMAssertionsTracker::handleCreateAssertion(OSData *newAssertion)
7354 {
7355 ASSERT_GATED();
7356
7357 if (newAssertion)
7358 {
7359 IOLockLock(assertionsArrayLock);
7360 assertionsArray->setObject(newAssertion);
7361 IOLockUnlock(assertionsArrayLock);
7362 newAssertion->release();
7363
7364 tabulate();
7365 }
7366 return kIOReturnSuccess;
7367 }
7368
7369 /* PMAssertionsTracker::createAssertion
7370 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
7371 * appropiate.
7372 */
7373 IOReturn PMAssertionsTracker::createAssertion(
7374 IOPMDriverAssertionType which,
7375 IOPMDriverAssertionLevel level,
7376 IOService *serviceID,
7377 const char *whoItIs,
7378 IOPMDriverAssertionID *outID)
7379 {
7380 OSData *dataStore = NULL;
7381 PMAssertStruct track;
7382
7383 // Warning: trillions and trillions of created assertions may overflow the unique ID.
7384 track.id = OSIncrementAtomic64((SInt64*) &issuingUniqueID);
7385 track.level = level;
7386 track.assertionBits = which;
7387 track.ownerString = whoItIs ? OSSymbol::withCString(whoItIs) : 0;
7388 track.ownerService = serviceID;
7389 track.modifiedTime = 0;
7390 pmEventTimeStamp(&track.createdTime);
7391
7392 dataStore = OSData::withBytes(&track, sizeof(PMAssertStruct));
7393 if (!dataStore)
7394 {
7395 if (track.ownerString)
7396 track.ownerString->release();
7397 return kIOReturnNoMemory;
7398 }
7399
7400 *outID = track.id;
7401
7402 if (owner && owner->pmPowerStateQueue) {
7403 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionCreate, (void *)dataStore);
7404 }
7405
7406 return kIOReturnSuccess;
7407 }
7408
7409 /* PMAssertionsTracker::handleReleaseAssertion
7410 * Runs in PM workloop. Do not call directly.
7411 */
7412 IOReturn PMAssertionsTracker::handleReleaseAssertion(
7413 IOPMDriverAssertionID _id)
7414 {
7415 ASSERT_GATED();
7416
7417 int index;
7418 PMAssertStruct *assertStruct = detailsForID(_id, &index);
7419
7420 if (!assertStruct)
7421 return kIOReturnNotFound;
7422
7423 IOLockLock(assertionsArrayLock);
7424 if (assertStruct->ownerString)
7425 assertStruct->ownerString->release();
7426
7427 assertionsArray->removeObject(index);
7428 IOLockUnlock(assertionsArrayLock);
7429
7430 tabulate();
7431 return kIOReturnSuccess;
7432 }
7433
7434 /* PMAssertionsTracker::releaseAssertion
7435 * Releases an assertion and affects system behavior if appropiate.
7436 * Actual work happens on PM workloop.
7437 */
7438 IOReturn PMAssertionsTracker::releaseAssertion(
7439 IOPMDriverAssertionID _id)
7440 {
7441 if (owner && owner->pmPowerStateQueue) {
7442 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionRelease, 0, _id);
7443 }
7444 return kIOReturnSuccess;
7445 }
7446
7447 /* PMAssertionsTracker::handleSetAssertionLevel
7448 * Runs in PM workloop. Do not call directly.
7449 */
7450 IOReturn PMAssertionsTracker::handleSetAssertionLevel(
7451 IOPMDriverAssertionID _id,
7452 IOPMDriverAssertionLevel _level)
7453 {
7454 PMAssertStruct *assertStruct = detailsForID(_id, NULL);
7455
7456 ASSERT_GATED();
7457
7458 if (!assertStruct) {
7459 return kIOReturnNotFound;
7460 }
7461
7462 IOLockLock(assertionsArrayLock);
7463 pmEventTimeStamp(&assertStruct->modifiedTime);
7464 assertStruct->level = _level;
7465 IOLockUnlock(assertionsArrayLock);
7466
7467 tabulate();
7468 return kIOReturnSuccess;
7469 }
7470
7471 /* PMAssertionsTracker::setAssertionLevel
7472 */
7473 IOReturn PMAssertionsTracker::setAssertionLevel(
7474 IOPMDriverAssertionID _id,
7475 IOPMDriverAssertionLevel _level)
7476 {
7477 if (owner && owner->pmPowerStateQueue) {
7478 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionSetLevel,
7479 (void *)_level, _id);
7480 }
7481
7482 return kIOReturnSuccess;
7483 }
7484
7485 IOReturn PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0)
7486 {
7487 IOPMDriverAssertionType new_user_levels = *(IOPMDriverAssertionType *) arg0;
7488
7489 ASSERT_GATED();
7490
7491 if (new_user_levels != assertionsUser)
7492 {
7493 assertionsUser = new_user_levels;
7494 DLOG("assertionsUser 0x%llx\n", assertionsUser);
7495 }
7496
7497 tabulate();
7498 return kIOReturnSuccess;
7499 }
7500
7501 IOReturn PMAssertionsTracker::setUserAssertionLevels(
7502 IOPMDriverAssertionType new_user_levels)
7503 {
7504 if (gIOPMWorkLoop) {
7505 gIOPMWorkLoop->runAction(
7506 OSMemberFunctionCast(
7507 IOWorkLoop::Action,
7508 this,
7509 &PMAssertionsTracker::handleSetUserAssertionLevels),
7510 this,
7511 (void *) &new_user_levels, 0, 0, 0);
7512 }
7513
7514 return kIOReturnSuccess;
7515 }
7516
7517
7518 OSArray *PMAssertionsTracker::copyAssertionsArray(void)
7519 {
7520 int count;
7521 int i;
7522 OSArray *outArray = NULL;
7523
7524 if (!assertionsArray ||
7525 (0 == (count = assertionsArray->getCount())) ||
7526 (NULL == (outArray = OSArray::withCapacity(count))))
7527 {
7528 goto exit;
7529 }
7530
7531 for (i=0; i<count; i++)
7532 {
7533 PMAssertStruct *_a = NULL;
7534 OSData *_d = NULL;
7535 OSDictionary *details = NULL;
7536
7537 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
7538 if (_d && (_a = (PMAssertStruct *)_d->getBytesNoCopy()))
7539 {
7540 OSNumber *_n = NULL;
7541
7542 details = OSDictionary::withCapacity(7);
7543 if (!details)
7544 continue;
7545
7546 outArray->setObject(details);
7547 details->release();
7548
7549 _n = OSNumber::withNumber(_a->id, 64);
7550 if (_n) {
7551 details->setObject(kIOPMDriverAssertionIDKey, _n);
7552 _n->release();
7553 }
7554 _n = OSNumber::withNumber(_a->createdTime, 64);
7555 if (_n) {
7556 details->setObject(kIOPMDriverAssertionCreatedTimeKey, _n);
7557 _n->release();
7558 }
7559 _n = OSNumber::withNumber(_a->modifiedTime, 64);
7560 if (_n) {
7561 details->setObject(kIOPMDriverAssertionModifiedTimeKey, _n);
7562 _n->release();
7563 }
7564 _n = OSNumber::withNumber((uintptr_t)_a->ownerService, 64);
7565 if (_n) {
7566 details->setObject(kIOPMDriverAssertionOwnerServiceKey, _n);
7567 _n->release();
7568 }
7569 _n = OSNumber::withNumber(_a->level, 64);
7570 if (_n) {
7571 details->setObject(kIOPMDriverAssertionLevelKey, _n);
7572 _n->release();
7573 }
7574 _n = OSNumber::withNumber(_a->assertionBits, 64);
7575 if (_n) {
7576 details->setObject(kIOPMDriverAssertionAssertedKey, _n);
7577 _n->release();
7578 }
7579
7580 if (_a->ownerString) {
7581 details->setObject(kIOPMDriverAssertionOwnerStringKey, _a->ownerString);
7582 }
7583 }
7584 }
7585
7586 exit:
7587 return outArray;
7588 }
7589
7590 IOPMDriverAssertionType PMAssertionsTracker::getActivatedAssertions(void)
7591 {
7592 return assertionsCombined;
7593 }
7594
7595 IOPMDriverAssertionLevel PMAssertionsTracker::getAssertionLevel(
7596 IOPMDriverAssertionType type)
7597 {
7598 if (type && ((type & assertionsKernel) == assertionsKernel))
7599 {
7600 return kIOPMDriverAssertionLevelOn;
7601 } else {
7602 return kIOPMDriverAssertionLevelOff;
7603 }
7604 }
7605
7606 //*********************************************************************************
7607 //*********************************************************************************
7608 //*********************************************************************************
7609
7610
7611 static void pmEventTimeStamp(uint64_t *recordTS)
7612 {
7613 clock_sec_t tsec;
7614 clock_usec_t tusec;
7615
7616 if (!recordTS)
7617 return;
7618
7619 // We assume tsec fits into 32 bits; 32 bits holds enough
7620 // seconds for 136 years since the epoch in 1970.
7621 clock_get_calendar_microtime(&tsec, &tusec);
7622
7623
7624 // Pack the sec & microsec calendar time into a uint64_t, for fun.
7625 *recordTS = 0;
7626 *recordTS |= (uint32_t)tusec;
7627 *recordTS |= ((uint64_t)tsec << 32);
7628
7629 return;
7630 }
7631
7632 // MARK: -
7633 // MARK: IORootParent
7634
7635 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7636
7637 OSDefineMetaClassAndFinalStructors(IORootParent, IOService)
7638
7639 // The reason that root domain needs a root parent is to facilitate demand
7640 // sleep, since a power change from the root parent cannot be vetoed.
7641 //
7642 // The above statement is no longer true since root domain now performs
7643 // demand sleep using overrides. But root parent remains to avoid changing
7644 // the power tree stacking. Root parent is parked at the max power state.
7645
7646
7647 static IOPMPowerState patriarchPowerStates[2] =
7648 {
7649 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0},
7650 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0},
7651 };
7652
7653 void IORootParent::initialize( void )
7654 {
7655 }
7656
7657 bool IORootParent::start( IOService * nub )
7658 {
7659 IOService::start(nub);
7660 attachToParent( getRegistryRoot(), gIOPowerPlane );
7661 PMinit();
7662 registerPowerDriver(this, patriarchPowerStates, 2);
7663 makeUsable();
7664 return true;
7665 }
7666
7667 void IORootParent::shutDownSystem( void )
7668 {
7669 }
7670
7671 void IORootParent::restartSystem( void )
7672 {
7673 }
7674
7675 void IORootParent::sleepSystem( void )
7676 {
7677 }
7678
7679 void IORootParent::dozeSystem( void )
7680 {
7681 }
7682
7683 void IORootParent::sleepToDoze( void )
7684 {
7685 }
7686
7687 void IORootParent::wakeSystem( void )
7688 {
7689 }
7690
7691 OSObject * IORootParent::copyProperty( const char * aKey) const
7692 {
7693 return (IOService::copyProperty(aKey));
7694 }
7695