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