]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOPMrootDomain.cpp
848f67200d5bf6baa39be9c06e50e43dc8b62b78
[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 <IOKit/IOWorkLoop.h>
31 #include <IOKit/IOCommandGate.h>
32 #include <IOKit/IOPlatformExpert.h>
33 #include <IOKit/IOKitDebug.h>
34 #include <IOKit/IOTimeStamp.h>
35 #include <IOKit/pwr_mgt/IOPMlog.h>
36 #include <IOKit/pwr_mgt/RootDomain.h>
37 #include <IOKit/pwr_mgt/IOPMPrivate.h>
38 #include <IOKit/IODeviceTreeSupport.h>
39 #include <IOKit/IOMessage.h>
40 #include <IOKit/IOReturn.h>
41 #include "RootDomainUserClient.h"
42 #include "IOKit/pwr_mgt/IOPowerConnection.h"
43 #include "IOPMPowerStateQueue.h"
44 #include <IOKit/IOCatalogue.h>
45 #include <IOKit/IOCommand.h> // IOServicePMPrivate
46 #if HIBERNATION
47 #include <IOKit/IOHibernatePrivate.h>
48 #endif
49 #include <sys/syslog.h>
50 #include <sys/sysctl.h>
51 #include <sys/time.h>
52 #include "IOServicePrivate.h" // _IOServiceInterestNotifier
53 #include "IOServicePMPrivate.h"
54
55 __BEGIN_DECLS
56 #include <mach/shared_region.h>
57 __END_DECLS
58
59 #if defined(__i386__) || defined(__x86_64__)
60 __BEGIN_DECLS
61 #include "IOPMrootDomainInternal.h"
62 __END_DECLS
63 #endif
64
65 #define kIOPMrootDomainClass "IOPMrootDomain"
66
67 #define LOG_PREFIX "PMRD: "
68
69 #define LOG(x...) do { \
70 kprintf(LOG_PREFIX x); IOLog(x); } while (false)
71
72 #define KLOG(x...) do { \
73 kprintf(LOG_PREFIX x); } while (false)
74
75 #define DLOG(x...) do { \
76 if (kIOLogPMRootDomain & gIOKitDebug) \
77 kprintf(LOG_PREFIX x); } while (false)
78
79 #define CHECK_THREAD_CONTEXT
80 #ifdef CHECK_THREAD_CONTEXT
81 static IOWorkLoop * gIOPMWorkLoop = 0;
82 #define ASSERT_GATED(x) \
83 do { \
84 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
85 panic("RootDomain: not inside PM gate"); \
86 } \
87 } while(false)
88 #else
89 #define ASSERT_GATED(x)
90 #endif /* CHECK_THREAD_CONTEXT */
91
92 // Event types for IOPMPowerStateQueue::submitPowerEvent()
93 enum {
94 kPowerEventFeatureChanged = 1,
95 kPowerEventReceivedPowerNotification,
96 kPowerEventSystemBootCompleted,
97 kPowerEventSystemShutdown,
98 kPowerEventUserDisabledSleep,
99 kPowerEventConfigdRegisteredInterest,
100 kPowerEventAggressivenessChanged
101 };
102
103 extern "C" {
104 IOReturn OSKextSystemSleepOrWake( UInt32 );
105 }
106
107 extern const IORegistryPlane * gIOPowerPlane;
108
109 static void idleSleepTimerExpired( thread_call_param_t, thread_call_param_t );
110 static void wakeupClamshellTimerExpired( thread_call_param_t us, thread_call_param_t );
111 static void notifySystemShutdown( IOService * root, unsigned long event );
112 static bool clientMessageFilter( OSObject * object, void * context );
113 static void handleAggressivesFunction( thread_call_param_t param1, thread_call_param_t param2 );
114
115 // "IOPMSetSleepSupported" callPlatformFunction name
116 static const OSSymbol *sleepSupportedPEFunction = NULL;
117
118 #define kIOSleepSupportedKey "IOSleepSupported"
119
120 #define kRD_AllPowerSources (kIOPMSupportedOnAC \
121 | kIOPMSupportedOnBatt \
122 | kIOPMSupportedOnUPS)
123
124 enum
125 {
126 // not idle around autowake time, secs
127 kAutoWakePreWindow = 45,
128 kAutoWakePostWindow = 15
129 };
130
131 #define kLocalEvalClamshellCommand (1 << 15)
132
133 enum {
134 OFF_STATE = 0,
135 RESTART_STATE = 1,
136 SLEEP_STATE = 2,
137 DOZE_STATE = 3,
138 ON_STATE = 4,
139 NUM_POWER_STATES
140 };
141
142 #define ON_POWER kIOPMPowerOn
143 #define RESTART_POWER kIOPMRestart
144 #define SLEEP_POWER kIOPMAuxPowerOn
145 #define DOZE_POWER kIOPMDoze
146
147 static IOPMPowerState ourPowerStates[NUM_POWER_STATES] =
148 {
149 {1, 0, 0, 0, 0,0,0,0,0,0,0,0},
150 {1, kIOPMRestartCapability, kIOPMRestart, RESTART_POWER, 0,0,0,0,0,0,0,0},
151 {1, kIOPMSleepCapability, kIOPMSleep, SLEEP_POWER, 0,0,0,0,0,0,0,0},
152 {1, kIOPMDoze, kIOPMDoze, DOZE_POWER, 0,0,0,0,0,0,0,0},
153 {1, kIOPMPowerOn, kIOPMPowerOn, ON_POWER, 0,0,0,0,0,0,0,0}
154 };
155
156 // Clients eligible to receive system power messages.
157 enum {
158 kMessageClientNone = 0,
159 kMessageClientAll,
160 kMessageClientConfigd
161 };
162
163 // Run states (R-state) defined within the ON power state.
164 enum {
165 kRStateNormal = 0,
166 kRStateDark,
167 kRStateMaintenance,
168 kRStateCount
169 };
170
171 // IOService in power plane can be tagged with following flags.
172 enum {
173 kServiceFlagGraphics = 0x01,
174 kServiceFlagNoPowerUp = 0x02,
175 kServiceFlagTopLevelPCI = 0x04
176 };
177
178 // Flags describing R-state features and capabilities.
179 enum {
180 kRStateFlagNone = 0x00000000,
181 kRStateFlagSuppressGraphics = 0x00000001,
182 kRStateFlagSuppressMessages = 0x00000002,
183 kRStateFlagSuppressPCICheck = 0x00000004,
184 kRStateFlagDisableIdleSleep = 0x00000008
185 };
186
187 #if ROOT_DOMAIN_RUN_STATES
188
189 // Table of flags for each R-state.
190 static uint32_t gRStateFlags[ kRStateCount ] =
191 {
192 kRStateFlagNone,
193
194 /* Dark wake */
195 kRStateFlagSuppressGraphics,
196
197 /* Maintenance wake */
198 kRStateFlagSuppressGraphics |
199 kRStateFlagSuppressMessages |
200 kRStateFlagSuppressPCICheck |
201 kRStateFlagDisableIdleSleep
202 };
203
204 static IONotifier * gConfigdNotifier = 0;
205
206 #define kIOPMRootDomainRunStateKey "Run State"
207 #define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
208
209 #endif /* ROOT_DOMAIN_RUN_STATES */
210
211 // Special interest that entitles the interested client from receiving
212 // all system messages. Used by pmconfigd to support maintenance wake.
213 //
214 #define kIOPMPrivilegedPowerInterest "IOPMPrivilegedPowerInterest"
215
216 static IONotifier * gSysPowerDownNotifier = 0;
217
218 /*
219 * Aggressiveness
220 */
221 #define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
222 #define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
223
224 #define kAggressivesMinValue 1
225
226 static uint32_t gAggressivesState = 0;
227
228 enum {
229 kAggressivesStateBusy = 0x01,
230 kAggressivesStateQuickSpindown = 0x02
231 };
232
233 struct AggressivesRecord {
234 uint32_t flags;
235 uint32_t type;
236 uint32_t value;
237 };
238
239 struct AggressivesRequest {
240 queue_chain_t chain;
241 uint32_t options;
242 uint32_t dataType;
243 union {
244 IOService * service;
245 AggressivesRecord record;
246 } data;
247 };
248
249 enum {
250 kAggressivesRequestTypeService = 1,
251 kAggressivesRequestTypeRecord
252 };
253
254 enum {
255 kAggressivesOptionSynchronous = 0x00000001,
256 kAggressivesOptionQuickSpindownEnable = 0x00000100,
257 kAggressivesOptionQuickSpindownDisable = 0x00000200,
258 kAggressivesOptionQuickSpindownMask = 0x00000300
259 };
260
261 enum {
262 kAggressivesRecordFlagModified = 0x00000001,
263 kAggressivesRecordFlagMinValue = 0x00000002
264
265 };
266
267 static IOPMrootDomain * gRootDomain;
268 static UInt32 gSleepOrShutdownPending = 0;
269 static UInt32 gWillShutdown = 0;
270 static uint32_t gMessageClientType = kMessageClientNone;
271 static UInt32 gSleepWakeUUIDIsSet = false;
272
273 struct timeval gIOLastSleepTime;
274 struct timeval gIOLastWakeTime;
275
276 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
277 #define kCPUUnknownIndex 9999999
278 enum {
279 kInformAC = 0,
280 kInformLid = 1,
281 kInformableCount = 2
282 };
283
284 const OSSymbol *gIOPMStatsApplicationResponseTimedOut;
285 const OSSymbol *gIOPMStatsApplicationResponseCancel;
286 const OSSymbol *gIOPMStatsApplicationResponseSlow;
287
288 class PMSettingObject : public OSObject
289 {
290 OSDeclareFinalStructors(PMSettingObject)
291 private:
292 IOPMrootDomain *parent;
293 IOPMSettingControllerCallback func;
294 OSObject *target;
295 uintptr_t refcon;
296 uint32_t *publishedFeatureID;
297 int releaseAtCount;
298 public:
299 static PMSettingObject *pmSettingObject(
300 IOPMrootDomain *parent_arg,
301 IOPMSettingControllerCallback handler_arg,
302 OSObject *target_arg,
303 uintptr_t refcon_arg,
304 uint32_t supportedPowerSources,
305 const OSSymbol *settings[]);
306
307 void setPMSetting(const OSSymbol *type, OSObject *obj);
308
309 void taggedRelease(const void *tag, const int when) const;
310 void free(void);
311 };
312
313
314 /*
315 * PMTraceWorker
316 * Internal helper object for logging trace points to RTC
317 * IOPMrootDomain and only IOPMrootDomain should instantiate
318 * exactly one of these.
319 */
320
321 typedef void (*IOPMTracePointHandler)(
322 void * target, uint32_t code, uint32_t data );
323
324 class PMTraceWorker : public OSObject
325 {
326 OSDeclareDefaultStructors(PMTraceWorker)
327 public:
328 typedef enum { kPowerChangeStart, kPowerChangeCompleted } change_t;
329
330 static PMTraceWorker *tracer( IOPMrootDomain * );
331 void tracePCIPowerChange(change_t, IOService *, uint32_t, uint32_t);
332 void tracePoint(uint8_t phase);
333 void traceLoginWindowPhase(uint8_t phase);
334 int recordTopLevelPCIDevice(IOService *);
335 void RTC_TRACE(void);
336 virtual bool serialize(OSSerialize *s) const;
337
338 IOPMTracePointHandler tracePointHandler;
339 void * tracePointTarget;
340 private:
341 IOPMrootDomain *owner;
342 IOLock *pciMappingLock;
343 OSArray *pciDeviceBitMappings;
344
345 uint8_t tracePhase;
346 uint8_t loginWindowPhase;
347 uint8_t addedToRegistry;
348 uint8_t unused0;
349 uint32_t pciBusyBitMask;
350 };
351
352 /*
353 * PMHaltWorker
354 * Internal helper object for Shutdown/Restart notifications.
355 */
356 #define kPMHaltMaxWorkers 8
357 #define kPMHaltTimeoutMS 100
358
359 class PMHaltWorker : public OSObject
360 {
361 OSDeclareFinalStructors( PMHaltWorker )
362
363 public:
364 IOService * service; // service being worked on
365 AbsoluteTime startTime; // time when work started
366 int depth; // work on nubs at this PM-tree depth
367 int visits; // number of nodes visited (debug)
368 IOLock * lock;
369 bool timeout; // service took too long
370
371 static PMHaltWorker * worker( void );
372 static void main( void * arg, wait_result_t waitResult );
373 static void work( PMHaltWorker * me );
374 static void checkTimeout( PMHaltWorker * me, AbsoluteTime * now );
375 virtual void free( void );
376 };
377
378 OSDefineMetaClassAndFinalStructors( PMHaltWorker, OSObject )
379
380
381 #define super IOService
382 OSDefineMetaClassAndFinalStructors(IOPMrootDomain, IOService)
383
384 extern "C"
385 {
386 IONotifier * registerSleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
387 {
388 return gRootDomain->registerInterest( gIOGeneralInterest, handler, self, ref );
389 }
390
391 IONotifier * registerPrioritySleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
392 {
393 return gRootDomain->registerInterest( gIOPriorityPowerStateInterest, handler, self, ref );
394 }
395
396 IOReturn acknowledgeSleepWakeNotification(void * PMrefcon)
397 {
398 return gRootDomain->allowPowerChange ( (unsigned long)PMrefcon );
399 }
400
401 IOReturn vetoSleepWakeNotification(void * PMrefcon)
402 {
403 return gRootDomain->cancelPowerChange ( (unsigned long)PMrefcon );
404 }
405
406 IOReturn rootDomainRestart ( void )
407 {
408 return gRootDomain->restartSystem();
409 }
410
411 IOReturn rootDomainShutdown ( void )
412 {
413 return gRootDomain->shutdownSystem();
414 }
415
416 void IOSystemShutdownNotification ( void )
417 {
418 if (OSCompareAndSwap(0, 1, &gWillShutdown))
419 {
420 OSKext::willShutdown();
421 for (int i = 0; i < 100; i++)
422 {
423 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending)) break;
424 IOSleep( 100 );
425 }
426 }
427 }
428
429 int sync_internal(void);
430 }
431
432 /*
433 A device is always in the highest power state which satisfies its driver, its policy-maker, and any power domain
434 children it has, but within the constraint of the power state provided by its parent. The driver expresses its desire by
435 calling changePowerStateTo(), the policy-maker expresses its desire by calling changePowerStateToPriv(), and the children
436 express their desires by calling requestPowerDomainState().
437
438 The Root Power Domain owns the policy for idle and demand sleep and doze for the system. It is a power-managed IOService just
439 like the others in the system. It implements several power states which correspond to what we see as Sleep, Doze, etc.
440
441 The sleep/doze policy is as follows:
442 Sleep and Doze are prevented if the case is open so that nobody will think the machine is off and plug/unplug cards.
443 Sleep and Doze are prevented if the sleep timeout slider in the preferences panel is at zero.
444 The system cannot Sleep, but can Doze if some object in the tree is in a power state marked kIOPMPreventSystemSleep.
445
446 These three conditions are enforced using the "driver clamp" by calling changePowerStateTo(). For example, if the case is
447 opened, changePowerStateTo(ON_STATE) is called to hold the system on regardless of the desires of the children of the root or
448 the state of the other clamp.
449
450 Demand Sleep/Doze is initiated by pressing the front panel power button, closing the clamshell, or selecting the menu item.
451 In this case the root's parent actually initiates the power state change so that the root has no choice and does not give
452 applications the opportunity to veto the change.
453
454 Idle Sleep/Doze occurs if no objects in the tree are in a state marked kIOPMPreventIdleSleep. When this is true, the root's
455 children are not holding the root on, so it sets the "policy-maker clamp" by calling changePowerStateToPriv(ON_STATE)
456 to hold itself on until the sleep timer expires. This timer is set for the difference between the sleep timeout slider and
457 the larger of the display dim timeout slider and the disk spindown timeout slider in the Preferences panel. For example, if
458 the system is set to sleep after thirty idle minutes, and the display and disk are set to sleep after five idle minutes,
459 when there is no longer an object in the tree holding the system out of Idle Sleep (via kIOPMPreventIdleSleep), the root
460 sets its timer for 25 minutes (30 - 5). When the timer expires, it releases its clamp and now nothing is holding it awake,
461 so it falls asleep.
462
463 Demand sleep is prevented when the system is booting. When preferences are transmitted by the loginwindow at the end of
464 boot, a flag is cleared, and this allows subsequent Demand Sleep.
465
466 The system will not Sleep, but will Doze if some object calls setSleepSupported(kPCICantSleep) during a power change to the sleep state (this can be done by the PCI Aux Power Supply drivers, Slots99, MacRISC299, etc.). This is not enforced with
467 a clamp, but sets a flag which is noticed before actually sleeping the kernel. If the flag is set, the root steps up
468 one power state from Sleep to Doze, and any objects in the tree for which this is relevent will act appropriately (USB and
469 ADB will turn on again so that they can wake the system out of Doze (keyboard/mouse activity will cause the Display Wrangler
470 to be tickled)).
471 */
472
473 //******************************************************************************
474
475 IOPMrootDomain * IOPMrootDomain::construct( void )
476 {
477 IOPMrootDomain *root;
478
479 root = new IOPMrootDomain;
480 if( root)
481 root->init();
482
483 return( root );
484 }
485
486 //******************************************************************************
487
488 static void disk_sync_callout( thread_call_param_t p0, thread_call_param_t p1 )
489 {
490 IOService *rootDomain = (IOService *) p0;
491 unsigned long pmRef = (unsigned long) p1;
492
493 DLOG("disk_sync_callout start\n");
494
495 #if HIBERNATION
496 IOHibernateSystemSleep();
497 #endif
498 sync_internal();
499 rootDomain->allowPowerChange(pmRef);
500 DLOG("disk_sync_callout finish\n");
501 }
502
503 //******************************************************************************
504
505 static UInt32 computeDeltaTimeMS( const AbsoluteTime * startTime )
506 {
507 AbsoluteTime endTime;
508 UInt64 nano = 0;
509
510 clock_get_uptime(&endTime);
511 if (CMP_ABSOLUTETIME(&endTime, startTime) > 0)
512 {
513 SUB_ABSOLUTETIME(&endTime, startTime);
514 absolutetime_to_nanoseconds(endTime, &nano);
515 }
516
517 return (UInt32)(nano / 1000000ULL);
518 }
519
520 //******************************************************************************
521
522 static int
523 sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
524 {
525 struct timeval *swt = (struct timeval *)arg1;
526 struct proc *p = req->p;
527
528 if (p == kernproc) {
529 return sysctl_io_opaque(req, swt, sizeof(*swt), NULL);
530 } else if(proc_is64bit(p)) {
531 struct user64_timeval t;
532 t.tv_sec = swt->tv_sec;
533 t.tv_usec = swt->tv_usec;
534 return sysctl_io_opaque(req, &t, sizeof(t), NULL);
535 } else {
536 struct user32_timeval t;
537 t.tv_sec = swt->tv_sec;
538 t.tv_usec = swt->tv_usec;
539 return sysctl_io_opaque(req, &t, sizeof(t), NULL);
540 }
541 }
542
543 static SYSCTL_PROC(_kern, OID_AUTO, sleeptime,
544 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN,
545 &gIOLastSleepTime, 0, sysctl_sleepwaketime, "S,timeval", "");
546
547 static SYSCTL_PROC(_kern, OID_AUTO, waketime,
548 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN,
549 &gIOLastWakeTime, 0, sysctl_sleepwaketime, "S,timeval", "");
550
551
552 static int
553 sysctl_willshutdown
554 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
555 {
556 int new_value, changed;
557 int error = sysctl_io_number(req, gWillShutdown, sizeof(int), &new_value, &changed);
558 if (changed) {
559 if (!gWillShutdown && (new_value == 1)) {
560 IOSystemShutdownNotification();
561 } else
562 error = EINVAL;
563 }
564 return(error);
565 }
566
567 static SYSCTL_PROC(_kern, OID_AUTO, willshutdown,
568 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN,
569 0, 0, sysctl_willshutdown, "I", "");
570
571 #if !CONFIG_EMBEDDED
572
573 static int
574 sysctl_progressmeterenable
575 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
576 {
577 int error;
578 int new_value, changed;
579
580 error = sysctl_io_number(req, vc_progress_meter_enable, sizeof(int), &new_value, &changed);
581
582 if (changed)
583 vc_enable_progressmeter(new_value);
584
585 return (error);
586 }
587
588 static int
589 sysctl_progressmeter
590 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
591 {
592 int error;
593 int new_value, changed;
594
595 error = sysctl_io_number(req, vc_progress_meter_value, sizeof(int), &new_value, &changed);
596
597 if (changed)
598 vc_set_progressmeter(new_value);
599
600 return (error);
601 }
602
603 static SYSCTL_PROC(_kern, OID_AUTO, progressmeterenable,
604 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN,
605 0, 0, sysctl_progressmeterenable, "I", "");
606
607 static SYSCTL_PROC(_kern, OID_AUTO, progressmeter,
608 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN,
609 0, 0, sysctl_progressmeter, "I", "");
610
611 #endif
612
613 static const OSSymbol * gIOPMSettingAutoWakeSecondsKey;
614 static const OSSymbol * gIOPMSettingMaintenanceWakeCalendarKey;
615
616 //******************************************************************************
617 // start
618 //
619 //******************************************************************************
620
621 #define kRootDomainSettingsCount 16
622
623 bool IOPMrootDomain::start( IOService * nub )
624 {
625 OSIterator *psIterator;
626 OSDictionary *tmpDict;
627
628 super::start(nub);
629
630 gRootDomain = this;
631 gIOPMSettingAutoWakeSecondsKey = OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey);
632 gIOPMSettingMaintenanceWakeCalendarKey =
633 OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey);
634
635 gIOPMStatsApplicationResponseTimedOut = OSSymbol::withCString(kIOPMStatsResponseTimedOut);
636 gIOPMStatsApplicationResponseCancel = OSSymbol::withCString(kIOPMStatsResponseCancel);
637 gIOPMStatsApplicationResponseSlow = OSSymbol::withCString(kIOPMStatsResponseSlow);
638
639 sleepSupportedPEFunction = OSSymbol::withCString("IOPMSetSleepSupported");
640
641 const OSSymbol *settingsArr[kRootDomainSettingsCount] =
642 {
643 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey),
644 gIOPMSettingAutoWakeSecondsKey,
645 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey),
646 OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey),
647 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey),
648 OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey),
649 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey),
650 OSSymbol::withCString(kIOPMSettingWakeOnRingKey),
651 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey),
652 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey),
653 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey),
654 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey),
655 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey),
656 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey),
657 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey),
658 OSSymbol::withCString(kIOPMStateConsoleShutdown)
659 };
660
661 queue_init(&aggressivesQueue);
662 aggressivesThreadCall = thread_call_allocate(handleAggressivesFunction, this);
663 aggressivesData = OSData::withCapacity(
664 sizeof(AggressivesRecord) * (kPMLastAggressivenessType + 4));
665
666 featuresDictLock = IOLockAlloc();
667 settingsCtrlLock = IORecursiveLockAlloc();
668 setPMRootDomain(this);
669
670 extraSleepTimer = thread_call_allocate(
671 idleSleepTimerExpired,
672 (thread_call_param_t) this);
673
674 clamshellWakeupIgnore = thread_call_allocate(
675 wakeupClamshellTimerExpired,
676 (thread_call_param_t) this);
677
678 diskSyncCalloutEntry = thread_call_allocate(
679 &disk_sync_callout,
680 (thread_call_param_t) this);
681
682 canSleep = true;
683 setProperty(kIOSleepSupportedKey, true);
684
685 bzero(&pmStats, sizeof(pmStats));
686
687 pmTracer = PMTraceWorker::tracer(this);
688
689 updateRunState(kRStateNormal);
690 userDisabledAllSleep = false;
691 allowSleep = true;
692 sleepIsSupported = true;
693 systemBooting = true;
694 sleepSlider = 0;
695 idleSleepTimerPending = false;
696 wrangler = NULL;
697 sleepASAP = false;
698 clamshellIsClosed = false;
699 clamshellExists = false;
700 ignoringClamshell = true;
701 ignoringClamshellOnWake = false;
702 acAdaptorConnected = true;
703
704 queuedSleepWakeUUIDString = NULL;
705 pmStatsAppResponses = OSArray::withCapacity(5);
706 _statsNameKey = OSSymbol::withCString(kIOPMStatsNameKey);
707 _statsPIDKey = OSSymbol::withCString(kIOPMStatsPIDKey);
708 _statsTimeMSKey = OSSymbol::withCString(kIOPMStatsTimeMSKey);
709 _statsResponseTypeKey = OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey);
710 _statsMessageTypeKey = OSSymbol::withCString(kIOPMStatsMessageTypeKey);
711
712 idxPMCPUClamshell = kCPUUnknownIndex;
713 idxPMCPULimitedPower = kCPUUnknownIndex;
714
715 tmpDict = OSDictionary::withCapacity(1);
716 setProperty(kRootDomainSupportedFeatures, tmpDict);
717 tmpDict->release();
718
719 settingsCallbacks = OSDictionary::withCapacity(1);
720
721 // Create a list of the valid PM settings that we'll relay to
722 // interested clients in setProperties() => setPMSetting()
723 allowedPMSettings = OSArray::withObjects(
724 (const OSObject **)settingsArr,
725 kRootDomainSettingsCount,
726 0);
727
728 fPMSettingsDict = OSDictionary::withCapacity(5);
729
730 PMinit(); // creates gIOPMWorkLoop
731
732 // Create IOPMPowerStateQueue used to queue external power
733 // events, and to handle those events on the PM work loop.
734 pmPowerStateQueue = IOPMPowerStateQueue::PMPowerStateQueue(
735 this, OSMemberFunctionCast(IOEventSource::Action, this,
736 &IOPMrootDomain::dispatchPowerEvent));
737 getPMworkloop()->addEventSource(pmPowerStateQueue);
738 #ifdef CHECK_THREAD_CONTEXT
739 gIOPMWorkLoop = getPMworkloop();
740 #endif
741
742 // create our power parent
743 patriarch = new IORootParent;
744 patriarch->init();
745 patriarch->attach(this);
746 patriarch->start(this);
747 patriarch->addPowerChild(this);
748
749 registerPowerDriver(this, ourPowerStates, NUM_POWER_STATES);
750
751 // set a clamp until we sleep
752 changePowerStateToPriv(ON_STATE);
753
754 // install power change handler
755 gSysPowerDownNotifier = registerPrioritySleepWakeInterest( &sysPowerDownHandler, this, 0);
756
757 #if !NO_KERNEL_HID
758 // Register for a notification when IODisplayWrangler is published
759 if ((tmpDict = serviceMatching("IODisplayWrangler")))
760 {
761 _displayWranglerNotifier = addMatchingNotification(
762 gIOPublishNotification, tmpDict,
763 (IOServiceMatchingNotificationHandler) &displayWranglerPublished,
764 this, 0);
765 tmpDict->release();
766 }
767 #endif
768
769 // Battery location published - ApplePMU support only
770 if ((tmpDict = serviceMatching("IOPMPowerSource")))
771 {
772 _batteryPublishNotifier = addMatchingNotification(
773 gIOPublishNotification, tmpDict,
774 (IOServiceMatchingNotificationHandler) &batteryPublished,
775 this, this);
776 tmpDict->release();
777 }
778
779 const OSSymbol *ucClassName = OSSymbol::withCStringNoCopy("RootDomainUserClient");
780 setProperty(gIOUserClientClassKey, (OSObject *) ucClassName);
781 ucClassName->release();
782
783 // IOBacklightDisplay can take a long time to load at boot, or it may
784 // not load at all if you're booting with clamshell closed. We publish
785 // 'DisplayDims' here redundantly to get it published early and at all.
786 psIterator = getMatchingServices( serviceMatching("IOPMPowerSource") );
787 if( psIterator && psIterator->getNextObject() )
788 {
789 // There's at least one battery on the system, so we publish
790 // 'DisplayDims' support for the LCD.
791 publishFeature("DisplayDims");
792 }
793 if(psIterator) {
794 psIterator->release();
795 }
796
797 sysctl_register_oid(&sysctl__kern_sleeptime);
798 sysctl_register_oid(&sysctl__kern_waketime);
799 sysctl_register_oid(&sysctl__kern_willshutdown);
800 #if !CONFIG_EMBEDDED
801 sysctl_register_oid(&sysctl__kern_progressmeterenable);
802 sysctl_register_oid(&sysctl__kern_progressmeter);
803 #endif /* !CONFIG_EMBEDDED */
804
805 #if HIBERNATION
806 IOHibernateSystemInit(this);
807 #endif
808
809 registerService(); // let clients find us
810
811 return true;
812 }
813
814
815 //******************************************************************************
816 // setProperties
817 //
818 // Receive a setProperty call
819 // The "System Boot" property means the system is completely booted.
820 //******************************************************************************
821
822 IOReturn IOPMrootDomain::setProperties( OSObject * props_obj )
823 {
824 IOReturn return_value = kIOReturnSuccess;
825 OSDictionary *dict = OSDynamicCast(OSDictionary, props_obj);
826 OSBoolean *b;
827 OSNumber *n;
828 OSString *str;
829 OSSymbol *type;
830 OSObject *obj;
831 unsigned int i;
832
833 const OSSymbol *boot_complete_string =
834 OSSymbol::withCString("System Boot Complete");
835 const OSSymbol *sys_shutdown_string =
836 OSSymbol::withCString("System Shutdown");
837 const OSSymbol *stall_halt_string =
838 OSSymbol::withCString("StallSystemAtHalt");
839 const OSSymbol *battery_warning_disabled_string =
840 OSSymbol::withCString("BatteryWarningsDisabled");
841 const OSSymbol *idle_seconds_string =
842 OSSymbol::withCString("System Idle Seconds");
843 #if HIBERNATION
844 const OSSymbol *hibernatemode_string =
845 OSSymbol::withCString(kIOHibernateModeKey);
846 const OSSymbol *hibernatefile_string =
847 OSSymbol::withCString(kIOHibernateFileKey);
848 const OSSymbol *hibernatefreeratio_string =
849 OSSymbol::withCString(kIOHibernateFreeRatioKey);
850 const OSSymbol *hibernatefreetime_string =
851 OSSymbol::withCString(kIOHibernateFreeTimeKey);
852 #endif
853 const OSSymbol *sleepdisabled_string =
854 OSSymbol::withCString("SleepDisabled");
855 const OSSymbol *ondeck_sleepwake_uuid_string =
856 OSSymbol::withCString(kIOPMSleepWakeUUIDKey);
857 const OSSymbol *loginwindow_tracepoint_string =
858 OSSymbol::withCString(kIOPMLoginWindowSecurityDebugKey);
859
860 if(!dict)
861 {
862 return_value = kIOReturnBadArgument;
863 goto exit;
864 }
865
866 if ((n = OSDynamicCast(OSNumber, dict->getObject(idle_seconds_string))))
867 {
868 setProperty(idle_seconds_string, n);
869 idleSeconds = n->unsigned32BitValue();
870 }
871
872 if (boot_complete_string && dict->getObject(boot_complete_string))
873 {
874 pmPowerStateQueue->submitPowerEvent( kPowerEventSystemBootCompleted );
875 }
876
877 if( battery_warning_disabled_string
878 && dict->getObject(battery_warning_disabled_string))
879 {
880 setProperty( battery_warning_disabled_string,
881 dict->getObject(battery_warning_disabled_string));
882 }
883
884 if( sys_shutdown_string
885 && (b = OSDynamicCast(OSBoolean, dict->getObject(sys_shutdown_string))))
886 {
887 pmPowerStateQueue->submitPowerEvent(kPowerEventSystemShutdown, (void *) b);
888 }
889
890 if( stall_halt_string
891 && (b = OSDynamicCast(OSBoolean, dict->getObject(stall_halt_string))) )
892 {
893 setProperty(stall_halt_string, b);
894 }
895
896 #if HIBERNATION
897 if ( hibernatemode_string
898 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatemode_string))))
899 {
900 setProperty(hibernatemode_string, n);
901 }
902 if ( hibernatefreeratio_string
903 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatefreeratio_string))))
904 {
905 setProperty(hibernatefreeratio_string, n);
906 }
907 if ( hibernatefreetime_string
908 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatefreetime_string))))
909 {
910 setProperty(hibernatefreetime_string, n);
911 }
912 if ( hibernatefile_string
913 && (str = OSDynamicCast(OSString, dict->getObject(hibernatefile_string))))
914 {
915 setProperty(hibernatefile_string, str);
916 }
917 #endif
918
919 if( sleepdisabled_string
920 && (b = OSDynamicCast(OSBoolean, dict->getObject(sleepdisabled_string))) )
921 {
922 setProperty(sleepdisabled_string, b);
923 pmPowerStateQueue->submitPowerEvent(kPowerEventUserDisabledSleep, (void *) b);
924 }
925
926 if (ondeck_sleepwake_uuid_string
927 && (obj = dict->getObject(ondeck_sleepwake_uuid_string)))
928 {
929 // Clear the currently published UUID
930 if (kOSBooleanFalse == obj)
931 {
932 publishSleepWakeUUID(NULL);
933 }
934
935 // Cache UUID for an upcoming sleep/wake
936 if ((str = OSDynamicCast(OSString, obj)))
937 {
938 if (queuedSleepWakeUUIDString) {
939 queuedSleepWakeUUIDString->release();
940 queuedSleepWakeUUIDString = NULL;
941 }
942 queuedSleepWakeUUIDString = str;
943 queuedSleepWakeUUIDString->retain();
944 DLOG("SleepWake UUID queued: %s\n",
945 queuedSleepWakeUUIDString->getCStringNoCopy());
946 }
947 }
948
949 if (loginwindow_tracepoint_string
950 && (n = OSDynamicCast(OSNumber, dict->getObject(loginwindow_tracepoint_string)))
951 && pmTracer)
952 {
953 pmTracer->traceLoginWindowPhase( n->unsigned8BitValue() );
954 }
955
956 // Relay our allowed PM settings onto our registered PM clients
957 for(i = 0; i < allowedPMSettings->getCount(); i++) {
958
959 type = (OSSymbol *)allowedPMSettings->getObject(i);
960 if(!type) continue;
961
962 obj = dict->getObject(type);
963 if(!obj) continue;
964
965 if ((gIOPMSettingAutoWakeSecondsKey == type) && ((n = OSDynamicCast(OSNumber, obj))))
966 {
967 UInt32 rsecs = n->unsigned32BitValue();
968 if (!rsecs)
969 autoWakeStart = autoWakeEnd = 0;
970 else
971 {
972 AbsoluteTime deadline;
973 clock_interval_to_deadline(rsecs + kAutoWakePostWindow, kSecondScale, &deadline);
974 autoWakeEnd = AbsoluteTime_to_scalar(&deadline);
975 if (rsecs > kAutoWakePreWindow)
976 rsecs -= kAutoWakePreWindow;
977 else
978 rsecs = 0;
979 clock_interval_to_deadline(rsecs, kSecondScale, &deadline);
980 autoWakeStart = AbsoluteTime_to_scalar(&deadline);
981 }
982 }
983
984 return_value = setPMSetting(type, obj);
985
986 if(kIOReturnSuccess != return_value) goto exit;
987 }
988
989 exit:
990 if(boot_complete_string) boot_complete_string->release();
991 if(sys_shutdown_string) sys_shutdown_string->release();
992 if(stall_halt_string) stall_halt_string->release();
993 if (battery_warning_disabled_string) battery_warning_disabled_string->release();
994 if(idle_seconds_string) idle_seconds_string->release();
995 if(sleepdisabled_string) sleepdisabled_string->release();
996 if(ondeck_sleepwake_uuid_string) ondeck_sleepwake_uuid_string->release();
997 #if HIBERNATION
998 if(hibernatemode_string) hibernatemode_string->release();
999 if(hibernatefile_string) hibernatefile_string->release();
1000 if(hibernatefreeratio_string) hibernatefreeratio_string->release();
1001 if(hibernatefreetime_string) hibernatefreetime_string->release();
1002 #endif
1003 return return_value;
1004 }
1005
1006
1007 //******************************************************************************
1008 // aggressivenessChanged
1009 //
1010 // We are behind the command gate to examine changes to aggressives.
1011 //******************************************************************************
1012
1013 void IOPMrootDomain::aggressivenessChanged( void )
1014 {
1015 unsigned long minutesToSleep = 0;
1016 unsigned long minutesToDisplayDim = 0;
1017
1018 ASSERT_GATED();
1019
1020 // Fetch latest display and system sleep slider values.
1021 getAggressiveness(kPMMinutesToSleep, &minutesToSleep);
1022 getAggressiveness(kPMMinutesToDim, &minutesToDisplayDim);
1023 DLOG("aggressiveness changed system %u, display %u\n",
1024 (uint32_t) minutesToSleep, (uint32_t) minutesToDisplayDim);
1025
1026 DLOG("idle time -> %ld secs (ena %d)\n",
1027 idleSeconds, (minutesToSleep != 0));
1028
1029 if (0x7fffffff == minutesToSleep)
1030 minutesToSleep = idleSeconds;
1031
1032 // How long to wait before sleeping the system once the displays turns
1033 // off is indicated by 'extraSleepDelay'.
1034
1035 if ( minutesToSleep > minutesToDisplayDim ) {
1036 extraSleepDelay = minutesToSleep - minutesToDisplayDim;
1037 }
1038 else {
1039 extraSleepDelay = 0;
1040 }
1041
1042 // system sleep timer was disabled, but not anymore.
1043 if ( (sleepSlider == 0) && (minutesToSleep != 0) ) {
1044 if (!wrangler)
1045 {
1046 sleepASAP = false;
1047 changePowerStateToPriv(ON_STATE);
1048 if (idleSeconds)
1049 {
1050 startIdleSleepTimer( idleSeconds );
1051 }
1052 }
1053 else
1054 {
1055 // Start idle sleep timer if wrangler went to sleep
1056 // while system sleep was disabled.
1057
1058 sleepASAP = false;
1059 if (wranglerAsleep)
1060 {
1061 AbsoluteTime now;
1062 uint64_t nanos;
1063 uint32_t minutesSinceDisplaySleep = 0;
1064 uint32_t sleepDelay;
1065
1066 clock_get_uptime(&now);
1067 if (CMP_ABSOLUTETIME(&now, &wranglerSleepTime) > 0)
1068 {
1069 SUB_ABSOLUTETIME(&now, &wranglerSleepTime);
1070 absolutetime_to_nanoseconds(now, &nanos);
1071 minutesSinceDisplaySleep = nanos / (60000000000ULL);
1072 }
1073
1074 if (extraSleepDelay > minutesSinceDisplaySleep)
1075 {
1076 sleepDelay = extraSleepDelay - minutesSinceDisplaySleep;
1077 }
1078 else
1079 {
1080 // 1 min idle sleep.
1081 sleepDelay = 1;
1082 }
1083
1084 startIdleSleepTimer(sleepDelay * 60);
1085 DLOG("display slept %u min, set idle timer to %u min\n",
1086 minutesSinceDisplaySleep, sleepDelay);
1087 }
1088 }
1089 }
1090
1091 sleepSlider = minutesToSleep;
1092 if ( sleepSlider == 0 ) {
1093 cancelIdleSleepTimer();
1094 // idle sleep is now disabled
1095 adjustPowerState();
1096 // make sure we're powered
1097 patriarch->wakeSystem();
1098 }
1099 }
1100
1101
1102 //******************************************************************************
1103 // setAggressiveness
1104 //
1105 // Override IOService::setAggressiveness()
1106 //******************************************************************************
1107
1108 IOReturn IOPMrootDomain::setAggressiveness(
1109 unsigned long type,
1110 unsigned long value )
1111 {
1112 return setAggressiveness( type, value, 0 );
1113 }
1114
1115 /*
1116 * Private setAggressiveness() with an internal options argument.
1117 */
1118 IOReturn IOPMrootDomain::setAggressiveness(
1119 unsigned long type,
1120 unsigned long value,
1121 IOOptionBits options )
1122 {
1123 AggressivesRequest * entry;
1124 AggressivesRequest * request;
1125 bool found = false;
1126
1127 DLOG("setAggressiveness 0x%x = %u, options 0x%x\n",
1128 (uint32_t) type, (uint32_t) value, (uint32_t) options);
1129
1130 request = IONew(AggressivesRequest, 1);
1131 if (!request)
1132 return kIOReturnNoMemory;
1133
1134 memset(request, 0, sizeof(*request));
1135 request->options = options;
1136 request->dataType = kAggressivesRequestTypeRecord;
1137 request->data.record.type = (uint32_t) type;
1138 request->data.record.value = (uint32_t) value;
1139
1140 AGGRESSIVES_LOCK();
1141
1142 // Update disk quick spindown flag used by getAggressiveness().
1143 // Never merge requests with quick spindown flags set.
1144
1145 if (options & kAggressivesOptionQuickSpindownEnable)
1146 gAggressivesState |= kAggressivesStateQuickSpindown;
1147 else if (options & kAggressivesOptionQuickSpindownDisable)
1148 gAggressivesState &= ~kAggressivesStateQuickSpindown;
1149 else
1150 {
1151 // Coalesce requests with identical aggressives types.
1152 // Deal with callers that calls us too "aggressively".
1153
1154 queue_iterate(&aggressivesQueue, entry, AggressivesRequest *, chain)
1155 {
1156 if ((entry->dataType == kAggressivesRequestTypeRecord) &&
1157 (entry->data.record.type == type) &&
1158 ((entry->options & kAggressivesOptionQuickSpindownMask) == 0))
1159 {
1160 entry->data.record.value = value;
1161 found = true;
1162 break;
1163 }
1164 }
1165 }
1166
1167 if (!found)
1168 {
1169 queue_enter(&aggressivesQueue, request, AggressivesRequest *, chain);
1170 }
1171
1172 AGGRESSIVES_UNLOCK();
1173
1174 if (found)
1175 IODelete(request, AggressivesRequest, 1);
1176
1177 if (options & kAggressivesOptionSynchronous)
1178 handleAggressivesRequests(); // not truly synchronous
1179 else
1180 thread_call_enter(aggressivesThreadCall);
1181
1182 return kIOReturnSuccess;
1183 }
1184
1185
1186 //******************************************************************************
1187 // getAggressiveness
1188 //
1189 // Override IOService::setAggressiveness()
1190 // Fetch the aggressiveness factor with the given type.
1191 //******************************************************************************
1192
1193 IOReturn IOPMrootDomain::getAggressiveness (
1194 unsigned long type,
1195 unsigned long * outLevel )
1196 {
1197 uint32_t value = 0;
1198 int source = 0;
1199
1200 if (!outLevel)
1201 return kIOReturnBadArgument;
1202
1203 AGGRESSIVES_LOCK();
1204
1205 // Disk quick spindown in effect, report value = 1
1206
1207 if ((gAggressivesState & kAggressivesStateQuickSpindown) &&
1208 (type == kPMMinutesToSpinDown))
1209 {
1210 value = kAggressivesMinValue;
1211 source = 1;
1212 }
1213
1214 // Consult the pending request queue.
1215
1216 if (!source)
1217 {
1218 AggressivesRequest * entry;
1219
1220 queue_iterate(&aggressivesQueue, entry, AggressivesRequest *, chain)
1221 {
1222 if ((entry->dataType == kAggressivesRequestTypeRecord) &&
1223 (entry->data.record.type == type) &&
1224 ((entry->options & kAggressivesOptionQuickSpindownMask) == 0))
1225 {
1226 value = entry->data.record.value;
1227 source = 2;
1228 break;
1229 }
1230 }
1231 }
1232
1233 // Consult the backend records.
1234
1235 if (!source && aggressivesData)
1236 {
1237 AggressivesRecord * record;
1238 int i, count;
1239
1240 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
1241 record = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
1242
1243 for (i = 0; i < count; i++, record++)
1244 {
1245 if (record->type == type)
1246 {
1247 value = record->value;
1248 source = 3;
1249 break;
1250 }
1251 }
1252 }
1253
1254 AGGRESSIVES_UNLOCK();
1255
1256 if (source)
1257 {
1258 DLOG("getAggressiveness 0x%x = %u, source %d\n",
1259 (uint32_t) type, value, source);
1260 *outLevel = (unsigned long) value;
1261 return kIOReturnSuccess;
1262 }
1263 else
1264 {
1265 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type);
1266 *outLevel = 0; // default return = 0, driver may not check for error
1267 return kIOReturnInvalid;
1268 }
1269 }
1270
1271
1272 //******************************************************************************
1273 // joinAggressiveness
1274 //
1275 // Request from IOService to join future aggressiveness broadcasts.
1276 //******************************************************************************
1277
1278 IOReturn IOPMrootDomain::joinAggressiveness(
1279 IOService * service )
1280 {
1281 AggressivesRequest * request;
1282
1283 if (!service || (service == this))
1284 return kIOReturnBadArgument;
1285
1286 DLOG("joinAggressiveness %s (%p)\n", service->getName(), service);
1287
1288 request = IONew(AggressivesRequest, 1);
1289 if (!request)
1290 return kIOReturnNoMemory;
1291
1292 service->retain(); // released by synchronizeAggressives()
1293
1294 memset(request, 0, sizeof(*request));
1295 request->dataType = kAggressivesRequestTypeService;
1296 request->data.service = service;
1297
1298 AGGRESSIVES_LOCK();
1299 queue_enter(&aggressivesQueue, request, AggressivesRequest *, chain);
1300 AGGRESSIVES_UNLOCK();
1301
1302 thread_call_enter(aggressivesThreadCall);
1303
1304 return kIOReturnSuccess;
1305 }
1306
1307
1308 //******************************************************************************
1309 // handleAggressivesRequests
1310 //
1311 // Backend thread processes all incoming aggressiveness requests in the queue.
1312 //******************************************************************************
1313
1314 static void
1315 handleAggressivesFunction(
1316 thread_call_param_t param1,
1317 thread_call_param_t param2 )
1318 {
1319 if (param1)
1320 {
1321 ((IOPMrootDomain *) param1)->handleAggressivesRequests();
1322 }
1323 }
1324
1325 void IOPMrootDomain::handleAggressivesRequests( void )
1326 {
1327 AggressivesRecord * start;
1328 AggressivesRecord * record;
1329 AggressivesRequest * request;
1330 queue_head_t joinedQueue;
1331 int i, count;
1332 bool broadcast;
1333 bool found;
1334 bool pingSelf = false;
1335
1336 AGGRESSIVES_LOCK();
1337
1338 if ((gAggressivesState & kAggressivesStateBusy) || !aggressivesData ||
1339 queue_empty(&aggressivesQueue))
1340 goto unlock_done;
1341
1342 gAggressivesState |= kAggressivesStateBusy;
1343 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
1344 start = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
1345
1346 do
1347 {
1348 broadcast = false;
1349 queue_init(&joinedQueue);
1350
1351 do
1352 {
1353 // Remove request from the incoming queue in FIFO order.
1354 queue_remove_first(&aggressivesQueue, request, AggressivesRequest *, chain);
1355 switch (request->dataType)
1356 {
1357 case kAggressivesRequestTypeRecord:
1358 // Update existing record if found.
1359 found = false;
1360 for (i = 0, record = start; i < count; i++, record++)
1361 {
1362 if (record->type == request->data.record.type)
1363 {
1364 found = true;
1365
1366 if (request->options & kAggressivesOptionQuickSpindownEnable)
1367 {
1368 if ((record->flags & kAggressivesRecordFlagMinValue) == 0)
1369 {
1370 broadcast = true;
1371 record->flags |= (kAggressivesRecordFlagMinValue |
1372 kAggressivesRecordFlagModified);
1373 DLOG("quick spindown accelerated, was %u min\n",
1374 record->value);
1375 }
1376 }
1377 else if (request->options & kAggressivesOptionQuickSpindownDisable)
1378 {
1379 if (record->flags & kAggressivesRecordFlagMinValue)
1380 {
1381 broadcast = true;
1382 record->flags |= kAggressivesRecordFlagModified;
1383 record->flags &= ~kAggressivesRecordFlagMinValue;
1384 DLOG("disk spindown restored to %u min\n",
1385 record->value);
1386 }
1387 }
1388 else if (record->value != request->data.record.value)
1389 {
1390 record->value = request->data.record.value;
1391 if ((record->flags & kAggressivesRecordFlagMinValue) == 0)
1392 {
1393 broadcast = true;
1394 record->flags |= kAggressivesRecordFlagModified;
1395 }
1396 }
1397 break;
1398 }
1399 }
1400
1401 // No matching record, append a new record.
1402 if (!found &&
1403 ((request->options & kAggressivesOptionQuickSpindownDisable) == 0))
1404 {
1405 AggressivesRecord newRecord;
1406
1407 newRecord.flags = kAggressivesRecordFlagModified;
1408 newRecord.type = request->data.record.type;
1409 newRecord.value = request->data.record.value;
1410 if (request->options & kAggressivesOptionQuickSpindownEnable)
1411 {
1412 newRecord.flags |= kAggressivesRecordFlagMinValue;
1413 DLOG("disk spindown accelerated\n");
1414 }
1415
1416 aggressivesData->appendBytes(&newRecord, sizeof(newRecord));
1417
1418 // OSData may have switched to another (larger) buffer.
1419 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
1420 start = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
1421 broadcast = true;
1422 }
1423
1424 // Finished processing the request, release it.
1425 IODelete(request, AggressivesRequest, 1);
1426 break;
1427
1428 case kAggressivesRequestTypeService:
1429 // synchronizeAggressives() will free request.
1430 queue_enter(&joinedQueue, request, AggressivesRequest *, chain);
1431 break;
1432
1433 default:
1434 panic("bad aggressives request type %x\n", request->dataType);
1435 break;
1436 }
1437 } while (!queue_empty(&aggressivesQueue));
1438
1439 // Release the lock to perform work, with busy flag set.
1440 if (!queue_empty(&joinedQueue) || broadcast)
1441 {
1442 AGGRESSIVES_UNLOCK();
1443 if (!queue_empty(&joinedQueue))
1444 synchronizeAggressives(&joinedQueue, start, count);
1445 if (broadcast)
1446 broadcastAggressives(start, count);
1447 AGGRESSIVES_LOCK();
1448 }
1449
1450 // Remove the modified flag from all records.
1451 for (i = 0, record = start; i < count; i++, record++)
1452 {
1453 if ((record->flags & kAggressivesRecordFlagModified) &&
1454 ((record->type == kPMMinutesToDim) ||
1455 (record->type == kPMMinutesToSleep)))
1456 pingSelf = true;
1457
1458 record->flags &= ~kAggressivesRecordFlagModified;
1459 }
1460
1461 // Check the incoming queue again since new entries may have been
1462 // added while lock was released above.
1463
1464 } while (!queue_empty(&aggressivesQueue));
1465
1466 gAggressivesState &= ~kAggressivesStateBusy;
1467
1468 unlock_done:
1469 AGGRESSIVES_UNLOCK();
1470
1471 // Root domain is interested in system and display sleep slider changes.
1472 // Submit a power event to handle those changes on the PM work loop.
1473
1474 if (pingSelf && pmPowerStateQueue) {
1475 pmPowerStateQueue->submitPowerEvent( kPowerEventAggressivenessChanged );
1476 }
1477 }
1478
1479
1480 //******************************************************************************
1481 // synchronizeAggressives
1482 //
1483 // Push all known aggressiveness records to one or more IOService.
1484 //******************************************************************************
1485
1486 void IOPMrootDomain::synchronizeAggressives(
1487 queue_head_t * joinedQueue,
1488 const AggressivesRecord * array,
1489 int count )
1490 {
1491 IOService * service;
1492 AggressivesRequest * request;
1493 const AggressivesRecord * record;
1494 uint32_t value;
1495 int i;
1496
1497 while (!queue_empty(joinedQueue))
1498 {
1499 queue_remove_first(joinedQueue, request, AggressivesRequest *, chain);
1500 if (request->dataType == kAggressivesRequestTypeService)
1501 service = request->data.service;
1502 else
1503 service = 0;
1504
1505 IODelete(request, AggressivesRequest, 1);
1506 request = 0;
1507
1508 if (service)
1509 {
1510 if (service->assertPMThreadCall())
1511 {
1512 for (i = 0, record = array; i < count; i++, record++)
1513 {
1514 value = record->value;
1515 if (record->flags & kAggressivesRecordFlagMinValue)
1516 value = kAggressivesMinValue;
1517
1518 DLOG("synchronizeAggressives 0x%x = %u to %s\n",
1519 record->type, value, service->getName());
1520 service->setAggressiveness(record->type, value);
1521 }
1522 service->deassertPMThreadCall();
1523 }
1524 service->release(); // retained by joinAggressiveness()
1525 }
1526 }
1527 }
1528
1529
1530 //******************************************************************************
1531 // broadcastAggressives
1532 //
1533 // Traverse PM tree and call setAggressiveness() for records that have changed.
1534 //******************************************************************************
1535
1536 void IOPMrootDomain::broadcastAggressives(
1537 const AggressivesRecord * array,
1538 int count )
1539 {
1540 IORegistryIterator * iter;
1541 IORegistryEntry * entry;
1542 IOPowerConnection * connect;
1543 IOService * service;
1544 const AggressivesRecord * record;
1545 uint32_t value;
1546 int i;
1547
1548 iter = IORegistryIterator::iterateOver(
1549 this, gIOPowerPlane, kIORegistryIterateRecursively);
1550 if (iter)
1551 {
1552 do
1553 {
1554 iter->reset();
1555 while ((entry = iter->getNextObject()))
1556 {
1557 connect = OSDynamicCast(IOPowerConnection, entry);
1558 if (!connect || !connect->getReadyFlag())
1559 continue;
1560
1561 if ((service = (IOService *) connect->copyChildEntry(gIOPowerPlane)))
1562 {
1563 if (service->assertPMThreadCall())
1564 {
1565 for (i = 0, record = array; i < count; i++, record++)
1566 {
1567 if (record->flags & kAggressivesRecordFlagModified)
1568 {
1569 value = record->value;
1570 if (record->flags & kAggressivesRecordFlagMinValue)
1571 value = kAggressivesMinValue;
1572 DLOG("broadcastAggressives %x = %u to %s\n",
1573 record->type, value, service->getName());
1574 service->setAggressiveness(record->type, value);
1575 }
1576 }
1577 service->deassertPMThreadCall();
1578 }
1579 service->release();
1580 }
1581 }
1582 }
1583 while (!entry && !iter->isValid());
1584 iter->release();
1585 }
1586 }
1587
1588
1589 //******************************************************************************
1590 // startIdleSleepTimer
1591 //
1592 //******************************************************************************
1593
1594 void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds )
1595 {
1596 AbsoluteTime deadline;
1597
1598 ASSERT_GATED();
1599 if (inSeconds)
1600 {
1601 clock_interval_to_deadline(inSeconds, kSecondScale, &deadline);
1602 thread_call_enter_delayed(extraSleepTimer, deadline);
1603 idleSleepTimerPending = true;
1604 DLOG("idle timer set for %u seconds\n", inSeconds);
1605 }
1606 }
1607
1608
1609 //******************************************************************************
1610 // cancelIdleSleepTimer
1611 //
1612 //******************************************************************************
1613
1614 void IOPMrootDomain::cancelIdleSleepTimer( void )
1615 {
1616 ASSERT_GATED();
1617 if (idleSleepTimerPending)
1618 {
1619 DLOG("idle timer cancelled\n");
1620 thread_call_cancel(extraSleepTimer);
1621 idleSleepTimerPending = false;
1622 }
1623 }
1624
1625
1626 //******************************************************************************
1627 // idleSleepTimerExpired
1628 //
1629 //******************************************************************************
1630
1631 static void idleSleepTimerExpired(
1632 thread_call_param_t us, thread_call_param_t )
1633 {
1634 ((IOPMrootDomain *)us)->handleSleepTimerExpiration();
1635 }
1636
1637 static void wakeupClamshellTimerExpired(
1638 thread_call_param_t us, thread_call_param_t )
1639 {
1640 ((IOPMrootDomain *)us)->stopIgnoringClamshellEventsDuringWakeup();
1641 }
1642
1643
1644 //******************************************************************************
1645 // handleSleepTimerExpiration
1646 //
1647 // The time between the sleep idle timeout and the next longest one has elapsed.
1648 // It's time to sleep. Start that by removing the clamp that's holding us awake.
1649 //******************************************************************************
1650
1651 void IOPMrootDomain::handleSleepTimerExpiration( void )
1652 {
1653 if (!getPMworkloop()->inGate())
1654 {
1655 getPMworkloop()->runAction(
1656 OSMemberFunctionCast(IOWorkLoop::Action, this,
1657 &IOPMrootDomain::handleSleepTimerExpiration),
1658 this);
1659 return;
1660 }
1661
1662 AbsoluteTime time;
1663
1664 DLOG("sleep timer expired\n");
1665 ASSERT_GATED();
1666
1667 idleSleepTimerPending = false;
1668
1669 clock_get_uptime(&time);
1670 if ((AbsoluteTime_to_scalar(&time) > autoWakeStart) &&
1671 (AbsoluteTime_to_scalar(&time) < autoWakeEnd))
1672 {
1673 thread_call_enter_delayed(extraSleepTimer, *((AbsoluteTime *) &autoWakeEnd));
1674 return;
1675 }
1676
1677 // accelerate disk spin down if spin down timer is non-zero
1678 setQuickSpinDownTimeout();
1679
1680 sleepASAP = true;
1681 adjustPowerState();
1682 }
1683
1684
1685 //******************************************************************************
1686 // stopIgnoringClamshellEventsDuringWakeup
1687 //
1688 //******************************************************************************
1689
1690 void IOPMrootDomain::stopIgnoringClamshellEventsDuringWakeup( void )
1691 {
1692 if (!getPMworkloop()->inGate())
1693 {
1694 getPMworkloop()->runAction(
1695 OSMemberFunctionCast(IOWorkLoop::Action, this,
1696 &IOPMrootDomain::stopIgnoringClamshellEventsDuringWakeup),
1697 this);
1698 return;
1699 }
1700
1701 ASSERT_GATED();
1702
1703 // Allow clamshell-induced sleep now
1704 ignoringClamshellOnWake = false;
1705
1706 // Re-send clamshell event, in case it causes a sleep
1707 if (clamshellIsClosed)
1708 handlePowerNotification( kLocalEvalClamshellCommand );
1709 }
1710
1711
1712 //******************************************************************************
1713 // sleepSystem
1714 //
1715 //******************************************************************************
1716
1717 /* public */
1718 IOReturn IOPMrootDomain::sleepSystem( void )
1719 {
1720 return sleepSystemOptions(NULL);
1721 }
1722
1723 /* private */
1724 IOReturn IOPMrootDomain::sleepSystemOptions( OSDictionary *options )
1725 {
1726 /* sleepSystem is a public function, and may be called by any kernel driver.
1727 * And that's bad - drivers should sleep the system by calling
1728 * receivePowerNotification() instead. Drivers should not use sleepSystem.
1729 *
1730 * Note that user space app calls to IOPMSleepSystem() will also travel
1731 * this code path and thus be correctly identified as software sleeps.
1732 */
1733
1734 if (options && options->getObject("OSSwitch"))
1735 {
1736
1737 // Log specific sleep cause for OS Switch hibernation
1738 return privateSleepSystem( kIOPMOSSwitchHibernationKey) ;
1739
1740 } else {
1741
1742 return privateSleepSystem( kIOPMSoftwareSleepKey);
1743
1744 }
1745 }
1746
1747 /* private */
1748 IOReturn IOPMrootDomain::privateSleepSystem( const char *sleepReason )
1749 {
1750 if ( userDisabledAllSleep )
1751 {
1752 LOG("Sleep prevented by user disable\n");
1753
1754 /* Prevent sleep of all kinds if directed to by user space */
1755 return kIOReturnNotPermitted;
1756 }
1757
1758 if ( systemBooting || systemShutdown || !allowSleep )
1759 {
1760 LOG("Sleep prevented by SB %d, SS %d, AS %d\n",
1761 systemBooting, systemShutdown, allowSleep);
1762
1763 // Unable to sleep because system is in the process of booting or
1764 // shutting down, or sleep has otherwise been disallowed.
1765 return kIOReturnError;
1766 }
1767
1768 // Record sleep cause in IORegistry
1769 if (sleepReason) {
1770 setProperty(kRootDomainSleepReasonKey, sleepReason);
1771 }
1772
1773 patriarch->sleepSystem();
1774 return kIOReturnSuccess;
1775 }
1776
1777
1778 //******************************************************************************
1779 // shutdownSystem
1780 //
1781 //******************************************************************************
1782
1783 IOReturn IOPMrootDomain::shutdownSystem( void )
1784 {
1785 //patriarch->shutDownSystem();
1786 return kIOReturnUnsupported;
1787 }
1788
1789
1790 //******************************************************************************
1791 // restartSystem
1792 //
1793 //******************************************************************************
1794
1795 IOReturn IOPMrootDomain::restartSystem( void )
1796 {
1797 //patriarch->restartSystem();
1798 return kIOReturnUnsupported;
1799 }
1800
1801
1802 //******************************************************************************
1803 // powerChangeDone
1804 //
1805 // This overrides powerChangeDone in IOService.
1806 //
1807 // Menu sleep and idle sleep move us from the ON state to the SLEEP_STATE.
1808 // In this case:
1809 // If we finished going to the SLEEP_STATE, and the platform is capable of
1810 // true sleep, then sleep the kernel. Otherwise switch up to the DOZE_STATE
1811 // which will keep almost everything as off as it can get.
1812 //******************************************************************************
1813
1814 void IOPMrootDomain::powerChangeDone( unsigned long previousState )
1815 {
1816 ASSERT_GATED();
1817 DLOG("PowerChangeDone: %u->%u\n",
1818 (uint32_t) previousState, (uint32_t) getPowerState());
1819
1820 switch ( getPowerState() ) {
1821 case SLEEP_STATE:
1822 if ( previousState != ON_STATE )
1823 break;
1824
1825 if ( canSleep )
1826 {
1827 // re-enable this timer for next sleep
1828 cancelIdleSleepTimer();
1829 wranglerTickled = true;
1830
1831 clock_sec_t secs;
1832 clock_usec_t microsecs;
1833 clock_get_calendar_microtime(&secs, &microsecs);
1834 logtime(secs);
1835 gIOLastSleepTime.tv_sec = secs;
1836 gIOLastSleepTime.tv_usec = microsecs;
1837 gIOLastWakeTime.tv_sec = 0;
1838 gIOLastWakeTime.tv_usec = 0;
1839
1840 #if HIBERNATION
1841 LOG("System %sSleep\n", gIOHibernateState ? "Safe" : "");
1842
1843 tracePoint(kIOPMTracePointSystemHibernatePhase);
1844
1845 IOHibernateSystemHasSlept();
1846 #else
1847 LOG("System Sleep\n");
1848 #endif
1849
1850 tracePoint(kIOPMTracePointSystemSleepPlatformPhase);
1851
1852 getPlatform()->sleepKernel();
1853
1854 // The CPU(s) are off at this point. When they're awakened by CPU interrupt,
1855 // code will resume execution here.
1856
1857 // Now we're waking...
1858 tracePoint(kIOPMTracePointSystemWakeDriversPhase);
1859
1860 #if HIBERNATION
1861 IOHibernateSystemWake();
1862 #endif
1863
1864 // sleep transition complete
1865 gSleepOrShutdownPending = 0;
1866
1867 // trip the reset of the calendar clock
1868 clock_wakeup_calendar();
1869
1870 // get us some power
1871 patriarch->wakeSystem();
1872
1873 // Set indicator if UUID was set - allow it to be cleared.
1874 if (getProperty(kIOPMSleepWakeUUIDKey))
1875 gSleepWakeUUIDIsSet = true;
1876
1877 #if !ROOT_DOMAIN_RUN_STATES
1878 tellClients(kIOMessageSystemWillPowerOn, clientMessageFilter);
1879 #endif
1880
1881 #if HIBERNATION
1882 LOG("System %sWake\n", gIOHibernateState ? "SafeSleep " : "");
1883 #endif
1884
1885 // log system wake
1886 getPlatform()->PMLog(kIOPMrootDomainClass, kPMLogSystemWake, 0, 0);
1887
1888 #ifndef __LP64__
1889 // tell the tree we're waking
1890 systemWake();
1891 #endif
1892
1893
1894 #if defined(__i386__) || defined(__x86_64__)
1895 #if ROOT_DOMAIN_RUN_STATES
1896 OSString * wakeType = OSDynamicCast(
1897 OSString, getProperty(kIOPMRootDomainWakeTypeKey));
1898 if (wakeType && wakeType->isEqualTo(kIOPMRootDomainWakeTypeMaintenance))
1899 {
1900 updateRunState(kRStateMaintenance);
1901 wranglerTickled = false;
1902 }
1903 else
1904 #endif /* ROOT_DOMAIN_RUN_STATES */
1905 {
1906 updateRunState(kRStateNormal);
1907 reportUserInput();
1908 }
1909 #else /* !__i386__ && !__x86_64__ */
1910 // stay awake for at least 30 seconds
1911 startIdleSleepTimer(30);
1912 reportUserInput();
1913 #endif
1914
1915 changePowerStateToPriv(ON_STATE);
1916 } else {
1917 updateRunState(kRStateNormal);
1918
1919 // allow us to step up a power state
1920 patriarch->sleepToDoze();
1921
1922 // ignore children's request for higher power during doze.
1923 changePowerStateWithOverrideTo(DOZE_STATE);
1924 }
1925 break;
1926
1927 case DOZE_STATE:
1928 if ( previousState != DOZE_STATE )
1929 {
1930 LOG("System Doze\n");
1931 }
1932 // re-enable this timer for next sleep
1933 cancelIdleSleepTimer();
1934 gSleepOrShutdownPending = 0;
1935
1936 // Invalidate prior activity tickles to allow wake from doze.
1937 if (wrangler) wrangler->changePowerStateTo(0);
1938 break;
1939
1940 #if ROOT_DOMAIN_RUN_STATES
1941 case ON_STATE:
1942 // SLEEP -> ON (Maintenance)
1943 // Go back to sleep, unless cancelled by a HID event.
1944
1945 if ((previousState == SLEEP_STATE) &&
1946 (runStateIndex == kRStateMaintenance) &&
1947 !wranglerTickled)
1948 {
1949 setProperty(kRootDomainSleepReasonKey, kIOPMMaintenanceSleepKey);
1950 changePowerStateWithOverrideTo(SLEEP_STATE);
1951 }
1952
1953 // ON -> ON triggered by R-state changes.
1954
1955 if ((previousState == ON_STATE) &&
1956 (runStateIndex != nextRunStateIndex) &&
1957 (nextRunStateIndex < kRStateCount))
1958 {
1959 LOG("R-state changed %u->%u\n",
1960 runStateIndex, nextRunStateIndex);
1961 updateRunState(nextRunStateIndex);
1962
1963 DLOG("kIOMessageSystemHasPoweredOn (%u)\n",
1964 gMessageClientType);
1965 tellClients(kIOMessageSystemHasPoweredOn, clientMessageFilter);
1966 }
1967
1968 break;
1969 #endif /* ROOT_DOMAIN_RUN_STATES */
1970 }
1971 }
1972
1973
1974 //******************************************************************************
1975 // wakeFromDoze
1976 //
1977 // The Display Wrangler calls here when it switches to its highest state.
1978 // If the system is currently dozing, allow it to wake by making sure the
1979 // parent is providing power.
1980 //******************************************************************************
1981
1982 void IOPMrootDomain::wakeFromDoze( void )
1983 {
1984 if ( getPowerState() == DOZE_STATE )
1985 {
1986 tracePoint(kIOPMTracePointSystemWakeDriversPhase);
1987 changePowerStateToPriv(ON_STATE);
1988 patriarch->wakeSystem();
1989 }
1990 }
1991
1992
1993 //******************************************************************************
1994 // publishFeature
1995 //
1996 // Adds a new feature to the supported features dictionary
1997 //******************************************************************************
1998
1999 void IOPMrootDomain::publishFeature( const char * feature )
2000 {
2001 publishFeature(feature, kRD_AllPowerSources, NULL);
2002 }
2003
2004
2005 //******************************************************************************
2006 // publishFeature (with supported power source specified)
2007 //
2008 // Adds a new feature to the supported features dictionary
2009 //******************************************************************************
2010
2011 void IOPMrootDomain::publishFeature(
2012 const char *feature,
2013 uint32_t supportedWhere,
2014 uint32_t *uniqueFeatureID)
2015 {
2016 static uint16_t next_feature_id = 500;
2017
2018 OSNumber *new_feature_data = NULL;
2019 OSNumber *existing_feature = NULL;
2020 OSArray *existing_feature_arr = NULL;
2021 OSObject *osObj = NULL;
2022 uint32_t feature_value = 0;
2023
2024 supportedWhere &= kRD_AllPowerSources; // mask off any craziness!
2025
2026 if(!supportedWhere) {
2027 // Feature isn't supported anywhere!
2028 return;
2029 }
2030
2031 if(next_feature_id > 5000) {
2032 // Far, far too many features!
2033 return;
2034 }
2035
2036 if(featuresDictLock) IOLockLock(featuresDictLock);
2037
2038 OSDictionary *features =
2039 (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
2040
2041 // Create new features dict if necessary
2042 if ( features && OSDynamicCast(OSDictionary, features)) {
2043 features = OSDictionary::withDictionary(features);
2044 } else {
2045 features = OSDictionary::withCapacity(1);
2046 }
2047
2048 // Create OSNumber to track new feature
2049
2050 next_feature_id += 1;
2051 if( uniqueFeatureID ) {
2052 // We don't really mind if the calling kext didn't give us a place
2053 // to stash their unique id. Many kexts don't plan to unload, and thus
2054 // have no need to remove themselves later.
2055 *uniqueFeatureID = next_feature_id;
2056 }
2057
2058 feature_value = (uint32_t)next_feature_id;
2059 feature_value <<= 16;
2060 feature_value += supportedWhere;
2061
2062 new_feature_data = OSNumber::withNumber(
2063 (unsigned long long)feature_value, 32);
2064
2065 // Does features object already exist?
2066 if( (osObj = features->getObject(feature)) )
2067 {
2068 if(( existing_feature = OSDynamicCast(OSNumber, osObj) ))
2069 {
2070 // We need to create an OSArray to hold the now 2 elements.
2071 existing_feature_arr = OSArray::withObjects(
2072 (const OSObject **)&existing_feature, 1, 2);
2073 } else if(( existing_feature_arr = OSDynamicCast(OSArray, osObj) ))
2074 {
2075 // Add object to existing array
2076 existing_feature_arr = OSArray::withArray(
2077 existing_feature_arr,
2078 existing_feature_arr->getCount() + 1);
2079 }
2080
2081 if (existing_feature_arr)
2082 {
2083 existing_feature_arr->setObject(new_feature_data);
2084 features->setObject(feature, existing_feature_arr);
2085 existing_feature_arr->release();
2086 existing_feature_arr = 0;
2087 }
2088 } else {
2089 // The easy case: no previously existing features listed. We simply
2090 // set the OSNumber at key 'feature' and we're on our way.
2091 features->setObject(feature, new_feature_data);
2092 }
2093
2094 new_feature_data->release();
2095
2096 setProperty(kRootDomainSupportedFeatures, features);
2097
2098 features->release();
2099
2100 if(featuresDictLock) IOLockUnlock(featuresDictLock);
2101
2102 // Notify EnergySaver and all those in user space so they might
2103 // re-populate their feature specific UI
2104 if(pmPowerStateQueue) {
2105 pmPowerStateQueue->submitPowerEvent( kPowerEventFeatureChanged );
2106 }
2107 }
2108
2109
2110 //******************************************************************************
2111 // removePublishedFeature
2112 //
2113 // Removes previously published feature
2114 //******************************************************************************
2115
2116 IOReturn IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID )
2117 {
2118 IOReturn ret = kIOReturnError;
2119 uint32_t feature_value = 0;
2120 uint16_t feature_id = 0;
2121 bool madeAChange = false;
2122
2123 OSSymbol *dictKey = NULL;
2124 OSCollectionIterator *dictIterator = NULL;
2125 OSArray *arrayMember = NULL;
2126 OSNumber *numberMember = NULL;
2127 OSObject *osObj = NULL;
2128 OSNumber *osNum = NULL;
2129 OSArray *arrayMemberCopy;
2130
2131 if(featuresDictLock) IOLockLock(featuresDictLock);
2132
2133 OSDictionary *features =
2134 (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
2135
2136 if ( features && OSDynamicCast(OSDictionary, features) )
2137 {
2138 // Any modifications to the dictionary are made to the copy to prevent
2139 // races & crashes with userland clients. Dictionary updated
2140 // automically later.
2141 features = OSDictionary::withDictionary(features);
2142 } else {
2143 features = NULL;
2144 ret = kIOReturnNotFound;
2145 goto exit;
2146 }
2147
2148 // We iterate 'features' dictionary looking for an entry tagged
2149 // with 'removeFeatureID'. If found, we remove it from our tracking
2150 // structures and notify the OS via a general interest message.
2151
2152 dictIterator = OSCollectionIterator::withCollection(features);
2153 if(!dictIterator) {
2154 goto exit;
2155 }
2156
2157 while( (dictKey = OSDynamicCast(OSSymbol, dictIterator->getNextObject())) )
2158 {
2159 osObj = features->getObject(dictKey);
2160
2161 // Each Feature is either tracked by an OSNumber
2162 if( osObj && (numberMember = OSDynamicCast(OSNumber, osObj)) )
2163 {
2164 feature_value = numberMember->unsigned32BitValue();
2165 feature_id = (uint16_t)(feature_value >> 16);
2166
2167 if( feature_id == (uint16_t)removeFeatureID )
2168 {
2169 // Remove this node
2170 features->removeObject(dictKey);
2171 madeAChange = true;
2172 break;
2173 }
2174
2175 // Or tracked by an OSArray of OSNumbers
2176 } else if( osObj && (arrayMember = OSDynamicCast(OSArray, osObj)) )
2177 {
2178 unsigned int arrayCount = arrayMember->getCount();
2179
2180 for(unsigned int i=0; i<arrayCount; i++)
2181 {
2182 osNum = OSDynamicCast(OSNumber, arrayMember->getObject(i));
2183 if(!osNum) {
2184 continue;
2185 }
2186
2187 feature_value = osNum->unsigned32BitValue();
2188 feature_id = (uint16_t)(feature_value >> 16);
2189
2190 if( feature_id == (uint16_t)removeFeatureID )
2191 {
2192 // Remove this node
2193 if( 1 == arrayCount ) {
2194 // If the array only contains one element, remove
2195 // the whole thing.
2196 features->removeObject(dictKey);
2197 } else {
2198 // Otherwise remove the element from a copy of the array.
2199 arrayMemberCopy = OSArray::withArray(arrayMember);
2200 if (arrayMemberCopy)
2201 {
2202 arrayMemberCopy->removeObject(i);
2203 features->setObject(dictKey, arrayMemberCopy);
2204 arrayMemberCopy->release();
2205 }
2206 }
2207
2208 madeAChange = true;
2209 break;
2210 }
2211 }
2212 }
2213 }
2214
2215 dictIterator->release();
2216
2217 if( madeAChange )
2218 {
2219 ret = kIOReturnSuccess;
2220
2221 setProperty(kRootDomainSupportedFeatures, features);
2222
2223 // Notify EnergySaver and all those in user space so they might
2224 // re-populate their feature specific UI
2225 if(pmPowerStateQueue) {
2226 pmPowerStateQueue->submitPowerEvent( kPowerEventFeatureChanged );
2227 }
2228 } else {
2229 ret = kIOReturnNotFound;
2230 }
2231
2232 exit:
2233 if(features) features->release();
2234 if(featuresDictLock) IOLockUnlock(featuresDictLock);
2235 return ret;
2236 }
2237
2238
2239 //******************************************************************************
2240 // announcePowerSourceChange
2241 //
2242 // Notifies "interested parties" that the battery state has changed
2243 //******************************************************************************
2244
2245 void IOPMrootDomain::announcePowerSourceChange( void )
2246 {
2247 #ifdef __ppc__
2248 IORegistryEntry *_batteryRegEntry = (IORegistryEntry *) getProperty("BatteryEntry");
2249
2250 // (if possible) re-publish power source state under IOPMrootDomain;
2251 // only do so if the battery controller publishes an IOResource
2252 // defining battery location. Called from ApplePMU battery driver.
2253
2254 if(_batteryRegEntry)
2255 {
2256 OSArray *batt_info;
2257 batt_info = (OSArray *) _batteryRegEntry->getProperty(kIOBatteryInfoKey);
2258 if(batt_info)
2259 setProperty(kIOBatteryInfoKey, batt_info);
2260 }
2261 #endif
2262 }
2263
2264
2265 //******************************************************************************
2266 // setPMSetting (private)
2267 //
2268 // Internal helper to relay PM settings changes from user space to individual
2269 // drivers. Should be called only by IOPMrootDomain::setProperties.
2270 //******************************************************************************
2271
2272 IOReturn IOPMrootDomain::setPMSetting(
2273 const OSSymbol *type,
2274 OSObject *obj)
2275 {
2276 OSArray *arr = NULL;
2277 PMSettingObject *p_obj = NULL;
2278 int count;
2279 int i;
2280
2281 if(NULL == type) return kIOReturnBadArgument;
2282
2283 IORecursiveLockLock(settingsCtrlLock);
2284
2285 fPMSettingsDict->setObject(type, obj);
2286
2287 arr = (OSArray *)settingsCallbacks->getObject(type);
2288 if(NULL == arr) goto exit;
2289 count = arr->getCount();
2290 for(i=0; i<count; i++) {
2291 p_obj = (PMSettingObject *)OSDynamicCast(PMSettingObject, arr->getObject(i));
2292 if(p_obj) p_obj->setPMSetting(type, obj);
2293 }
2294
2295 exit:
2296 IORecursiveLockUnlock(settingsCtrlLock);
2297 return kIOReturnSuccess;
2298 }
2299
2300
2301 //******************************************************************************
2302 // copyPMSetting (public)
2303 //
2304 // Allows kexts to safely read setting values, without being subscribed to
2305 // notifications.
2306 //******************************************************************************
2307
2308 OSObject * IOPMrootDomain::copyPMSetting(
2309 OSSymbol *whichSetting)
2310 {
2311 OSObject *obj = NULL;
2312
2313 if(!whichSetting) return NULL;
2314
2315 IORecursiveLockLock(settingsCtrlLock);
2316 obj = fPMSettingsDict->getObject(whichSetting);
2317 if(obj) {
2318 obj->retain();
2319 }
2320 IORecursiveLockUnlock(settingsCtrlLock);
2321
2322 return obj;
2323 }
2324
2325
2326 //******************************************************************************
2327 // registerPMSettingController (public)
2328 //
2329 // direct wrapper to registerPMSettingController with uint32_t power source arg
2330 //******************************************************************************
2331
2332 IOReturn IOPMrootDomain::registerPMSettingController(
2333 const OSSymbol * settings[],
2334 IOPMSettingControllerCallback func,
2335 OSObject *target,
2336 uintptr_t refcon,
2337 OSObject **handle)
2338 {
2339 return registerPMSettingController(
2340 settings,
2341 (kIOPMSupportedOnAC | kIOPMSupportedOnBatt | kIOPMSupportedOnUPS),
2342 func, target, refcon, handle);
2343 }
2344
2345
2346 //******************************************************************************
2347 // registerPMSettingController (public)
2348 //
2349 // Kexts may register for notifications when a particular setting is changed.
2350 // A list of settings is available in IOPM.h.
2351 // Arguments:
2352 // * settings - An OSArray containing OSSymbols. Caller should populate this
2353 // array with a list of settings caller wants notifications from.
2354 // * func - A C function callback of the type IOPMSettingControllerCallback
2355 // * target - caller may provide an OSObject *, which PM will pass as an
2356 // target to calls to "func"
2357 // * refcon - caller may provide an void *, which PM will pass as an
2358 // argument to calls to "func"
2359 // * handle - This is a return argument. We will populate this pointer upon
2360 // call success. Hold onto this and pass this argument to
2361 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
2362 // Returns:
2363 // kIOReturnSuccess on success
2364 //******************************************************************************
2365
2366 IOReturn IOPMrootDomain::registerPMSettingController(
2367 const OSSymbol * settings[],
2368 uint32_t supportedPowerSources,
2369 IOPMSettingControllerCallback func,
2370 OSObject *target,
2371 uintptr_t refcon,
2372 OSObject **handle)
2373 {
2374 PMSettingObject *pmso = NULL;
2375 OSArray *list = NULL;
2376 IOReturn ret = kIOReturnSuccess;
2377 int i;
2378
2379 if( NULL == settings ||
2380 NULL == func ||
2381 NULL == handle)
2382 {
2383 return kIOReturnBadArgument;
2384 }
2385
2386 pmso = PMSettingObject::pmSettingObject(
2387 (IOPMrootDomain *)this, func, target,
2388 refcon, supportedPowerSources, settings);
2389
2390 if(!pmso) {
2391 ret = kIOReturnInternalError;
2392 goto bail_no_unlock;
2393 }
2394
2395 IORecursiveLockLock(settingsCtrlLock);
2396 for(i=0; settings[i]; i++)
2397 {
2398 list = (OSArray *)settingsCallbacks->getObject(settings[i]);
2399 if(!list) {
2400 // New array of callbacks for this setting
2401 list = OSArray::withCapacity(1);
2402 settingsCallbacks->setObject(settings[i], list);
2403 list->release();
2404 }
2405
2406 // Add caller to the callback list
2407 list->setObject(pmso);
2408 }
2409
2410 IORecursiveLockUnlock(settingsCtrlLock);
2411
2412 ret = kIOReturnSuccess;
2413
2414 // Track this instance by its OSData ptr from now on
2415 *handle = pmso;
2416
2417 bail_no_unlock:
2418 if(kIOReturnSuccess != ret)
2419 {
2420 // Error return case
2421 if(pmso) pmso->release();
2422 if(handle) *handle = NULL;
2423 }
2424 return ret;
2425 }
2426
2427
2428 //******************************************************************************
2429 // sleepOnClamshellClosed
2430 //
2431 // contains the logic to determine if the system should sleep when the clamshell
2432 // is closed.
2433 //******************************************************************************
2434
2435 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
2436 {
2437 DLOG("clamshell state %d, EX %d, IG %d, IW %d, DT %d, AC %d\n",
2438 clamshellIsClosed, clamshellExists, ignoringClamshell,
2439 ignoringClamshellOnWake, desktopMode, acAdaptorConnected);
2440
2441 return ( !ignoringClamshell
2442 && !ignoringClamshellOnWake
2443 && !(desktopMode && acAdaptorConnected) );
2444 }
2445
2446 void IOPMrootDomain::sendClientClamshellNotification( void )
2447 {
2448 /* Only broadcast clamshell alert if clamshell exists. */
2449 if (!clamshellExists)
2450 return;
2451
2452 setProperty(kAppleClamshellStateKey,
2453 clamshellIsClosed ? kOSBooleanTrue : kOSBooleanFalse);
2454
2455 setProperty(kAppleClamshellCausesSleepKey,
2456 shouldSleepOnClamshellClosed() ? kOSBooleanTrue : kOSBooleanFalse);
2457
2458 /* Argument to message is a bitfiel of
2459 * ( kClamshellStateBit | kClamshellSleepBit )
2460 */
2461 messageClients(kIOPMMessageClamshellStateChange,
2462 (void *) ( (clamshellIsClosed ? kClamshellStateBit : 0)
2463 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit : 0)) );
2464 }
2465
2466
2467 //******************************************************************************
2468 // informCPUStateChange
2469 //
2470 // Call into PM CPU code so that CPU power savings may dynamically adjust for
2471 // running on battery, with the lid closed, etc.
2472 //
2473 // informCPUStateChange is a no-op on non x86 systems
2474 // only x86 has explicit support in the IntelCPUPowerManagement kext
2475 //******************************************************************************
2476
2477 void IOPMrootDomain::informCPUStateChange(
2478 uint32_t type,
2479 uint32_t value )
2480 {
2481 #if defined(__i386__) || defined(__x86_64__)
2482
2483 pmioctlVariableInfo_t varInfoStruct;
2484 int pmCPUret = 0;
2485 const char *varNameStr = NULL;
2486 int32_t *varIndex = NULL;
2487
2488 if (kInformAC == type) {
2489 varNameStr = kIOPMRootDomainBatPowerCString;
2490 varIndex = &idxPMCPULimitedPower;
2491 } else if (kInformLid == type) {
2492 varNameStr = kIOPMRootDomainLidCloseCString;
2493 varIndex = &idxPMCPUClamshell;
2494 } else {
2495 return;
2496 }
2497
2498 // Set the new value!
2499 // pmCPUControl will assign us a new ID if one doesn't exist yet
2500 bzero(&varInfoStruct, sizeof(pmioctlVariableInfo_t));
2501 varInfoStruct.varID = *varIndex;
2502 varInfoStruct.varType = vBool;
2503 varInfoStruct.varInitValue = value;
2504 varInfoStruct.varCurValue = value;
2505 strncpy( (char *)varInfoStruct.varName,
2506 (const char *)varNameStr,
2507 strlen(varNameStr) + 1 );
2508
2509 // Set!
2510 pmCPUret = pmCPUControl( PMIOCSETVARINFO, (void *)&varInfoStruct );
2511
2512 // pmCPU only assigns numerical id's when a new varName is specified
2513 if ((0 == pmCPUret)
2514 && (*varIndex == kCPUUnknownIndex))
2515 {
2516 // pmCPUControl has assigned us a new variable ID.
2517 // Let's re-read the structure we just SET to learn that ID.
2518 pmCPUret = pmCPUControl( PMIOCGETVARNAMEINFO, (void *)&varInfoStruct );
2519
2520 if (0 == pmCPUret)
2521 {
2522 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
2523 *varIndex = varInfoStruct.varID;
2524 }
2525 }
2526
2527 return;
2528
2529 #endif /* __i386__ || __x86_64__ */
2530 }
2531
2532
2533 //******************************************************************************
2534 // dispatchPowerEvent
2535 //
2536 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
2537 //******************************************************************************
2538
2539 void IOPMrootDomain::dispatchPowerEvent(
2540 uint32_t event, void * arg0, void * arg1 )
2541 {
2542 DLOG("power event %x args %p %p\n", event, arg0, arg1);
2543 ASSERT_GATED();
2544
2545 switch (event)
2546 {
2547 case kPowerEventFeatureChanged:
2548 messageClients(kIOPMMessageFeatureChange, this);
2549 break;
2550
2551 case kPowerEventReceivedPowerNotification:
2552 handlePowerNotification( (UInt32)(uintptr_t) arg0 );
2553 break;
2554
2555 case kPowerEventSystemBootCompleted:
2556 if (systemBooting)
2557 {
2558 systemBooting = false;
2559 adjustPowerState();
2560
2561 // If lid is closed, re-send lid closed notification
2562 // now that booting is complete.
2563 if( clamshellIsClosed )
2564 {
2565 handlePowerNotification(kLocalEvalClamshellCommand);
2566 }
2567 }
2568 break;
2569
2570 case kPowerEventSystemShutdown:
2571 if (kOSBooleanTrue == (OSBoolean *) arg0)
2572 {
2573 /* We set systemShutdown = true during shutdown
2574 to prevent sleep at unexpected times while loginwindow is trying
2575 to shutdown apps and while the OS is trying to transition to
2576 complete power of.
2577
2578 Set to true during shutdown, as soon as loginwindow shows
2579 the "shutdown countdown dialog", through individual app
2580 termination, and through black screen kernel shutdown.
2581 */
2582 LOG("systemShutdown true\n");
2583 systemShutdown = true;
2584 } else {
2585 /*
2586 A shutdown was initiated, but then the shutdown
2587 was cancelled, clearing systemShutdown to false here.
2588 */
2589 LOG("systemShutdown false\n");
2590 systemShutdown = false;
2591 }
2592 break;
2593
2594 case kPowerEventUserDisabledSleep:
2595 userDisabledAllSleep = (kOSBooleanTrue == (OSBoolean *) arg0);
2596 break;
2597
2598 #if ROOT_DOMAIN_RUN_STATES
2599 case kPowerEventConfigdRegisteredInterest:
2600 if (gConfigdNotifier)
2601 {
2602 gConfigdNotifier->release();
2603 gConfigdNotifier = 0;
2604 }
2605 if (arg0)
2606 {
2607 gConfigdNotifier = (IONotifier *) arg0;
2608 }
2609 break;
2610 #endif
2611
2612 case kPowerEventAggressivenessChanged:
2613 aggressivenessChanged();
2614 break;
2615 }
2616 }
2617
2618
2619 //******************************************************************************
2620 // systemPowerEventOccurred
2621 //
2622 // The power controller is notifying us of a hardware-related power management
2623 // event that we must handle.
2624 //
2625 // systemPowerEventOccurred covers the same functionality that
2626 // receivePowerNotification does; it simply provides a richer API for conveying
2627 // more information.
2628 //******************************************************************************
2629
2630 IOReturn IOPMrootDomain::systemPowerEventOccurred(
2631 const OSSymbol *event,
2632 uint32_t intValue)
2633 {
2634 IOReturn attempt = kIOReturnSuccess;
2635 OSNumber *newNumber = NULL;
2636
2637 if (!event)
2638 return kIOReturnBadArgument;
2639
2640 newNumber = OSNumber::withNumber(intValue, 8*sizeof(intValue));
2641 if (!newNumber)
2642 return kIOReturnInternalError;
2643
2644 attempt = systemPowerEventOccurred(event, (OSObject *)newNumber);
2645
2646 newNumber->release();
2647
2648 return attempt;
2649 }
2650
2651 IOReturn IOPMrootDomain::systemPowerEventOccurred(
2652 const OSSymbol *event,
2653 OSObject *value)
2654 {
2655 OSDictionary *thermalsDict = NULL;
2656 bool shouldUpdate = true;
2657
2658 if (!event || !value)
2659 return kIOReturnBadArgument;
2660
2661 // LOCK
2662 // We reuse featuresDict Lock because it already exists and guards
2663 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
2664 // of stepping on that lock.
2665 if (featuresDictLock) IOLockLock(featuresDictLock);
2666
2667 thermalsDict = (OSDictionary *)getProperty(kIOPMRootDomainPowerStatusKey);
2668
2669 if (thermalsDict && OSDynamicCast(OSDictionary, thermalsDict)) {
2670 thermalsDict = OSDictionary::withDictionary(thermalsDict);
2671 } else {
2672 thermalsDict = OSDictionary::withCapacity(1);
2673 }
2674
2675 if (!thermalsDict) {
2676 shouldUpdate = false;
2677 goto exit;
2678 }
2679
2680 thermalsDict->setObject (event, value);
2681
2682 setProperty (kIOPMRootDomainPowerStatusKey, thermalsDict);
2683
2684 thermalsDict->release();
2685
2686 exit:
2687 // UNLOCK
2688 if (featuresDictLock) IOLockUnlock(featuresDictLock);
2689
2690 if (shouldUpdate)
2691 messageClients (kIOPMMessageSystemPowerEventOccurred, (void *)NULL);
2692
2693 return kIOReturnSuccess;
2694 }
2695
2696
2697 //******************************************************************************
2698 // receivePowerNotification
2699 //
2700 // The power controller is notifying us of a hardware-related power management
2701 // event that we must handle. This may be a result of an 'environment' interrupt
2702 // from the power mgt micro.
2703 //******************************************************************************
2704
2705 IOReturn IOPMrootDomain::receivePowerNotification( UInt32 msg )
2706 {
2707 pmPowerStateQueue->submitPowerEvent(
2708 kPowerEventReceivedPowerNotification, (void *) msg );
2709 return kIOReturnSuccess;
2710 }
2711
2712 void IOPMrootDomain::handlePowerNotification( UInt32 msg )
2713 {
2714 bool eval_clamshell = false;
2715
2716 ASSERT_GATED();
2717
2718 /*
2719 * Local (IOPMrootDomain only) eval clamshell command
2720 */
2721 if (msg & kLocalEvalClamshellCommand)
2722 {
2723 eval_clamshell = true;
2724 }
2725
2726 /*
2727 * Overtemp
2728 */
2729 if (msg & kIOPMOverTemp)
2730 {
2731 LOG("PowerManagement emergency overtemp signal. Going to sleep!");
2732 privateSleepSystem (kIOPMThermalEmergencySleepKey);
2733 }
2734
2735 #ifdef __ppc__
2736 /*
2737 * PMU Processor Speed Change
2738 */
2739 if (msg & kIOPMProcessorSpeedChange)
2740 {
2741 IOService *pmu = waitForService(serviceMatching("ApplePMU"));
2742 pmu->callPlatformFunction("prepareForSleep", false, 0, 0, 0, 0);
2743 getPlatform()->sleepKernel();
2744 pmu->callPlatformFunction("recoverFromSleep", false, 0, 0, 0, 0);
2745 }
2746 #endif
2747
2748 /*
2749 * Sleep Now!
2750 */
2751 if (msg & kIOPMSleepNow)
2752 {
2753 privateSleepSystem (kIOPMSoftwareSleepKey);
2754 }
2755
2756 /*
2757 * Power Emergency
2758 */
2759 if (msg & kIOPMPowerEmergency)
2760 {
2761 privateSleepSystem (kIOPMLowPowerSleepKey);
2762 }
2763
2764 /*
2765 * Clamshell OPEN
2766 */
2767 if (msg & kIOPMClamshellOpened)
2768 {
2769 // Received clamshel open message from clamshell controlling driver
2770 // Update our internal state and tell general interest clients
2771 clamshellIsClosed = false;
2772 clamshellExists = true;
2773
2774 // Tell PMCPU
2775 informCPUStateChange(kInformLid, 0);
2776
2777 // Tell general interest clients
2778 sendClientClamshellNotification();
2779 }
2780
2781 /*
2782 * Clamshell CLOSED
2783 * Send the clamshell interest notification since the lid is closing.
2784 */
2785 if (msg & kIOPMClamshellClosed)
2786 {
2787 // Received clamshel open message from clamshell controlling driver
2788 // Update our internal state and tell general interest clients
2789 clamshellIsClosed = true;
2790 clamshellExists = true;
2791
2792 // Tell PMCPU
2793 informCPUStateChange(kInformLid, 1);
2794
2795 // Tell general interest clients
2796 sendClientClamshellNotification();
2797
2798 // And set eval_clamshell = so we can attempt
2799 eval_clamshell = true;
2800 }
2801
2802 /*
2803 * Set Desktop mode (sent from graphics)
2804 *
2805 * -> reevaluate lid state
2806 */
2807 if (msg & kIOPMSetDesktopMode)
2808 {
2809 desktopMode = (0 != (msg & kIOPMSetValue));
2810 msg &= ~(kIOPMSetDesktopMode | kIOPMSetValue);
2811
2812 sendClientClamshellNotification();
2813
2814 // Re-evaluate the lid state
2815 if( clamshellIsClosed )
2816 {
2817 eval_clamshell = true;
2818 }
2819 }
2820
2821 /*
2822 * AC Adaptor connected
2823 *
2824 * -> reevaluate lid state
2825 */
2826 if (msg & kIOPMSetACAdaptorConnected)
2827 {
2828 acAdaptorConnected = (0 != (msg & kIOPMSetValue));
2829 msg &= ~(kIOPMSetACAdaptorConnected | kIOPMSetValue);
2830
2831 // Tell CPU PM
2832 informCPUStateChange(kInformAC, !acAdaptorConnected);
2833
2834 // Tell BSD if AC is connected
2835 // 0 == external power source; 1 == on battery
2836 post_sys_powersource(acAdaptorConnected ? 0:1);
2837
2838 sendClientClamshellNotification();
2839
2840 // Re-evaluate the lid state
2841 if( clamshellIsClosed )
2842 {
2843 eval_clamshell = true;
2844 }
2845 }
2846
2847 /*
2848 * Enable Clamshell (external display disappear)
2849 *
2850 * -> reevaluate lid state
2851 */
2852 if (msg & kIOPMEnableClamshell)
2853 {
2854 // Re-evaluate the lid state
2855 // System should sleep on external display disappearance
2856 // in lid closed operation.
2857 if( clamshellIsClosed && (true == ignoringClamshell) )
2858 {
2859 eval_clamshell = true;
2860 }
2861
2862 ignoringClamshell = false;
2863
2864 sendClientClamshellNotification();
2865 }
2866
2867 /*
2868 * Disable Clamshell (external display appeared)
2869 * We don't bother re-evaluating clamshell state. If the system is awake,
2870 * the lid is probably open.
2871 */
2872 if (msg & kIOPMDisableClamshell)
2873 {
2874 ignoringClamshell = true;
2875
2876 sendClientClamshellNotification();
2877 }
2878
2879 /*
2880 * Evaluate clamshell and SLEEP if appropiate
2881 */
2882 if ( eval_clamshell && shouldSleepOnClamshellClosed() )
2883 {
2884
2885
2886 // SLEEP!
2887 privateSleepSystem (kIOPMClamshellSleepKey);
2888 }
2889
2890 /*
2891 * Power Button
2892 */
2893 if (msg & kIOPMPowerButton)
2894 {
2895 // toggle state of sleep/wake
2896 // are we dozing?
2897 if ( getPowerState() == DOZE_STATE )
2898 {
2899 #ifndef __LP64__
2900 // yes, tell the tree we're waking
2901 systemWake();
2902 #endif
2903 // wake the Display Wrangler
2904 reportUserInput();
2905 }
2906 else {
2907 OSString *pbs = OSString::withCString("DisablePowerButtonSleep");
2908 // Check that power button sleep is enabled
2909 if( pbs ) {
2910 if( kOSBooleanTrue != getProperty(pbs))
2911 privateSleepSystem (kIOPMPowerButtonSleepKey);
2912 }
2913 }
2914 }
2915
2916 /*
2917 * Allow Sleep
2918 *
2919 */
2920 if ( (msg & kIOPMAllowSleep) && !allowSleep )
2921 {
2922 allowSleep = true;
2923 adjustPowerState();
2924 }
2925
2926 /*
2927 * Prevent Sleep
2928 *
2929 */
2930 if (msg & kIOPMPreventSleep) {
2931 allowSleep = false;
2932 // are we dozing?
2933 if ( getPowerState() == DOZE_STATE ) {
2934 #ifndef __LP64__
2935 // yes, tell the tree we're waking
2936 systemWake();
2937 #endif
2938 adjustPowerState();
2939 // wake the Display Wrangler
2940 reportUserInput();
2941 } else {
2942 adjustPowerState();
2943 // make sure we have power to clamp
2944 patriarch->wakeSystem();
2945 }
2946 }
2947 }
2948
2949
2950 //******************************************************************************
2951 // getSleepSupported
2952 //
2953 //******************************************************************************
2954
2955 IOOptionBits IOPMrootDomain::getSleepSupported( void )
2956 {
2957 return( platformSleepSupport );
2958 }
2959
2960
2961 //******************************************************************************
2962 // setSleepSupported
2963 //
2964 //******************************************************************************
2965
2966 void IOPMrootDomain::setSleepSupported( IOOptionBits flags )
2967 {
2968 DLOG("setSleepSupported(%x)\n", (uint32_t) flags);
2969 OSBitOrAtomic(flags, &platformSleepSupport);
2970 }
2971
2972
2973 //******************************************************************************
2974 // requestPowerDomainState
2975 //
2976 // The root domain intercepts this call to the superclass.
2977 // Called on the PM work loop thread.
2978 //
2979 // If the clamp bit is not set in the desire, then the child doesn't need the power
2980 // state it's requesting; it just wants it. The root ignores desires but not needs.
2981 // If the clamp bit is not set, the root takes it that the child can tolerate no
2982 // power and interprets the request accordingly. If all children can thus tolerate
2983 // no power, we are on our way to idle sleep.
2984 //******************************************************************************
2985
2986 IOReturn IOPMrootDomain::requestPowerDomainState (
2987 IOPMPowerFlags desiredFlags,
2988 IOPowerConnection * whichChild,
2989 unsigned long specification )
2990 {
2991 OSIterator *iter;
2992 OSObject *next;
2993 IOPowerConnection *connection;
2994 IOPMPowerFlags powerRequestFlag = 0;
2995 IOPMPowerFlags editedDesire;
2996
2997 ASSERT_GATED();
2998
2999 if (kIOLogPMRootDomain & gIOKitDebug)
3000 {
3001 IOService * powerChild =
3002 (IOService *) whichChild->getChildEntry(gIOPowerPlane);
3003 DLOG("child %p, flags %lx, spec %lx - %s\n",
3004 powerChild, desiredFlags, specification,
3005 powerChild ? powerChild->getName() : "?");
3006 }
3007
3008 // Force the child's input power requirements to 0 unless the prevent
3009 // idle-sleep flag is set. No input power flags map to our state 0.
3010 // Our power clamp (deviceDesire) keeps the minimum power state at 2.
3011
3012 if (desiredFlags & kIOPMPreventIdleSleep)
3013 editedDesire = kIOPMPreventIdleSleep | kIOPMPowerOn;
3014 else
3015 editedDesire = 0;
3016
3017 // Recompute sleep supported flag (doze if not supported)
3018 sleepIsSupported = true;
3019
3020 iter = getChildIterator(gIOPowerPlane);
3021 if ( iter )
3022 {
3023 while ( (next = iter->getNextObject()) )
3024 {
3025 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
3026 {
3027 // Ignore child that are in the process of joining.
3028 if (connection->getReadyFlag() == false)
3029 continue;
3030
3031 // Is this connection attached to the child that called
3032 // requestPowerDomainState()?
3033
3034 if (connection == whichChild)
3035 {
3036 // OR in the child's input power requirements.
3037 powerRequestFlag |= editedDesire;
3038
3039 if ( desiredFlags & kIOPMPreventSystemSleep )
3040 sleepIsSupported = false;
3041 }
3042 else
3043 {
3044 if (kIOLogPMRootDomain & gIOKitDebug)
3045 {
3046 IOService * powerChild =
3047 (IOService *) connection->getChildEntry(gIOPowerPlane);
3048 DLOG("child %p, state %ld, noIdle %d, noSleep %d - %s\n",
3049 powerChild,
3050 connection->getDesiredDomainState(),
3051 connection->getPreventIdleSleepFlag(),
3052 connection->getPreventSystemSleepFlag(),
3053 powerChild ? powerChild->getName() : "?");
3054 }
3055
3056 // OR in the child's desired power state (0 or ON_STATE).
3057 powerRequestFlag |= connection->getDesiredDomainState();
3058
3059 if ( connection->getPreventSystemSleepFlag() )
3060 sleepIsSupported = false;
3061 }
3062 }
3063 }
3064 iter->release();
3065 }
3066
3067 DLOG("childPowerFlags 0x%lx, extraSleepDelay %ld\n",
3068 powerRequestFlag, extraSleepDelay);
3069
3070 if ( !powerRequestFlag && !systemBooting )
3071 {
3072 if (!wrangler)
3073 {
3074 sleepASAP = false;
3075 changePowerStateToPriv(ON_STATE);
3076 if (idleSeconds)
3077 {
3078 // stay awake for at least idleSeconds
3079 startIdleSleepTimer(idleSeconds);
3080 }
3081 }
3082 else if (!extraSleepDelay && !idleSleepTimerPending)
3083 {
3084 sleepASAP = true;
3085 }
3086 }
3087
3088 // Drop our power clamp to SLEEP_STATE when all children became idle,
3089 // and the system sleep and display sleep values are equal.
3090
3091 adjustPowerState();
3092
3093 // If our power clamp has already dropped to SLEEP_STATE, and no child
3094 // is keeping us at ON_STATE, then this will trigger idle sleep.
3095
3096 editedDesire |= (desiredFlags & kIOPMPreventSystemSleep);
3097
3098 return super::requestPowerDomainState(
3099 editedDesire, whichChild, specification);
3100 }
3101
3102
3103 //******************************************************************************
3104 // handlePlatformHaltRestart
3105 //
3106 //******************************************************************************
3107
3108 struct HaltRestartApplierContext {
3109 IOPMrootDomain * RootDomain;
3110 unsigned long PowerState;
3111 IOPMPowerFlags PowerFlags;
3112 UInt32 MessageType;
3113 UInt32 Counter;
3114 };
3115
3116 static void
3117 platformHaltRestartApplier( OSObject * object, void * context )
3118 {
3119 IOPowerStateChangeNotification notify;
3120 HaltRestartApplierContext * ctx;
3121 AbsoluteTime startTime;
3122 UInt32 deltaTime;
3123
3124 ctx = (HaltRestartApplierContext *) context;
3125
3126 memset(&notify, 0, sizeof(notify));
3127 notify.powerRef = (void *)ctx->Counter;
3128 notify.returnValue = 0;
3129 notify.stateNumber = ctx->PowerState;
3130 notify.stateFlags = ctx->PowerFlags;
3131
3132 clock_get_uptime(&startTime);
3133 ctx->RootDomain->messageClient( ctx->MessageType, object, (void *)&notify );
3134 deltaTime = computeDeltaTimeMS(&startTime);
3135
3136 if ((deltaTime > kPMHaltTimeoutMS) || (gIOKitDebug & kIOLogDebugPower))
3137 {
3138 _IOServiceInterestNotifier * notifier;
3139 notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
3140
3141 // IOService children of IOPMrootDomain are not instrumented.
3142 // Only IORootParent currently falls under that group.
3143
3144 if (notifier)
3145 {
3146 KLOG("%s handler %p took %u ms\n",
3147 (ctx->MessageType == kIOMessageSystemWillPowerOff) ?
3148 "PowerOff" : "Restart",
3149 notifier->handler, (uint32_t) deltaTime );
3150 }
3151 }
3152
3153 ctx->Counter++;
3154 }
3155
3156 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type )
3157 {
3158 HaltRestartApplierContext ctx;
3159 AbsoluteTime startTime;
3160 UInt32 deltaTime;
3161
3162 memset(&ctx, 0, sizeof(ctx));
3163 ctx.RootDomain = this;
3164
3165 clock_get_uptime(&startTime);
3166 switch (pe_type)
3167 {
3168 case kPEHaltCPU:
3169 case kPEUPSDelayHaltCPU:
3170 ctx.PowerState = OFF_STATE;
3171 ctx.MessageType = kIOMessageSystemWillPowerOff;
3172 break;
3173
3174 case kPERestartCPU:
3175 ctx.PowerState = RESTART_STATE;
3176 ctx.MessageType = kIOMessageSystemWillRestart;
3177 break;
3178
3179 default:
3180 return;
3181 }
3182
3183 // Notify legacy clients
3184 applyToInterested(gIOPriorityPowerStateInterest, platformHaltRestartApplier, &ctx);
3185
3186 // For UPS shutdown leave File Server Mode intact, otherwise turn it off.
3187 if (kPEUPSDelayHaltCPU != pe_type)
3188 {
3189 const OSSymbol * setting = OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey);
3190 OSNumber * num = OSNumber::withNumber((unsigned long long) 0, 32);
3191 if (setting && num)
3192 {
3193 setPMSetting(setting, num);
3194 setting->release();
3195 num->release();
3196 }
3197 }
3198
3199 // Notify in power tree order
3200 notifySystemShutdown(this, ctx.MessageType);
3201
3202 deltaTime = computeDeltaTimeMS(&startTime);
3203 KLOG("%s all drivers took %u ms\n",
3204 (ctx.MessageType == kIOMessageSystemWillPowerOff) ?
3205 "PowerOff" : "Restart",
3206 (uint32_t) deltaTime );
3207 }
3208
3209
3210 //******************************************************************************
3211 // registerInterest
3212 //
3213 //******************************************************************************
3214
3215 IONotifier * IOPMrootDomain::registerInterest(
3216 const OSSymbol * typeOfInterest,
3217 IOServiceInterestHandler handler,
3218 void * target, void * ref )
3219 {
3220 IONotifier * notifier;
3221 bool isConfigd;
3222
3223 isConfigd = typeOfInterest &&
3224 typeOfInterest->isEqualTo(kIOPMPrivilegedPowerInterest);
3225
3226 if (isConfigd)
3227 typeOfInterest = gIOAppPowerStateInterest;
3228
3229 notifier = super::registerInterest(typeOfInterest, handler, target, ref);
3230
3231 #if ROOT_DOMAIN_RUN_STATES
3232 if (isConfigd && notifier && pmPowerStateQueue)
3233 {
3234 notifier->retain();
3235 if (pmPowerStateQueue->submitPowerEvent(
3236 kPowerEventConfigdRegisteredInterest, notifier) == false)
3237 notifier->release();
3238 }
3239 #endif
3240
3241 return notifier;
3242 }
3243
3244 static bool clientMessageFilter( OSObject * object, void * arg )
3245 {
3246 #if ROOT_DOMAIN_RUN_STATES
3247 #if LOG_INTEREST_CLIENTS
3248 IOPMInterestContext * context = (IOPMInterestContext *) arg;
3249 #endif
3250 bool allow = false;
3251
3252 switch (gMessageClientType)
3253 {
3254 case kMessageClientNone:
3255 allow = false;
3256 break;
3257
3258 case kMessageClientAll:
3259 allow = true;
3260 break;
3261
3262 case kMessageClientConfigd:
3263 allow = ((object == (OSObject *) gConfigdNotifier) ||
3264 (object == (OSObject *) gSysPowerDownNotifier));
3265 break;
3266 }
3267
3268 #if LOG_INTEREST_CLIENTS
3269 if (allow)
3270 DLOG("system message %x to %p\n",
3271 context->msgType, object);
3272 #endif
3273
3274 return allow;
3275 #else
3276 return true;
3277 #endif
3278 }
3279
3280
3281 //******************************************************************************
3282 // tellChangeDown
3283 //
3284 // We override the superclass implementation so we can send a different message
3285 // type to the client or application being notified.
3286 //******************************************************************************
3287
3288 bool IOPMrootDomain::tellChangeDown( unsigned long stateNum )
3289 {
3290 bool done;
3291
3292 DLOG("tellChangeDown %u->%u, R-state %u\n",
3293 (uint32_t) getPowerState(), (uint32_t) stateNum, runStateIndex);
3294
3295 switch ( stateNum ) {
3296 case DOZE_STATE:
3297 case SLEEP_STATE:
3298
3299 if (!ignoreChangeDown)
3300 {
3301 // Direct callout into OSKext so it can disable kext unloads
3302 // during sleep/wake to prevent deadlocks.
3303 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep );
3304
3305 if ( (SLEEP_STATE == stateNum) && sleepSupportedPEFunction )
3306 {
3307 // Reset PCI prevent sleep flag before calling platform driver.
3308 OSBitAndAtomic(~kPCICantSleep, &platformSleepSupport);
3309
3310 // Skip PCI check for maintenance sleep.
3311 if ((runStateFlags & kRStateFlagSuppressPCICheck) == 0)
3312 {
3313 // Determine if the machine supports sleep, or must doze.
3314 getPlatform()->callPlatformFunction(
3315 sleepSupportedPEFunction, false,
3316 NULL, NULL, NULL, NULL);
3317 }
3318
3319 // If the machine only supports doze, the callPlatformFunction call
3320 // boils down to IOPMrootDomain::setSleepSupported(kPCICantSleep),
3321 // otherwise nothing.
3322 }
3323
3324 // Update canSleep and kIOSleepSupportedKey property so drivers
3325 // can tell if platform is going to sleep versus doze.
3326
3327 #if CONFIG_SLEEP
3328 canSleep = true;
3329 #else
3330 canSleep = false;
3331 #endif
3332 if (!sleepIsSupported)
3333 canSleep = false;
3334 if (platformSleepSupport & kPCICantSleep)
3335 canSleep = false;
3336 setProperty(kIOSleepSupportedKey, canSleep);
3337 DLOG("canSleep %d\n", canSleep);
3338
3339 // Publish the new sleep-wake UUID
3340 publishSleepWakeUUID(true);
3341
3342 // Two change downs are sent by IOServicePM. Ignore the 2nd.
3343 ignoreChangeDown = true;
3344
3345 tracePoint( kIOPMTracePointSystemSleepAppsPhase);
3346 }
3347
3348 DLOG("kIOMessageSystemWillSleep (%d)\n", gMessageClientType);
3349 done = super::tellClientsWithResponse(
3350 kIOMessageSystemWillSleep, clientMessageFilter);
3351 break;
3352
3353 default:
3354 done = super::tellChangeDown(stateNum);
3355 break;
3356 }
3357 return done;
3358 }
3359
3360
3361 //******************************************************************************
3362 // askChangeDown
3363 //
3364 // We override the superclass implementation so we can send a different message
3365 // type to the client or application being notified.
3366 //
3367 // This must be idle sleep since we don't ask during any other power change.
3368 //******************************************************************************
3369
3370 bool IOPMrootDomain::askChangeDown( unsigned long stateNum )
3371 {
3372 DLOG("askChangeDown %u->%u, R-state %u\n",
3373 (uint32_t) getPowerState(), (uint32_t) stateNum, runStateIndex);
3374 DLOG("kIOMessageCanSystemSleep (%d)\n", gMessageClientType);
3375
3376 return super::tellClientsWithResponse(
3377 kIOMessageCanSystemSleep,
3378 clientMessageFilter);
3379 }
3380
3381
3382 //******************************************************************************
3383 // tellNoChangeDown
3384 //
3385 // Notify registered applications and kernel clients that we are not dropping
3386 // power.
3387 //
3388 // We override the superclass implementation so we can send a different message
3389 // type to the client or application being notified.
3390 //
3391 // This must be a vetoed idle sleep, since no other power change can be vetoed.
3392 //******************************************************************************
3393
3394 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum )
3395 {
3396 DLOG("tellNoChangeDown %u->%u, R-state %u\n",
3397 (uint32_t) getPowerState(), (uint32_t) stateNum, runStateIndex);
3398
3399 // Sleep canceled, clear the sleep trace point.
3400 tracePoint(kIOPMTracePointSystemUp);
3401
3402 if (idleSeconds && !wrangler)
3403 {
3404 // stay awake for at least idleSeconds
3405 sleepASAP = false;
3406 startIdleSleepTimer(idleSeconds);
3407 }
3408 DLOG("kIOMessageSystemWillNotSleep (%d)\n", gMessageClientType);
3409 return tellClients(kIOMessageSystemWillNotSleep, clientMessageFilter);
3410 }
3411
3412
3413 //******************************************************************************
3414 // tellChangeUp
3415 //
3416 // Notify registered applications and kernel clients that we are raising power.
3417 //
3418 // We override the superclass implementation so we can send a different message
3419 // type to the client or application being notified.
3420 //******************************************************************************
3421
3422 void IOPMrootDomain::tellChangeUp( unsigned long stateNum )
3423 {
3424 OSData *publishPMStats = NULL;
3425
3426 DLOG("tellChangeUp %u->%u, R-state %u\n",
3427 (uint32_t) getPowerState(), (uint32_t) stateNum, runStateIndex);
3428
3429 ignoreChangeDown = false;
3430
3431 if ( stateNum == ON_STATE )
3432 {
3433 // Direct callout into OSKext so it can disable kext unloads
3434 // during sleep/wake to prevent deadlocks.
3435 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn );
3436
3437 if (getPowerState() == ON_STATE)
3438 {
3439 // this is a quick wake from aborted sleep
3440 if (idleSeconds && !wrangler)
3441 {
3442 // stay awake for at least idleSeconds
3443 sleepASAP = false;
3444 startIdleSleepTimer(idleSeconds);
3445 }
3446 DLOG("kIOMessageSystemWillPowerOn (%d)\n", gMessageClientType);
3447 tellClients(kIOMessageSystemWillPowerOn, clientMessageFilter);
3448 }
3449 #if HIBERNATION
3450 else
3451 {
3452 IOHibernateSystemPostWake();
3453 }
3454 #endif
3455
3456 tracePoint(kIOPMTracePointSystemWakeAppsPhase);
3457 publishPMStats = OSData::withBytes(&pmStats, sizeof(pmStats));
3458 setProperty(kIOPMSleepStatisticsKey, publishPMStats);
3459 publishPMStats->release();
3460 bzero(&pmStats, sizeof(pmStats));
3461
3462 if (pmStatsAppResponses)
3463 {
3464 setProperty(kIOPMSleepStatisticsAppsKey, pmStatsAppResponses);
3465 pmStatsAppResponses->release();
3466 pmStatsAppResponses = OSArray::withCapacity(5);
3467 }
3468
3469 DLOG("kIOMessageSystemHasPoweredOn (%d)\n", gMessageClientType);
3470 tellClients(kIOMessageSystemHasPoweredOn, clientMessageFilter);
3471
3472 tracePoint(kIOPMTracePointSystemUp);
3473 }
3474 }
3475
3476
3477 //******************************************************************************
3478 // reportUserInput
3479 //
3480 //******************************************************************************
3481
3482 void IOPMrootDomain::reportUserInput( void )
3483 {
3484 #if !NO_KERNEL_HID
3485 OSIterator * iter;
3486
3487 if(!wrangler)
3488 {
3489 iter = getMatchingServices(serviceMatching("IODisplayWrangler"));
3490 if(iter)
3491 {
3492 wrangler = (IOService *) iter->getNextObject();
3493 iter->release();
3494 }
3495 }
3496
3497 if(wrangler)
3498 wrangler->activityTickle(0,0);
3499 #endif
3500 }
3501
3502
3503 //******************************************************************************
3504 // setQuickSpinDownTimeout
3505 //
3506 //******************************************************************************
3507
3508 void IOPMrootDomain::setQuickSpinDownTimeout( void )
3509 {
3510 ASSERT_GATED();
3511 setAggressiveness(
3512 kPMMinutesToSpinDown, 0, kAggressivesOptionQuickSpindownEnable );
3513 }
3514
3515
3516 //******************************************************************************
3517 // restoreUserSpinDownTimeout
3518 //
3519 //******************************************************************************
3520
3521 void IOPMrootDomain::restoreUserSpinDownTimeout( void )
3522 {
3523 ASSERT_GATED();
3524 setAggressiveness(
3525 kPMMinutesToSpinDown, 0, kAggressivesOptionQuickSpindownDisable );
3526 }
3527
3528
3529 //******************************************************************************
3530 // changePowerStateTo & changePowerStateToPriv
3531 //
3532 // Override of these methods for logging purposes.
3533 //******************************************************************************
3534
3535 IOReturn IOPMrootDomain::changePowerStateTo( unsigned long ordinal )
3536 {
3537 return kIOReturnUnsupported; // ignored
3538 }
3539
3540 IOReturn IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal )
3541 {
3542 DLOG("changePowerStateToPriv(%lu)\n", ordinal);
3543
3544 if ( (getPowerState() == DOZE_STATE) && (ordinal != ON_STATE) )
3545 {
3546 return kIOReturnSuccess;
3547 }
3548
3549 if ( (userDisabledAllSleep || systemBooting || systemShutdown) &&
3550 (ordinal == SLEEP_STATE) )
3551 {
3552 DLOG("SLEEP rejected, forced to ON state (UD %d, SB %d, SS %d)\n",
3553 userDisabledAllSleep, systemBooting, systemShutdown);
3554
3555 super::changePowerStateToPriv(ON_STATE);
3556 }
3557
3558 return super::changePowerStateToPriv(ordinal);
3559 }
3560
3561
3562 //******************************************************************************
3563 // updateRunState
3564 //
3565 //******************************************************************************
3566
3567 void IOPMrootDomain::updateRunState( uint32_t inRunState )
3568 {
3569 #if ROOT_DOMAIN_RUN_STATES
3570 if (inRunState < kRStateCount)
3571 {
3572 runStateIndex = nextRunStateIndex = inRunState;
3573 runStateFlags = gRStateFlags[inRunState];
3574
3575 setProperty(
3576 kIOPMRootDomainRunStateKey,
3577 (unsigned long long) inRunState, 32);
3578 }
3579 #endif
3580 }
3581
3582
3583 #if ROOT_DOMAIN_RUN_STATES
3584 //******************************************************************************
3585 // tagPowerPlaneService
3586 //
3587 // Running on PM work loop thread.
3588 //******************************************************************************
3589
3590 void IOPMrootDomain::tagPowerPlaneService(
3591 IOService * service,
3592 uint32_t * rdFlags )
3593 {
3594 *rdFlags = 0;
3595
3596 if (service->getProperty("IOPMStrictTreeOrder") ||
3597 service->metaCast("IODisplayWrangler") ||
3598 OSDynamicCast(OSNumber,
3599 service->getProperty("IOPMUnattendedWakePowerState")))
3600 {
3601 *rdFlags |= kServiceFlagGraphics;
3602 DLOG("tagged device %s %x\n", service->getName(), *rdFlags);
3603 }
3604
3605 // Locate the first PCI host bridge.
3606 if (!pciHostBridgeDevice && service->metaCast("IOPCIBridge"))
3607 {
3608 IOService * provider = service->getProvider();
3609 if (OSDynamicCast(IOPlatformDevice, provider) &&
3610 provider->inPlane(gIODTPlane))
3611 {
3612 pciHostBridgeDevice = provider;
3613 DLOG("PMTrace found PCI host bridge %s->%s\n",
3614 provider->getName(), service->getName());
3615 }
3616 }
3617
3618 // Tag top-level PCI devices. The order of PMinit() call does not
3619 // change across boots and is used as the PCI bit number.
3620 if (pciHostBridgeDevice && service->metaCast("IOPCIDevice"))
3621 {
3622 // Would prefer to check built-in property, but tagPowerPlaneService()
3623 // is called before pciDevice->registerService().
3624 IORegistryEntry * parent = service->getParentEntry(gIODTPlane);
3625 if ((parent == pciHostBridgeDevice) && service->getProperty("acpi-device"))
3626 {
3627 int bit = pmTracer->recordTopLevelPCIDevice( service );
3628 if (bit >= 0)
3629 {
3630 // Save the assigned bit for fast lookup.
3631 bit &= 0xff;
3632 *rdFlags |= (kServiceFlagTopLevelPCI | (bit << 8));
3633 }
3634 }
3635 }
3636 }
3637
3638
3639 //******************************************************************************
3640 // handleActivityTickleForService
3641 //
3642 // Called by IOService::activityTickle() for a tickle that is requesting the
3643 // service to raise power state. Called from driver thread.
3644 //******************************************************************************
3645
3646 void IOPMrootDomain::handleActivityTickleForService( IOService * service )
3647 {
3648 // Tickle directed to IODisplayWrangler while graphics is disabled.
3649 // Bring graphics online.
3650
3651 if ((service == wrangler) &&
3652 (runStateIndex > kRStateNormal) &&
3653 (false == wranglerTickled))
3654 {
3655 DLOG("display wrangler tickled\n");
3656 wranglerTickled = true;
3657 synchronizePowerTree();
3658 }
3659 }
3660
3661
3662 //******************************************************************************
3663 // handlePowerChangeStartForService
3664 //
3665 // Running on PM work loop thread.
3666 //******************************************************************************
3667
3668 void IOPMrootDomain::handlePowerChangeStartForService(
3669 IOService * service,
3670 uint32_t * rdFlags,
3671 uint32_t newPowerState,
3672 uint32_t changeFlags )
3673 {
3674 if (service == this)
3675 {
3676 uint32_t currentPowerState = (uint32_t) getPowerState();
3677 uint32_t nextRunStateFlags;
3678
3679 assert(nextRunStateIndex < kRStateCount);
3680 nextRunStateFlags = gRStateFlags[nextRunStateIndex];
3681
3682 gMessageClientType = kMessageClientNone;
3683
3684 // Transition towards or away from ON power state.
3685
3686 if ((currentPowerState != newPowerState) &&
3687 ((ON_STATE == newPowerState) || (ON_STATE == currentPowerState)))
3688 {
3689 if ((runStateFlags & kRStateFlagSuppressMessages) == 0)
3690 gMessageClientType = kMessageClientAll;
3691 else
3692 gMessageClientType = kMessageClientConfigd;
3693 }
3694
3695 // Transition caused by deassertion of system notification suppression.
3696
3697 if ((ON_STATE == newPowerState) &&
3698 (ON_STATE == currentPowerState) &&
3699 ((runStateFlags ^ nextRunStateFlags) & kRStateFlagSuppressMessages))
3700 {
3701 gMessageClientType = kMessageClientAll;
3702 }
3703
3704 if (ON_STATE == newPowerState)
3705 {
3706 DLOG("kIOMessageSystemWillPowerOn (%d)\n",
3707 gMessageClientType);
3708 tellClients(kIOMessageSystemWillPowerOn, clientMessageFilter);
3709 }
3710
3711 if (SLEEP_STATE == newPowerState)
3712 {
3713 tracePoint(kIOPMTracePointSleepStarted);
3714 }
3715 }
3716
3717 if (*rdFlags & kServiceFlagTopLevelPCI)
3718 {
3719 pmTracer->tracePCIPowerChange(
3720 PMTraceWorker::kPowerChangeStart,
3721 service, changeFlags,
3722 (*rdFlags >> 8) & 0xff);
3723 }
3724 }
3725
3726
3727 //******************************************************************************
3728 // handlePowerChangeDoneForService
3729 //
3730 // Running on PM work loop thread.
3731 //******************************************************************************
3732
3733 void IOPMrootDomain::handlePowerChangeDoneForService(
3734 IOService * service,
3735 uint32_t * rdFlags,
3736 uint32_t newPowerState,
3737 uint32_t changeFlags )
3738 {
3739 if (*rdFlags & kServiceFlagTopLevelPCI)
3740 {
3741 pmTracer->tracePCIPowerChange(
3742 PMTraceWorker::kPowerChangeCompleted,
3743 service, changeFlags,
3744 (*rdFlags >> 8) & 0xff);
3745 }
3746 }
3747
3748
3749 //******************************************************************************
3750 // overridePowerStateForService
3751 //
3752 // Runs on PM work loop thread.
3753 //******************************************************************************
3754
3755 void IOPMrootDomain::overridePowerStateForService(
3756 IOService * service,
3757 uint32_t * rdFlags,
3758 unsigned long * powerState,
3759 uint32_t changeFlags )
3760 {
3761 uint32_t inPowerState = (uint32_t) *powerState;
3762
3763 if ((service == this) && (inPowerState == ON_STATE) &&
3764 (changeFlags & kIOPMSynchronize))
3765 {
3766 DLOG("sync root domain %u->%u\n",
3767 (uint32_t) getPowerState(), inPowerState);
3768
3769 // Root Domain is in a reduced R-state, and a HID tickle has
3770 // requested a PM tree sync. Begin R-state transition.
3771
3772 if (runStateIndex != kRStateNormal)
3773 {
3774 nextRunStateIndex = kRStateNormal;
3775 setProperty(
3776 kIOPMRootDomainRunStateKey,
3777 (unsigned long long) kRStateNormal, 32);
3778 }
3779 }
3780
3781 if (*rdFlags & kServiceFlagGraphics)
3782 {
3783 DLOG("graphics device %s %u->%u (flags 0x%x)\n",
3784 service->getName(), (uint32_t) service->getPowerState(),
3785 inPowerState, changeFlags);
3786
3787 if (inPowerState == 0)
3788 {
3789 // Graphics device is powering down, apply limit preventing
3790 // device from powering back up later unless we consent.
3791
3792 if ((*rdFlags & kServiceFlagNoPowerUp) == 0)
3793 {
3794 *rdFlags |= kServiceFlagNoPowerUp;
3795 DLOG("asserted power limit for %s\n",
3796 service->getName());
3797 }
3798 }
3799 else
3800 {
3801 uint32_t nextRunStateFlags;
3802
3803 assert(nextRunStateIndex < kRStateCount);
3804 nextRunStateFlags = gRStateFlags[nextRunStateIndex];
3805
3806 // Graphics device is powering up. Release power limit at the
3807 // did-change machine state.
3808
3809 if (changeFlags & kIOPMSynchronize)
3810 {
3811 if ((runStateFlags & kRStateFlagSuppressGraphics) &&
3812 ((nextRunStateFlags & kRStateFlagSuppressGraphics) == 0) &&
3813 (changeFlags & kIOPMDomainDidChange))
3814 {
3815 // Woke up without graphics power, but
3816 // HID event has tickled display wrangler.
3817 *rdFlags &= ~kServiceFlagNoPowerUp;
3818 DLOG("removed power limit for %s\n",
3819 service->getName());
3820 }
3821 }
3822 else if ((runStateFlags & kRStateFlagSuppressGraphics) == 0)
3823 {
3824 *rdFlags &= ~kServiceFlagNoPowerUp;
3825 }
3826
3827 if (*rdFlags & kServiceFlagNoPowerUp)
3828 {
3829 DLOG("limited %s to power state 0\n",
3830 service->getName());
3831 *powerState = 0;
3832 }
3833 }
3834 }
3835 }
3836
3837
3838 //******************************************************************************
3839 // setMaintenanceWakeCalendar
3840 //
3841 //******************************************************************************
3842
3843 IOReturn IOPMrootDomain::setMaintenanceWakeCalendar(
3844 const IOPMCalendarStruct * calendar )
3845 {
3846 OSData * data;
3847 IOReturn ret;
3848
3849 if (!calendar)
3850 return kIOReturnBadArgument;
3851
3852 data = OSData::withBytesNoCopy((void *) calendar, sizeof(*calendar));
3853 if (!data)
3854 return kIOReturnNoMemory;
3855
3856 ret = setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey, data);
3857
3858 data->release();
3859 return ret;
3860 }
3861 #endif /* ROOT_DOMAIN_RUN_STATES */
3862
3863
3864 //******************************************************************************
3865 // sysPowerDownHandler
3866 //
3867 // Receives a notification when the RootDomain changes state.
3868 //
3869 // Allows us to take action on system sleep, power down, and restart after
3870 // applications have received their power change notifications and replied,
3871 // but before drivers have powered down. We perform a vfs sync on power down.
3872 //******************************************************************************
3873
3874 IOReturn IOPMrootDomain::sysPowerDownHandler( void * target, void * refCon,
3875 UInt32 messageType, IOService * service,
3876 void * messageArgument, vm_size_t argSize )
3877 {
3878 IOReturn ret;
3879 IOPowerStateChangeNotification *params = (IOPowerStateChangeNotification *) messageArgument;
3880 IOPMrootDomain *rootDomain = OSDynamicCast(IOPMrootDomain, service);
3881
3882 DLOG("sysPowerDownHandler message %x\n", (uint32_t) messageType);
3883
3884 if(!rootDomain)
3885 return kIOReturnUnsupported;
3886
3887 switch (messageType) {
3888 case kIOMessageSystemWillSleep:
3889 // Interested applications have been notified of an impending power
3890 // change and have acked (when applicable).
3891 // This is our chance to save whatever state we can before powering
3892 // down.
3893 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
3894 // via callout
3895
3896 // We will ack within 20 seconds
3897 params->returnValue = 20 * 1000 * 1000;
3898 #if HIBERNATION
3899 if (gIOHibernateState)
3900 params->returnValue += gIOHibernateFreeTime * 1000; //add in time we could spend freeing pages
3901 #endif
3902
3903 if ( ! OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending ) )
3904 {
3905 // Purposely delay the ack and hope that shutdown occurs quickly.
3906 // Another option is not to schedule the thread and wait for
3907 // ack timeout...
3908 AbsoluteTime deadline;
3909 clock_interval_to_deadline( 30, kSecondScale, &deadline );
3910 thread_call_enter1_delayed( rootDomain->diskSyncCalloutEntry,
3911 (thread_call_param_t)params->powerRef,
3912 deadline );
3913 }
3914 else
3915 thread_call_enter1(rootDomain->diskSyncCalloutEntry, (thread_call_param_t)params->powerRef);
3916 ret = kIOReturnSuccess;
3917 break;
3918
3919 case kIOMessageSystemWillPowerOff:
3920 case kIOMessageSystemWillRestart:
3921 ret = kIOReturnUnsupported;
3922 break;
3923
3924 default:
3925 ret = kIOReturnUnsupported;
3926 break;
3927 }
3928 return ret;
3929 }
3930
3931 //******************************************************************************
3932 // publishSleepWakeUUID
3933 //
3934 //
3935 //******************************************************************************
3936 void IOPMrootDomain::publishSleepWakeUUID( bool shouldPublish )
3937 {
3938 if (shouldPublish)
3939 {
3940 if (queuedSleepWakeUUIDString)
3941 {
3942 if (OSCompareAndSwap(/*old*/ true, /*new*/ false, &gSleepWakeUUIDIsSet))
3943 {
3944 // Upon wake, it takes some time for userland to invalidate the
3945 // UUID. If another sleep is initiated during that period, force
3946 // a CLEAR message to balance the upcoming SET message.
3947
3948 messageClients( kIOPMMessageSleepWakeUUIDChange,
3949 kIOPMMessageSleepWakeUUIDCleared );
3950
3951 DLOG("SleepWake UUID forced clear\n");
3952 }
3953
3954 setProperty(kIOPMSleepWakeUUIDKey, queuedSleepWakeUUIDString);
3955 DLOG("SleepWake UUID published: %s\n", queuedSleepWakeUUIDString->getCStringNoCopy());
3956 queuedSleepWakeUUIDString->release();
3957 queuedSleepWakeUUIDString = NULL;
3958 messageClients(kIOPMMessageSleepWakeUUIDChange,
3959 kIOPMMessageSleepWakeUUIDSet);
3960 }
3961 } else {
3962 if (OSCompareAndSwap(/*old*/ true, /*new*/ false, &gSleepWakeUUIDIsSet))
3963 {
3964 DLOG("SleepWake UUID cleared\n");
3965 removeProperty(kIOPMSleepWakeUUIDKey);
3966 messageClients(kIOPMMessageSleepWakeUUIDChange,
3967 kIOPMMessageSleepWakeUUIDCleared);
3968 }
3969 }
3970 }
3971
3972
3973 //******************************************************************************
3974 // displayWranglerNotification
3975 //
3976 // Receives a notification when the IODisplayWrangler changes state.
3977 //
3978 // Allows us to take action on display dim/undim.
3979 //
3980 // When the display sleeps we:
3981 // - Start the idle sleep timer
3982 // - set the quick spin down timeout
3983 //
3984 // On wake from display sleep:
3985 // - Cancel the idle sleep timer
3986 // - restore the user's chosen spindown timer from the "quick" spin down value
3987 //******************************************************************************
3988
3989 IOReturn IOPMrootDomain::displayWranglerNotification(
3990 void * target, void * refCon,
3991 UInt32 messageType, IOService * service,
3992 void * messageArgument, vm_size_t argSize )
3993 {
3994 #if !NO_KERNEL_HID
3995 int displayPowerState;
3996 IOPowerStateChangeNotification * params =
3997 (IOPowerStateChangeNotification *) messageArgument;
3998
3999 if ((messageType != kIOMessageDeviceWillPowerOff) &&
4000 (messageType != kIOMessageDeviceHasPoweredOn))
4001 return kIOReturnUnsupported;
4002
4003 ASSERT_GATED();
4004 if (!gRootDomain)
4005 return kIOReturnUnsupported;
4006
4007 displayPowerState = params->stateNumber;
4008 DLOG("DisplayWrangler message 0x%x, new power state %d\n",
4009 (uint32_t) messageType, displayPowerState);
4010
4011 switch (messageType) {
4012 case kIOMessageDeviceWillPowerOff:
4013
4014 // The display wrangler has dropped power because of idle display sleep
4015 // or force system sleep.
4016 //
4017 // 4 Display ON
4018 // 3 Display Dim
4019 // 2 Display Sleep
4020 // 1 Not visible to user
4021 // 0 Not visible to user
4022
4023 if (gRootDomain->wranglerAsleep || (displayPowerState > 2))
4024 break;
4025
4026 // Record the time the display wrangler went to sleep.
4027
4028 gRootDomain->wranglerAsleep = true;
4029 clock_get_uptime(&gRootDomain->wranglerSleepTime);
4030
4031 // We start a timer here if the System Sleep timer is greater than the
4032 // Display Sleep timer. We kick off this timer when the display sleeps.
4033 //
4034 // Note that, although Display Dim timings may change adaptively accordingly
4035 // to the user's activity patterns, Display Sleep _always_ occurs at the
4036 // specified interval since last user activity.
4037
4038 if ( gRootDomain->extraSleepDelay )
4039 {
4040 gRootDomain->startIdleSleepTimer(gRootDomain->extraSleepDelay * 60);
4041 }
4042 else if ( gRootDomain->sleepSlider )
4043 {
4044 // Accelerate disk spindown if system sleep and display sleep
4045 // sliders are set to the same value (e.g. both set to 5 min),
4046 // and display is about to go dark. Check that spin down timer
4047 // is non-zero (zero = never spin down) and system sleep is
4048 // not set to never sleep.
4049
4050 gRootDomain->setQuickSpinDownTimeout();
4051 }
4052
4053 break;
4054
4055 case kIOMessageDeviceHasPoweredOn:
4056
4057 // The display wrangler has powered on either because of user activity
4058 // or wake from sleep/doze.
4059
4060 if ( 4 != displayPowerState )
4061 break;
4062
4063 gRootDomain->wranglerAsleep = false;
4064 gRootDomain->adjustPowerState();
4065 gRootDomain->cancelIdleSleepTimer();
4066
4067 // Change the spindown value back to the user's selection from our
4068 // accelerated setting.
4069 gRootDomain->restoreUserSpinDownTimeout();
4070
4071 break;
4072
4073 default:
4074 break;
4075 }
4076 #endif
4077 return kIOReturnUnsupported;
4078 }
4079
4080
4081 //******************************************************************************
4082 // displayWranglerPublished
4083 //
4084 // Receives a notification when the IODisplayWrangler is published.
4085 // When it's published we install a power state change handler.
4086 //******************************************************************************
4087
4088 bool IOPMrootDomain::displayWranglerPublished(
4089 void * target,
4090 void * refCon,
4091 IOService * newService)
4092 {
4093 #if !NO_KERNEL_HID
4094 if(!gRootDomain)
4095 return false;
4096
4097 gRootDomain->wrangler = newService;
4098
4099 // we found the display wrangler, now install a handler
4100 if( !gRootDomain->wrangler->registerInterest( gIOGeneralInterest,
4101 &displayWranglerNotification, target, 0) )
4102 {
4103 return false;
4104 }
4105 #endif
4106 return true;
4107 }
4108
4109
4110 //******************************************************************************
4111 // batteryPublished
4112 //
4113 // Notification on battery class IOPowerSource appearance
4114 //******************************************************************************
4115
4116 bool IOPMrootDomain::batteryPublished(
4117 void * target,
4118 void * root_domain,
4119 IOService * resourceService )
4120 {
4121 // rdar://2936060&4435589
4122 // All laptops have dimmable LCD displays
4123 // All laptops have batteries
4124 // So if this machine has a battery, publish the fact that the backlight
4125 // supports dimming.
4126 ((IOPMrootDomain *)root_domain)->publishFeature("DisplayDims");
4127
4128 return (true);
4129 }
4130
4131
4132 //******************************************************************************
4133 // adjustPowerState
4134 //
4135 // Some condition that affects our wake/sleep/doze decision has changed.
4136 //
4137 // If the sleep slider is in the off position, we cannot sleep or doze.
4138 // If the enclosure is open, we cannot sleep or doze.
4139 // If the system is still booting, we cannot sleep or doze.
4140 //
4141 // In those circumstances, we prevent sleep and doze by holding power on with
4142 // changePowerStateToPriv(ON).
4143 //
4144 // If the above conditions do not exist, and also the sleep timer has expired,
4145 // we allow sleep or doze to occur with either changePowerStateToPriv(SLEEP) or
4146 // changePowerStateToPriv(DOZE) depending on whether or not we already know the
4147 // platform cannot sleep.
4148 //
4149 // In this case, sleep or doze will either occur immediately or at the next time
4150 // that no children are holding the system out of idle sleep via the
4151 // kIOPMPreventIdleSleep flag in their power state arrays.
4152 //******************************************************************************
4153
4154 void IOPMrootDomain::adjustPowerState( void )
4155 {
4156 DLOG("adjustPowerState "
4157 "PS %u, ASAP %d, SL %ld, AS %d, SB %d, SS %d, UD %d\n",
4158 (uint32_t) getPowerState(), sleepASAP, sleepSlider,
4159 allowSleep, systemBooting, systemShutdown, userDisabledAllSleep);
4160
4161 ASSERT_GATED();
4162
4163 if ( (sleepSlider == 0)
4164 || !allowSleep
4165 || systemBooting
4166 || systemShutdown
4167 || userDisabledAllSleep
4168 || (runStateFlags & kRStateFlagDisableIdleSleep) )
4169 {
4170 changePowerStateToPriv(ON_STATE);
4171 } else {
4172 if ( sleepASAP )
4173 {
4174 /* Convenient place to run any code at idle sleep time
4175 * IOPMrootDomain initiates an idle sleep here
4176 *
4177 * Set last sleep cause accordingly.
4178 */
4179 setProperty(kRootDomainSleepReasonKey, kIOPMIdleSleepKey);
4180
4181 sleepASAP = false;
4182 changePowerStateToPriv(SLEEP_STATE);
4183 }
4184 }
4185 }
4186
4187 void IOPMrootDomain::pmStatsRecordEvent(
4188 int eventIndex,
4189 AbsoluteTime timestamp)
4190 {
4191 bool starting = eventIndex & kIOPMStatsEventStartFlag ? true:false;
4192 bool stopping = eventIndex & kIOPMStatsEventStopFlag ? true:false;
4193 uint64_t delta;
4194 uint64_t nsec;
4195
4196 eventIndex &= ~(kIOPMStatsEventStartFlag | kIOPMStatsEventStopFlag);
4197
4198 absolutetime_to_nanoseconds(timestamp, &nsec);
4199
4200 switch (eventIndex) {
4201 case kIOPMStatsHibernateImageWrite:
4202 if (starting)
4203 pmStats.hibWrite.start = nsec;
4204 else if (stopping)
4205 pmStats.hibWrite.stop = nsec;
4206
4207 if (stopping) {
4208 delta = pmStats.hibWrite.stop - pmStats.hibWrite.start;
4209 IOLog("PMStats: Hibernate write took %qd ms\n", delta/1000000ULL);
4210 }
4211 break;
4212 case kIOPMStatsHibernateImageRead:
4213 if (starting)
4214 pmStats.hibRead.start = nsec;
4215 else if (stopping)
4216 pmStats.hibRead.stop = nsec;
4217
4218 if (stopping) {
4219 delta = pmStats.hibRead.stop - pmStats.hibRead.start;
4220 IOLog("PMStats: Hibernate read took %qd ms\n", delta/1000000ULL);
4221 }
4222 break;
4223 }
4224 }
4225
4226 /*
4227 * Appends a record of the application response to
4228 * IOPMrootDomain::pmStatsAppResponses
4229 */
4230 void IOPMrootDomain::pmStatsRecordApplicationResponse(
4231 const OSSymbol *response,
4232 const char *name,
4233 int messageType,
4234 uint32_t delay_ms,
4235 int app_pid)
4236 {
4237 OSDictionary *responseDescription = NULL;
4238 OSNumber *delayNum = NULL;
4239 OSNumber *pidNum = NULL;
4240 OSNumber *msgNum = NULL;
4241 const OSSymbol *appname;
4242 const OSSymbol *entryName;
4243 OSObject *entryType;
4244 int i;
4245
4246 if (!pmStatsAppResponses || pmStatsAppResponses->getCount() > 50)
4247 return;
4248
4249 i = 0;
4250 while ((responseDescription = (OSDictionary *) pmStatsAppResponses->getObject(i++)))
4251 {
4252 entryType = responseDescription->getObject(_statsResponseTypeKey);
4253 entryName = (OSSymbol *) responseDescription->getObject(_statsNameKey);
4254 if (entryName && (entryType == response) && entryName->isEqualTo(name))
4255 {
4256 OSNumber * entryValue;
4257 entryValue = (OSNumber *) responseDescription->getObject(_statsTimeMSKey);
4258 if (entryValue && (entryValue->unsigned32BitValue() < delay_ms))
4259 entryValue->setValue(delay_ms);
4260 return;
4261 }
4262 }
4263
4264 responseDescription = OSDictionary::withCapacity(5);
4265 if (responseDescription)
4266 {
4267 if (response) {
4268 responseDescription->setObject(_statsResponseTypeKey, response);
4269 }
4270
4271 if (messageType != 0) {
4272 msgNum = OSNumber::withNumber(messageType, 32);
4273 if (msgNum) {
4274 responseDescription->setObject(_statsMessageTypeKey, msgNum);
4275 msgNum->release();
4276 }
4277 }
4278
4279 if (name && (strlen(name) > 0))
4280 {
4281 appname = OSSymbol::withCString(name);
4282 if (appname) {
4283 responseDescription->setObject(_statsNameKey, appname);
4284 appname->release();
4285 }
4286 }
4287
4288 if (app_pid != -1) {
4289 pidNum = OSNumber::withNumber(app_pid, 32);
4290 if (pidNum) {
4291 responseDescription->setObject(_statsPIDKey, pidNum);
4292 pidNum->release();
4293 }
4294 }
4295
4296 delayNum = OSNumber::withNumber(delay_ms, 32);
4297 if (delayNum) {
4298 responseDescription->setObject(_statsTimeMSKey, delayNum);
4299 delayNum->release();
4300 }
4301
4302 if (pmStatsAppResponses) {
4303 pmStatsAppResponses->setObject(responseDescription);
4304 }
4305
4306 responseDescription->release();
4307 }
4308 return;
4309 }
4310
4311
4312 //******************************************************************************
4313 // TracePoint support
4314 //
4315 //******************************************************************************
4316
4317 #define kIOPMRegisterNVRAMTracePointHandlerKey \
4318 "IOPMRegisterNVRAMTracePointHandler"
4319
4320 IOReturn IOPMrootDomain::callPlatformFunction(
4321 const OSSymbol * functionName,
4322 bool waitForFunction,
4323 void * param1, void * param2,
4324 void * param3, void * param4 )
4325 {
4326 if (pmTracer && functionName &&
4327 functionName->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey) &&
4328 !pmTracer->tracePointHandler && !pmTracer->tracePointTarget)
4329 {
4330 uint32_t tracePointPhases, tracePointPCI;
4331 uint64_t statusCode;
4332
4333 pmTracer->tracePointHandler = (IOPMTracePointHandler) param1;
4334 pmTracer->tracePointTarget = (void *) param2;
4335 tracePointPCI = (uint32_t)(uintptr_t) param3;
4336 tracePointPhases = (uint32_t)(uintptr_t) param4;
4337 statusCode = (((uint64_t)tracePointPCI) << 32) | tracePointPhases;
4338 if ((tracePointPhases >> 24) != kIOPMTracePointSystemUp)
4339 {
4340 LOG("Sleep failure code 0x%08x 0x%08x\n",
4341 tracePointPCI, tracePointPhases);
4342 }
4343 setProperty(kIOPMSleepWakeFailureCodeKey, statusCode, 64);
4344 pmTracer->tracePointHandler( pmTracer->tracePointTarget, 0, 0 );
4345
4346 return kIOReturnSuccess;
4347 }
4348
4349 return super::callPlatformFunction(
4350 functionName, waitForFunction, param1, param2, param3, param4);
4351 }
4352
4353 void IOPMrootDomain::tracePoint( uint8_t point )
4354 {
4355 pmTracer->tracePoint(point);
4356 }
4357
4358 //******************************************************************************
4359 // PMTraceWorker Class
4360 //
4361 //******************************************************************************
4362
4363 #undef super
4364 #define super OSObject
4365 OSDefineMetaClassAndStructors(PMTraceWorker, OSObject)
4366
4367 #define kPMBestGuessPCIDevicesCount 25
4368 #define kPMMaxRTCBitfieldSize 32
4369
4370 PMTraceWorker *PMTraceWorker::tracer(IOPMrootDomain *owner)
4371 {
4372 PMTraceWorker *me;
4373
4374 me = OSTypeAlloc( PMTraceWorker );
4375 if (!me || !me->init())
4376 {
4377 return NULL;
4378 }
4379
4380 DLOG("PMTraceWorker %p\n", me);
4381
4382 // Note that we cannot instantiate the PCI device -> bit mappings here, since
4383 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
4384 // this dictionary lazily.
4385 me->owner = owner;
4386 me->pciDeviceBitMappings = NULL;
4387 me->pciMappingLock = IOLockAlloc();
4388 me->tracePhase = kIOPMTracePointSystemUp;
4389 me->loginWindowPhase = 0;
4390 me->pciBusyBitMask = 0;
4391 return me;
4392 }
4393
4394 void PMTraceWorker::RTC_TRACE(void)
4395 {
4396 if (tracePointHandler && tracePointTarget)
4397 {
4398 uint32_t wordA;
4399
4400 wordA = tracePhase; // destined for bits 24-31
4401 wordA <<= 8;
4402 wordA |= loginWindowPhase; // destined for bits 16-23
4403 wordA <<= 16;
4404
4405 tracePointHandler( tracePointTarget, pciBusyBitMask, wordA );
4406 DLOG("RTC_TRACE wrote 0x%08x 0x%08x\n", pciBusyBitMask, wordA);
4407 }
4408 }
4409
4410 int PMTraceWorker::recordTopLevelPCIDevice(IOService * pciDevice)
4411 {
4412 const OSSymbol * deviceName;
4413 int index = -1;
4414
4415 IOLockLock(pciMappingLock);
4416
4417 if (!pciDeviceBitMappings)
4418 {
4419 pciDeviceBitMappings = OSArray::withCapacity(kPMBestGuessPCIDevicesCount);
4420 if (!pciDeviceBitMappings)
4421 goto exit;
4422 }
4423
4424 // Check for bitmask overflow.
4425 if (pciDeviceBitMappings->getCount() >= kPMMaxRTCBitfieldSize)
4426 goto exit;
4427
4428 if ((deviceName = pciDevice->copyName()) &&
4429 (pciDeviceBitMappings->getNextIndexOfObject(deviceName, 0) == (unsigned int)-1) &&
4430 pciDeviceBitMappings->setObject(deviceName))
4431 {
4432 index = pciDeviceBitMappings->getCount() - 1;
4433 DLOG("PMTrace PCI array: set object %s => %d\n",
4434 deviceName->getCStringNoCopy(), index);
4435 }
4436 if (deviceName)
4437 deviceName->release();
4438 if (!addedToRegistry && (index >= 0))
4439 addedToRegistry = owner->setProperty("PCITopLevel", this);
4440
4441 exit:
4442 IOLockUnlock(pciMappingLock);
4443 return index;
4444 }
4445
4446 bool PMTraceWorker::serialize(OSSerialize *s) const
4447 {
4448 bool ok = false;
4449 if (pciDeviceBitMappings)
4450 {
4451 IOLockLock(pciMappingLock);
4452 ok = pciDeviceBitMappings->serialize(s);
4453 IOLockUnlock(pciMappingLock);
4454 }
4455 return ok;
4456 }
4457
4458 void PMTraceWorker::tracePoint(uint8_t phase)
4459 {
4460 tracePhase = phase;
4461
4462 DLOG("IOPMrootDomain: trace point 0x%02x\n", tracePhase);
4463 RTC_TRACE();
4464 }
4465
4466 void PMTraceWorker::traceLoginWindowPhase(uint8_t phase)
4467 {
4468 loginWindowPhase = phase;
4469
4470 DLOG("IOPMrootDomain: loginwindow tracepoint 0x%02x\n", loginWindowPhase);
4471 RTC_TRACE();
4472 }
4473
4474 void PMTraceWorker::tracePCIPowerChange(
4475 change_t type, IOService *service, uint32_t changeFlags, uint32_t bitNum)
4476 {
4477 uint32_t bitMask;
4478 uint32_t expectedFlag;
4479
4480 // Ignore PCI changes outside of system sleep/wake.
4481 if ((kIOPMTracePointSystemSleepDriversPhase != tracePhase) &&
4482 (kIOPMTracePointSystemWakeDriversPhase != tracePhase))
4483 return;
4484
4485 // Only record the WillChange transition when going to sleep,
4486 // and the DidChange on the way up.
4487 changeFlags &= (kIOPMDomainWillChange | kIOPMDomainDidChange);
4488 expectedFlag = (kIOPMTracePointSystemSleepDriversPhase == tracePhase) ?
4489 kIOPMDomainWillChange : kIOPMDomainDidChange;
4490 if (changeFlags != expectedFlag)
4491 return;
4492
4493 // Mark this device off in our bitfield
4494 if (bitNum < kPMMaxRTCBitfieldSize)
4495 {
4496 bitMask = (1 << bitNum);
4497
4498 if (kPowerChangeStart == type)
4499 {
4500 pciBusyBitMask |= bitMask;
4501 DLOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
4502 service->getName(), bitNum, bitMask, pciBusyBitMask);
4503 }
4504 else
4505 {
4506 pciBusyBitMask &= ~bitMask;
4507 DLOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
4508 service->getName(), bitNum, bitMask, pciBusyBitMask);
4509 }
4510
4511 RTC_TRACE();
4512 }
4513 }
4514
4515
4516 //******************************************************************************
4517 // PMHaltWorker Class
4518 //
4519 //******************************************************************************
4520
4521 static unsigned int gPMHaltBusyCount;
4522 static unsigned int gPMHaltIdleCount;
4523 static int gPMHaltDepth;
4524 static unsigned long gPMHaltEvent;
4525 static IOLock * gPMHaltLock = 0;
4526 static OSArray * gPMHaltArray = 0;
4527 static const OSSymbol * gPMHaltClientAcknowledgeKey = 0;
4528
4529 PMHaltWorker * PMHaltWorker::worker( void )
4530 {
4531 PMHaltWorker * me;
4532 IOThread thread;
4533
4534 do {
4535 me = OSTypeAlloc( PMHaltWorker );
4536 if (!me || !me->init())
4537 break;
4538
4539 me->lock = IOLockAlloc();
4540 if (!me->lock)
4541 break;
4542
4543 DLOG("PMHaltWorker %p\n", me);
4544 me->retain(); // thread holds extra retain
4545 if (KERN_SUCCESS != kernel_thread_start(&PMHaltWorker::main, (void *) me, &thread))
4546 {
4547 me->release();
4548 break;
4549 }
4550 thread_deallocate(thread);
4551 return me;
4552
4553 } while (false);
4554
4555 if (me) me->release();
4556 return 0;
4557 }
4558
4559 void PMHaltWorker::free( void )
4560 {
4561 DLOG("PMHaltWorker free %p\n", this);
4562 if (lock)
4563 {
4564 IOLockFree(lock);
4565 lock = 0;
4566 }
4567 return OSObject::free();
4568 }
4569
4570 void PMHaltWorker::main( void * arg, wait_result_t waitResult )
4571 {
4572 PMHaltWorker * me = (PMHaltWorker *) arg;
4573
4574 IOLockLock( gPMHaltLock );
4575 gPMHaltBusyCount++;
4576 me->depth = gPMHaltDepth;
4577 IOLockUnlock( gPMHaltLock );
4578
4579 while (me->depth >= 0)
4580 {
4581 PMHaltWorker::work( me );
4582
4583 IOLockLock( gPMHaltLock );
4584 if (++gPMHaltIdleCount >= gPMHaltBusyCount)
4585 {
4586 // This is the last thread to finish work on this level,
4587 // inform everyone to start working on next lower level.
4588 gPMHaltDepth--;
4589 me->depth = gPMHaltDepth;
4590 gPMHaltIdleCount = 0;
4591 thread_wakeup((event_t) &gPMHaltIdleCount);
4592 }
4593 else
4594 {
4595 // One or more threads are still working on this level,
4596 // this thread must wait.
4597 me->depth = gPMHaltDepth - 1;
4598 do {
4599 IOLockSleep(gPMHaltLock, &gPMHaltIdleCount, THREAD_UNINT);
4600 } while (me->depth != gPMHaltDepth);
4601 }
4602 IOLockUnlock( gPMHaltLock );
4603 }
4604
4605 // No more work to do, terminate thread
4606 DLOG("All done for worker: %p (visits = %u)\n", me, me->visits);
4607 thread_wakeup( &gPMHaltDepth );
4608 me->release();
4609 }
4610
4611 void PMHaltWorker::work( PMHaltWorker * me )
4612 {
4613 IOService * service;
4614 OSSet * inner;
4615 AbsoluteTime startTime;
4616 UInt32 deltaTime;
4617 bool timeout;
4618
4619 while (true)
4620 {
4621 service = 0;
4622 timeout = false;
4623
4624 // Claim an unit of work from the shared pool
4625 IOLockLock( gPMHaltLock );
4626 inner = (OSSet *)gPMHaltArray->getObject(me->depth);
4627 if (inner)
4628 {
4629 service = (IOService *)inner->getAnyObject();
4630 if (service)
4631 {
4632 service->retain();
4633 inner->removeObject(service);
4634 }
4635 }
4636 IOLockUnlock( gPMHaltLock );
4637 if (!service)
4638 break; // no more work at this depth
4639
4640 clock_get_uptime(&startTime);
4641
4642 if (!service->isInactive() &&
4643 service->setProperty(gPMHaltClientAcknowledgeKey, me))
4644 {
4645 IOLockLock(me->lock);
4646 me->startTime = startTime;
4647 me->service = service;
4648 me->timeout = false;
4649 IOLockUnlock(me->lock);
4650
4651 service->systemWillShutdown( gPMHaltEvent );
4652
4653 // Wait for driver acknowledgement
4654 IOLockLock(me->lock);
4655 while (service->getProperty(gPMHaltClientAcknowledgeKey))
4656 {
4657 IOLockSleep(me->lock, me, THREAD_UNINT);
4658 }
4659 me->service = 0;
4660 timeout = me->timeout;
4661 IOLockUnlock(me->lock);
4662 }
4663
4664 deltaTime = computeDeltaTimeMS(&startTime);
4665 if ((deltaTime > kPMHaltTimeoutMS) || timeout ||
4666 (gIOKitDebug & (kIOLogDebugPower | kIOLogPMRootDomain)))
4667 {
4668 KLOG("%s driver %s (%p) took %u ms\n",
4669 (gPMHaltEvent == kIOMessageSystemWillPowerOff) ?
4670 "PowerOff" : "Restart",
4671 service->getName(), service,
4672 (uint32_t) deltaTime );
4673 }
4674
4675 service->release();
4676 me->visits++;
4677 }
4678 }
4679
4680 void PMHaltWorker::checkTimeout( PMHaltWorker * me, AbsoluteTime * now )
4681 {
4682 UInt64 nano;
4683 AbsoluteTime startTime;
4684 AbsoluteTime endTime;
4685
4686 endTime = *now;
4687
4688 IOLockLock(me->lock);
4689 if (me->service && !me->timeout)
4690 {
4691 startTime = me->startTime;
4692 nano = 0;
4693 if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0)
4694 {
4695 SUB_ABSOLUTETIME(&endTime, &startTime);
4696 absolutetime_to_nanoseconds(endTime, &nano);
4697 }
4698 if (nano > 3000000000ULL)
4699 {
4700 me->timeout = true;
4701 LOG("%s still waiting on %s\n",
4702 (gPMHaltEvent == kIOMessageSystemWillPowerOff) ?
4703 "PowerOff" : "Restart",
4704 me->service->getName());
4705 }
4706 }
4707 IOLockUnlock(me->lock);
4708 }
4709
4710
4711 //******************************************************************************
4712 // acknowledgeSystemWillShutdown
4713 //
4714 // Acknowledgement from drivers that they have prepared for shutdown/restart.
4715 //******************************************************************************
4716
4717 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService * from )
4718 {
4719 PMHaltWorker * worker;
4720 OSObject * prop;
4721
4722 if (!from)
4723 return;
4724
4725 //DLOG("%s acknowledged\n", from->getName());
4726 prop = from->copyProperty( gPMHaltClientAcknowledgeKey );
4727 if (prop)
4728 {
4729 worker = (PMHaltWorker *) prop;
4730 IOLockLock(worker->lock);
4731 from->removeProperty( gPMHaltClientAcknowledgeKey );
4732 thread_wakeup((event_t) worker);
4733 IOLockUnlock(worker->lock);
4734 worker->release();
4735 }
4736 else
4737 {
4738 DLOG("%s acknowledged without worker property\n",
4739 from->getName());
4740 }
4741 }
4742
4743
4744 //******************************************************************************
4745 // notifySystemShutdown
4746 //
4747 // Notify all objects in PM tree that system will shutdown or restart
4748 //******************************************************************************
4749
4750 static void
4751 notifySystemShutdown( IOService * root, unsigned long event )
4752 {
4753 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
4754 IORegistryIterator * iter;
4755 IORegistryEntry * entry;
4756 IOService * node;
4757 OSSet * inner;
4758 PMHaltWorker * workers[kPMHaltMaxWorkers];
4759 AbsoluteTime deadline;
4760 unsigned int totalNodes = 0;
4761 unsigned int depth;
4762 unsigned int rootDepth;
4763 unsigned int numWorkers;
4764 unsigned int count;
4765 int waitResult;
4766 void * baseFunc;
4767 bool ok;
4768
4769 DLOG("%s event = %lx\n", __FUNCTION__, event);
4770
4771 baseFunc = OSMemberFunctionCast(void *, root, &IOService::systemWillShutdown);
4772
4773 // Iterate the entire PM tree starting from root
4774
4775 rootDepth = root->getDepth( gIOPowerPlane );
4776 if (!rootDepth) goto done;
4777
4778 // debug - for repeated test runs
4779 while (PMHaltWorker::metaClass->getInstanceCount())
4780 IOSleep(1);
4781
4782 if (!gPMHaltArray)
4783 {
4784 gPMHaltArray = OSArray::withCapacity(40);
4785 if (!gPMHaltArray) goto done;
4786 }
4787 else // debug
4788 gPMHaltArray->flushCollection();
4789
4790 if (!gPMHaltLock)
4791 {
4792 gPMHaltLock = IOLockAlloc();
4793 if (!gPMHaltLock) goto done;
4794 }
4795
4796 if (!gPMHaltClientAcknowledgeKey)
4797 {
4798 gPMHaltClientAcknowledgeKey =
4799 OSSymbol::withCStringNoCopy("PMShutdown");
4800 if (!gPMHaltClientAcknowledgeKey) goto done;
4801 }
4802
4803 gPMHaltEvent = event;
4804
4805 // Depth-first walk of PM plane
4806
4807 iter = IORegistryIterator::iterateOver(
4808 root, gIOPowerPlane, kIORegistryIterateRecursively);
4809
4810 if (iter)
4811 {
4812 while ((entry = iter->getNextObject()))
4813 {
4814 node = OSDynamicCast(IOService, entry);
4815 if (!node)
4816 continue;
4817
4818 if (baseFunc ==
4819 OSMemberFunctionCast(void *, node, &IOService::systemWillShutdown))
4820 continue;
4821
4822 depth = node->getDepth( gIOPowerPlane );
4823 if (depth <= rootDepth)
4824 continue;
4825
4826 ok = false;
4827
4828 // adjust to zero based depth
4829 depth -= (rootDepth + 1);
4830
4831 // gPMHaltArray is an array of containers, each container
4832 // refers to nodes with the same depth.
4833
4834 count = gPMHaltArray->getCount();
4835 while (depth >= count)
4836 {
4837 // expand array and insert placeholders
4838 gPMHaltArray->setObject(PLACEHOLDER);
4839 count++;
4840 }
4841 count = gPMHaltArray->getCount();
4842 if (depth < count)
4843 {
4844 inner = (OSSet *)gPMHaltArray->getObject(depth);
4845 if (inner == PLACEHOLDER)
4846 {
4847 inner = OSSet::withCapacity(40);
4848 if (inner)
4849 {
4850 gPMHaltArray->replaceObject(depth, inner);
4851 inner->release();
4852 }
4853 }
4854
4855 // PM nodes that appear more than once in the tree will have
4856 // the same depth, OSSet will refuse to add the node twice.
4857 if (inner)
4858 ok = inner->setObject(node);
4859 }
4860 if (!ok)
4861 DLOG("Skipped PM node %s\n", node->getName());
4862 }
4863 iter->release();
4864 }
4865
4866 // debug only
4867 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); i++)
4868 {
4869 count = 0;
4870 if (inner != PLACEHOLDER)
4871 count = inner->getCount();
4872 DLOG("Nodes at depth %u = %u\n", i, count);
4873 }
4874
4875 // strip placeholders (not all depths are populated)
4876 numWorkers = 0;
4877 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); )
4878 {
4879 if (inner == PLACEHOLDER)
4880 {
4881 gPMHaltArray->removeObject(i);
4882 continue;
4883 }
4884 count = inner->getCount();
4885 if (count > numWorkers)
4886 numWorkers = count;
4887 totalNodes += count;
4888 i++;
4889 }
4890
4891 if (gPMHaltArray->getCount() == 0 || !numWorkers)
4892 goto done;
4893
4894 gPMHaltBusyCount = 0;
4895 gPMHaltIdleCount = 0;
4896 gPMHaltDepth = gPMHaltArray->getCount() - 1;
4897
4898 // Create multiple workers (and threads)
4899
4900 if (numWorkers > kPMHaltMaxWorkers)
4901 numWorkers = kPMHaltMaxWorkers;
4902
4903 DLOG("PM nodes = %u, maxDepth = %u, workers = %u\n",
4904 totalNodes, gPMHaltArray->getCount(), numWorkers);
4905
4906 for (unsigned int i = 0; i < numWorkers; i++)
4907 workers[i] = PMHaltWorker::worker();
4908
4909 // Wait for workers to exhaust all available work
4910
4911 IOLockLock(gPMHaltLock);
4912 while (gPMHaltDepth >= 0)
4913 {
4914 clock_interval_to_deadline(1000, kMillisecondScale, &deadline);
4915
4916 waitResult = IOLockSleepDeadline(
4917 gPMHaltLock, &gPMHaltDepth, deadline, THREAD_UNINT);
4918 if (THREAD_TIMED_OUT == waitResult)
4919 {
4920 AbsoluteTime now;
4921 clock_get_uptime(&now);
4922
4923 IOLockUnlock(gPMHaltLock);
4924 for (unsigned int i = 0 ; i < numWorkers; i++)
4925 {
4926 if (workers[i])
4927 PMHaltWorker::checkTimeout(workers[i], &now);
4928 }
4929 IOLockLock(gPMHaltLock);
4930 }
4931 }
4932 IOLockUnlock(gPMHaltLock);
4933
4934 // Release all workers
4935
4936 for (unsigned int i = 0; i < numWorkers; i++)
4937 {
4938 if (workers[i])
4939 workers[i]->release();
4940 // worker also retained by it's own thread
4941 }
4942
4943 done:
4944 DLOG("%s done\n", __FUNCTION__);
4945 return;
4946 }
4947
4948
4949 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4950
4951
4952 #undef super
4953 #define super OSObject
4954 OSDefineMetaClassAndFinalStructors(PMSettingObject, OSObject)
4955
4956 void PMSettingObject::setPMSetting(const OSSymbol *type, OSObject *obj)
4957 {
4958 (*func)(target, type, obj, refcon);
4959 }
4960
4961 /*
4962 * Static constructor/initializer for PMSettingObject
4963 */
4964 PMSettingObject *PMSettingObject::pmSettingObject(
4965 IOPMrootDomain *parent_arg,
4966 IOPMSettingControllerCallback handler_arg,
4967 OSObject *target_arg,
4968 uintptr_t refcon_arg,
4969 uint32_t supportedPowerSources,
4970 const OSSymbol * settings[])
4971 {
4972 uint32_t objCount = 0;
4973 PMSettingObject *pmso;
4974
4975 if( !parent_arg || !handler_arg || !settings ) return NULL;
4976
4977 // count OSSymbol entries in NULL terminated settings array
4978 while( settings[objCount] ) {
4979 objCount++;
4980 }
4981 if(0 == objCount) return NULL;
4982
4983 pmso = new PMSettingObject;
4984 if(!pmso || !pmso->init()) return NULL;
4985
4986 pmso->parent = parent_arg;
4987 pmso->func = handler_arg;
4988 pmso->target = target_arg;
4989 pmso->refcon = refcon_arg;
4990 pmso->releaseAtCount = objCount + 1; // release when it has count+1 retains
4991
4992 pmso->publishedFeatureID = (uint32_t *)IOMalloc(sizeof(uint32_t)*objCount);
4993 if(pmso->publishedFeatureID) {
4994 for(unsigned int i=0; i<objCount; i++) {
4995 // Since there is now at least one listener to this setting, publish
4996 // PM root domain support for it.
4997 parent_arg->publishFeature( settings[i]->getCStringNoCopy(),
4998 supportedPowerSources, &pmso->publishedFeatureID[i] );
4999 }
5000 }
5001
5002 return pmso;
5003 }
5004
5005 void PMSettingObject::free(void)
5006 {
5007 OSCollectionIterator *settings_iter;
5008 OSSymbol *sym;
5009 OSArray *arr;
5010 int arr_idx;
5011 int i;
5012 int objCount = releaseAtCount - 1;
5013
5014 if(publishedFeatureID) {
5015 for(i=0; i<objCount; i++) {
5016 if(0 != publishedFeatureID[i]) {
5017 parent->removePublishedFeature( publishedFeatureID[i] );
5018 }
5019 }
5020
5021 IOFree(publishedFeatureID, sizeof(uint32_t) * objCount);
5022 }
5023
5024 IORecursiveLockLock(parent->settingsCtrlLock);
5025
5026 // Search each PM settings array in the kernel.
5027 settings_iter = OSCollectionIterator::withCollection(parent->settingsCallbacks);
5028 if(settings_iter)
5029 {
5030 while(( sym = OSDynamicCast(OSSymbol, settings_iter->getNextObject()) ))
5031 {
5032 arr = (OSArray *)parent->settingsCallbacks->getObject(sym);
5033 arr_idx = arr->getNextIndexOfObject(this, 0);
5034 if(-1 != arr_idx) {
5035 // 'this' was found in the array; remove it
5036 arr->removeObject(arr_idx);
5037 }
5038 }
5039
5040 settings_iter->release();
5041 }
5042
5043 IORecursiveLockUnlock(parent->settingsCtrlLock);
5044
5045 super::free();
5046 }
5047
5048 void PMSettingObject::taggedRelease(const void *tag, const int when) const
5049 {
5050 // We have n+1 retains - 1 per array that this PMSettingObject is a member
5051 // of, and 1 retain to ourself. When we get a release with n+1 retains
5052 // remaining, we go ahead and free ourselves, cleaning up array pointers
5053 // in free();
5054
5055 super::taggedRelease(tag, releaseAtCount);
5056 }
5057
5058
5059
5060 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5061
5062 #undef super
5063 #define super IOService
5064
5065 OSDefineMetaClassAndFinalStructors(IORootParent, IOService)
5066
5067 // This array exactly parallels the state array for the root domain.
5068 // Power state changes initiated by a device can be vetoed by a client of the device, and
5069 // power state changes initiated by the parent of a device cannot be vetoed by a client of the device,
5070 // so when the root domain wants a power state change that cannot be vetoed (e.g. demand sleep), it asks
5071 // its parent to make the change. That is the reason for this complexity.
5072
5073 static IOPMPowerState patriarchPowerStates[NUM_POWER_STATES] =
5074 {
5075 {1,0,0,0,0,0,0,0,0,0,0,0}, // off (not used)
5076 {1,0,RESTART_POWER,0,0,0,0,0,0,0,0,0}, // reset (not used)
5077 {1,0,SLEEP_POWER,0,0,0,0,0,0,0,0,0}, // sleep
5078 {1,0,DOZE_POWER,0,0,0,0,0,0,0,0,0}, // doze
5079 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0}, // running
5080 };
5081
5082 bool IORootParent::start( IOService * nub )
5083 {
5084 mostRecentChange = ON_STATE;
5085 super::start(nub);
5086 attachToParent( getRegistryRoot(), gIOPowerPlane );
5087 PMinit();
5088 registerPowerDriver(this, patriarchPowerStates, NUM_POWER_STATES);
5089 wakeSystem();
5090 powerOverrideOnPriv();
5091 return true;
5092 }
5093
5094 void IORootParent::shutDownSystem( void )
5095 {
5096 }
5097
5098 void IORootParent::restartSystem( void )
5099 {
5100 }
5101
5102 void IORootParent::sleepSystem( void )
5103 {
5104 mostRecentChange = SLEEP_STATE;
5105 changePowerStateToPriv(SLEEP_STATE);
5106 }
5107
5108 void IORootParent::dozeSystem( void )
5109 {
5110 mostRecentChange = DOZE_STATE;
5111 changePowerStateToPriv(DOZE_STATE);
5112 }
5113
5114 // Called in demand sleep when sleep discovered to be impossible after actually attaining that state.
5115 // This brings the parent to doze, which allows the root to step up from sleep to doze.
5116
5117 // In idle sleep, do nothing because the parent is still on and the root can freely change state.
5118
5119 void IORootParent::sleepToDoze( void )
5120 {
5121 if ( mostRecentChange == SLEEP_STATE ) {
5122 changePowerStateToPriv(DOZE_STATE);
5123 }
5124 }
5125
5126 void IORootParent::wakeSystem( void )
5127 {
5128 mostRecentChange = ON_STATE;
5129 changePowerStateToPriv(ON_STATE);
5130 }