]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOServicePM.cpp
bd7bcd0024d8918dbc85e7a347af2c1d3ff7e8fd
[apple/xnu.git] / iokit / Kernel / IOServicePM.cpp
1 /*
2 * Copyright (c) 1998-2006 Apple Computer, 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
29 //#undef IOASSERT
30 //#define IOASSERT 1
31
32 #include <IOKit/assert.h>
33 #include <IOKit/IOKitDebug.h>
34 #include <IOKit/IOLib.h>
35 #include <IOKit/IOMessage.h>
36 #include <IOKit/IOPlatformExpert.h>
37 #include <IOKit/IOService.h>
38 #include <IOKit/IOEventSource.h>
39 #include <IOKit/IOWorkLoop.h>
40 #include <IOKit/IOCommand.h>
41
42 #include <IOKit/pwr_mgt/IOPMlog.h>
43 #include <IOKit/pwr_mgt/IOPMinformee.h>
44 #include <IOKit/pwr_mgt/IOPMinformeeList.h>
45 #include <IOKit/pwr_mgt/IOPowerConnection.h>
46 #include <IOKit/pwr_mgt/RootDomain.h>
47 #include <IOKit/pwr_mgt/IOPMPrivate.h>
48
49 #include <sys/proc.h>
50 #include <libkern/OSDebug.h>
51
52 // Required for notification instrumentation
53 #include "IOServicePrivate.h"
54 #include "IOServicePMPrivate.h"
55 #include "IOKitKernelInternal.h"
56
57 static void settle_timer_expired(thread_call_param_t, thread_call_param_t);
58 static void idle_timer_expired(thread_call_param_t, thread_call_param_t);
59 static void tellKernelClientApplier(OSObject * object, void * arg);
60 static void tellAppClientApplier(OSObject * object, void * arg);
61
62 static uint64_t computeTimeDeltaNS( const AbsoluteTime * start )
63 {
64 AbsoluteTime now;
65 uint64_t nsec;
66
67 clock_get_uptime(&now);
68 SUB_ABSOLUTETIME(&now, start);
69 absolutetime_to_nanoseconds(now, &nsec);
70 return nsec;
71 }
72
73 #if PM_VARS_SUPPORT
74 OSDefineMetaClassAndStructors(IOPMprot, OSObject)
75 #endif
76
77 // Container class for recording system power events
78 OSDefineMetaClassAndStructors( PMEventDetails, OSObject );
79
80 //******************************************************************************
81 // Globals
82 //******************************************************************************
83
84 static bool gIOPMInitialized = false;
85 static uint32_t gIOPMBusyCount = 0;
86 static uint32_t gIOPMWorkCount = 0;
87 static IOWorkLoop * gIOPMWorkLoop = 0;
88 static IOPMRequestQueue * gIOPMRequestQueue = 0;
89 static IOPMRequestQueue * gIOPMReplyQueue = 0;
90 static IOPMWorkQueue * gIOPMWorkQueue = 0;
91 static IOPMCompletionQueue * gIOPMFreeQueue = 0;
92 static IOPMRequest * gIOPMRequest = 0;
93 static IOPlatformExpert * gPlatform = 0;
94 static IOService * gIOPMRootNode = 0;
95
96 static const OSSymbol * gIOPMPowerClientDevice = 0;
97 static const OSSymbol * gIOPMPowerClientDriver = 0;
98 static const OSSymbol * gIOPMPowerClientChildProxy = 0;
99 static const OSSymbol * gIOPMPowerClientChildren = 0;
100
101 static uint32_t getPMRequestType( void )
102 {
103 uint32_t type = kIOPMRequestTypeInvalid;
104 if (gIOPMRequest)
105 type = gIOPMRequest->getType();
106 return type;
107 }
108
109 //******************************************************************************
110 // Macros
111 //******************************************************************************
112
113 #define PM_ERROR(x...) do { kprintf(x); IOLog(x); } while (false)
114 #define PM_LOG(x...) do { kprintf(x); } while (false)
115
116 #define PM_LOG1(x...) do { \
117 if (kIOLogDebugPower & gIOKitDebug) \
118 kprintf(x); } while (false)
119
120 #define PM_LOG2(x...) do { \
121 if (kIOLogDebugPower & gIOKitDebug) \
122 kprintf(x); } while (false)
123
124 #if 0
125 #define PM_LOG3(x...) do { kprintf(x); } while (false)
126 #else
127 #define PM_LOG3(x...)
128 #endif
129
130 #define RD_LOG(x...) do { \
131 if ((kIOLogPMRootDomain & gIOKitDebug) && \
132 (getPMRootDomain() == this)) \
133 kprintf("PMRD: " x); } while (false)
134
135 #define PM_ASSERT_IN_GATE(x) \
136 do { \
137 assert(gIOPMWorkLoop->inGate()); \
138 } while(false)
139
140 #define PM_LOCK() IOLockLock(fPMLock)
141 #define PM_UNLOCK() IOLockUnlock(fPMLock)
142 #define PM_LOCK_SLEEP(event, dl) IOLockSleepDeadline(fPMLock, event, dl, THREAD_UNINT)
143 #define PM_LOCK_WAKEUP(event) IOLockWakeup(fPMLock, event, false)
144
145 #define ns_per_us 1000
146 #define k30seconds (30*1000000)
147 #define kMinAckTimeoutTicks (10*1000000)
148 #define kIOPMTardyAckSPSKey "IOPMTardyAckSetPowerState"
149 #define kIOPMTardyAckPSCKey "IOPMTardyAckPowerStateChange"
150 #define kPwrMgtKey "IOPowerManagement"
151
152 #define OUR_PMLog(t, a, b) \
153 do { gPlatform->PMLog( fName, t, a, b); } while(0)
154
155 #define NS_TO_MS(nsec) ((int)((nsec) / 1000000ULL))
156 #define NS_TO_US(nsec) ((int)((nsec) / 1000ULL))
157
158 #if CONFIG_EMBEDDED
159 #define SUPPORT_IDLE_CANCEL 1
160 #endif
161
162 #define kIOPMPowerStateMax 0xFFFFFFFF
163
164 #define IS_PM_ROOT (this == gIOPMRootNode)
165 #define IS_ROOT_DOMAIN (getPMRootDomain() == this)
166 #define IS_POWER_DROP (fHeadNotePowerState < fCurrentPowerState)
167 #define IS_POWER_RISE (fHeadNotePowerState > fCurrentPowerState)
168
169 // log setPowerStates longer than (ns):
170 #define LOG_SETPOWER_TIMES (50ULL * 1000ULL * 1000ULL)
171 // log app responses longer than (ns):
172 #define LOG_APP_RESPONSE_TIMES (100ULL * 1000ULL * 1000ULL)
173 // use message tracer to log messages longer than (ns):
174 #define LOG_APP_RESPONSE_MSG_TRACER (3 * 1000ULL * 1000ULL * 1000ULL)
175
176 enum {
177 kReserveDomainPower = 1
178 };
179
180 #define MS_PUSH(n) \
181 do { assert(kIOPM_BadMachineState == fSavedMachineState); \
182 assert(kIOPM_BadMachineState != n); \
183 fSavedMachineState = n; } while (false)
184
185 #define MS_POP() \
186 do { assert(kIOPM_BadMachineState != fSavedMachineState); \
187 fMachineState = fSavedMachineState; \
188 fSavedMachineState = kIOPM_BadMachineState; } while (false)
189
190 #define PM_ACTION_0(a) \
191 do { if (fPMActions.a) { \
192 (fPMActions.a)(fPMActions.target, this, &fPMActions); } \
193 } while (false)
194
195 #define PM_ACTION_2(a, x, y) \
196 do { if (fPMActions.a) { \
197 (fPMActions.a)(fPMActions.target, this, &fPMActions, x, y); } \
198 } while (false)
199
200 //*********************************************************************************
201 // PM machine states
202 //
203 // Check kgmacros after modifying machine states.
204 //*********************************************************************************
205
206 enum {
207 kIOPM_Finished = 0,
208
209 kIOPM_OurChangeTellClientsPowerDown = 1,
210 kIOPM_OurChangeTellPriorityClientsPowerDown = 2,
211 kIOPM_OurChangeNotifyInterestedDriversWillChange = 3,
212 kIOPM_OurChangeSetPowerState = 4,
213 kIOPM_OurChangeWaitForPowerSettle = 5,
214 kIOPM_OurChangeNotifyInterestedDriversDidChange = 6,
215 kIOPM_OurChangeTellCapabilityDidChange = 7,
216 kIOPM_OurChangeFinish = 8,
217
218 kIOPM_ParentChangeTellPriorityClientsPowerDown = 10,
219 kIOPM_ParentChangeNotifyInterestedDriversWillChange = 11,
220 kIOPM_ParentChangeSetPowerState = 12,
221 kIOPM_ParentChangeWaitForPowerSettle = 13,
222 kIOPM_ParentChangeNotifyInterestedDriversDidChange = 14,
223 kIOPM_ParentChangeTellCapabilityDidChange = 15,
224 kIOPM_ParentChangeAcknowledgePowerChange = 16,
225
226 kIOPM_NotifyChildrenStart = 17,
227 kIOPM_NotifyChildrenOrdered = 18,
228 kIOPM_NotifyChildrenDelayed = 19,
229 kIOPM_SyncTellClientsPowerDown = 20,
230 kIOPM_SyncTellPriorityClientsPowerDown = 21,
231 kIOPM_SyncNotifyWillChange = 22,
232 kIOPM_SyncNotifyDidChange = 23,
233 kIOPM_SyncTellCapabilityDidChange = 24,
234 kIOPM_SyncFinish = 25,
235 kIOPM_TellCapabilityChangeDone = 26,
236 kIOPM_DriverThreadCallDone = 27,
237
238 kIOPM_BadMachineState = 0xFFFFFFFF
239 };
240
241
242 /*
243 Power Management defines a few roles that drivers can play in their own,
244 and other drivers', power management. We briefly define those here.
245
246 Many drivers implement their policy maker and power controller within the same
247 IOService object, but that is not required.
248
249 == Policy Maker ==
250 * Virtual IOService PM methods a "policy maker" may implement
251 * maxCapabilityForDomainState()
252 * initialPowerStateForDomainState()
253 * powerStateForDomainState()
254
255 * Virtual IOService PM methods a "policy maker" may CALL
256 * PMinit()
257
258 == Power Controller ==
259 * Virtual IOService PM methods a "power controller" may implement
260 * setPowerState()
261
262 * Virtual IOService PM methods a "power controller" may CALL
263 * joinPMtree()
264 * registerPowerDriver()
265
266 =======================
267 There are two different kinds of power state changes.
268 * One is initiated by a subclassed device object which has either decided
269 to change power state, or its controlling driver has suggested it, or
270 some other driver wants to use the idle device and has asked it to become
271 usable.
272 * The second kind of power state change is initiated by the power domain
273 parent.
274 The two are handled through different code paths.
275
276 We maintain a queue of "change notifications," or change notes.
277 * Usually the queue is empty.
278 * When it isn't, usually there is one change note in it
279 * It's possible to have more than one power state change pending at one
280 time, so a queue is implemented.
281 Example:
282 * The subclass device decides it's idle and initiates a change to a lower
283 power state. This causes interested parties to be notified, but they
284 don't all acknowledge right away. This causes the change note to sit
285 in the queue until all the acks are received. During this time, the
286 device decides it isn't idle anymore and wants to raise power back up
287 again. This change can't be started, however, because the previous one
288 isn't complete yet, so the second one waits in the queue. During this
289 time, the parent decides to lower or raise the power state of the entire
290 power domain and notifies the device, and that notification goes into
291 the queue, too, and can't be actioned until the others are.
292
293 == SelfInitiated ==
294 This is how a power change initiated by the subclass device is handled:
295 -> First, all interested parties are notified of the change via their
296 powerStateWillChangeTo method. If they all don't acknowledge via return
297 code, then we have to wait. If they do, or when they finally all
298 acknowledge via our acknowledgePowerChange method, then we can continue.
299 -> We call the controlling driver, instructing it to change to the new state
300 -> Then we wait for power to settle. If there is no settling-time, or after
301 it has passed,
302 -> we notify interested parties again, this time via their
303 powerStateDidChangeTo methods.
304 -> When they have all acked, we're done.
305 If we lowered power and don't need the power domain to be in its current power
306 state, we suggest to the parent that it lower the power domain state.
307
308 == PowerDomainDownInitiated ==
309 How a change to a lower power domain state initiated by the parent is handled:
310 -> First, we figure out what power state we will be in when the new domain
311 state is reached.
312 -> Then all interested parties are notified that we are moving to that new
313 state.
314 -> When they have acknowledged, we call the controlling driver to assume
315 that state and we wait for power to settle.
316 -> Then we acknowledge our preparedness to our parent. When all its
317 interested parties have acknowledged,
318 -> it lowers power and then notifies its interested parties again.
319 -> When we get this call, we notify our interested parties that the power
320 state has changed, and when they have all acknowledged, we're done.
321
322 == PowerDomainUpInitiated ==
323 How a change to a higher power domain state initiated by the parent is handled:
324 -> We figure out what power state we will be in when the new domain state is
325 reached.
326 -> If it is different from our current state we acknowledge the parent.
327 -> When all the parent's interested parties have acknowledged, it raises
328 power in the domain and waits for power to settle.
329 -> Then it notifies everyone that the new state has been reached.
330 -> When we get this call, we call the controlling driver, instructing it to
331 assume the new state, and wait for power to settle.
332 -> Then we notify our interested parties. When they all acknowledge we are
333 done.
334
335 In either of the two power domain state cases above, it is possible that we
336 will not be changing state even though the domain is.
337 Examples:
338 * A change to a lower domain state may not affect us because we are already
339 in a low enough state,
340 * We will not take advantage of a change to a higher domain state, because
341 we have no need of the higher power. In such cases, there is nothing to
342 do but acknowledge the parent. So when the parent calls our
343 powerDomainWillChange method, and we decide that we will not be changing
344 state, we merely acknowledge the parent, via return code, and wait.
345 When the parent subsequently calls powerStateDidChange, we acknowledge again
346 via return code, and the change is complete.
347
348 == 4 Paths Through State Machine ==
349 Power state changes are processed in a state machine, and since there are four
350 varieties of power state changes, there are four major paths through the state
351 machine.
352
353 == 5. No Need To change ==
354 The fourth is nearly trivial. In this path, the parent is changing the domain
355 state, but we are not changing the device state. The change starts when the
356 parent calls powerDomainWillChange. All we do is acknowledge the parent. When
357 the parent calls powerStateDidChange, we acknowledge the parent again, and
358 we're done.
359
360 == 1. OurChange Down == XXX gvdl
361 The first is fairly simple. It starts:
362 * when a power domain child calls requestPowerDomainState and we decide to
363 change power states to accomodate the child,
364 * or if our power-controlling driver calls changePowerStateTo,
365 * or if some other driver which is using our device calls makeUsable,
366 * or if a subclassed object calls changePowerStateToPriv.
367 These are all power changes initiated by us, not forced upon us by the parent.
368
369 -> We start by notifying interested parties.
370 -> If they all acknowledge via return code, we can go on to state
371 "msSetPowerState".
372 -> Otherwise, we start the ack timer and wait for the stragglers to
373 acknowlege by calling acknowledgePowerChange.
374 -> We move on to state "msSetPowerState" when all the
375 stragglers have acknowledged, or when the ack timer expires on
376 all those which didn't acknowledge.
377 In "msSetPowerState" we call the power-controlling driver to change the
378 power state of the hardware.
379 -> If it returns saying it has done so, we go on to state
380 "msWaitForPowerSettle".
381 -> Otherwise, we have to wait for it, so we set the ack timer and wait.
382 -> When it calls acknowledgeSetPowerState, or when the ack timer
383 expires, we go on.
384 In "msWaitForPowerSettle", we look in the power state array to see if
385 there is any settle time required when changing from our current state to the
386 new state.
387 -> If not, we go right away to "msNotifyInterestedDriversDidChange".
388 -> Otherwise, we set the settle timer and wait. When it expires, we move on.
389 In "msNotifyInterestedDriversDidChange" state, we notify all our
390 interested parties via their powerStateDidChange methods that we have finished
391 changing power state.
392 -> If they all acknowledge via return code, we move on to "msFinish".
393 -> Otherwise we set the ack timer and wait. When they have all
394 acknowledged, or when the ack timer has expired for those that didn't,
395 we move on to "msFinish".
396 In "msFinish" we remove the used change note from the head of the queue
397 and start the next one if one exists.
398
399 == 2. Parent Change Down ==
400 Start at Stage 2 of OurChange Down XXX gvdl
401
402 == 3. Change Up ==
403 Start at Stage 4 of OurChange Down XXX gvdl
404
405 Note all parent requested changes need to acknowledge the power has changed to the parent when done.
406 */
407
408 //*********************************************************************************
409 // [public] PMinit
410 //
411 // Initialize power management.
412 //*********************************************************************************
413
414 void IOService::PMinit ( void )
415 {
416 if ( !initialized )
417 {
418 if ( !gIOPMInitialized )
419 {
420 gPlatform = getPlatform();
421 gIOPMWorkLoop = IOWorkLoop::workLoop();
422 if (gIOPMWorkLoop)
423 {
424 gIOPMRequestQueue = IOPMRequestQueue::create(
425 this, OSMemberFunctionCast(IOPMRequestQueue::Action,
426 this, &IOService::servicePMRequestQueue));
427
428 gIOPMReplyQueue = IOPMRequestQueue::create(
429 this, OSMemberFunctionCast(IOPMRequestQueue::Action,
430 this, &IOService::servicePMReplyQueue));
431
432 gIOPMWorkQueue = IOPMWorkQueue::create(
433 this,
434 OSMemberFunctionCast(IOPMWorkQueue::Action, this,
435 &IOService::servicePMRequest),
436 OSMemberFunctionCast(IOPMWorkQueue::Action, this,
437 &IOService::retirePMRequest));
438
439 gIOPMFreeQueue = IOPMCompletionQueue::create(
440 this, OSMemberFunctionCast(IOPMCompletionQueue::Action,
441 this, &IOService::servicePMFreeQueue));
442
443 if (gIOPMWorkLoop->addEventSource(gIOPMRequestQueue) !=
444 kIOReturnSuccess)
445 {
446 gIOPMRequestQueue->release();
447 gIOPMRequestQueue = 0;
448 }
449
450 if (gIOPMWorkLoop->addEventSource(gIOPMReplyQueue) !=
451 kIOReturnSuccess)
452 {
453 gIOPMReplyQueue->release();
454 gIOPMReplyQueue = 0;
455 }
456
457 if (gIOPMWorkLoop->addEventSource(gIOPMWorkQueue) !=
458 kIOReturnSuccess)
459 {
460 gIOPMWorkQueue->release();
461 gIOPMWorkQueue = 0;
462 }
463
464 if (gIOPMWorkLoop->addEventSource(gIOPMFreeQueue) !=
465 kIOReturnSuccess)
466 {
467 gIOPMFreeQueue->release();
468 gIOPMFreeQueue = 0;
469 }
470
471 gIOPMPowerClientDevice =
472 OSSymbol::withCStringNoCopy( "DevicePowerState" );
473
474 gIOPMPowerClientDriver =
475 OSSymbol::withCStringNoCopy( "DriverPowerState" );
476
477 gIOPMPowerClientChildProxy =
478 OSSymbol::withCStringNoCopy( "ChildProxyPowerState" );
479
480 gIOPMPowerClientChildren =
481 OSSymbol::withCStringNoCopy( "ChildrenPowerState" );
482 }
483
484 if (gIOPMRequestQueue && gIOPMReplyQueue && gIOPMFreeQueue)
485 gIOPMInitialized = true;
486 }
487 if (!gIOPMInitialized)
488 return;
489
490 pwrMgt = new IOServicePM;
491 pwrMgt->init();
492 setProperty(kPwrMgtKey, pwrMgt);
493
494 queue_init(&pwrMgt->WorkChain);
495 queue_init(&pwrMgt->RequestHead);
496 queue_init(&pwrMgt->PMDriverCallQueue);
497
498 fOwner = this;
499 fPMLock = IOLockAlloc();
500 fInterestedDrivers = new IOPMinformeeList;
501 fInterestedDrivers->initialize();
502 fDesiredPowerState = 0;
503 fDeviceDesire = 0;
504 fInitialPowerChange = true;
505 fInitialSetPowerState = true;
506 fPreviousRequestPowerFlags = 0;
507 fDeviceOverrideEnabled = false;
508 fMachineState = kIOPM_Finished;
509 fSavedMachineState = kIOPM_BadMachineState;
510 fIdleTimerMinPowerState = 0;
511 fActivityLock = IOLockAlloc();
512 fStrictTreeOrder = false;
513 fActivityTicklePowerState = -1;
514 fControllingDriver = NULL;
515 fPowerStates = NULL;
516 fNumberOfPowerStates = 0;
517 fCurrentPowerState = 0;
518 fParentsCurrentPowerFlags = 0;
519 fMaxPowerState = 0;
520 fName = getName();
521 fParentsKnowState = false;
522 fSerialNumber = 0;
523 fResponseArray = NULL;
524 fNotifyClientArray = NULL;
525 fCurrentPowerConsumption = kIOPMUnknown;
526 fOverrideMaxPowerState = kIOPMPowerStateMax;
527
528 if (!gIOPMRootNode && (getParentEntry(gIOPowerPlane) == getRegistryRoot()))
529 {
530 gIOPMRootNode = this;
531 fParentsKnowState = true;
532 }
533
534 fAckTimer = thread_call_allocate(
535 &IOService::ack_timer_expired, (thread_call_param_t)this);
536 fSettleTimer = thread_call_allocate(
537 &settle_timer_expired, (thread_call_param_t)this);
538 fIdleTimer = thread_call_allocate(
539 &idle_timer_expired, (thread_call_param_t)this);
540 fDriverCallEntry = thread_call_allocate(
541 (thread_call_func_t) &IOService::pmDriverCallout, this);
542 assert(fDriverCallEntry);
543
544 // Check for powerChangeDone override.
545 if (OSMemberFunctionCast(void (*)(void),
546 getResourceService(), &IOService::powerChangeDone) !=
547 OSMemberFunctionCast(void (*)(void),
548 this, &IOService::powerChangeDone))
549 {
550 fPCDFunctionOverride = true;
551 }
552
553 #if PM_VARS_SUPPORT
554 IOPMprot * prot = new IOPMprot;
555 if (prot)
556 {
557 prot->init();
558 prot->ourName = fName;
559 prot->thePlatform = gPlatform;
560 fPMVars = prot;
561 pm_vars = prot;
562 }
563 #else
564 pm_vars = (void *) (uintptr_t) true;
565 #endif
566
567 initialized = true;
568 }
569 }
570
571 //*********************************************************************************
572 // [private] PMfree
573 //
574 // Free the data created by PMinit. Only called from IOService::free().
575 //*********************************************************************************
576
577 void IOService::PMfree ( void )
578 {
579 initialized = false;
580 pm_vars = 0;
581
582 if ( pwrMgt )
583 {
584 assert(fMachineState == kIOPM_Finished);
585 assert(fInsertInterestSet == NULL);
586 assert(fRemoveInterestSet == NULL);
587 assert(fNotifyChildArray == NULL);
588 assert(queue_empty(&pwrMgt->RequestHead));
589 assert(queue_empty(&fPMDriverCallQueue));
590
591 if ( fSettleTimer ) {
592 thread_call_cancel(fSettleTimer);
593 thread_call_free(fSettleTimer);
594 fSettleTimer = NULL;
595 }
596 if ( fAckTimer ) {
597 thread_call_cancel(fAckTimer);
598 thread_call_free(fAckTimer);
599 fAckTimer = NULL;
600 }
601 if ( fIdleTimer ) {
602 thread_call_cancel(fIdleTimer);
603 thread_call_free(fIdleTimer);
604 fIdleTimer = NULL;
605 }
606 if ( fDriverCallEntry ) {
607 thread_call_free(fDriverCallEntry);
608 fDriverCallEntry = NULL;
609 }
610 if ( fPMLock ) {
611 IOLockFree(fPMLock);
612 fPMLock = NULL;
613 }
614 if ( fActivityLock ) {
615 IOLockFree(fActivityLock);
616 fActivityLock = NULL;
617 }
618 if ( fInterestedDrivers ) {
619 fInterestedDrivers->release();
620 fInterestedDrivers = NULL;
621 }
622 if (fDriverCallParamSlots && fDriverCallParamPtr) {
623 IODelete(fDriverCallParamPtr, DriverCallParam, fDriverCallParamSlots);
624 fDriverCallParamPtr = 0;
625 fDriverCallParamSlots = 0;
626 }
627 if ( fResponseArray ) {
628 fResponseArray->release();
629 fResponseArray = NULL;
630 }
631 if ( fNotifyClientArray ) {
632 fNotifyClientArray->release();
633 fNotifyClientArray = NULL;
634 }
635 if (fPowerStates && fNumberOfPowerStates) {
636 IODelete(fPowerStates, IOPMPSEntry, fNumberOfPowerStates);
637 fNumberOfPowerStates = 0;
638 fPowerStates = NULL;
639 }
640 if (fPowerClients) {
641 fPowerClients->release();
642 fPowerClients = 0;
643 }
644
645 #if PM_VARS_SUPPORT
646 if (fPMVars)
647 {
648 fPMVars->release();
649 fPMVars = 0;
650 }
651 #endif
652
653 pwrMgt->release();
654 pwrMgt = 0;
655 }
656 }
657
658 //*********************************************************************************
659 // [public] joinPMtree
660 //
661 // A policy-maker calls its nub here when initializing, to be attached into
662 // the power management hierarchy. The default function is to call the
663 // platform expert, which knows how to do it. This method is overridden
664 // by a nub subclass which may either know how to do it, or may need to
665 // take other action.
666 //
667 // This may be the only "power management" method used in a nub,
668 // meaning it may not be initialized for power management.
669 //*********************************************************************************
670
671 void IOService::joinPMtree ( IOService * driver )
672 {
673 IOPlatformExpert * platform;
674
675 platform = getPlatform();
676 assert(platform != 0);
677 platform->PMRegisterDevice(this, driver);
678 }
679
680 #ifndef __LP64__
681 //*********************************************************************************
682 // [deprecated] youAreRoot
683 //
684 // Power Managment is informing us that we are the root power domain.
685 //*********************************************************************************
686
687 IOReturn IOService::youAreRoot ( void )
688 {
689 return IOPMNoErr;
690 }
691 #endif /* !__LP64__ */
692
693 //*********************************************************************************
694 // [public] PMstop
695 //
696 // Immediately stop driver callouts. Schedule an async stop request to detach
697 // from power plane.
698 //*********************************************************************************
699
700 void IOService::PMstop ( void )
701 {
702 IOPMRequest * request;
703
704 if (!initialized)
705 return;
706
707 PM_LOCK();
708
709 if (fLockedFlags.PMStop)
710 {
711 PM_LOG2("%s: PMstop() already stopped\n", fName);
712 PM_UNLOCK();
713 return;
714 }
715
716 // Inhibit future driver calls.
717 fLockedFlags.PMStop = true;
718
719 // Wait for all prior driver calls to finish.
720 waitForPMDriverCall();
721
722 PM_UNLOCK();
723
724 // The rest of the work is performed async.
725 request = acquirePMRequest( this, kIOPMRequestTypePMStop );
726 if (request)
727 {
728 PM_LOG2("%s: %p PMstop\n", getName(), this);
729 submitPMRequest( request );
730 }
731 }
732
733 //*********************************************************************************
734 // [private] handlePMstop
735 //
736 // Disconnect the node from all parents and children in the power plane.
737 //*********************************************************************************
738
739 void IOService::handlePMstop ( IOPMRequest * request )
740 {
741 OSIterator * iter;
742 OSObject * next;
743 IOPowerConnection * connection;
744 IOService * theChild;
745 IOService * theParent;
746
747 PM_ASSERT_IN_GATE();
748 PM_LOG2("%s: %p %s start\n", getName(), this, __FUNCTION__);
749
750 // remove the property
751 removeProperty(kPwrMgtKey);
752
753 // detach parents
754 iter = getParentIterator(gIOPowerPlane);
755 if ( iter )
756 {
757 while ( (next = iter->getNextObject()) )
758 {
759 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
760 {
761 theParent = (IOService *)connection->copyParentEntry(gIOPowerPlane);
762 if ( theParent )
763 {
764 theParent->removePowerChild(connection);
765 theParent->release();
766 }
767 }
768 }
769 iter->release();
770 }
771
772 // detach IOConnections
773 detachAbove( gIOPowerPlane );
774
775 // no more power state changes
776 fParentsKnowState = false;
777
778 // detach children
779 iter = getChildIterator(gIOPowerPlane);
780 if ( iter )
781 {
782 while ( (next = iter->getNextObject()) )
783 {
784 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
785 {
786 theChild = ((IOService *)(connection->copyChildEntry(gIOPowerPlane)));
787 if ( theChild )
788 {
789 // detach nub from child
790 connection->detachFromChild(theChild, gIOPowerPlane);
791 theChild->release();
792 }
793 // detach us from nub
794 detachFromChild(connection, gIOPowerPlane);
795 }
796 }
797 iter->release();
798 }
799
800 // Remove all interested drivers from the list, including the power
801 // controlling driver.
802 //
803 // Usually, the controlling driver and the policy-maker functionality
804 // are implemented by the same object, and without the deregistration,
805 // the object will be holding an extra retain on itself, and cannot
806 // be freed.
807
808 if ( fInterestedDrivers )
809 {
810 IOPMinformeeList * list = fInterestedDrivers;
811 IOPMinformee * item;
812
813 PM_LOCK();
814 while ((item = list->firstInList()))
815 {
816 list->removeFromList(item->whatObject);
817 }
818 PM_UNLOCK();
819 }
820
821 // Tell idleTimerExpired() to ignore idle timer.
822 fIdleTimerPeriod = 0;
823 if (fIdleTimer && thread_call_cancel(fIdleTimer))
824 release();
825
826 PM_LOG2("%s: %p %s done\n", getName(), this, __FUNCTION__);
827 }
828
829 //*********************************************************************************
830 // [public] addPowerChild
831 //
832 // Power Management is informing us who our children are.
833 //*********************************************************************************
834
835 IOReturn IOService::addPowerChild ( IOService * child )
836 {
837 IOPowerConnection * connection = 0;
838 IOPMRequest * requests[3] = {0, 0, 0};
839 OSIterator * iter;
840 bool ok = true;
841
842 if (!child)
843 return kIOReturnBadArgument;
844
845 if (!initialized || !child->initialized)
846 return IOPMNotYetInitialized;
847
848 OUR_PMLog( kPMLogAddChild, (uintptr_t) child, 0 );
849
850 do {
851 // Is this child already one of our children?
852
853 iter = child->getParentIterator( gIOPowerPlane );
854 if ( iter )
855 {
856 IORegistryEntry * entry;
857 OSObject * next;
858
859 while ((next = iter->getNextObject()))
860 {
861 if ((entry = OSDynamicCast(IORegistryEntry, next)) &&
862 isChild(entry, gIOPowerPlane))
863 {
864 ok = false;
865 break;
866 }
867 }
868 iter->release();
869 }
870 if (!ok)
871 {
872 PM_LOG("%s: %s (%p) is already a child\n",
873 getName(), child->getName(), child);
874 break;
875 }
876
877 // Add the child to the power plane immediately, but the
878 // joining connection is marked as not ready.
879 // We want the child to appear in the power plane before
880 // returning to the caller, but don't want the caller to
881 // block on the PM work loop.
882
883 connection = new IOPowerConnection;
884 if (!connection)
885 break;
886
887 // Create a chain of PM requests to perform the bottom-half
888 // work from the PM work loop.
889
890 requests[0] = acquirePMRequest(
891 /* target */ this,
892 /* type */ kIOPMRequestTypeAddPowerChild1 );
893
894 requests[1] = acquirePMRequest(
895 /* target */ child,
896 /* type */ kIOPMRequestTypeAddPowerChild2 );
897
898 requests[2] = acquirePMRequest(
899 /* target */ this,
900 /* type */ kIOPMRequestTypeAddPowerChild3 );
901
902 if (!requests[0] || !requests[1] || !requests[2])
903 break;
904
905 requests[0]->attachNextRequest( requests[1] );
906 requests[1]->attachNextRequest( requests[2] );
907
908 connection->init();
909 connection->start(this);
910 connection->setAwaitingAck(false);
911 connection->setReadyFlag(false);
912
913 attachToChild( connection, gIOPowerPlane );
914 connection->attachToChild( child, gIOPowerPlane );
915
916 // connection needs to be released
917 requests[0]->fArg0 = connection;
918 requests[1]->fArg0 = connection;
919 requests[2]->fArg0 = connection;
920
921 submitPMRequest( requests, 3 );
922 return kIOReturnSuccess;
923 }
924 while (false);
925
926 if (connection) connection->release();
927 if (requests[0]) releasePMRequest(requests[0]);
928 if (requests[1]) releasePMRequest(requests[1]);
929 if (requests[2]) releasePMRequest(requests[2]);
930
931 // Silent failure, to prevent platform drivers from adding the child
932 // to the root domain.
933
934 return kIOReturnSuccess;
935 }
936
937 //*********************************************************************************
938 // [private] addPowerChild1
939 //
940 // Step 1/3 of adding a power child. Called on the power parent.
941 //*********************************************************************************
942
943 void IOService::addPowerChild1 ( IOPMRequest * request )
944 {
945 unsigned long tempDesire = 0;
946
947 // Make us temporary usable before adding the child.
948
949 PM_ASSERT_IN_GATE();
950 OUR_PMLog( kPMLogMakeUsable, kPMLogMakeUsable, 0 );
951
952 if (fControllingDriver && inPlane(gIOPowerPlane) && fParentsKnowState)
953 {
954 tempDesire = fNumberOfPowerStates - 1;
955 }
956
957 if (tempDesire && (IS_PM_ROOT || (fMaxPowerState >= tempDesire)))
958 {
959 adjustPowerState(tempDesire);
960 }
961 }
962
963 //*********************************************************************************
964 // [private] addPowerChild2
965 //
966 // Step 2/3 of adding a power child. Called on the joining child.
967 // Execution blocked behind addPowerChild1.
968 //*********************************************************************************
969
970 void IOService::addPowerChild2 ( IOPMRequest * request )
971 {
972 IOPowerConnection * connection = (IOPowerConnection *) request->fArg0;
973 IOService * parent;
974 IOPMPowerFlags powerFlags;
975 bool knowsState;
976 unsigned long powerState;
977 unsigned long tempDesire;
978
979 PM_ASSERT_IN_GATE();
980 parent = (IOService *) connection->getParentEntry(gIOPowerPlane);
981
982 if (!parent || !inPlane(gIOPowerPlane))
983 {
984 PM_LOG("%s: addPowerChild2 not in power plane\n", getName());
985 return;
986 }
987
988 // Parent will be waiting for us to complete this stage.
989 // It is safe to directly access parent's vars.
990
991 knowsState = (parent->fPowerStates) && (parent->fParentsKnowState);
992 powerState = parent->fCurrentPowerState;
993
994 if (knowsState)
995 powerFlags = parent->fPowerStates[powerState].outputPowerFlags;
996 else
997 powerFlags = 0;
998
999 // Set our power parent.
1000
1001 OUR_PMLog(kPMLogSetParent, knowsState, powerFlags);
1002
1003 setParentInfo( powerFlags, connection, knowsState );
1004
1005 connection->setReadyFlag(true);
1006
1007 if ( fControllingDriver && fParentsKnowState )
1008 {
1009 fMaxPowerState = fControllingDriver->maxCapabilityForDomainState(fParentsCurrentPowerFlags);
1010 // initially change into the state we are already in
1011 tempDesire = fControllingDriver->initialPowerStateForDomainState(fParentsCurrentPowerFlags);
1012 fPreviousRequestPowerFlags = (IOPMPowerFlags)(-1);
1013 adjustPowerState(tempDesire);
1014 }
1015
1016 getPMRootDomain()->tagPowerPlaneService(this, &fPMActions);
1017 }
1018
1019 //*********************************************************************************
1020 // [private] addPowerChild3
1021 //
1022 // Step 3/3 of adding a power child. Called on the parent.
1023 // Execution blocked behind addPowerChild2.
1024 //*********************************************************************************
1025
1026 void IOService::addPowerChild3 ( IOPMRequest * request )
1027 {
1028 IOPowerConnection * connection = (IOPowerConnection *) request->fArg0;
1029 IOService * child;
1030 IOPMrootDomain * rootDomain = getPMRootDomain();
1031
1032 PM_ASSERT_IN_GATE();
1033 child = (IOService *) connection->getChildEntry(gIOPowerPlane);
1034
1035 if (child && inPlane(gIOPowerPlane))
1036 {
1037 if (child->getProperty("IOPMStrictTreeOrder"))
1038 {
1039 PM_LOG1("%s: strict PM order enforced\n", getName());
1040 fStrictTreeOrder = true;
1041 }
1042
1043 if (rootDomain)
1044 rootDomain->joinAggressiveness( child );
1045 }
1046 else
1047 {
1048 PM_LOG("%s: addPowerChild3 not in power plane\n", getName());
1049 }
1050
1051 connection->release();
1052 }
1053
1054 #ifndef __LP64__
1055 //*********************************************************************************
1056 // [deprecated] setPowerParent
1057 //
1058 // Power Management is informing us who our parent is.
1059 // If we have a controlling driver, find out, given our newly-informed
1060 // power domain state, what state it would be in, and then tell it
1061 // to assume that state.
1062 //*********************************************************************************
1063
1064 IOReturn IOService::setPowerParent (
1065 IOPowerConnection * theParent, bool stateKnown, IOPMPowerFlags powerFlags )
1066 {
1067 return kIOReturnUnsupported;
1068 }
1069 #endif /* !__LP64__ */
1070
1071 //*********************************************************************************
1072 // [public] removePowerChild
1073 //
1074 // Called on a parent whose child is being removed by PMstop().
1075 //*********************************************************************************
1076
1077 IOReturn IOService::removePowerChild ( IOPowerConnection * theNub )
1078 {
1079 IORegistryEntry * theChild;
1080
1081 PM_ASSERT_IN_GATE();
1082 OUR_PMLog( kPMLogRemoveChild, 0, 0 );
1083
1084 theNub->retain();
1085
1086 // detach nub from child
1087 theChild = theNub->copyChildEntry(gIOPowerPlane);
1088 if ( theChild )
1089 {
1090 theNub->detachFromChild(theChild, gIOPowerPlane);
1091 theChild->release();
1092 }
1093 // detach from the nub
1094 detachFromChild(theNub, gIOPowerPlane);
1095
1096 // Are we awaiting an ack from this child?
1097 if ( theNub->getAwaitingAck() )
1098 {
1099 // yes, pretend we got one
1100 theNub->setAwaitingAck(false);
1101 if (fHeadNotePendingAcks != 0 )
1102 {
1103 // that's one fewer ack to worry about
1104 fHeadNotePendingAcks--;
1105
1106 // is that the last?
1107 if ( fHeadNotePendingAcks == 0 )
1108 {
1109 stop_ack_timer();
1110
1111 // Request unblocked, work queue
1112 // should re-scan all busy requests.
1113 gIOPMWorkQueue->incrementProducerCount();
1114 }
1115 }
1116 }
1117
1118 theNub->release();
1119
1120 // A child has gone away, re-scan children desires and clamp bits.
1121 // The fPendingAdjustPowerRequest helps to reduce redundant parent work.
1122
1123 if (!fAdjustPowerScheduled)
1124 {
1125 IOPMRequest * request;
1126 request = acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState );
1127 if (request)
1128 {
1129 submitPMRequest( request );
1130 fAdjustPowerScheduled = true;
1131 }
1132 }
1133
1134 return IOPMNoErr;
1135 }
1136
1137 //*********************************************************************************
1138 // [public] registerPowerDriver
1139 //
1140 // A driver has called us volunteering to control power to our device.
1141 //*********************************************************************************
1142
1143 IOReturn IOService::registerPowerDriver (
1144 IOService * powerDriver,
1145 IOPMPowerState * powerStates,
1146 unsigned long numberOfStates )
1147 {
1148 IOPMRequest * request;
1149 IOPMPSEntry * powerStatesCopy = 0;
1150
1151 if (!initialized)
1152 return IOPMNotYetInitialized;
1153
1154 // Validate arguments.
1155 if (!powerStates || (numberOfStates < 2))
1156 {
1157 OUR_PMLog(kPMLogControllingDriverErr5, numberOfStates, 0);
1158 return kIOReturnBadArgument;
1159 }
1160
1161 if (!powerDriver || !powerDriver->initialized)
1162 {
1163 OUR_PMLog(kPMLogControllingDriverErr4, 0, 0);
1164 return kIOReturnBadArgument;
1165 }
1166
1167 if (powerStates[0].version != kIOPMPowerStateVersion1)
1168 {
1169 OUR_PMLog(kPMLogControllingDriverErr1, powerStates[0].version, 0);
1170 return kIOReturnBadArgument;
1171 }
1172
1173 do {
1174 // Make a copy of the supplied power state array.
1175 powerStatesCopy = IONew(IOPMPSEntry, numberOfStates);
1176 if (!powerStatesCopy)
1177 break;
1178
1179 for (uint32_t i = 0; i < numberOfStates; i++)
1180 {
1181 powerStatesCopy[i].capabilityFlags = powerStates[i].capabilityFlags;
1182 powerStatesCopy[i].outputPowerFlags = powerStates[i].outputPowerCharacter;
1183 powerStatesCopy[i].inputPowerFlags = powerStates[i].inputPowerRequirement;
1184 powerStatesCopy[i].staticPower = powerStates[i].staticPower;
1185 powerStatesCopy[i].settleUpTime = powerStates[i].settleUpTime;
1186 powerStatesCopy[i].settleDownTime = powerStates[i].settleDownTime;
1187 }
1188
1189 request = acquirePMRequest( this, kIOPMRequestTypeRegisterPowerDriver );
1190 if (!request)
1191 break;
1192
1193 powerDriver->retain();
1194 request->fArg0 = (void *) powerDriver;
1195 request->fArg1 = (void *) powerStatesCopy;
1196 request->fArg2 = (void *) numberOfStates;
1197
1198 submitPMRequest( request );
1199 return kIOReturnSuccess;
1200 }
1201 while (false);
1202
1203 if (powerStatesCopy)
1204 IODelete(powerStatesCopy, IOPMPSEntry, numberOfStates);
1205 return kIOReturnNoMemory;
1206 }
1207
1208 //*********************************************************************************
1209 // [private] handleRegisterPowerDriver
1210 //*********************************************************************************
1211
1212 void IOService::handleRegisterPowerDriver ( IOPMRequest * request )
1213 {
1214 IOService * powerDriver = (IOService *) request->fArg0;
1215 IOPMPSEntry * powerStates = (IOPMPSEntry *) request->fArg1;
1216 unsigned long numberOfStates = (unsigned long) request->fArg2;
1217 unsigned long i;
1218 IOService * root;
1219 OSIterator * iter;
1220
1221 PM_ASSERT_IN_GATE();
1222 assert(powerStates);
1223 assert(powerDriver);
1224 assert(numberOfStates > 1);
1225
1226 if ( !fNumberOfPowerStates )
1227 {
1228 OUR_PMLog(kPMLogControllingDriver,
1229 (unsigned long) numberOfStates,
1230 (unsigned long) kIOPMPowerStateVersion1);
1231
1232 fPowerStates = powerStates;
1233 fNumberOfPowerStates = numberOfStates;
1234 fControllingDriver = powerDriver;
1235 fCurrentCapabilityFlags = fPowerStates[0].capabilityFlags;
1236
1237 // make a mask of all the character bits we know about
1238 fOutputPowerCharacterFlags = 0;
1239 for ( i = 0; i < numberOfStates; i++ ) {
1240 fOutputPowerCharacterFlags |= fPowerStates[i].outputPowerFlags;
1241 }
1242
1243 // Register powerDriver as interested, unless already done.
1244 // We don't want to register the default implementation since
1245 // it does nothing. One ramification of not always registering
1246 // is the one fewer retain count held.
1247
1248 root = getPlatform()->getProvider();
1249 assert(root);
1250 if (!root ||
1251 ((OSMemberFunctionCast(void (*)(void),
1252 root, &IOService::powerStateDidChangeTo)) !=
1253 ((OSMemberFunctionCast(void (*)(void),
1254 this, &IOService::powerStateDidChangeTo)))) ||
1255 ((OSMemberFunctionCast(void (*)(void),
1256 root, &IOService::powerStateWillChangeTo)) !=
1257 ((OSMemberFunctionCast(void (*)(void),
1258 this, &IOService::powerStateWillChangeTo)))))
1259 {
1260 if (fInterestedDrivers->findItem(powerDriver) == NULL)
1261 {
1262 PM_LOCK();
1263 fInterestedDrivers->appendNewInformee(powerDriver);
1264 PM_UNLOCK();
1265 }
1266 }
1267
1268 // Examine all existing power clients and perform limit check.
1269
1270 if (fPowerClients)
1271 {
1272 iter = OSCollectionIterator::withCollection(fPowerClients);
1273 if (iter)
1274 {
1275 const OSSymbol * client;
1276 while ((client = (const OSSymbol *) iter->getNextObject()))
1277 {
1278 uint32_t powerState = getPowerStateForClient(client);
1279 if (powerState >= numberOfStates)
1280 {
1281 updatePowerClient(client, numberOfStates - 1);
1282 }
1283 }
1284 iter->release();
1285 }
1286 }
1287
1288 if ( inPlane(gIOPowerPlane) && fParentsKnowState )
1289 {
1290 unsigned long tempDesire;
1291 fMaxPowerState = fControllingDriver->maxCapabilityForDomainState(fParentsCurrentPowerFlags);
1292 // initially change into the state we are already in
1293 tempDesire = fControllingDriver->initialPowerStateForDomainState(fParentsCurrentPowerFlags);
1294 adjustPowerState(tempDesire);
1295 }
1296 }
1297 else
1298 {
1299 OUR_PMLog(kPMLogControllingDriverErr2, numberOfStates, 0);
1300 IODelete(powerStates, IOPMPSEntry, numberOfStates);
1301 }
1302
1303 powerDriver->release();
1304 }
1305
1306 //*********************************************************************************
1307 // [public] registerInterestedDriver
1308 //
1309 // Add the caller to our list of interested drivers and return our current
1310 // power state. If we don't have a power-controlling driver yet, we will
1311 // call this interested driver again later when we do get a driver and find
1312 // out what the current power state of the device is.
1313 //*********************************************************************************
1314
1315 IOPMPowerFlags IOService::registerInterestedDriver ( IOService * driver )
1316 {
1317 IOPMRequest * request;
1318 bool signal;
1319
1320 if (!driver || !initialized || !fInterestedDrivers)
1321 return 0;
1322
1323 PM_LOCK();
1324 signal = (!fInsertInterestSet && !fRemoveInterestSet);
1325 if (fInsertInterestSet == NULL)
1326 fInsertInterestSet = OSSet::withCapacity(4);
1327 if (fInsertInterestSet)
1328 {
1329 fInsertInterestSet->setObject(driver);
1330 if (fRemoveInterestSet)
1331 fRemoveInterestSet->removeObject(driver);
1332 }
1333 PM_UNLOCK();
1334
1335 if (signal)
1336 {
1337 request = acquirePMRequest( this, kIOPMRequestTypeInterestChanged );
1338 if (request)
1339 submitPMRequest( request );
1340 }
1341
1342 // This return value cannot be trusted, but return a value
1343 // for those clients that care.
1344
1345 OUR_PMLog(kPMLogInterestedDriver, kIOPMDeviceUsable, 2);
1346 return kIOPMDeviceUsable;
1347 }
1348
1349 //*********************************************************************************
1350 // [public] deRegisterInterestedDriver
1351 //*********************************************************************************
1352
1353 IOReturn IOService::deRegisterInterestedDriver ( IOService * driver )
1354 {
1355 IOPMinformeeList * list;
1356 IOPMinformee * item;
1357 IOPMRequest * request;
1358 bool signal;
1359
1360 if (!driver)
1361 return kIOReturnBadArgument;
1362 if (!initialized || !fInterestedDrivers)
1363 return IOPMNotPowerManaged;
1364
1365 PM_LOCK();
1366 signal = (!fRemoveInterestSet && !fInsertInterestSet);
1367 if (fRemoveInterestSet == NULL)
1368 fRemoveInterestSet = OSSet::withCapacity(4);
1369 if (fRemoveInterestSet)
1370 {
1371 fRemoveInterestSet->setObject(driver);
1372 if (fInsertInterestSet)
1373 fInsertInterestSet->removeObject(driver);
1374
1375 list = fInterestedDrivers;
1376 item = list->findItem(driver);
1377 if (item && item->active)
1378 {
1379 item->active = false;
1380 waitForPMDriverCall( driver );
1381 }
1382 }
1383 PM_UNLOCK();
1384
1385 if (signal)
1386 {
1387 request = acquirePMRequest( this, kIOPMRequestTypeInterestChanged );
1388 if (request)
1389 submitPMRequest( request );
1390 }
1391
1392 return IOPMNoErr;
1393 }
1394
1395 //*********************************************************************************
1396 // [private] handleInterestChanged
1397 //
1398 // Handle interest added or removed.
1399 //*********************************************************************************
1400
1401 void IOService::handleInterestChanged( IOPMRequest * request )
1402 {
1403 IOService * driver;
1404 IOPMinformee * informee;
1405 IOPMinformeeList * list = fInterestedDrivers;
1406
1407 PM_LOCK();
1408
1409 if (fInsertInterestSet)
1410 {
1411 while ((driver = (IOService *) fInsertInterestSet->getAnyObject()))
1412 {
1413 if (list->findItem(driver) == NULL)
1414 {
1415 informee = list->appendNewInformee(driver);
1416 }
1417 fInsertInterestSet->removeObject(driver);
1418 }
1419 fInsertInterestSet->release();
1420 fInsertInterestSet = 0;
1421 }
1422
1423 if (fRemoveInterestSet)
1424 {
1425 while ((driver = (IOService *) fRemoveInterestSet->getAnyObject()))
1426 {
1427 informee = list->findItem(driver);
1428 if (informee)
1429 {
1430 // Clean-up async interest acknowledgement
1431 if (fHeadNotePendingAcks && informee->timer)
1432 {
1433 informee->timer = 0;
1434 fHeadNotePendingAcks--;
1435 }
1436 list->removeFromList(driver);
1437 }
1438 fRemoveInterestSet->removeObject(driver);
1439 }
1440 fRemoveInterestSet->release();
1441 fRemoveInterestSet = 0;
1442 }
1443
1444 PM_UNLOCK();
1445 }
1446
1447 //*********************************************************************************
1448 // [public] acknowledgePowerChange
1449 //
1450 // After we notified one of the interested drivers or a power-domain child
1451 // of an impending change in power, it has called to say it is now
1452 // prepared for the change. If this object is the last to
1453 // acknowledge this change, we take whatever action we have been waiting
1454 // for.
1455 // That may include acknowledging to our parent. In this case, we do it
1456 // last of all to insure that this doesn't cause the parent to call us some-
1457 // where else and alter data we are relying on here (like the very existance
1458 // of a "current change note".)
1459 //*********************************************************************************
1460
1461 IOReturn IOService::acknowledgePowerChange ( IOService * whichObject )
1462 {
1463 IOPMRequest * request;
1464
1465 if (!initialized)
1466 return IOPMNotYetInitialized;
1467 if (!whichObject)
1468 return kIOReturnBadArgument;
1469
1470 request = acquirePMRequest( this, kIOPMRequestTypeAckPowerChange );
1471 if (!request)
1472 return kIOReturnNoMemory;
1473
1474 whichObject->retain();
1475 request->fArg0 = whichObject;
1476
1477 submitPMRequest( request );
1478 return IOPMNoErr;
1479 }
1480
1481 //*********************************************************************************
1482 // [private] handleAcknowledgePowerChange
1483 //*********************************************************************************
1484
1485 bool IOService::handleAcknowledgePowerChange ( IOPMRequest * request )
1486 {
1487 IOPMinformee * informee;
1488 unsigned long childPower = kIOPMUnknown;
1489 IOService * theChild;
1490 IOService * whichObject;
1491 bool all_acked = false;
1492
1493 PM_ASSERT_IN_GATE();
1494 whichObject = (IOService *) request->fArg0;
1495 assert(whichObject);
1496
1497 // one of our interested drivers?
1498 informee = fInterestedDrivers->findItem( whichObject );
1499 if ( informee == NULL )
1500 {
1501 if ( !isChild(whichObject, gIOPowerPlane) )
1502 {
1503 OUR_PMLog(kPMLogAcknowledgeErr1, 0, 0);
1504 goto no_err;
1505 } else {
1506 OUR_PMLog(kPMLogChildAcknowledge, fHeadNotePendingAcks, 0);
1507 }
1508 } else {
1509 OUR_PMLog(kPMLogDriverAcknowledge, fHeadNotePendingAcks, 0);
1510 }
1511
1512 if ( fHeadNotePendingAcks != 0 )
1513 {
1514 assert(fPowerStates != NULL);
1515
1516 // yes, make sure we're expecting acks
1517 if ( informee != NULL )
1518 {
1519 // it's an interested driver
1520 // make sure we're expecting this ack
1521 if ( informee->timer != 0 )
1522 {
1523 #if LOG_SETPOWER_TIMES
1524 if (informee->timer > 0)
1525 {
1526 uint64_t nsec = computeTimeDeltaNS(&informee->startTime);
1527 if (nsec > LOG_SETPOWER_TIMES)
1528 PM_LOG("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) async took %d ms\n",
1529 informee->whatObject->getName(),
1530 (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
1531 informee->whatObject,
1532 fName, fCurrentPowerState, fHeadNotePowerState, NS_TO_US(nsec));
1533
1534 uint16_t logType = (fDriverCallReason == kDriverCallInformPreChange)
1535 ? kIOPMEventTypePSWillChangeTo
1536 : kIOPMEventTypePSDidChangeTo;
1537
1538 PMEventDetails *details = PMEventDetails::eventDetails(
1539 logType,
1540 fName,
1541 (uintptr_t)this,
1542 informee->whatObject->getName(),
1543 0, 0, 0,
1544 NS_TO_MS(nsec));
1545
1546 getPMRootDomain()->recordAndReleasePMEventGated( details );
1547 }
1548 #endif
1549 // mark it acked
1550 informee->timer = 0;
1551 // that's one fewer to worry about
1552 fHeadNotePendingAcks--;
1553 } else {
1554 // this driver has already acked
1555 OUR_PMLog(kPMLogAcknowledgeErr2, 0, 0);
1556 }
1557 } else {
1558 // it's a child
1559 // make sure we're expecting this ack
1560 if ( ((IOPowerConnection *)whichObject)->getAwaitingAck() )
1561 {
1562 // that's one fewer to worry about
1563 fHeadNotePendingAcks--;
1564 ((IOPowerConnection *)whichObject)->setAwaitingAck(false);
1565 theChild = (IOService *)whichObject->copyChildEntry(gIOPowerPlane);
1566 if ( theChild )
1567 {
1568 childPower = theChild->currentPowerConsumption();
1569 theChild->release();
1570 }
1571 if ( childPower == kIOPMUnknown )
1572 {
1573 fHeadNotePowerArrayEntry->staticPower = kIOPMUnknown;
1574 } else {
1575 if (fHeadNotePowerArrayEntry->staticPower != kIOPMUnknown)
1576 {
1577 fHeadNotePowerArrayEntry->staticPower += childPower;
1578 }
1579 }
1580 }
1581 }
1582
1583 if ( fHeadNotePendingAcks == 0 ) {
1584 // yes, stop the timer
1585 stop_ack_timer();
1586 // and now we can continue
1587 all_acked = true;
1588 }
1589 } else {
1590 OUR_PMLog(kPMLogAcknowledgeErr3, 0, 0); // not expecting anybody to ack
1591 }
1592
1593 no_err:
1594 if (whichObject)
1595 whichObject->release();
1596
1597 return all_acked;
1598 }
1599
1600 //*********************************************************************************
1601 // [public] acknowledgeSetPowerState
1602 //
1603 // After we instructed our controlling driver to change power states,
1604 // it has called to say it has finished doing so.
1605 // We continue to process the power state change.
1606 //*********************************************************************************
1607
1608 IOReturn IOService::acknowledgeSetPowerState ( void )
1609 {
1610 IOPMRequest * request;
1611
1612 if (!initialized)
1613 return IOPMNotYetInitialized;
1614
1615 request = acquirePMRequest( this, kIOPMRequestTypeAckSetPowerState );
1616 if (!request)
1617 return kIOReturnNoMemory;
1618
1619 submitPMRequest( request );
1620 return kIOReturnSuccess;
1621 }
1622
1623 //*********************************************************************************
1624 // [private] adjustPowerState
1625 //*********************************************************************************
1626
1627 void IOService::adjustPowerState ( uint32_t clamp )
1628 {
1629 PM_ASSERT_IN_GATE();
1630 computeDesiredState(clamp);
1631 if (fControllingDriver && fParentsKnowState && inPlane(gIOPowerPlane))
1632 {
1633 IOPMPowerChangeFlags changeFlags = kIOPMSelfInitiated;
1634
1635 // Indicate that children desires were ignored, and do not ask
1636 // apps for permission to drop power. This is used by root domain
1637 // for demand sleep.
1638
1639 if (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride)
1640 changeFlags |= (kIOPMIgnoreChildren | kIOPMSkipAskPowerDown);
1641
1642 startPowerChange(
1643 /* flags */ changeFlags,
1644 /* power state */ fDesiredPowerState,
1645 /* domain flags */ 0,
1646 /* connection */ 0,
1647 /* parent flags */ 0);
1648 }
1649 }
1650
1651 //*********************************************************************************
1652 // [public] synchronizePowerTree
1653 //*********************************************************************************
1654
1655 IOReturn IOService::synchronizePowerTree (
1656 IOOptionBits options,
1657 IOService * notifyRoot )
1658 {
1659 IOPMRequest * request_c = 0;
1660 IOPMRequest * request_s;
1661
1662 if (this != getPMRootDomain())
1663 return kIOReturnBadArgument;
1664 if (!initialized)
1665 return kIOPMNotYetInitialized;
1666
1667 if (notifyRoot)
1668 {
1669 IOPMRequest * nr;
1670
1671 // Cancels don't need to be synchronized.
1672 nr = acquirePMRequest(notifyRoot, kIOPMRequestTypeChildNotifyDelayCancel);
1673 if (nr) submitPMRequest(nr);
1674 nr = acquirePMRequest(getPMRootDomain(), kIOPMRequestTypeChildNotifyDelayCancel);
1675 if (nr) submitPMRequest(nr);
1676 }
1677
1678 request_s = acquirePMRequest( this, kIOPMRequestTypeSynchronizePowerTree );
1679 if (!request_s)
1680 goto error_no_memory;
1681
1682 if (options & kIOPMSyncCancelPowerDown)
1683 request_c = acquirePMRequest( this, kIOPMRequestTypeIdleCancel );
1684 if (request_c)
1685 {
1686 request_c->attachNextRequest( request_s );
1687 submitPMRequest(request_c);
1688 }
1689
1690 request_s->fArg0 = (void *)(uintptr_t) options;
1691 submitPMRequest(request_s);
1692
1693 return kIOReturnSuccess;
1694
1695 error_no_memory:
1696 if (request_c) releasePMRequest(request_c);
1697 if (request_s) releasePMRequest(request_s);
1698 return kIOReturnNoMemory;
1699 }
1700
1701 //*********************************************************************************
1702 // [private] handleSynchronizePowerTree
1703 //*********************************************************************************
1704
1705 void IOService::handleSynchronizePowerTree ( IOPMRequest * request )
1706 {
1707 PM_ASSERT_IN_GATE();
1708 if (fControllingDriver && fParentsKnowState && inPlane(gIOPowerPlane) &&
1709 (fCurrentPowerState == fNumberOfPowerStates - 1))
1710 {
1711 IOOptionBits options = (uintptr_t) request->fArg0;
1712
1713 startPowerChange(
1714 /* flags */ kIOPMSelfInitiated | kIOPMSynchronize |
1715 (options & kIOPMSyncNoChildNotify),
1716 /* power state */ fCurrentPowerState,
1717 /* domain flags */ 0,
1718 /* connection */ 0,
1719 /* parent flags */ 0);
1720 }
1721 }
1722
1723 #ifndef __LP64__
1724 //*********************************************************************************
1725 // [deprecated] powerDomainWillChangeTo
1726 //
1727 // Called by the power-hierarchy parent notifying of a new power state
1728 // in the power domain.
1729 // We enqueue a parent power-change to our queue of power changes.
1730 // This may or may not cause us to change power, depending on what
1731 // kind of change is occuring in the domain.
1732 //*********************************************************************************
1733
1734 IOReturn IOService::powerDomainWillChangeTo (
1735 IOPMPowerFlags newPowerFlags,
1736 IOPowerConnection * whichParent )
1737 {
1738 assert(false);
1739 return kIOReturnUnsupported;
1740 }
1741 #endif /* !__LP64__ */
1742
1743 //*********************************************************************************
1744 // [private] handlePowerDomainWillChangeTo
1745 //*********************************************************************************
1746
1747 void IOService::handlePowerDomainWillChangeTo ( IOPMRequest * request )
1748 {
1749 IOPMPowerFlags parentPowerFlags = (IOPMPowerFlags) request->fArg0;
1750 IOPowerConnection * whichParent = (IOPowerConnection *) request->fArg1;
1751 IOPMPowerChangeFlags parentChangeFlags = (IOPMPowerChangeFlags)(uintptr_t) request->fArg2;
1752 IOPMPowerChangeFlags myChangeFlags;
1753 OSIterator * iter;
1754 OSObject * next;
1755 IOPowerConnection * connection;
1756 IOPMPowerStateIndex newPowerState;
1757 IOPMPowerFlags combinedPowerFlags;
1758 bool savedParentsKnowState;
1759 IOReturn result = IOPMAckImplied;
1760
1761 PM_ASSERT_IN_GATE();
1762 OUR_PMLog(kPMLogWillChange, parentPowerFlags, 0);
1763
1764 if (!inPlane(gIOPowerPlane) || !whichParent || !whichParent->getAwaitingAck())
1765 {
1766 PM_LOG("%s::%s not in power tree\n", getName(), __FUNCTION__);
1767 goto exit_no_ack;
1768 }
1769
1770 savedParentsKnowState = fParentsKnowState;
1771
1772 // Combine parents' output power flags.
1773
1774 combinedPowerFlags = 0;
1775
1776 iter = getParentIterator(gIOPowerPlane);
1777 if ( iter )
1778 {
1779 while ( (next = iter->getNextObject()) )
1780 {
1781 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
1782 {
1783 if ( connection == whichParent )
1784 combinedPowerFlags |= parentPowerFlags;
1785 else
1786 combinedPowerFlags |= connection->parentCurrentPowerFlags();
1787 }
1788 }
1789 iter->release();
1790 }
1791
1792 // If our initial change has yet to occur, then defer the power change
1793 // until after the power domain has completed its power transition.
1794
1795 if ( fControllingDriver && !fInitialPowerChange )
1796 {
1797 newPowerState = fControllingDriver->maxCapabilityForDomainState(
1798 combinedPowerFlags);
1799
1800 // Absorb parent's kIOPMSynchronize flag.
1801 myChangeFlags = kIOPMParentInitiated | kIOPMDomainWillChange |
1802 (parentChangeFlags & kIOPMSynchronize);
1803
1804 result = startPowerChange(
1805 /* flags */ myChangeFlags,
1806 /* power state */ newPowerState,
1807 /* domain flags */ combinedPowerFlags,
1808 /* connection */ whichParent,
1809 /* parent flags */ parentPowerFlags);
1810 }
1811
1812 // If parent is dropping power, immediately update the parent's
1813 // capability flags. Any future merging of parent(s) combined
1814 // power flags should account for this power drop.
1815
1816 if (parentChangeFlags & kIOPMDomainPowerDrop)
1817 {
1818 setParentInfo(parentPowerFlags, whichParent, true);
1819 }
1820
1821 // Parent is expecting an ACK from us. If we did not embark on a state
1822 // transition, i.e. startPowerChange() returned IOPMAckImplied. We are
1823 // still required to issue an ACK to our parent.
1824
1825 if (IOPMAckImplied == result)
1826 {
1827 IOService * parent;
1828 parent = (IOService *) whichParent->copyParentEntry(gIOPowerPlane);
1829 assert(parent);
1830 if ( parent )
1831 {
1832 parent->acknowledgePowerChange( whichParent );
1833 parent->release();
1834 }
1835 }
1836
1837 exit_no_ack:
1838 // Drop the retain from notifyChild().
1839 if (whichParent) whichParent->release();
1840 }
1841
1842 #ifndef __LP64__
1843 //*********************************************************************************
1844 // [deprecated] powerDomainDidChangeTo
1845 //
1846 // Called by the power-hierarchy parent after the power state of the power domain
1847 // has settled at a new level.
1848 // We enqueue a parent power-change to our queue of power changes.
1849 // This may or may not cause us to change power, depending on what
1850 // kind of change is occuring in the domain.
1851 //*********************************************************************************
1852
1853 IOReturn IOService::powerDomainDidChangeTo (
1854 IOPMPowerFlags newPowerFlags,
1855 IOPowerConnection * whichParent )
1856 {
1857 assert(false);
1858 return kIOReturnUnsupported;
1859 }
1860 #endif /* !__LP64__ */
1861
1862 //*********************************************************************************
1863 // [private] handlePowerDomainDidChangeTo
1864 //*********************************************************************************
1865
1866 void IOService::handlePowerDomainDidChangeTo ( IOPMRequest * request )
1867 {
1868 IOPMPowerFlags parentPowerFlags = (IOPMPowerFlags) request->fArg0;
1869 IOPowerConnection * whichParent = (IOPowerConnection *) request->fArg1;
1870 IOPMPowerChangeFlags parentChangeFlags = (IOPMPowerChangeFlags)(uintptr_t) request->fArg2;
1871 IOPMPowerChangeFlags myChangeFlags;
1872 IOPMPowerStateIndex newPowerState;
1873 IOPMPowerStateIndex initialDesire;
1874 bool savedParentsKnowState;
1875 IOReturn result = IOPMAckImplied;
1876
1877 PM_ASSERT_IN_GATE();
1878 OUR_PMLog(kPMLogDidChange, parentPowerFlags, 0);
1879
1880 if (!inPlane(gIOPowerPlane) || !whichParent || !whichParent->getAwaitingAck())
1881 {
1882 PM_LOG("%s::%s not in power tree\n", getName(), __FUNCTION__);
1883 goto exit_no_ack;
1884 }
1885
1886 savedParentsKnowState = fParentsKnowState;
1887
1888 setParentInfo(parentPowerFlags, whichParent, true);
1889
1890 if ( fControllingDriver )
1891 {
1892 newPowerState = fControllingDriver->maxCapabilityForDomainState(
1893 fParentsCurrentPowerFlags);
1894
1895 if (fInitialPowerChange)
1896 {
1897 initialDesire = fControllingDriver->initialPowerStateForDomainState(
1898 fParentsCurrentPowerFlags);
1899 computeDesiredState(initialDesire);
1900 }
1901
1902 // Absorb parent's kIOPMSynchronize flag.
1903 myChangeFlags = kIOPMParentInitiated | kIOPMDomainDidChange |
1904 (parentChangeFlags & kIOPMSynchronize);
1905
1906 result = startPowerChange(
1907 /* flags */ myChangeFlags,
1908 /* power state */ newPowerState,
1909 /* domain flags */ fParentsCurrentPowerFlags,
1910 /* connection */ whichParent,
1911 /* parent flags */ 0);
1912 }
1913
1914 // Parent is expecting an ACK from us. If we did not embark on a state
1915 // transition, i.e. startPowerChange() returned IOPMAckImplied. We are
1916 // still required to issue an ACK to our parent.
1917
1918 if (IOPMAckImplied == result)
1919 {
1920 IOService * parent;
1921 parent = (IOService *) whichParent->copyParentEntry(gIOPowerPlane);
1922 assert(parent);
1923 if ( parent )
1924 {
1925 parent->acknowledgePowerChange( whichParent );
1926 parent->release();
1927 }
1928 }
1929
1930 // If the parent registers its power driver late, then this is the
1931 // first opportunity to tell our parent about our desire.
1932
1933 if (!savedParentsKnowState && fParentsKnowState)
1934 {
1935 PM_LOG1("%s::powerDomainDidChangeTo parentsKnowState = true\n",
1936 getName());
1937 requestDomainPower( fDesiredPowerState );
1938 }
1939
1940 exit_no_ack:
1941 // Drop the retain from notifyChild().
1942 if (whichParent) whichParent->release();
1943 }
1944
1945 //*********************************************************************************
1946 // [private] setParentInfo
1947 //
1948 // Set our connection data for one specific parent, and then combine all the parent
1949 // data together.
1950 //*********************************************************************************
1951
1952 void IOService::setParentInfo (
1953 IOPMPowerFlags newPowerFlags,
1954 IOPowerConnection * whichParent,
1955 bool knowsState )
1956 {
1957 OSIterator * iter;
1958 OSObject * next;
1959 IOPowerConnection * conn;
1960
1961 PM_ASSERT_IN_GATE();
1962
1963 // set our connection data
1964 whichParent->setParentCurrentPowerFlags(newPowerFlags);
1965 whichParent->setParentKnowsState(knowsState);
1966
1967 // recompute our parent info
1968 fParentsCurrentPowerFlags = 0;
1969 fParentsKnowState = true;
1970
1971 iter = getParentIterator(gIOPowerPlane);
1972 if ( iter )
1973 {
1974 while ( (next = iter->getNextObject()) )
1975 {
1976 if ( (conn = OSDynamicCast(IOPowerConnection, next)) )
1977 {
1978 fParentsKnowState &= conn->parentKnowsState();
1979 fParentsCurrentPowerFlags |= conn->parentCurrentPowerFlags();
1980 }
1981 }
1982 iter->release();
1983 }
1984 }
1985
1986 //*********************************************************************************
1987 // [private] rebuildChildClampBits
1988 //
1989 // The ChildClamp bits (kIOPMChildClamp & kIOPMChildClamp2) in our capabilityFlags
1990 // indicate that one of our children (or grandchildren or great-grandchildren ...)
1991 // doesn't support idle or system sleep in its current state. Since we don't track
1992 // the origin of each bit, every time any child changes state we have to clear
1993 // these bits and rebuild them.
1994 //*********************************************************************************
1995
1996 void IOService::rebuildChildClampBits ( void )
1997 {
1998 unsigned long i;
1999 OSIterator * iter;
2000 OSObject * next;
2001 IOPowerConnection * connection;
2002 unsigned long powerState;
2003
2004 // A child's desires has changed. We need to rebuild the child-clamp bits in
2005 // our power state array. Start by clearing the bits in each power state.
2006
2007 for ( i = 0; i < fNumberOfPowerStates; i++ )
2008 {
2009 fPowerStates[i].capabilityFlags &= ~(kIOPMChildClamp | kIOPMChildClamp2);
2010 }
2011
2012 if (!inPlane(gIOPowerPlane))
2013 return;
2014
2015 // Loop through the children. When we encounter the calling child, save the
2016 // computed state as this child's desire. And set the ChildClamp bits in any
2017 // of our states that some child has clamp on.
2018
2019 iter = getChildIterator(gIOPowerPlane);
2020 if ( iter )
2021 {
2022 while ( (next = iter->getNextObject()) )
2023 {
2024 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
2025 {
2026 if (connection->getReadyFlag() == false)
2027 {
2028 PM_LOG3("[%s] %s: connection not ready\n",
2029 getName(), __FUNCTION__);
2030 continue;
2031 }
2032
2033 powerState = connection->getDesiredDomainState();
2034 if (powerState < fNumberOfPowerStates)
2035 {
2036 if ( connection->getPreventIdleSleepFlag() )
2037 fPowerStates[powerState].capabilityFlags |= kIOPMChildClamp;
2038 if ( connection->getPreventSystemSleepFlag() )
2039 fPowerStates[powerState].capabilityFlags |= kIOPMChildClamp2;
2040 }
2041 }
2042 }
2043 iter->release();
2044 }
2045 }
2046
2047 //*********************************************************************************
2048 // [public] requestPowerDomainState
2049 //
2050 // Called on a power parent when a child's power requirement changes.
2051 //*********************************************************************************
2052
2053 IOReturn IOService::requestPowerDomainState(
2054 IOPMPowerFlags childRequestPowerFlags,
2055 IOPowerConnection * childConnection,
2056 unsigned long specification )
2057 {
2058 IOPMPowerStateIndex ps;
2059 IOPMPowerFlags outputPowerFlags;
2060 IOService * child;
2061 IOPMRequest * subRequest;
2062 bool preventIdle, preventSleep;
2063 bool adjustPower = false;
2064
2065 if (!initialized)
2066 return IOPMNotYetInitialized;
2067
2068 if (gIOPMWorkLoop->onThread() == false)
2069 {
2070 PM_LOG("%s::requestPowerDomainState\n", getName());
2071 return kIOReturnSuccess;
2072 }
2073
2074 OUR_PMLog(kPMLogRequestDomain, childRequestPowerFlags, specification);
2075
2076 if (!isChild(childConnection, gIOPowerPlane))
2077 return kIOReturnNotAttached;
2078
2079 if (!fControllingDriver || !fNumberOfPowerStates)
2080 return kIOReturnNotReady;
2081
2082 child = (IOService *) childConnection->getChildEntry(gIOPowerPlane);
2083 assert(child);
2084
2085 preventIdle = ((childRequestPowerFlags & kIOPMPreventIdleSleep) != 0);
2086 preventSleep = ((childRequestPowerFlags & kIOPMPreventSystemSleep) != 0);
2087 childRequestPowerFlags &= ~(kIOPMPreventIdleSleep | kIOPMPreventSystemSleep);
2088
2089 // Merge in the power flags contributed by this power parent
2090 // at its current or impending power state.
2091
2092 outputPowerFlags = fPowerStates[fCurrentPowerState].outputPowerFlags;
2093 if (fMachineState != kIOPM_Finished)
2094 {
2095 if (IS_POWER_DROP && !IS_ROOT_DOMAIN)
2096 {
2097 // Use the lower power state when dropping power.
2098 // Must be careful since a power drop can be canceled
2099 // from the following states:
2100 // - kIOPM_OurChangeTellClientsPowerDown
2101 // - kIOPM_OurChangeTellPriorityClientsPowerDown
2102 //
2103 // The child must not wait for this parent to raise power
2104 // if the power drop was cancelled. The solution is to cancel
2105 // the power drop if possible, then schedule an adjustment to
2106 // re-evaluate the parent's power state.
2107 //
2108 // Root domain is excluded to avoid idle sleep issues. And permit
2109 // root domain children to pop up when system is going to sleep.
2110
2111 if ((fMachineState == kIOPM_OurChangeTellClientsPowerDown) ||
2112 (fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown))
2113 {
2114 fDoNotPowerDown = true; // cancel power drop
2115 adjustPower = true; // schedule an adjustment
2116 PM_LOG1("%s: power drop cancelled in state %u by %s\n",
2117 getName(), fMachineState, child->getName());
2118 }
2119 else
2120 {
2121 // Beyond cancellation point, report the impending state.
2122 outputPowerFlags =
2123 fPowerStates[fHeadNotePowerState].outputPowerFlags;
2124 }
2125 }
2126 else if (IS_POWER_RISE)
2127 {
2128 // When raising power, must report the output power flags from
2129 // child's perspective. A child power request may arrive while
2130 // parent is transitioning upwards. If a request arrives after
2131 // setParentInfo() has already recorded the output power flags
2132 // for the next power state, then using the power supplied by
2133 // fCurrentPowerState is incorrect, and might cause the child
2134 // to wait when it should not.
2135
2136 outputPowerFlags = childConnection->parentCurrentPowerFlags();
2137 }
2138 }
2139 child->fHeadNoteDomainTargetFlags |= outputPowerFlags;
2140
2141 // Map child's requested power flags to one of our power state.
2142
2143 for (ps = 0; ps < fNumberOfPowerStates; ps++)
2144 {
2145 if ((fPowerStates[ps].outputPowerFlags & childRequestPowerFlags) ==
2146 (fOutputPowerCharacterFlags & childRequestPowerFlags))
2147 break;
2148 }
2149 if (ps >= fNumberOfPowerStates)
2150 {
2151 ps = 0; // should never happen
2152 }
2153
2154 // Conditions that warrants a power adjustment on this parent.
2155 // Adjust power will also propagate any changes to the child's
2156 // prevent idle/sleep flags towards the root domain.
2157
2158 if (!childConnection->childHasRequestedPower() ||
2159 (ps != childConnection->getDesiredDomainState()) ||
2160 (childConnection->getPreventIdleSleepFlag() != preventIdle) ||
2161 (childConnection->getPreventSystemSleepFlag() != preventSleep))
2162 adjustPower = true;
2163
2164 #if ENABLE_DEBUG_LOGS
2165 if (adjustPower)
2166 {
2167 PM_LOG("requestPowerDomainState[%s]: %s, init %d, %u->%u\n",
2168 getName(), child->getName(),
2169 !childConnection->childHasRequestedPower(),
2170 (uint32_t) childConnection->getDesiredDomainState(),
2171 (uint32_t) ps);
2172 }
2173 #endif
2174
2175 // Record the child's desires on the connection.
2176 #if SUPPORT_IDLE_CANCEL
2177 bool attemptCancel = (preventIdle && !childConnection->getPreventIdleSleepFlag());
2178 #endif
2179 childConnection->setChildHasRequestedPower();
2180 childConnection->setDesiredDomainState( ps );
2181 childConnection->setPreventIdleSleepFlag( preventIdle );
2182 childConnection->setPreventSystemSleepFlag( preventSleep );
2183
2184 // Schedule a request to re-evaluate all children desires and
2185 // adjust power state. Submit a request if one wasn't pending,
2186 // or if the current request is part of a call tree.
2187
2188 if (adjustPower && !fDeviceOverrideEnabled &&
2189 (!fAdjustPowerScheduled || gIOPMRequest->getRootRequest()))
2190 {
2191 subRequest = acquirePMRequest(
2192 this, kIOPMRequestTypeAdjustPowerState, gIOPMRequest );
2193 if (subRequest)
2194 {
2195 submitPMRequest( subRequest );
2196 fAdjustPowerScheduled = true;
2197 }
2198 }
2199
2200 #if SUPPORT_IDLE_CANCEL
2201 if (attemptCancel)
2202 {
2203 subRequest = acquirePMRequest( this, kIOPMRequestTypeIdleCancel );
2204 if (subRequest)
2205 {
2206 submitPMRequest( subRequest );
2207 }
2208 }
2209 #endif
2210
2211 return kIOReturnSuccess;
2212 }
2213
2214 //*********************************************************************************
2215 // [public] temporaryPowerClampOn
2216 //
2217 // A power domain wants to clamp its power on till it has children which
2218 // will thendetermine the power domain state.
2219 //
2220 // We enter the highest state until addPowerChild is called.
2221 //*********************************************************************************
2222
2223 IOReturn IOService::temporaryPowerClampOn ( void )
2224 {
2225 return requestPowerState( gIOPMPowerClientChildProxy, kIOPMPowerStateMax );
2226 }
2227
2228 //*********************************************************************************
2229 // [public] makeUsable
2230 //
2231 // Some client of our device is asking that we become usable. Although
2232 // this has not come from a subclassed device object, treat it exactly
2233 // as if it had. In this way, subsequent requests for lower power from
2234 // a subclassed device object will pre-empt this request.
2235 //
2236 // We treat this as a subclass object request to switch to the
2237 // highest power state.
2238 //*********************************************************************************
2239
2240 IOReturn IOService::makeUsable ( void )
2241 {
2242 OUR_PMLog(kPMLogMakeUsable, 0, 0);
2243 return requestPowerState( gIOPMPowerClientDevice, kIOPMPowerStateMax );
2244 }
2245
2246 //*********************************************************************************
2247 // [public] currentCapability
2248 //*********************************************************************************
2249
2250 IOPMPowerFlags IOService::currentCapability ( void )
2251 {
2252 if (!initialized)
2253 return IOPMNotPowerManaged;
2254
2255 return fCurrentCapabilityFlags;
2256 }
2257
2258 //*********************************************************************************
2259 // [public] changePowerStateTo
2260 //
2261 // Called by our power-controlling driver to change power state. The new desired
2262 // power state is computed and compared against the current power state. If those
2263 // power states differ, then a power state change is initiated.
2264 //*********************************************************************************
2265
2266 IOReturn IOService::changePowerStateTo ( unsigned long ordinal )
2267 {
2268 OUR_PMLog(kPMLogChangeStateTo, ordinal, 0);
2269 return requestPowerState( gIOPMPowerClientDriver, ordinal );
2270 }
2271
2272 //*********************************************************************************
2273 // [protected] changePowerStateToPriv
2274 //
2275 // Called by our driver subclass to change power state. The new desired power
2276 // state is computed and compared against the current power state. If those
2277 // power states differ, then a power state change is initiated.
2278 //*********************************************************************************
2279
2280 IOReturn IOService::changePowerStateToPriv ( unsigned long ordinal )
2281 {
2282 OUR_PMLog(kPMLogChangeStateToPriv, ordinal, 0);
2283 return requestPowerState( gIOPMPowerClientDevice, ordinal );
2284 }
2285
2286 //*********************************************************************************
2287 // [protected] changePowerStateWithOverrideTo
2288 //
2289 // Called by our driver subclass to change power state. The new desired power
2290 // state is computed and compared against the current power state. If those
2291 // power states differ, then a power state change is initiated.
2292 // Override enforced - Children and Driver desires are ignored.
2293 //*********************************************************************************
2294
2295 IOReturn IOService::changePowerStateWithOverrideTo ( unsigned long ordinal )
2296 {
2297 IOPMRequest * request;
2298
2299 if (!initialized)
2300 return kIOPMNotYetInitialized;
2301
2302 OUR_PMLog(kPMLogChangeStateToPriv, ordinal, 0);
2303
2304 request = acquirePMRequest( this, kIOPMRequestTypeRequestPowerStateOverride );
2305 if (!request)
2306 return kIOReturnNoMemory;
2307
2308 gIOPMPowerClientDevice->retain();
2309 request->fArg0 = (void *) ordinal;
2310 request->fArg1 = (void *) gIOPMPowerClientDevice;
2311 request->fArg2 = 0;
2312 #if NOT_READY
2313 if (action)
2314 request->installCompletionAction( action, target, param );
2315 #endif
2316
2317 // Prevent needless downwards power transitions by clamping power
2318 // until the scheduled request is executed.
2319
2320 if (gIOPMWorkLoop->inGate() && (ordinal < fNumberOfPowerStates))
2321 {
2322 fTempClampPowerState = max(fTempClampPowerState, ordinal);
2323 fTempClampCount++;
2324 fOverrideMaxPowerState = ordinal;
2325 request->fArg2 = (void *) (uintptr_t) true;
2326 }
2327
2328 submitPMRequest( request );
2329 return IOPMNoErr;
2330 }
2331
2332 //*********************************************************************************
2333 // [private] requestPowerState
2334 //*********************************************************************************
2335
2336 IOReturn IOService::requestPowerState (
2337 const OSSymbol * client,
2338 uint32_t state )
2339 {
2340 IOPMRequest * request;
2341
2342 if (!client)
2343 return kIOReturnBadArgument;
2344 if (!initialized)
2345 return kIOPMNotYetInitialized;
2346
2347 request = acquirePMRequest( this, kIOPMRequestTypeRequestPowerState );
2348 if (!request)
2349 return kIOReturnNoMemory;
2350
2351 client->retain();
2352 request->fArg0 = (void *) state;
2353 request->fArg1 = (void *) client;
2354 request->fArg2 = 0;
2355 #if NOT_READY
2356 if (action)
2357 request->installCompletionAction( action, target, param );
2358 #endif
2359
2360 // Prevent needless downwards power transitions by clamping power
2361 // until the scheduled request is executed.
2362
2363 if (gIOPMWorkLoop->inGate() && (state < fNumberOfPowerStates))
2364 {
2365 fTempClampPowerState = max(fTempClampPowerState, state);
2366 fTempClampCount++;
2367 request->fArg2 = (void *) (uintptr_t) true;
2368 }
2369
2370 submitPMRequest( request );
2371 return IOPMNoErr;
2372 }
2373
2374 //*********************************************************************************
2375 // [private] handleRequestPowerState
2376 //*********************************************************************************
2377
2378 void IOService::handleRequestPowerState ( IOPMRequest * request )
2379 {
2380 const OSSymbol * client = (const OSSymbol *) request->fArg1;
2381 uint32_t state = (uint32_t)(uintptr_t) request->fArg0;
2382
2383 PM_ASSERT_IN_GATE();
2384 if (request->fArg2)
2385 {
2386 assert(fTempClampCount != 0);
2387 if (fTempClampCount) fTempClampCount--;
2388 if (!fTempClampCount) fTempClampPowerState = 0;
2389 }
2390
2391 if (fNumberOfPowerStates && (state >= fNumberOfPowerStates))
2392 state = fNumberOfPowerStates - 1;
2393
2394 // The power suppression due to changePowerStateWithOverrideTo() expires
2395 // upon the next "device" power request - changePowerStateToPriv().
2396
2397 if ((getPMRequestType() != kIOPMRequestTypeRequestPowerStateOverride) &&
2398 (client == gIOPMPowerClientDevice))
2399 fOverrideMaxPowerState = kIOPMPowerStateMax;
2400
2401 if ((state == 0) &&
2402 (client != gIOPMPowerClientDevice) &&
2403 (client != gIOPMPowerClientDriver) &&
2404 (client != gIOPMPowerClientChildProxy))
2405 removePowerClient(client);
2406 else
2407 updatePowerClient(client, state);
2408
2409 adjustPowerState();
2410 client->release();
2411 }
2412
2413 //*********************************************************************************
2414 // [private] Helper functions to update/remove power clients.
2415 //*********************************************************************************
2416
2417 void IOService::updatePowerClient( const OSSymbol * client, uint32_t powerState )
2418 {
2419 if (!fPowerClients)
2420 fPowerClients = OSDictionary::withCapacity(4);
2421 if (fPowerClients && client)
2422 {
2423 OSNumber * num = (OSNumber *) fPowerClients->getObject(client);
2424 if (num)
2425 num->setValue(powerState);
2426 else
2427 {
2428 num = OSNumber::withNumber(powerState, 32);
2429 if (num)
2430 {
2431 fPowerClients->setObject(client, num);
2432 num->release();
2433 }
2434 }
2435 }
2436 }
2437
2438 void IOService::removePowerClient( const OSSymbol * client )
2439 {
2440 if (fPowerClients && client)
2441 fPowerClients->removeObject(client);
2442 }
2443
2444 uint32_t IOService::getPowerStateForClient( const OSSymbol * client )
2445 {
2446 uint32_t powerState = 0;
2447
2448 if (fPowerClients && client)
2449 {
2450 OSNumber * num = (OSNumber *) fPowerClients->getObject(client);
2451 if (num) powerState = num->unsigned32BitValue();
2452 }
2453 return powerState;
2454 }
2455
2456 //*********************************************************************************
2457 // [protected] powerOverrideOnPriv
2458 //*********************************************************************************
2459
2460 IOReturn IOService::powerOverrideOnPriv ( void )
2461 {
2462 IOPMRequest * request;
2463
2464 if (!initialized)
2465 return IOPMNotYetInitialized;
2466
2467 if (gIOPMWorkLoop->inGate())
2468 {
2469 fDeviceOverrideEnabled = true;
2470 return IOPMNoErr;
2471 }
2472
2473 request = acquirePMRequest( this, kIOPMRequestTypePowerOverrideOnPriv );
2474 if (!request)
2475 return kIOReturnNoMemory;
2476
2477 submitPMRequest( request );
2478 return IOPMNoErr;
2479 }
2480
2481 //*********************************************************************************
2482 // [protected] powerOverrideOffPriv
2483 //*********************************************************************************
2484
2485 IOReturn IOService::powerOverrideOffPriv ( void )
2486 {
2487 IOPMRequest * request;
2488
2489 if (!initialized)
2490 return IOPMNotYetInitialized;
2491
2492 if (gIOPMWorkLoop->inGate())
2493 {
2494 fDeviceOverrideEnabled = false;
2495 return IOPMNoErr;
2496 }
2497
2498 request = acquirePMRequest( this, kIOPMRequestTypePowerOverrideOffPriv );
2499 if (!request)
2500 return kIOReturnNoMemory;
2501
2502 submitPMRequest( request );
2503 return IOPMNoErr;
2504 }
2505
2506 //*********************************************************************************
2507 // [private] handlePowerOverrideChanged
2508 //*********************************************************************************
2509
2510 void IOService::handlePowerOverrideChanged ( IOPMRequest * request )
2511 {
2512 PM_ASSERT_IN_GATE();
2513 if (request->getType() == kIOPMRequestTypePowerOverrideOnPriv)
2514 {
2515 OUR_PMLog(kPMLogOverrideOn, 0, 0);
2516 fDeviceOverrideEnabled = true;
2517 }
2518 else
2519 {
2520 OUR_PMLog(kPMLogOverrideOff, 0, 0);
2521 fDeviceOverrideEnabled = false;
2522 }
2523
2524 adjustPowerState();
2525 }
2526
2527 //*********************************************************************************
2528 // [private] computeDesiredState
2529 //*********************************************************************************
2530
2531 void IOService::computeDesiredState ( unsigned long localClamp )
2532 {
2533 OSIterator * iter;
2534 OSObject * next;
2535 IOPowerConnection * connection;
2536 uint32_t desiredState = 0;
2537 uint32_t newPowerState = 0;
2538 bool hasChildren = false;
2539
2540 // Desired power state is always 0 without a controlling driver.
2541
2542 if (!fNumberOfPowerStates)
2543 {
2544 fDesiredPowerState = 0;
2545 //PM_LOG("%s::%s no controlling driver\n", getName(), __FUNCTION__);
2546 return;
2547 }
2548
2549 // Examine the children's desired power state.
2550
2551 iter = getChildIterator(gIOPowerPlane);
2552 if (iter)
2553 {
2554 while ((next = iter->getNextObject()))
2555 {
2556 if ((connection = OSDynamicCast(IOPowerConnection, next)))
2557 {
2558 if (connection->getReadyFlag() == false)
2559 {
2560 PM_LOG3("[%s] %s: connection not ready\n",
2561 getName(), __FUNCTION__);
2562 continue;
2563 }
2564 if (connection->childHasRequestedPower())
2565 hasChildren = true;
2566 if (connection->getDesiredDomainState() > desiredState)
2567 desiredState = connection->getDesiredDomainState();
2568 }
2569 }
2570 iter->release();
2571 }
2572 if (hasChildren)
2573 updatePowerClient(gIOPMPowerClientChildren, desiredState);
2574 else
2575 removePowerClient(gIOPMPowerClientChildren);
2576
2577 // Iterate through all power clients to determine the min power state.
2578
2579 iter = OSCollectionIterator::withCollection(fPowerClients);
2580 if (iter)
2581 {
2582 const OSSymbol * client;
2583 while ((client = (const OSSymbol *) iter->getNextObject()))
2584 {
2585 // Ignore child and driver when override is in effect.
2586 if ((fDeviceOverrideEnabled ||
2587 (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride)) &&
2588 ((client == gIOPMPowerClientChildren) ||
2589 (client == gIOPMPowerClientDriver)))
2590 continue;
2591
2592 // Ignore child proxy when children are present.
2593 if (hasChildren && (client == gIOPMPowerClientChildProxy))
2594 continue;
2595
2596 desiredState = getPowerStateForClient(client);
2597 assert(desiredState < fNumberOfPowerStates);
2598 PM_LOG1(" %u %s\n",
2599 desiredState, client->getCStringNoCopy());
2600
2601 newPowerState = max(newPowerState, desiredState);
2602
2603 if (client == gIOPMPowerClientDevice)
2604 fDeviceDesire = desiredState;
2605 }
2606 iter->release();
2607 }
2608
2609 // Factor in the temporary power desires.
2610
2611 newPowerState = max(newPowerState, localClamp);
2612 newPowerState = max(newPowerState, fTempClampPowerState);
2613
2614 // Limit check against max power override.
2615
2616 newPowerState = min(newPowerState, fOverrideMaxPowerState);
2617
2618 // Limit check against number of power states.
2619
2620 if (newPowerState >= fNumberOfPowerStates)
2621 newPowerState = fNumberOfPowerStates - 1;
2622
2623 fDesiredPowerState = newPowerState;
2624
2625 PM_LOG1(" temp %u, clamp %u, current %u, new %u\n",
2626 (uint32_t) localClamp, (uint32_t) fTempClampPowerState,
2627 (uint32_t) fCurrentPowerState, newPowerState);
2628
2629 // Restart idle timer if stopped and device desire has increased.
2630
2631 if (fDeviceDesire && fIdleTimerStopped)
2632 {
2633 fIdleTimerStopped = false;
2634 fActivityTickleCount = 0;
2635 clock_get_uptime(&fIdleTimerStartTime);
2636 start_PM_idle_timer();
2637 }
2638
2639 // Invalidate cached tickle power state when desires change, and not
2640 // due to a tickle request. This invalidation must occur before the
2641 // power state change to minimize races. We want to err on the side
2642 // of servicing more activity tickles rather than dropping one when
2643 // the device is in a low power state.
2644
2645 if ((getPMRequestType() != kIOPMRequestTypeActivityTickle) &&
2646 (fActivityTicklePowerState != -1))
2647 {
2648 IOLockLock(fActivityLock);
2649 fActivityTicklePowerState = -1;
2650 IOLockUnlock(fActivityLock);
2651 }
2652 }
2653
2654 //*********************************************************************************
2655 // [public] currentPowerConsumption
2656 //
2657 //*********************************************************************************
2658
2659 unsigned long IOService::currentPowerConsumption ( void )
2660 {
2661 if (!initialized)
2662 return kIOPMUnknown;
2663
2664 return fCurrentPowerConsumption;
2665 }
2666
2667 //*********************************************************************************
2668 // [deprecated] getPMworkloop
2669 //*********************************************************************************
2670
2671 IOWorkLoop * IOService::getPMworkloop ( void )
2672 {
2673 return gIOPMWorkLoop;
2674 }
2675
2676 #if NOT_YET
2677
2678 //*********************************************************************************
2679 // Power Parent/Children Applier
2680 //*********************************************************************************
2681
2682 static void
2683 applyToPowerChildren(
2684 IOService * service,
2685 IOServiceApplierFunction applier,
2686 void * context,
2687 IOOptionBits options )
2688 {
2689 PM_ASSERT_IN_GATE();
2690
2691 IORegistryEntry * entry;
2692 IORegistryIterator * iter;
2693 IOPowerConnection * connection;
2694 IOService * child;
2695
2696 iter = IORegistryIterator::iterateOver(service, gIOPowerPlane, options);
2697 if (iter)
2698 {
2699 while ((entry = iter->getNextObject()))
2700 {
2701 // Get child of IOPowerConnection objects
2702 if ((connection = OSDynamicCast(IOPowerConnection, entry)))
2703 {
2704 child = (IOService *) connection->copyChildEntry(gIOPowerPlane);
2705 if (child)
2706 {
2707 (*applier)(child, context);
2708 child->release();
2709 }
2710 }
2711 }
2712 iter->release();
2713 }
2714 }
2715
2716 static void
2717 applyToPowerParent(
2718 IOService * service,
2719 IOServiceApplierFunction applier,
2720 void * context,
2721 IOOptionBits options )
2722 {
2723 PM_ASSERT_IN_GATE();
2724
2725 IORegistryEntry * entry;
2726 IORegistryIterator * iter;
2727 IOPowerConnection * connection;
2728 IOService * parent;
2729
2730 iter = IORegistryIterator::iterateOver(service, gIOPowerPlane,
2731 options | kIORegistryIterateParents);
2732 if (iter)
2733 {
2734 while ((entry = iter->getNextObject()))
2735 {
2736 // Get child of IOPowerConnection objects
2737 if ((connection = OSDynamicCast(IOPowerConnection, entry)))
2738 {
2739 parent = (IOService *) connection->copyParentEntry(gIOPowerPlane);
2740 if (parent)
2741 {
2742 (*applier)(parent, context);
2743 parent->release();
2744 }
2745 }
2746 }
2747 iter->release();
2748 }
2749 }
2750
2751 #endif /* NOT_YET */
2752
2753 // MARK: -
2754 // MARK: Activity Tickle & Idle Timer
2755
2756 //*********************************************************************************
2757 // [public] activityTickle
2758 //
2759 // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
2760 // flag to be set, and the device state checked. If the device has been
2761 // powered down, it is powered up again.
2762 // The tickle with parameter kIOPMSubclassPolicy is ignored here and
2763 // should be intercepted by a subclass.
2764 //*********************************************************************************
2765
2766 bool IOService::activityTickle ( unsigned long type, unsigned long stateNumber )
2767 {
2768 IOPMRequest * request;
2769 bool noPowerChange = true;
2770
2771 if ( initialized && stateNumber && (type == kIOPMSuperclassPolicy1) )
2772 {
2773 IOLockLock(fActivityLock);
2774
2775 // Record device activity for the idle timer handler.
2776
2777 fDeviceWasActive = true;
2778 fActivityTickleCount++;
2779 clock_get_uptime(&fDeviceActiveTimestamp);
2780
2781 PM_ACTION_0(actionActivityTickle);
2782
2783 // Record the last tickle power state.
2784 // This helps to filter out redundant tickles as
2785 // this function may be called from the data path.
2786
2787 if (fActivityTicklePowerState < (long)stateNumber)
2788 {
2789 fActivityTicklePowerState = stateNumber;
2790 noPowerChange = false;
2791
2792 request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
2793 if (request)
2794 {
2795 request->fArg0 = (void *) stateNumber; // power state
2796 request->fArg1 = (void *) (uintptr_t) true; // power rise
2797 submitPMRequest(request);
2798 }
2799 }
2800
2801 IOLockUnlock(fActivityLock);
2802 }
2803
2804 // Returns false if the activityTickle might cause a transition to a
2805 // higher powered state, true otherwise.
2806
2807 return noPowerChange;
2808 }
2809
2810 //*********************************************************************************
2811 // [private] handleActivityTickle
2812 //*********************************************************************************
2813
2814 void IOService::handleActivityTickle ( IOPMRequest * request )
2815 {
2816 uint32_t ticklePowerState = (uint32_t)(uintptr_t) request->fArg0;
2817 bool adjustPower = false;
2818
2819 PM_ASSERT_IN_GATE();
2820 if (request->fArg1)
2821 {
2822 // Power rise from activity tickle.
2823 if ((ticklePowerState > fDeviceDesire) &&
2824 (ticklePowerState < fNumberOfPowerStates))
2825 {
2826 fIdleTimerMinPowerState = ticklePowerState;
2827 adjustPower = true;
2828 }
2829 }
2830 else if (fDeviceDesire > fIdleTimerMinPowerState)
2831 {
2832 // Power drop due to idle timer expiration.
2833 // Do not allow idle timer to reduce power below tickle power.
2834 ticklePowerState = fDeviceDesire - 1;
2835 adjustPower = true;
2836 }
2837
2838 if (adjustPower)
2839 {
2840 updatePowerClient(gIOPMPowerClientDevice, ticklePowerState);
2841 adjustPowerState();
2842 }
2843 }
2844
2845 //******************************************************************************
2846 // [public] setIdleTimerPeriod
2847 //
2848 // A subclass policy-maker is using our standard idleness detection service.
2849 // Start the idle timer. Period is in seconds.
2850 //******************************************************************************
2851
2852 IOReturn IOService::setIdleTimerPeriod ( unsigned long period )
2853 {
2854 if (!initialized)
2855 return IOPMNotYetInitialized;
2856
2857 OUR_PMLog(kPMLogSetIdleTimerPeriod, period, fIdleTimerPeriod);
2858
2859 IOPMRequest * request =
2860 acquirePMRequest( this, kIOPMRequestTypeSetIdleTimerPeriod );
2861 if (!request)
2862 return kIOReturnNoMemory;
2863
2864 request->fArg0 = (void *) period;
2865 submitPMRequest( request );
2866
2867 return kIOReturnSuccess;
2868 }
2869
2870 //******************************************************************************
2871 // [public] nextIdleTimeout
2872 //
2873 // Returns how many "seconds from now" the device should idle into its
2874 // next lowest power state.
2875 //******************************************************************************
2876
2877 SInt32 IOService::nextIdleTimeout(
2878 AbsoluteTime currentTime,
2879 AbsoluteTime lastActivity,
2880 unsigned int powerState)
2881 {
2882 AbsoluteTime delta;
2883 UInt64 delta_ns;
2884 SInt32 delta_secs;
2885 SInt32 delay_secs;
2886
2887 // Calculate time difference using funky macro from clock.h.
2888 delta = currentTime;
2889 SUB_ABSOLUTETIME(&delta, &lastActivity);
2890
2891 // Figure it in seconds.
2892 absolutetime_to_nanoseconds(delta, &delta_ns);
2893 delta_secs = (SInt32)(delta_ns / NSEC_PER_SEC);
2894
2895 // Be paranoid about delta somehow exceeding timer period.
2896 if (delta_secs < (int) fIdleTimerPeriod)
2897 delay_secs = (int) fIdleTimerPeriod - delta_secs;
2898 else
2899 delay_secs = (int) fIdleTimerPeriod;
2900
2901 return (SInt32)delay_secs;
2902 }
2903
2904 //*********************************************************************************
2905 // [public] start_PM_idle_timer
2906 //*********************************************************************************
2907
2908 void IOService::start_PM_idle_timer ( void )
2909 {
2910 static const int maxTimeout = 100000;
2911 static const int minTimeout = 1;
2912 AbsoluteTime uptime, deadline;
2913 SInt32 idle_in = 0;
2914 boolean_t pending;
2915
2916 if (!initialized || !fIdleTimerPeriod)
2917 return;
2918
2919 IOLockLock(fActivityLock);
2920
2921 clock_get_uptime(&uptime);
2922
2923 // Subclasses may modify idle sleep algorithm
2924 idle_in = nextIdleTimeout(uptime, fDeviceActiveTimestamp, fCurrentPowerState);
2925
2926 // Check for out-of range responses
2927 if (idle_in > maxTimeout)
2928 {
2929 // use standard implementation
2930 idle_in = IOService::nextIdleTimeout(uptime,
2931 fDeviceActiveTimestamp,
2932 fCurrentPowerState);
2933 } else if (idle_in < minTimeout) {
2934 idle_in = fIdleTimerPeriod;
2935 }
2936
2937 IOLockUnlock(fActivityLock);
2938
2939 retain();
2940 clock_interval_to_absolutetime_interval(idle_in, kSecondScale, &deadline);
2941 ADD_ABSOLUTETIME(&deadline, &uptime);
2942 pending = thread_call_enter_delayed(fIdleTimer, deadline);
2943 if (pending) release();
2944 }
2945
2946 //*********************************************************************************
2947 // idle_timer_expired
2948 //*********************************************************************************
2949
2950 static void
2951 idle_timer_expired (
2952 thread_call_param_t arg0, thread_call_param_t arg1 )
2953 {
2954 IOService * me = (IOService *) arg0;
2955
2956 if (gIOPMWorkLoop)
2957 gIOPMWorkLoop->runAction(
2958 OSMemberFunctionCast(IOWorkLoop::Action, me,
2959 &IOService::idleTimerExpired),
2960 me);
2961
2962 me->release();
2963 }
2964
2965 //*********************************************************************************
2966 // [private] idleTimerExpired
2967 //
2968 // The idle timer has expired. If there has been activity since the last
2969 // expiration, just restart the timer and return. If there has not been
2970 // activity, switch to the next lower power state and restart the timer.
2971 //*********************************************************************************
2972
2973 void IOService::idleTimerExpired( void )
2974 {
2975 IOPMRequest * request;
2976 bool restartTimer = true;
2977
2978 if ( !initialized || !fIdleTimerPeriod || fLockedFlags.PMStop )
2979 return;
2980
2981 IOLockLock(fActivityLock);
2982
2983 // Check for device activity (tickles) over last timer period.
2984
2985 if (fDeviceWasActive)
2986 {
2987 // Device was active - do not drop power, restart timer.
2988 fDeviceWasActive = false;
2989 }
2990 else
2991 {
2992 // No device activity - drop power state by one level.
2993 // Decrement the cached tickle power state when possible.
2994 // This value may be (-1) before activityTickle() is called,
2995 // but the power drop request must be issued regardless.
2996
2997 if (fActivityTicklePowerState > 0)
2998 {
2999 fActivityTicklePowerState--;
3000 }
3001
3002 request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
3003 if (request)
3004 {
3005 request->fArg0 = (void *) 0; // power state (irrelevant)
3006 request->fArg1 = (void *) (uintptr_t) false; // power drop
3007 submitPMRequest( request );
3008
3009 // Do not restart timer until after the tickle request has been
3010 // processed.
3011
3012 restartTimer = false;
3013 }
3014 }
3015
3016 IOLockUnlock(fActivityLock);
3017
3018 if (restartTimer)
3019 start_PM_idle_timer();
3020 }
3021
3022 #ifndef __LP64__
3023 //*********************************************************************************
3024 // [deprecated] PM_idle_timer_expiration
3025 //*********************************************************************************
3026
3027 void IOService::PM_idle_timer_expiration ( void )
3028 {
3029 }
3030
3031 //*********************************************************************************
3032 // [deprecated] command_received
3033 //*********************************************************************************
3034
3035 void IOService::command_received ( void *statePtr , void *, void * , void * )
3036 {
3037 }
3038 #endif /* !__LP64__ */
3039
3040 //*********************************************************************************
3041 // [public] setAggressiveness
3042 //
3043 // Pass on the input parameters to all power domain children. All those which are
3044 // power domains will pass it on to their children, etc.
3045 //*********************************************************************************
3046
3047 IOReturn IOService::setAggressiveness ( unsigned long type, unsigned long newLevel )
3048 {
3049 return kIOReturnSuccess;
3050 }
3051
3052 //*********************************************************************************
3053 // [public] getAggressiveness
3054 //
3055 // Called by the user client.
3056 //*********************************************************************************
3057
3058 IOReturn IOService::getAggressiveness ( unsigned long type, unsigned long * currentLevel )
3059 {
3060 IOPMrootDomain * rootDomain = getPMRootDomain();
3061
3062 if (!rootDomain)
3063 return kIOReturnNotReady;
3064
3065 return rootDomain->getAggressiveness( type, currentLevel );
3066 }
3067
3068 //*********************************************************************************
3069 // [public] getPowerState
3070 //
3071 //*********************************************************************************
3072
3073 UInt32 IOService::getPowerState ( void )
3074 {
3075 if (!initialized)
3076 return 0;
3077
3078 return fCurrentPowerState;
3079 }
3080
3081 #ifndef __LP64__
3082 //*********************************************************************************
3083 // [deprecated] systemWake
3084 //
3085 // Pass this to all power domain children. All those which are
3086 // power domains will pass it on to their children, etc.
3087 //*********************************************************************************
3088
3089 IOReturn IOService::systemWake ( void )
3090 {
3091 OSIterator * iter;
3092 OSObject * next;
3093 IOPowerConnection * connection;
3094 IOService * theChild;
3095
3096 iter = getChildIterator(gIOPowerPlane);
3097 if ( iter )
3098 {
3099 while ( (next = iter->getNextObject()) )
3100 {
3101 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
3102 {
3103 if (connection->getReadyFlag() == false)
3104 {
3105 PM_LOG3("[%s] %s: connection not ready\n",
3106 getName(), __FUNCTION__);
3107 continue;
3108 }
3109
3110 theChild = (IOService *)connection->copyChildEntry(gIOPowerPlane);
3111 if ( theChild )
3112 {
3113 theChild->systemWake();
3114 theChild->release();
3115 }
3116 }
3117 }
3118 iter->release();
3119 }
3120
3121 if ( fControllingDriver != NULL )
3122 {
3123 if ( fControllingDriver->didYouWakeSystem() )
3124 {
3125 makeUsable();
3126 }
3127 }
3128
3129 return IOPMNoErr;
3130 }
3131
3132 //*********************************************************************************
3133 // [deprecated] temperatureCriticalForZone
3134 //*********************************************************************************
3135
3136 IOReturn IOService::temperatureCriticalForZone ( IOService * whichZone )
3137 {
3138 IOService * theParent;
3139 IOService * theNub;
3140
3141 OUR_PMLog(kPMLogCriticalTemp, 0, 0);
3142
3143 if ( inPlane(gIOPowerPlane) && !IS_PM_ROOT )
3144 {
3145 theNub = (IOService *)copyParentEntry(gIOPowerPlane);
3146 if ( theNub )
3147 {
3148 theParent = (IOService *)theNub->copyParentEntry(gIOPowerPlane);
3149 theNub->release();
3150 if ( theParent )
3151 {
3152 theParent->temperatureCriticalForZone(whichZone);
3153 theParent->release();
3154 }
3155 }
3156 }
3157 return IOPMNoErr;
3158 }
3159 #endif /* !__LP64__ */
3160
3161 // MARK: -
3162 // MARK: Power Change (Common)
3163
3164 //*********************************************************************************
3165 // [private] startPowerChange
3166 //
3167 // All power state changes starts here.
3168 //*********************************************************************************
3169
3170 IOReturn IOService::startPowerChange(
3171 IOPMPowerChangeFlags changeFlags,
3172 IOPMPowerStateIndex powerState,
3173 IOPMPowerFlags domainFlags,
3174 IOPowerConnection * parentConnection,
3175 IOPMPowerFlags parentFlags )
3176 {
3177 PM_ASSERT_IN_GATE();
3178 assert( fMachineState == kIOPM_Finished );
3179 assert( powerState < fNumberOfPowerStates );
3180
3181 if (powerState >= fNumberOfPowerStates)
3182 return IOPMAckImplied;
3183
3184 fIsPreChange = true;
3185 PM_ACTION_2(actionPowerChangeOverride, &powerState, &changeFlags);
3186
3187 // Forks to either Driver or Parent initiated power change paths.
3188
3189 fHeadNoteChangeFlags = changeFlags;
3190 fHeadNotePowerState = powerState;
3191 fHeadNotePowerArrayEntry = &fPowerStates[ powerState ];
3192 fHeadNoteParentConnection = NULL;
3193
3194 if (changeFlags & kIOPMSelfInitiated)
3195 {
3196 if (changeFlags & kIOPMSynchronize)
3197 OurSyncStart();
3198 else
3199 OurChangeStart();
3200 return 0;
3201 }
3202 else
3203 {
3204 assert(changeFlags & kIOPMParentInitiated);
3205 fHeadNoteDomainFlags = domainFlags;
3206 fHeadNoteParentFlags = parentFlags;
3207 fHeadNoteParentConnection = parentConnection;
3208 return ParentChangeStart();
3209 }
3210 }
3211
3212 //*********************************************************************************
3213 // [private] notifyInterestedDrivers
3214 //*********************************************************************************
3215
3216 bool IOService::notifyInterestedDrivers ( void )
3217 {
3218 IOPMinformee * informee;
3219 IOPMinformeeList * list = fInterestedDrivers;
3220 DriverCallParam * param;
3221 IOItemCount count;
3222
3223 PM_ASSERT_IN_GATE();
3224 assert( fDriverCallParamCount == 0 );
3225 assert( fHeadNotePendingAcks == 0 );
3226
3227 fHeadNotePendingAcks = 0;
3228
3229 count = list->numberOfItems();
3230 if (!count)
3231 goto done; // no interested drivers
3232
3233 // Allocate an array of interested drivers and their return values
3234 // for the callout thread. Everything else is still "owned" by the
3235 // PM work loop, which can run to process acknowledgePowerChange()
3236 // responses.
3237
3238 param = (DriverCallParam *) fDriverCallParamPtr;
3239 if (count > fDriverCallParamSlots)
3240 {
3241 if (fDriverCallParamSlots)
3242 {
3243 assert(fDriverCallParamPtr);
3244 IODelete(fDriverCallParamPtr, DriverCallParam, fDriverCallParamSlots);
3245 fDriverCallParamPtr = 0;
3246 fDriverCallParamSlots = 0;
3247 }
3248
3249 param = IONew(DriverCallParam, count);
3250 if (!param)
3251 goto done; // no memory
3252
3253 fDriverCallParamPtr = (void *) param;
3254 fDriverCallParamSlots = count;
3255 }
3256
3257 informee = list->firstInList();
3258 assert(informee);
3259 for (IOItemCount i = 0; i < count; i++)
3260 {
3261 informee->timer = -1;
3262 param[i].Target = informee;
3263 informee->retain();
3264 informee = list->nextInList( informee );
3265 }
3266
3267 fDriverCallParamCount = count;
3268 fHeadNotePendingAcks = count;
3269
3270 // Block state machine and wait for callout completion.
3271 assert(!fDriverCallBusy);
3272 fDriverCallBusy = true;
3273 thread_call_enter( fDriverCallEntry );
3274 return true;
3275
3276 done:
3277 // Return false if there are no interested drivers or could not schedule
3278 // callout thread due to error.
3279 return false;
3280 }
3281
3282 //*********************************************************************************
3283 // [private] notifyInterestedDriversDone
3284 //*********************************************************************************
3285
3286 void IOService::notifyInterestedDriversDone ( void )
3287 {
3288 IOPMinformee * informee;
3289 IOItemCount count;
3290 DriverCallParam * param;
3291 IOReturn result;
3292
3293 PM_ASSERT_IN_GATE();
3294 assert( fDriverCallBusy == false );
3295 assert( fMachineState == kIOPM_DriverThreadCallDone );
3296
3297 param = (DriverCallParam *) fDriverCallParamPtr;
3298 count = fDriverCallParamCount;
3299
3300 if (param && count)
3301 {
3302 for (IOItemCount i = 0; i < count; i++, param++)
3303 {
3304 informee = (IOPMinformee *) param->Target;
3305 result = param->Result;
3306
3307 if ((result == IOPMAckImplied) || (result < 0))
3308 {
3309 // Interested driver return IOPMAckImplied.
3310 // If informee timer is zero, it must have de-registered
3311 // interest during the thread callout. That also drops
3312 // the pending ack count.
3313
3314 if (fHeadNotePendingAcks && informee->timer)
3315 fHeadNotePendingAcks--;
3316
3317 informee->timer = 0;
3318 }
3319 else if (informee->timer)
3320 {
3321 assert(informee->timer == -1);
3322
3323 // Driver has not acked, and has returned a positive result.
3324 // Enforce a minimum permissible timeout value.
3325 // Make the min value large enough so timeout is less likely
3326 // to occur if a driver misinterpreted that the return value
3327 // should be in microsecond units. And make it large enough
3328 // to be noticeable if a driver neglects to ack.
3329
3330 if (result < kMinAckTimeoutTicks)
3331 result = kMinAckTimeoutTicks;
3332
3333 informee->timer = (result / (ACK_TIMER_PERIOD / ns_per_us)) + 1;
3334 }
3335 // else, child has already acked or driver has removed interest,
3336 // and head_note_pendingAcks decremented.
3337 // informee may have been removed from the interested drivers list,
3338 // thus the informee must be retained across the callout.
3339
3340 informee->release();
3341 }
3342
3343 fDriverCallParamCount = 0;
3344
3345 if ( fHeadNotePendingAcks )
3346 {
3347 OUR_PMLog(kPMLogStartAckTimer, 0, 0);
3348 start_ack_timer();
3349 }
3350 }
3351
3352 MS_POP(); // pushed by notifyAll()
3353
3354 // If interest acks are outstanding, wait for fHeadNotePendingAcks to become
3355 // zero before notifying children. This enforces the children after interest
3356 // ordering even for async interest clients.
3357
3358 if (!fHeadNotePendingAcks)
3359 {
3360 notifyChildren();
3361 }
3362 else
3363 {
3364 MS_PUSH(fMachineState);
3365 fMachineState = kIOPM_NotifyChildrenStart;
3366 PM_LOG2("%s: %u outstanding async interest\n",
3367 getName(), fHeadNotePendingAcks);
3368 }
3369 }
3370
3371 //*********************************************************************************
3372 // [private] notifyChildren
3373 //*********************************************************************************
3374
3375 void IOService::notifyChildren ( void )
3376 {
3377 OSIterator * iter;
3378 OSObject * next;
3379 IOPowerConnection * connection;
3380 OSArray * children = 0;
3381 IOPMrootDomain * rootDomain;
3382 bool delayNotify = false;
3383
3384 if ((fHeadNotePowerState != fCurrentPowerState) &&
3385 (IS_POWER_DROP == fIsPreChange) &&
3386 ((rootDomain = getPMRootDomain()) == this))
3387 {
3388 rootDomain->tracePoint( IS_POWER_DROP ?
3389 kIOPMTracePointSleepPowerPlaneDrivers :
3390 kIOPMTracePointWakePowerPlaneDrivers );
3391 }
3392
3393 if (fStrictTreeOrder)
3394 children = OSArray::withCapacity(8);
3395
3396 // Sum child power consumption in notifyChild()
3397 fHeadNotePowerArrayEntry->staticPower = 0;
3398
3399 iter = getChildIterator(gIOPowerPlane);
3400 if ( iter )
3401 {
3402 while ((next = iter->getNextObject()))
3403 {
3404 if ((connection = OSDynamicCast(IOPowerConnection, next)))
3405 {
3406 if (connection->getReadyFlag() == false)
3407 {
3408 PM_LOG3("[%s] %s: connection not ready\n",
3409 getName(), __FUNCTION__);
3410 continue;
3411 }
3412
3413 // Mechanism to postpone the did-change notification to
3414 // certain power children to order those children last.
3415 // Cannot be used together with strict tree ordering.
3416
3417 if (!fIsPreChange &&
3418 (connection->delayChildNotification) &&
3419 getPMRootDomain()->shouldDelayChildNotification(this))
3420 {
3421 if (!children)
3422 {
3423 children = OSArray::withCapacity(8);
3424 if (children)
3425 delayNotify = true;
3426 }
3427 if (delayNotify)
3428 {
3429 children->setObject( connection );
3430 continue;
3431 }
3432 }
3433
3434 if (!delayNotify && children)
3435 children->setObject( connection );
3436 else
3437 notifyChild( connection );
3438 }
3439 }
3440 iter->release();
3441 }
3442
3443 if (children && (children->getCount() == 0))
3444 {
3445 children->release();
3446 children = 0;
3447 }
3448 if (children)
3449 {
3450 assert(fNotifyChildArray == 0);
3451 fNotifyChildArray = children;
3452 MS_PUSH(fMachineState);
3453
3454 if (delayNotify)
3455 {
3456 // Wait for exiting child notifications to complete,
3457 // before notifying the children in the array.
3458 fMachineState = kIOPM_NotifyChildrenDelayed;
3459 PM_LOG2("%s: %d children in delayed array\n",
3460 getName(), children->getCount());
3461 }
3462 else
3463 {
3464 // Notify children in the array one at a time.
3465 fMachineState = kIOPM_NotifyChildrenOrdered;
3466 }
3467 }
3468 }
3469
3470 //*********************************************************************************
3471 // [private] notifyChildrenOrdered
3472 //*********************************************************************************
3473
3474 void IOService::notifyChildrenOrdered ( void )
3475 {
3476 PM_ASSERT_IN_GATE();
3477 assert(fNotifyChildArray);
3478 assert(fMachineState == kIOPM_NotifyChildrenOrdered);
3479
3480 // Notify one child, wait for it to ack, then repeat for next child.
3481 // This is a workaround for some drivers with multiple instances at
3482 // the same branch in the power tree, but the driver is slow to power
3483 // up unless the tree ordering is observed. Problem observed only on
3484 // system wake, not on system sleep.
3485 //
3486 // We have the ability to power off in reverse child index order.
3487 // That works nicely on some machines, but not on all HW configs.
3488
3489 if (fNotifyChildArray->getCount())
3490 {
3491 IOPowerConnection * connection;
3492 connection = (IOPowerConnection *) fNotifyChildArray->getObject(0);
3493 fNotifyChildArray->removeObject(0);
3494 notifyChild( connection );
3495 }
3496 else
3497 {
3498 fNotifyChildArray->release();
3499 fNotifyChildArray = 0;
3500
3501 MS_POP(); // pushed by notifyChildren()
3502 }
3503 }
3504
3505 //*********************************************************************************
3506 // [private] notifyChildrenDelayed
3507 //*********************************************************************************
3508
3509 void IOService::notifyChildrenDelayed ( void )
3510 {
3511 IOPowerConnection * connection;
3512
3513 PM_ASSERT_IN_GATE();
3514 assert(fNotifyChildArray);
3515 assert(fMachineState == kIOPM_NotifyChildrenDelayed);
3516
3517 // Wait after all non-delayed children and interested drivers have ack'ed,
3518 // then notify all delayed children. When explicitly cancelled, interest
3519 // acks (and ack timer) may still be outstanding.
3520
3521 for (int i = 0; ; i++)
3522 {
3523 connection = (IOPowerConnection *) fNotifyChildArray->getObject(i);
3524 if (!connection)
3525 break;
3526
3527 notifyChild( connection );
3528 }
3529
3530 PM_LOG2("%s: notified delayed children\n", getName());
3531 fNotifyChildArray->release();
3532 fNotifyChildArray = 0;
3533
3534 MS_POP(); // pushed by notifyChildren()
3535 }
3536
3537 //*********************************************************************************
3538 // [private] notifyAll
3539 //*********************************************************************************
3540
3541 IOReturn IOService::notifyAll ( uint32_t nextMS )
3542 {
3543 // Save the next machine_state to be restored by notifyInterestedDriversDone()
3544
3545 PM_ASSERT_IN_GATE();
3546 MS_PUSH(nextMS);
3547 fMachineState = kIOPM_DriverThreadCallDone;
3548 fDriverCallReason = fIsPreChange ?
3549 kDriverCallInformPreChange : kDriverCallInformPostChange;
3550
3551 if (!notifyInterestedDrivers())
3552 notifyInterestedDriversDone();
3553
3554 return IOPMWillAckLater;
3555 }
3556
3557 //*********************************************************************************
3558 // [private, static] pmDriverCallout
3559 //
3560 // Thread call context
3561 //*********************************************************************************
3562
3563 IOReturn IOService::actionDriverCalloutDone (
3564 OSObject * target,
3565 void * arg0, void * arg1,
3566 void * arg2, void * arg3 )
3567 {
3568 IOServicePM * pwrMgt = (IOServicePM *) arg0;
3569
3570 assert( fDriverCallBusy );
3571 fDriverCallBusy = false;
3572
3573 assert(gIOPMWorkQueue);
3574 gIOPMWorkQueue->signalWorkAvailable();
3575
3576 return kIOReturnSuccess;
3577 }
3578
3579 void IOService::pmDriverCallout ( IOService * from )
3580 {
3581 assert(from);
3582 switch (from->fDriverCallReason)
3583 {
3584 case kDriverCallSetPowerState:
3585 from->driverSetPowerState();
3586 break;
3587
3588 case kDriverCallInformPreChange:
3589 case kDriverCallInformPostChange:
3590 from->driverInformPowerChange();
3591 break;
3592
3593 default:
3594 panic("IOService::pmDriverCallout bad machine state %x",
3595 from->fDriverCallReason);
3596 }
3597
3598 gIOPMWorkLoop->runAction(actionDriverCalloutDone,
3599 /* target */ from,
3600 /* arg0 */ (void *) from->pwrMgt );
3601 }
3602
3603 //*********************************************************************************
3604 // [private] driverSetPowerState
3605 //
3606 // Thread call context
3607 //*********************************************************************************
3608
3609 void IOService::driverSetPowerState ( void )
3610 {
3611 IOPMPowerStateIndex powerState;
3612 DriverCallParam * param;
3613 IOPMDriverCallEntry callEntry;
3614 AbsoluteTime end;
3615 IOReturn result;
3616 uint32_t oldPowerState = getPowerState();
3617
3618 assert( fDriverCallBusy );
3619 assert( fDriverCallParamPtr );
3620 assert( fDriverCallParamCount == 1 );
3621
3622 param = (DriverCallParam *) fDriverCallParamPtr;
3623 powerState = fHeadNotePowerState;
3624
3625 if (assertPMDriverCall(&callEntry))
3626 {
3627 OUR_PMLog( kPMLogProgramHardware, (uintptr_t) this, powerState);
3628 clock_get_uptime(&fDriverCallStartTime);
3629 result = fControllingDriver->setPowerState( powerState, this );
3630 clock_get_uptime(&end);
3631 OUR_PMLog((UInt32) -kPMLogProgramHardware, (uintptr_t) this, (UInt32) result);
3632
3633 deassertPMDriverCall(&callEntry);
3634
3635 if (result < 0)
3636 {
3637 PM_LOG("%s::setPowerState(%p, %lu -> %lu) returned 0x%x\n",
3638 fName, this, fCurrentPowerState, powerState, result);
3639 }
3640
3641 #if LOG_SETPOWER_TIMES
3642 if ((result == IOPMAckImplied) || (result < 0))
3643 {
3644 uint64_t nsec;
3645
3646 SUB_ABSOLUTETIME(&end, &fDriverCallStartTime);
3647 absolutetime_to_nanoseconds(end, &nsec);
3648 if (nsec > LOG_SETPOWER_TIMES)
3649 PM_LOG("%s::setPowerState(%p, %lu -> %lu) took %d ms\n",
3650 fName, this, fCurrentPowerState, powerState, NS_TO_MS(nsec));
3651
3652 PMEventDetails *details = PMEventDetails::eventDetails(
3653 kIOPMEventTypeSetPowerStateImmediate, // type
3654 fName, // who
3655 (uintptr_t)this, // owner unique
3656 NULL, // interest name
3657 (uint8_t)oldPowerState, // old
3658 (uint8_t)powerState, // new
3659 0, // result
3660 NS_TO_US(nsec)); // usec completion time
3661
3662 getPMRootDomain()->recordAndReleasePMEventGated( details );
3663 }
3664 #endif
3665 }
3666 else
3667 result = kIOPMAckImplied;
3668
3669 param->Result = result;
3670 }
3671
3672 //*********************************************************************************
3673 // [private] driverInformPowerChange
3674 //
3675 // Thread call context
3676 //*********************************************************************************
3677
3678 void IOService::driverInformPowerChange ( void )
3679 {
3680 IOPMinformee * informee;
3681 IOService * driver;
3682 DriverCallParam * param;
3683 IOPMDriverCallEntry callEntry;
3684 IOPMPowerFlags powerFlags;
3685 IOPMPowerStateIndex powerState;
3686 AbsoluteTime end;
3687 IOReturn result;
3688 IOItemCount count;
3689
3690 assert( fDriverCallBusy );
3691 assert( fDriverCallParamPtr );
3692 assert( fDriverCallParamCount );
3693
3694 param = (DriverCallParam *) fDriverCallParamPtr;
3695 count = fDriverCallParamCount;
3696
3697 powerFlags = fHeadNotePowerArrayEntry->capabilityFlags;
3698 powerState = fHeadNotePowerState;
3699
3700 for (IOItemCount i = 0; i < count; i++)
3701 {
3702 informee = (IOPMinformee *) param->Target;
3703 driver = informee->whatObject;
3704
3705 if (assertPMDriverCall(&callEntry, 0, informee))
3706 {
3707 if (fDriverCallReason == kDriverCallInformPreChange)
3708 {
3709 OUR_PMLog(kPMLogInformDriverPreChange, (uintptr_t) this, powerState);
3710 clock_get_uptime(&informee->startTime);
3711 result = driver->powerStateWillChangeTo(powerFlags, powerState, this);
3712 clock_get_uptime(&end);
3713 OUR_PMLog((UInt32)-kPMLogInformDriverPreChange, (uintptr_t) this, result);
3714 }
3715 else
3716 {
3717 OUR_PMLog(kPMLogInformDriverPostChange, (uintptr_t) this, powerState);
3718 clock_get_uptime(&informee->startTime);
3719 result = driver->powerStateDidChangeTo(powerFlags, powerState, this);
3720 clock_get_uptime(&end);
3721 OUR_PMLog((UInt32)-kPMLogInformDriverPostChange, (uintptr_t) this, result);
3722 }
3723
3724 deassertPMDriverCall(&callEntry);
3725
3726 #if LOG_SETPOWER_TIMES
3727 if ((result == IOPMAckImplied) || (result < 0))
3728 {
3729 uint64_t nsec;
3730
3731 SUB_ABSOLUTETIME(&end, &informee->startTime);
3732 absolutetime_to_nanoseconds(end, &nsec);
3733 if (nsec > LOG_SETPOWER_TIMES)
3734 PM_LOG("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) took %d ms\n",
3735 driver->getName(),
3736 (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
3737 driver, fName, fCurrentPowerState, powerState, NS_TO_MS(nsec));
3738
3739 uint16_t logType = (fDriverCallReason == kDriverCallInformPreChange)
3740 ? kIOPMEventTypePSWillChangeTo
3741 : kIOPMEventTypePSDidChangeTo;
3742
3743 PMEventDetails *details = PMEventDetails::eventDetails(
3744 logType, // type
3745 fName, // who
3746 (uintptr_t)this, // owner unique
3747 driver->getName(), // interest name
3748 (uint8_t)fCurrentPowerState, // old
3749 (uint8_t)fHeadNotePowerState, // new
3750 0, // result
3751 NS_TO_US(nsec)); // usec completion time
3752
3753 getPMRootDomain()->recordAndReleasePMEventGated( details );
3754 }
3755 #endif
3756 }
3757 else
3758 result = kIOPMAckImplied;
3759
3760 param->Result = result;
3761 param++;
3762 }
3763 }
3764
3765 //*********************************************************************************
3766 // [private] notifyChild
3767 //
3768 // Notify a power domain child of an upcoming power change.
3769 // If the object acknowledges the current change, we return TRUE.
3770 //*********************************************************************************
3771
3772 bool IOService::notifyChild ( IOPowerConnection * theNub )
3773 {
3774 IOReturn ret = IOPMAckImplied;
3775 unsigned long childPower;
3776 IOService * theChild;
3777 IOPMRequest * childRequest;
3778 IOPMPowerChangeFlags requestArg2;
3779 int requestType;
3780
3781 PM_ASSERT_IN_GATE();
3782 theChild = (IOService *)(theNub->copyChildEntry(gIOPowerPlane));
3783 if (!theChild)
3784 {
3785 assert(false);
3786 return true;
3787 }
3788
3789 // Unless the child handles the notification immediately and returns
3790 // kIOPMAckImplied, we'll be awaiting their acknowledgement later.
3791 fHeadNotePendingAcks++;
3792 theNub->setAwaitingAck(true);
3793
3794 requestArg2 = fHeadNoteChangeFlags;
3795 if (fHeadNotePowerState < fCurrentPowerState)
3796 requestArg2 |= kIOPMDomainPowerDrop;
3797
3798 requestType = fIsPreChange ?
3799 kIOPMRequestTypePowerDomainWillChange :
3800 kIOPMRequestTypePowerDomainDidChange;
3801
3802 childRequest = acquirePMRequest( theChild, requestType );
3803 if (childRequest)
3804 {
3805 theNub->retain();
3806 childRequest->fArg0 = (void *) fHeadNotePowerArrayEntry->outputPowerFlags;
3807 childRequest->fArg1 = (void *) theNub;
3808 childRequest->fArg2 = (void *) requestArg2;
3809 theChild->submitPMRequest( childRequest );
3810 ret = IOPMWillAckLater;
3811 }
3812 else
3813 {
3814 ret = IOPMAckImplied;
3815 fHeadNotePendingAcks--;
3816 theNub->setAwaitingAck(false);
3817 childPower = theChild->currentPowerConsumption();
3818 if ( childPower == kIOPMUnknown )
3819 {
3820 fHeadNotePowerArrayEntry->staticPower = kIOPMUnknown;
3821 } else {
3822 if (fHeadNotePowerArrayEntry->staticPower != kIOPMUnknown )
3823 fHeadNotePowerArrayEntry->staticPower += childPower;
3824 }
3825 }
3826
3827 theChild->release();
3828 return (IOPMAckImplied == ret);
3829 }
3830
3831 //*********************************************************************************
3832 // [private] notifyControllingDriver
3833 //*********************************************************************************
3834
3835 bool IOService::notifyControllingDriver ( void )
3836 {
3837 DriverCallParam * param;
3838
3839 PM_ASSERT_IN_GATE();
3840 assert( fDriverCallParamCount == 0 );
3841 assert( fControllingDriver );
3842
3843 if (fInitialSetPowerState)
3844 {
3845 // Driver specified flag to skip the inital setPowerState()
3846 if (fHeadNotePowerArrayEntry->capabilityFlags & kIOPMInitialDeviceState)
3847 {
3848 return false;
3849 }
3850 fInitialSetPowerState = false;
3851 }
3852
3853 param = (DriverCallParam *) fDriverCallParamPtr;
3854 if (!param)
3855 {
3856 param = IONew(DriverCallParam, 1);
3857 if (!param)
3858 return false; // no memory
3859
3860 fDriverCallParamPtr = (void *) param;
3861 fDriverCallParamSlots = 1;
3862 }
3863
3864 param->Target = fControllingDriver;
3865 fDriverCallParamCount = 1;
3866 fDriverTimer = -1;
3867
3868 // Block state machine and wait for callout completion.
3869 assert(!fDriverCallBusy);
3870 fDriverCallBusy = true;
3871 thread_call_enter( fDriverCallEntry );
3872
3873 return true;
3874 }
3875
3876 //*********************************************************************************
3877 // [private] notifyControllingDriverDone
3878 //*********************************************************************************
3879
3880 void IOService::notifyControllingDriverDone( void )
3881 {
3882 DriverCallParam * param;
3883 IOReturn result;
3884
3885 PM_ASSERT_IN_GATE();
3886 param = (DriverCallParam *) fDriverCallParamPtr;
3887
3888 assert( fDriverCallBusy == false );
3889 assert( fMachineState == kIOPM_DriverThreadCallDone );
3890
3891 if (param && fDriverCallParamCount)
3892 {
3893 assert(fDriverCallParamCount == 1);
3894
3895 // the return value from setPowerState()
3896 result = param->Result;
3897
3898 if ((result == IOPMAckImplied) || (result < 0))
3899 {
3900 fDriverTimer = 0;
3901 }
3902 else if (fDriverTimer)
3903 {
3904 assert(fDriverTimer == -1);
3905
3906 // Driver has not acked, and has returned a positive result.
3907 // Enforce a minimum permissible timeout value.
3908 // Make the min value large enough so timeout is less likely
3909 // to occur if a driver misinterpreted that the return value
3910 // should be in microsecond units. And make it large enough
3911 // to be noticeable if a driver neglects to ack.
3912
3913 if (result < kMinAckTimeoutTicks)
3914 result = kMinAckTimeoutTicks;
3915
3916 fDriverTimer = (result / (ACK_TIMER_PERIOD / ns_per_us)) + 1;
3917 }
3918 // else, child has already acked and driver_timer reset to 0.
3919
3920 fDriverCallParamCount = 0;
3921
3922 if ( fDriverTimer )
3923 {
3924 OUR_PMLog(kPMLogStartAckTimer, 0, 0);
3925 start_ack_timer();
3926 }
3927 }
3928
3929 MS_POP(); // pushed by OurChangeSetPowerState()
3930 fIsPreChange = false;
3931 }
3932
3933 //*********************************************************************************
3934 // [private] all_done
3935 //
3936 // A power change is done.
3937 //*********************************************************************************
3938
3939 void IOService::all_done ( void )
3940 {
3941 IOPMPowerStateIndex prevPowerState;
3942 const IOPMPSEntry * powerStatePtr;
3943 IOPMDriverCallEntry callEntry;
3944 uint32_t prevMachineState = fMachineState;
3945 bool callAction = false;
3946
3947 fMachineState = kIOPM_Finished;
3948
3949 if ((fHeadNoteChangeFlags & kIOPMSynchronize) &&
3950 ((prevMachineState == kIOPM_Finished) ||
3951 (prevMachineState == kIOPM_SyncFinish)))
3952 {
3953 // Sync operation and no power change occurred.
3954 // Do not inform driver and clients about this request completion,
3955 // except for the originator (root domain).
3956
3957 PM_ACTION_2(actionPowerChangeDone,
3958 fHeadNotePowerState, fHeadNoteChangeFlags);
3959
3960 if (getPMRequestType() == kIOPMRequestTypeSynchronizePowerTree)
3961 {
3962 powerChangeDone(fCurrentPowerState);
3963 }
3964
3965 return;
3966 }
3967
3968 // our power change
3969 if ( fHeadNoteChangeFlags & kIOPMSelfInitiated )
3970 {
3971 // could our driver switch to the new state?
3972 if ( !( fHeadNoteChangeFlags & kIOPMNotDone) )
3973 {
3974 // we changed, tell our parent
3975 requestDomainPower(fHeadNotePowerState);
3976
3977 // yes, did power raise?
3978 if ( fCurrentPowerState < fHeadNotePowerState )
3979 {
3980 // yes, inform clients and apps
3981 tellChangeUp (fHeadNotePowerState);
3982 }
3983 prevPowerState = fCurrentPowerState;
3984 // either way
3985 fCurrentPowerState = fHeadNotePowerState;
3986 #if PM_VARS_SUPPORT
3987 fPMVars->myCurrentState = fCurrentPowerState;
3988 #endif
3989 OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, 0);
3990 PM_ACTION_2(actionPowerChangeDone,
3991 fHeadNotePowerState, fHeadNoteChangeFlags);
3992 callAction = true;
3993
3994 powerStatePtr = &fPowerStates[fCurrentPowerState];
3995 fCurrentCapabilityFlags = powerStatePtr->capabilityFlags;
3996 if (fCurrentCapabilityFlags & kIOPMStaticPowerValid)
3997 fCurrentPowerConsumption = powerStatePtr->staticPower;
3998
3999 // inform subclass policy-maker
4000 if (fPCDFunctionOverride && fParentsKnowState &&
4001 assertPMDriverCall(&callEntry, kIOPMADC_NoInactiveCheck))
4002 {
4003 powerChangeDone(prevPowerState);
4004 deassertPMDriverCall(&callEntry);
4005 }
4006 }
4007 else if (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride)
4008 {
4009 // changePowerStateWithOverrideTo() was cancelled
4010 fOverrideMaxPowerState = kIOPMPowerStateMax;
4011 }
4012 }
4013
4014 // parent's power change
4015 if ( fHeadNoteChangeFlags & kIOPMParentInitiated)
4016 {
4017 if (((fHeadNoteChangeFlags & kIOPMDomainWillChange) &&
4018 (fCurrentPowerState >= fHeadNotePowerState)) ||
4019 ((fHeadNoteChangeFlags & kIOPMDomainDidChange) &&
4020 (fCurrentPowerState < fHeadNotePowerState)))
4021 {
4022 // did power raise?
4023 if ( fCurrentPowerState < fHeadNotePowerState )
4024 {
4025 // yes, inform clients and apps
4026 tellChangeUp (fHeadNotePowerState);
4027 }
4028 // either way
4029 prevPowerState = fCurrentPowerState;
4030 fCurrentPowerState = fHeadNotePowerState;
4031 #if PM_VARS_SUPPORT
4032 fPMVars->myCurrentState = fCurrentPowerState;
4033 #endif
4034 fMaxPowerState = fControllingDriver->maxCapabilityForDomainState(fHeadNoteDomainFlags);
4035
4036 OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, 0);
4037 PM_ACTION_2(actionPowerChangeDone,
4038 fHeadNotePowerState, fHeadNoteChangeFlags);
4039 callAction = true;
4040
4041 powerStatePtr = &fPowerStates[fCurrentPowerState];
4042 fCurrentCapabilityFlags = powerStatePtr->capabilityFlags;
4043 if (fCurrentCapabilityFlags & kIOPMStaticPowerValid)
4044 fCurrentPowerConsumption = powerStatePtr->staticPower;
4045
4046 // inform subclass policy-maker
4047 if (fPCDFunctionOverride && fParentsKnowState &&
4048 assertPMDriverCall(&callEntry, kIOPMADC_NoInactiveCheck))
4049 {
4050 powerChangeDone(prevPowerState);
4051 deassertPMDriverCall(&callEntry);
4052 }
4053 }
4054 }
4055
4056 // When power rises enough to satisfy the tickle's desire for more power,
4057 // the condition preventing idle-timer from dropping power is removed.
4058
4059 if (fCurrentPowerState >= fIdleTimerMinPowerState)
4060 {
4061 fIdleTimerMinPowerState = 0;
4062 }
4063
4064 if (!callAction)
4065 {
4066 PM_ACTION_2(actionPowerChangeDone,
4067 fHeadNotePowerState, fHeadNoteChangeFlags);
4068 }
4069 }
4070
4071 // MARK: -
4072 // MARK: Power Change Initiated by Driver
4073
4074 //*********************************************************************************
4075 // [private] OurChangeStart
4076 //
4077 // Begin the processing of a power change initiated by us.
4078 //*********************************************************************************
4079
4080 void IOService::OurChangeStart ( void )
4081 {
4082 PM_ASSERT_IN_GATE();
4083 OUR_PMLog( kPMLogStartDeviceChange, fHeadNotePowerState, fCurrentPowerState );
4084
4085 // fMaxPowerState is our maximum possible power state based on the current
4086 // power state of our parents. If we are trying to raise power beyond the
4087 // maximum, send an async request for more power to all parents.
4088
4089 if (!IS_PM_ROOT && (fMaxPowerState < fHeadNotePowerState))
4090 {
4091 fHeadNoteChangeFlags |= kIOPMNotDone;
4092 requestDomainPower(fHeadNotePowerState);
4093 OurChangeFinish();
4094 return;
4095 }
4096
4097 // Redundant power changes skips to the end of the state machine.
4098
4099 if (!fInitialPowerChange && (fHeadNotePowerState == fCurrentPowerState))
4100 {
4101 OurChangeFinish();
4102 return;
4103 }
4104 fInitialPowerChange = false;
4105
4106 // Change started, but may not complete...
4107 // Can be canceled (power drop) or deferred (power rise).
4108
4109 PM_ACTION_2(actionPowerChangeStart, fHeadNotePowerState, &fHeadNoteChangeFlags);
4110
4111 // Two separate paths, depending if power is being raised or lowered.
4112 // Lowering power is subject to approval by clients of this service.
4113
4114 if (IS_POWER_DROP)
4115 {
4116 fDoNotPowerDown = false;
4117
4118 // Ask for persmission to drop power state
4119 fMachineState = kIOPM_OurChangeTellClientsPowerDown;
4120 fOutOfBandParameter = kNotifyApps;
4121 askChangeDown(fHeadNotePowerState);
4122 }
4123 else
4124 {
4125 // This service is raising power and parents are able to support the
4126 // new power state. However a parent may have already committed to
4127 // drop power, which might force this object to temporarily drop power.
4128 // This results in "oscillations" before the state machines converge
4129 // to a steady state.
4130 //
4131 // To prevent this, a child must make a power reservation against all
4132 // parents before raising power. If the reservation fails, indicating
4133 // that the child will be unable to sustain the higher power state,
4134 // then the child will signal the parent to adjust power, and the child
4135 // will defer its power change.
4136
4137 IOReturn ret;
4138
4139 // Reserve parent power necessary to achieve fHeadNotePowerState.
4140 ret = requestDomainPower( fHeadNotePowerState, kReserveDomainPower );
4141 if (ret != kIOReturnSuccess)
4142 {
4143 // Reservation failed, defer power rise.
4144 fHeadNoteChangeFlags |= kIOPMNotDone;
4145 OurChangeFinish();
4146 return;
4147 }
4148
4149 OurChangeTellCapabilityWillChange();
4150 }
4151 }
4152
4153 //*********************************************************************************
4154
4155 struct IOPMRequestDomainPowerContext {
4156 IOService * child; // the requesting child
4157 IOPMPowerFlags requestPowerFlags; // power flags requested by child
4158 };
4159
4160 static void
4161 requestDomainPowerApplier(
4162 IORegistryEntry * entry,
4163 void * inContext )
4164 {
4165 IOPowerConnection * connection;
4166 IOService * parent;
4167 IOPMRequestDomainPowerContext * context;
4168
4169 if ((connection = OSDynamicCast(IOPowerConnection, entry)) == 0)
4170 return;
4171 parent = (IOService *) connection->copyParentEntry(gIOPowerPlane);
4172 if (!parent)
4173 return;
4174
4175 assert(inContext);
4176 context = (IOPMRequestDomainPowerContext *) inContext;
4177
4178 if (connection->parentKnowsState() && connection->getReadyFlag())
4179 {
4180 parent->requestPowerDomainState(
4181 context->requestPowerFlags,
4182 connection,
4183 IOPMLowestState);
4184 }
4185
4186 parent->release();
4187 }
4188
4189 //*********************************************************************************
4190 // [private] requestDomainPower
4191 //*********************************************************************************
4192
4193 IOReturn IOService::requestDomainPower(
4194 IOPMPowerStateIndex ourPowerState,
4195 IOOptionBits options )
4196 {
4197 const IOPMPSEntry * powerStateEntry;
4198 IOPMPowerFlags requestPowerFlags;
4199 IOPMPowerStateIndex maxPowerState;
4200 IOPMRequestDomainPowerContext context;
4201
4202 PM_ASSERT_IN_GATE();
4203 assert(ourPowerState < fNumberOfPowerStates);
4204 if (ourPowerState >= fNumberOfPowerStates)
4205 return kIOReturnBadArgument;
4206 if (IS_PM_ROOT)
4207 return kIOReturnSuccess;
4208
4209 // Fetch the input power flags for the requested power state.
4210 // Parent request is stated in terms of required power flags.
4211
4212 powerStateEntry = &fPowerStates[ourPowerState];
4213 requestPowerFlags = powerStateEntry->inputPowerFlags;
4214
4215 if (powerStateEntry->capabilityFlags & (kIOPMChildClamp | kIOPMPreventIdleSleep))
4216 requestPowerFlags |= kIOPMPreventIdleSleep;
4217 if (powerStateEntry->capabilityFlags & (kIOPMChildClamp2 | kIOPMPreventSystemSleep))
4218 requestPowerFlags |= kIOPMPreventSystemSleep;
4219
4220 // Disregard the "previous request" for power reservation.
4221
4222 if (((options & kReserveDomainPower) == 0) &&
4223 (fPreviousRequestPowerFlags == requestPowerFlags))
4224 {
4225 // skip if domain already knows our requirements
4226 goto done;
4227 }
4228 fPreviousRequestPowerFlags = requestPowerFlags;
4229
4230 context.child = this;
4231 context.requestPowerFlags = requestPowerFlags;
4232 fHeadNoteDomainTargetFlags = 0;
4233 applyToParents(requestDomainPowerApplier, &context, gIOPowerPlane);
4234
4235 if (options & kReserveDomainPower)
4236 {
4237 maxPowerState = fControllingDriver->maxCapabilityForDomainState(
4238 fHeadNoteDomainTargetFlags );
4239
4240 if (maxPowerState < fHeadNotePowerState)
4241 {
4242 PM_LOG1("%s: power desired %u:0x%x got %u:0x%x\n",
4243 getName(),
4244 (uint32_t) ourPowerState, (uint32_t) requestPowerFlags,
4245 (uint32_t) maxPowerState, (uint32_t) fHeadNoteDomainTargetFlags);
4246 return kIOReturnNoPower;
4247 }
4248 }
4249
4250 done:
4251 return kIOReturnSuccess;
4252 }
4253
4254 //*********************************************************************************
4255 // [private] OurSyncStart
4256 //*********************************************************************************
4257
4258 void IOService::OurSyncStart ( void )
4259 {
4260 PM_ASSERT_IN_GATE();
4261
4262 if (fInitialPowerChange)
4263 return;
4264
4265 PM_ACTION_2(actionPowerChangeStart, fHeadNotePowerState, &fHeadNoteChangeFlags);
4266
4267 if (fHeadNoteChangeFlags & kIOPMNotDone)
4268 {
4269 OurChangeFinish();
4270 return;
4271 }
4272
4273 if (fHeadNoteChangeFlags & kIOPMSyncTellPowerDown)
4274 {
4275 fDoNotPowerDown = false;
4276
4277 // Ask for permission to drop power state
4278 fMachineState = kIOPM_SyncTellClientsPowerDown;
4279 fOutOfBandParameter = kNotifyApps;
4280 askChangeDown(fHeadNotePowerState);
4281 }
4282 else
4283 {
4284 // Only inform capability app and clients.
4285 tellSystemCapabilityChange( kIOPM_SyncNotifyWillChange );
4286 }
4287 }
4288
4289 //*********************************************************************************
4290 // [private] OurChangeTellClientsPowerDown
4291 //
4292 // All applications and kernel clients have acknowledged our permission to drop
4293 // power. Here we notify them that we will lower the power and wait for acks.
4294 //*********************************************************************************
4295
4296 void IOService::OurChangeTellClientsPowerDown ( void )
4297 {
4298 fMachineState = kIOPM_OurChangeTellPriorityClientsPowerDown;
4299 tellChangeDown1(fHeadNotePowerState);
4300 }
4301
4302 //*********************************************************************************
4303 // [private] OurChangeTellPriorityClientsPowerDown
4304 //
4305 // All applications and kernel clients have acknowledged our intention to drop
4306 // power. Here we notify "priority" clients that we are lowering power.
4307 //*********************************************************************************
4308
4309 void IOService::OurChangeTellPriorityClientsPowerDown ( void )
4310 {
4311 fMachineState = kIOPM_OurChangeNotifyInterestedDriversWillChange;
4312 tellChangeDown2(fHeadNotePowerState);
4313 }
4314
4315 //*********************************************************************************
4316 // [private] OurChangeTellCapabilityWillChange
4317 //
4318 // Extra stage for root domain to notify apps and drivers about the
4319 // system capability change when raising power state.
4320 //*********************************************************************************
4321
4322 void IOService::OurChangeTellCapabilityWillChange ( void )
4323 {
4324 if (!IS_ROOT_DOMAIN)
4325 return OurChangeNotifyInterestedDriversWillChange();
4326
4327 tellSystemCapabilityChange( kIOPM_OurChangeNotifyInterestedDriversWillChange );
4328 }
4329
4330 //*********************************************************************************
4331 // [private] OurChangeNotifyInterestedDriversWillChange
4332 //
4333 // All applications and kernel clients have acknowledged our power state change.
4334 // Here we notify interested drivers pre-change.
4335 //*********************************************************************************
4336
4337 void IOService::OurChangeNotifyInterestedDriversWillChange ( void )
4338 {
4339 IOPMrootDomain * rootDomain;
4340 if ((rootDomain = getPMRootDomain()) == this)
4341 {
4342 if (IS_POWER_DROP)
4343 {
4344 rootDomain->tracePoint( kIOPMTracePointSleepWillChangeInterests );
4345
4346 PMEventDetails *details = PMEventDetails::eventDetails(
4347 kIOPMEventTypeAppNotificationsFinished,
4348 NULL,
4349 100,
4350 kIOReturnSuccess);
4351 rootDomain->recordAndReleasePMEventGated( details );
4352 }
4353 else
4354 rootDomain->tracePoint( kIOPMTracePointWakeWillChangeInterests );
4355 }
4356
4357 notifyAll( kIOPM_OurChangeSetPowerState );
4358 }
4359
4360 //*********************************************************************************
4361 // [private] OurChangeSetPowerState
4362 //
4363 // Instruct our controlling driver to program the hardware for the power state
4364 // change. Wait for async completions.
4365 //*********************************************************************************
4366
4367 void IOService::OurChangeSetPowerState ( void )
4368 {
4369 MS_PUSH( kIOPM_OurChangeWaitForPowerSettle );
4370 fMachineState = kIOPM_DriverThreadCallDone;
4371 fDriverCallReason = kDriverCallSetPowerState;
4372
4373 if (notifyControllingDriver() == false)
4374 notifyControllingDriverDone();
4375 }
4376
4377 //*********************************************************************************
4378 // [private] OurChangeWaitForPowerSettle
4379 //
4380 // Our controlling driver has completed the power state change we initiated.
4381 // Wait for the driver specified settle time to expire.
4382 //*********************************************************************************
4383
4384 void IOService::OurChangeWaitForPowerSettle ( void )
4385 {
4386 fMachineState = kIOPM_OurChangeNotifyInterestedDriversDidChange;
4387 startSettleTimer();
4388 }
4389
4390 //*********************************************************************************
4391 // [private] OurChangeNotifyInterestedDriversDidChange
4392 //
4393 // Power has settled on a power change we initiated. Here we notify
4394 // all our interested drivers post-change.
4395 //*********************************************************************************
4396
4397 void IOService::OurChangeNotifyInterestedDriversDidChange ( void )
4398 {
4399 IOPMrootDomain * rootDomain;
4400 if ((rootDomain = getPMRootDomain()) == this)
4401 {
4402 rootDomain->tracePoint( IS_POWER_DROP ?
4403 kIOPMTracePointSleepDidChangeInterests :
4404 kIOPMTracePointWakeDidChangeInterests );
4405 }
4406
4407 notifyAll( kIOPM_OurChangeTellCapabilityDidChange );
4408 }
4409
4410 //*********************************************************************************
4411 // [private] OurChangeTellCapabilityDidChange
4412 //
4413 // For root domain to notify capability power-change.
4414 //*********************************************************************************
4415
4416 void IOService::OurChangeTellCapabilityDidChange ( void )
4417 {
4418 if (!IS_ROOT_DOMAIN)
4419 return OurChangeFinish();
4420
4421 getPMRootDomain()->tracePoint( IS_POWER_DROP ?
4422 kIOPMTracePointSleepCapabilityClients :
4423 kIOPMTracePointWakeCapabilityClients );
4424
4425 tellSystemCapabilityChange( kIOPM_OurChangeFinish );
4426 }
4427
4428 //*********************************************************************************
4429 // [private] OurChangeFinish
4430 //
4431 // Done with this self-induced power state change.
4432 //*********************************************************************************
4433
4434 void IOService::OurChangeFinish ( void )
4435 {
4436 all_done();
4437 }
4438
4439 // MARK: -
4440 // MARK: Power Change Initiated by Parent
4441
4442 //*********************************************************************************
4443 // [private] ParentChangeStart
4444 //
4445 // Here we begin the processing of a power change initiated by our parent.
4446 //*********************************************************************************
4447
4448 IOReturn IOService::ParentChangeStart ( void )
4449 {
4450 PM_ASSERT_IN_GATE();
4451 OUR_PMLog( kPMLogStartParentChange, fHeadNotePowerState, fCurrentPowerState );
4452
4453 // Power domain is lowering power
4454 if ( fHeadNotePowerState < fCurrentPowerState )
4455 {
4456 // TODO: redundant? See handlePowerDomainWillChangeTo()
4457 setParentInfo( fHeadNoteParentFlags, fHeadNoteParentConnection, true );
4458
4459 PM_ACTION_2(actionPowerChangeStart, fHeadNotePowerState, &fHeadNoteChangeFlags);
4460
4461 // Tell apps and kernel clients
4462 fInitialPowerChange = false;
4463 fMachineState = kIOPM_ParentChangeTellPriorityClientsPowerDown;
4464 tellChangeDown1(fHeadNotePowerState);
4465 return IOPMWillAckLater;
4466 }
4467
4468 // Power domain is raising power
4469 if ( fHeadNotePowerState > fCurrentPowerState )
4470 {
4471 if ( fDesiredPowerState > fCurrentPowerState )
4472 {
4473 if ( fDesiredPowerState < fHeadNotePowerState )
4474 {
4475 // We power up, but not all the way
4476 fHeadNotePowerState = fDesiredPowerState;
4477 fHeadNotePowerArrayEntry = &fPowerStates[fDesiredPowerState];
4478 OUR_PMLog(kPMLogAmendParentChange, fHeadNotePowerState, 0);
4479 }
4480 } else {
4481 // We don't need to change
4482 fHeadNotePowerState = fCurrentPowerState;
4483 fHeadNotePowerArrayEntry = &fPowerStates[fCurrentPowerState];
4484 OUR_PMLog(kPMLogAmendParentChange, fHeadNotePowerState, 0);
4485 }
4486 }
4487
4488 if ( fHeadNoteChangeFlags & kIOPMDomainDidChange )
4489 {
4490 if ( fHeadNotePowerState > fCurrentPowerState )
4491 {
4492 PM_ACTION_2(actionPowerChangeStart,
4493 fHeadNotePowerState, &fHeadNoteChangeFlags);
4494
4495 // Parent did change up - start our change up
4496 fInitialPowerChange = false;
4497 ParentChangeTellCapabilityWillChange();
4498 return IOPMWillAckLater;
4499 }
4500 else if (fHeadNoteChangeFlags & kIOPMSynchronize)
4501 {
4502 // We do not need to change power state, but notify
4503 // children to propagate tree synchronization.
4504 fMachineState = kIOPM_SyncNotifyDidChange;
4505 fDriverCallReason = kDriverCallInformPreChange;
4506 notifyChildren();
4507 return IOPMWillAckLater;
4508 }
4509 }
4510
4511 all_done();
4512 return IOPMAckImplied;
4513 }
4514
4515 //*********************************************************************************
4516 // [private] ParentChangeTellPriorityClientsPowerDown
4517 //
4518 // All applications and kernel clients have acknowledged our intention to drop
4519 // power. Here we notify "priority" clients that we are lowering power.
4520 //*********************************************************************************
4521
4522 void IOService::ParentChangeTellPriorityClientsPowerDown ( void )
4523 {
4524 fMachineState = kIOPM_ParentChangeNotifyInterestedDriversWillChange;
4525 tellChangeDown2(fHeadNotePowerState);
4526 }
4527
4528 //*********************************************************************************
4529 // [private] ParentChangeTellCapabilityWillChange
4530 //
4531 // All (legacy) applications and kernel clients have acknowledged, extra stage for
4532 // root domain to notify apps and drivers about the system capability change.
4533 //*********************************************************************************
4534
4535 void IOService::ParentChangeTellCapabilityWillChange ( void )
4536 {
4537 if (!IS_ROOT_DOMAIN)
4538 return ParentChangeNotifyInterestedDriversWillChange();
4539
4540 tellSystemCapabilityChange( kIOPM_ParentChangeNotifyInterestedDriversWillChange );
4541 }
4542
4543 //*********************************************************************************
4544 // [private] ParentChangeNotifyInterestedDriversWillChange
4545 //
4546 // All applications and kernel clients have acknowledged our power state change.
4547 // Here we notify interested drivers pre-change.
4548 //*********************************************************************************
4549
4550 void IOService::ParentChangeNotifyInterestedDriversWillChange ( void )
4551 {
4552 notifyAll( kIOPM_ParentChangeSetPowerState );
4553 }
4554
4555 //*********************************************************************************
4556 // [private] ParentChangeSetPowerState
4557 //
4558 // Instruct our controlling driver to program the hardware for the power state
4559 // change. Wait for async completions.
4560 //*********************************************************************************
4561
4562 void IOService::ParentChangeSetPowerState ( void )
4563 {
4564 MS_PUSH( kIOPM_ParentChangeWaitForPowerSettle );
4565 fMachineState = kIOPM_DriverThreadCallDone;
4566 fDriverCallReason = kDriverCallSetPowerState;
4567
4568 if (notifyControllingDriver() == false)
4569 notifyControllingDriverDone();
4570 }
4571
4572 //*********************************************************************************
4573 // [private] ParentChangeWaitForPowerSettle
4574 //
4575 // Our controlling driver has completed the power state change initiated by our
4576 // parent. Wait for the driver specified settle time to expire.
4577 //*********************************************************************************
4578
4579 void IOService::ParentChangeWaitForPowerSettle ( void )
4580 {
4581 fMachineState = kIOPM_ParentChangeNotifyInterestedDriversDidChange;
4582 startSettleTimer();
4583 }
4584
4585 //*********************************************************************************
4586 // [private] ParentChangeNotifyInterestedDriversDidChange
4587 //
4588 // Power has settled on a power change initiated by our parent. Here we notify
4589 // all our interested drivers post-change.
4590 //*********************************************************************************
4591
4592 void IOService::ParentChangeNotifyInterestedDriversDidChange ( void )
4593 {
4594 notifyAll( kIOPM_ParentChangeTellCapabilityDidChange );
4595 }
4596
4597 //*********************************************************************************
4598 // [private] ParentChangeTellCapabilityDidChange
4599 //
4600 // For root domain to notify capability power-change.
4601 //*********************************************************************************
4602
4603 void IOService::ParentChangeTellCapabilityDidChange ( void )
4604 {
4605 if (!IS_ROOT_DOMAIN)
4606 return ParentChangeAcknowledgePowerChange();
4607
4608 tellSystemCapabilityChange( kIOPM_ParentChangeAcknowledgePowerChange );
4609 }
4610
4611 //*********************************************************************************
4612 // [private] ParentAcknowledgePowerChange
4613 //
4614 // Acknowledge our power parent that our power change is done.
4615 //*********************************************************************************
4616
4617 void IOService::ParentChangeAcknowledgePowerChange ( void )
4618 {
4619 IORegistryEntry * nub;
4620 IOService * parent;
4621
4622 nub = fHeadNoteParentConnection;
4623 nub->retain();
4624 all_done();
4625 parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
4626 if ( parent )
4627 {
4628 parent->acknowledgePowerChange((IOService *)nub);
4629 parent->release();
4630 }
4631 nub->release();
4632 }
4633
4634 // MARK: -
4635 // MARK: Ack and Settle timers
4636
4637 //*********************************************************************************
4638 // [private] settleTimerExpired
4639 //
4640 // Power has settled after our last change. Notify interested parties that
4641 // there is a new power state.
4642 //*********************************************************************************
4643
4644 void IOService::settleTimerExpired( void )
4645 {
4646 fSettleTimeUS = 0;
4647 gIOPMWorkQueue->signalWorkAvailable();
4648 }
4649
4650 //*********************************************************************************
4651 // settle_timer_expired
4652 //
4653 // Holds a retain while the settle timer callout is in flight.
4654 //*********************************************************************************
4655
4656 static void
4657 settle_timer_expired( thread_call_param_t arg0, thread_call_param_t arg1 )
4658 {
4659 IOService * me = (IOService *) arg0;
4660
4661 if (gIOPMWorkLoop && gIOPMWorkQueue)
4662 {
4663 gIOPMWorkLoop->runAction(
4664 OSMemberFunctionCast(IOWorkLoop::Action, me, &IOService::settleTimerExpired),
4665 me);
4666 }
4667 me->release();
4668 }
4669
4670 //*********************************************************************************
4671 // [private] startSettleTimer
4672 //
4673 // Calculate a power-settling delay in microseconds and start a timer.
4674 //*********************************************************************************
4675
4676 void IOService::startSettleTimer( void )
4677 {
4678 AbsoluteTime deadline;
4679 IOPMPowerStateIndex i;
4680 uint32_t settleTime = 0;
4681 boolean_t pending;
4682
4683 PM_ASSERT_IN_GATE();
4684
4685 i = fCurrentPowerState;
4686
4687 // lowering power
4688 if ( fHeadNotePowerState < fCurrentPowerState )
4689 {
4690 while ( i > fHeadNotePowerState )
4691 {
4692 settleTime += (uint32_t) fPowerStates[i].settleDownTime;
4693 i--;
4694 }
4695 }
4696
4697 // raising power
4698 if ( fHeadNotePowerState > fCurrentPowerState )
4699 {
4700 while ( i < fHeadNotePowerState )
4701 {
4702 settleTime += (uint32_t) fPowerStates[i+1].settleUpTime;
4703 i++;
4704 }
4705 }
4706
4707 if (settleTime)
4708 {
4709 retain();
4710 clock_interval_to_deadline(settleTime, kMicrosecondScale, &deadline);
4711 pending = thread_call_enter_delayed(fSettleTimer, deadline);
4712 if (pending) release();
4713 }
4714 }
4715
4716 //*********************************************************************************
4717 // [private] ackTimerTick
4718 //
4719 // The acknowledgement timeout periodic timer has ticked.
4720 // If we are awaiting acks for a power change notification,
4721 // we decrement the timer word of each interested driver which hasn't acked.
4722 // If a timer word becomes zero, we pretend the driver aknowledged.
4723 // If we are waiting for the controlling driver to change the power
4724 // state of the hardware, we decrement its timer word, and if it becomes
4725 // zero, we pretend the driver acknowledged.
4726 //
4727 // Returns true if the timer tick made it possible to advance to the next
4728 // machine state, false otherwise.
4729 //*********************************************************************************
4730
4731 #ifndef __LP64__
4732 void IOService::ack_timer_ticked ( void )
4733 {
4734 assert(false);
4735 }
4736 #endif /* !__LP64__ */
4737
4738 bool IOService::ackTimerTick( void )
4739 {
4740 IOPMinformee * nextObject;
4741 bool done = false;
4742
4743 PM_ASSERT_IN_GATE();
4744 switch (fMachineState) {
4745 case kIOPM_OurChangeWaitForPowerSettle:
4746 case kIOPM_ParentChangeWaitForPowerSettle:
4747 // are we waiting for controlling driver to acknowledge?
4748 if ( fDriverTimer > 0 )
4749 {
4750 // yes, decrement timer tick
4751 fDriverTimer--;
4752 if ( fDriverTimer == 0 )
4753 {
4754 // controlling driver is tardy
4755 uint64_t nsec = computeTimeDeltaNS(&fDriverCallStartTime);
4756 OUR_PMLog(kPMLogCtrlDriverTardy, 0, 0);
4757 setProperty(kIOPMTardyAckSPSKey, kOSBooleanTrue);
4758 PM_ERROR("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms\n",
4759 fName, this, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
4760
4761 #if LOG_SETPOWER_TIMES
4762 PMEventDetails *details = PMEventDetails::eventDetails(
4763 kIOPMEventTypeSetPowerStateDelayed, // type
4764 fName, // who
4765 (uintptr_t)this, // owner unique
4766 NULL, // interest name
4767 (uint8_t)getPowerState(), // old
4768 0, // new
4769 kIOReturnTimeout, // result
4770 NS_TO_US(nsec)); // usec completion time
4771
4772 getPMRootDomain()->recordAndReleasePMEventGated( details );
4773 #endif
4774
4775 if (gIOKitDebug & kIOLogDebugPower)
4776 {
4777 panic("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms",
4778 fName, this, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
4779 }
4780 else
4781 {
4782 // Unblock state machine and pretend driver has acked.
4783 done = true;
4784 }
4785 } else {
4786 // still waiting, set timer again
4787 start_ack_timer();
4788 }
4789 }
4790 break;
4791
4792 case kIOPM_NotifyChildrenStart:
4793 // are we waiting for interested parties to acknowledge?
4794 if ( fHeadNotePendingAcks != 0 )
4795 {
4796 // yes, go through the list of interested drivers
4797 nextObject = fInterestedDrivers->firstInList();
4798 // and check each one
4799 while ( nextObject != NULL )
4800 {
4801 if ( nextObject->timer > 0 )
4802 {
4803 nextObject->timer--;
4804 // this one should have acked by now
4805 if ( nextObject->timer == 0 )
4806 {
4807 uint64_t nsec = computeTimeDeltaNS(&nextObject->startTime);
4808 OUR_PMLog(kPMLogIntDriverTardy, 0, 0);
4809 nextObject->whatObject->setProperty(kIOPMTardyAckPSCKey, kOSBooleanTrue);
4810 PM_ERROR("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) timed out after %d ms\n",
4811 nextObject->whatObject->getName(),
4812 (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
4813 nextObject->whatObject, fName, fCurrentPowerState, fHeadNotePowerState,
4814 NS_TO_MS(nsec));
4815
4816 #if LOG_SETPOWER_TIMES
4817 uint16_t logType = (fDriverCallReason == kDriverCallInformPreChange)
4818 ? kIOPMEventTypePSWillChangeTo
4819 : kIOPMEventTypePSDidChangeTo;
4820
4821 PMEventDetails *details = PMEventDetails::eventDetails(
4822 logType, // type
4823 fName, // who
4824 (uintptr_t)this, // owner unique
4825 nextObject->whatObject->getName(), // interest name
4826 (uint8_t)fCurrentPowerState, // old
4827 (uint8_t)fHeadNotePowerState, // new
4828 kIOReturnTimeout, // result
4829 NS_TO_US(nsec)); // usec completion time
4830
4831 getPMRootDomain()->recordAndReleasePMEventGated( details );
4832 #endif
4833
4834 // Pretend driver has acked.
4835 fHeadNotePendingAcks--;
4836 }
4837 }
4838 nextObject = fInterestedDrivers->nextInList(nextObject);
4839 }
4840
4841 // is that the last?
4842 if ( fHeadNotePendingAcks == 0 )
4843 {
4844 // yes, we can continue
4845 done = true;
4846 } else {
4847 // no, set timer again
4848 start_ack_timer();
4849 }
4850 }
4851 break;
4852
4853 // TODO: aggreggate this
4854 case kIOPM_OurChangeTellClientsPowerDown:
4855 case kIOPM_OurChangeTellPriorityClientsPowerDown:
4856 case kIOPM_OurChangeNotifyInterestedDriversWillChange:
4857 case kIOPM_ParentChangeTellPriorityClientsPowerDown:
4858 case kIOPM_ParentChangeNotifyInterestedDriversWillChange:
4859 case kIOPM_SyncTellClientsPowerDown:
4860 case kIOPM_SyncTellPriorityClientsPowerDown:
4861 case kIOPM_SyncNotifyWillChange:
4862 case kIOPM_TellCapabilityChangeDone:
4863 // apps didn't respond in time
4864 cleanClientResponses(true);
4865 OUR_PMLog(kPMLogClientTardy, 0, 1);
4866 // tardy equates to approval
4867 done = true;
4868 break;
4869
4870 default:
4871 PM_LOG1("%s: unexpected ack timer tick (state = %d)\n",
4872 getName(), fMachineState);
4873 break;
4874 }
4875 return done;
4876 }
4877
4878 //*********************************************************************************
4879 // [private] start_ack_timer
4880 //*********************************************************************************
4881
4882 void IOService::start_ack_timer ( void )
4883 {
4884 start_ack_timer( ACK_TIMER_PERIOD, kNanosecondScale );
4885 }
4886
4887 void IOService::start_ack_timer ( UInt32 interval, UInt32 scale )
4888 {
4889 AbsoluteTime deadline;
4890 boolean_t pending;
4891
4892 clock_interval_to_deadline(interval, scale, &deadline);
4893
4894 retain();
4895 pending = thread_call_enter_delayed(fAckTimer, deadline);
4896 if (pending) release();
4897 }
4898
4899 //*********************************************************************************
4900 // [private] stop_ack_timer
4901 //*********************************************************************************
4902
4903 void IOService::stop_ack_timer ( void )
4904 {
4905 boolean_t pending;
4906
4907 pending = thread_call_cancel(fAckTimer);
4908 if (pending) release();
4909 }
4910
4911 //*********************************************************************************
4912 // [static] actionAckTimerExpired
4913 //
4914 // Inside PM work loop's gate.
4915 //*********************************************************************************
4916
4917 IOReturn
4918 IOService::actionAckTimerExpired (
4919 OSObject * target,
4920 void * arg0, void * arg1,
4921 void * arg2, void * arg3 )
4922 {
4923 IOService * me = (IOService *) target;
4924 bool done;
4925
4926 // done will be true if the timer tick unblocks the machine state,
4927 // otherwise no need to signal the work loop.
4928
4929 done = me->ackTimerTick();
4930 if (done && gIOPMWorkQueue)
4931 gIOPMWorkQueue->signalWorkAvailable();
4932
4933 return kIOReturnSuccess;
4934 }
4935
4936 //*********************************************************************************
4937 // ack_timer_expired
4938 //
4939 // Thread call function. Holds a retain while the callout is in flight.
4940 //*********************************************************************************
4941
4942 void
4943 IOService::ack_timer_expired ( thread_call_param_t arg0, thread_call_param_t arg1 )
4944 {
4945 IOService * me = (IOService *) arg0;
4946
4947 if (gIOPMWorkLoop)
4948 {
4949 gIOPMWorkLoop->runAction(&actionAckTimerExpired, me);
4950 }
4951 me->release();
4952 }
4953
4954 // MARK: -
4955 // MARK: Client Messaging
4956
4957 //*********************************************************************************
4958 // [private] tellSystemCapabilityChange
4959 //*********************************************************************************
4960
4961 void IOService::tellSystemCapabilityChange( uint32_t nextMS )
4962 {
4963 MS_PUSH( nextMS );
4964 fMachineState = kIOPM_TellCapabilityChangeDone;
4965 fOutOfBandMessage = kIOMessageSystemCapabilityChange;
4966
4967 if (fIsPreChange)
4968 {
4969 // Notify app first on pre-change.
4970 fOutOfBandParameter = kNotifyCapabilityChangeApps;
4971 }
4972 else
4973 {
4974 // Notify kernel clients first on post-change.
4975 fOutOfBandParameter = kNotifyCapabilityChangePriority;
4976 }
4977
4978 tellClientsWithResponse( fOutOfBandMessage );
4979 }
4980
4981 //*********************************************************************************
4982 // [public] askChangeDown
4983 //
4984 // Ask registered applications and kernel clients if we can change to a lower
4985 // power state.
4986 //
4987 // Subclass can override this to send a different message type. Parameter is
4988 // the destination state number.
4989 //
4990 // Return true if we don't have to wait for acknowledgements
4991 //*********************************************************************************
4992
4993 bool IOService::askChangeDown ( unsigned long stateNum )
4994 {
4995 return tellClientsWithResponse( kIOMessageCanDevicePowerOff );
4996 }
4997
4998 //*********************************************************************************
4999 // [private] tellChangeDown1
5000 //
5001 // Notify registered applications and kernel clients that we are definitely
5002 // dropping power.
5003 //
5004 // Return true if we don't have to wait for acknowledgements
5005 //*********************************************************************************
5006
5007 bool IOService::tellChangeDown1 ( unsigned long stateNum )
5008 {
5009 fOutOfBandParameter = kNotifyApps;
5010 return tellChangeDown(stateNum);
5011 }
5012
5013 //*********************************************************************************
5014 // [private] tellChangeDown2
5015 //
5016 // Notify priority clients that we are definitely dropping power.
5017 //
5018 // Return true if we don't have to wait for acknowledgements
5019 //*********************************************************************************
5020
5021 bool IOService::tellChangeDown2 ( unsigned long stateNum )
5022 {
5023 fOutOfBandParameter = kNotifyPriority;
5024 return tellChangeDown(stateNum);
5025 }
5026
5027 //*********************************************************************************
5028 // [public] tellChangeDown
5029 //
5030 // Notify registered applications and kernel clients that we are definitely
5031 // dropping power.
5032 //
5033 // Subclass can override this to send a different message type. Parameter is
5034 // the destination state number.
5035 //
5036 // Return true if we don't have to wait for acknowledgements
5037 //*********************************************************************************
5038
5039 bool IOService::tellChangeDown ( unsigned long stateNum )
5040 {
5041 return tellClientsWithResponse( kIOMessageDeviceWillPowerOff );
5042 }
5043
5044 //*********************************************************************************
5045 // cleanClientResponses
5046 //
5047 //*********************************************************************************
5048
5049 static void logAppTimeouts ( OSObject * object, void * arg )
5050 {
5051 IOPMInterestContext * context = (IOPMInterestContext *) arg;
5052 OSObject * flag;
5053 unsigned int clientIndex;
5054
5055 if (OSDynamicCast(_IOServiceInterestNotifier, object))
5056 {
5057 // Discover the 'counter' value or index assigned to this client
5058 // when it was notified, by searching for the array index of the
5059 // client in an array holding the cached interested clients.
5060
5061 clientIndex = context->notifyClients->getNextIndexOfObject(object, 0);
5062
5063 if ((clientIndex != (unsigned int) -1) &&
5064 (flag = context->responseArray->getObject(clientIndex)) &&
5065 (flag != kOSBooleanTrue))
5066 {
5067 OSString * clientID = 0;
5068 context->us->messageClient(context->messageType, object, &clientID);
5069 PM_ERROR(context->errorLog, clientID ? clientID->getCStringNoCopy() : "");
5070
5071 // TODO: record message type if possible
5072 IOService::getPMRootDomain()->pmStatsRecordApplicationResponse(
5073 gIOPMStatsApplicationResponseTimedOut,
5074 clientID ? clientID->getCStringNoCopy() : "",
5075 0, (30*1000), -1);
5076
5077 if (clientID)
5078 clientID->release();
5079 }
5080 }
5081 }
5082
5083 void IOService::cleanClientResponses ( bool logErrors )
5084 {
5085 if (logErrors && fResponseArray)
5086 {
5087 switch ( fOutOfBandParameter ) {
5088 case kNotifyApps:
5089 case kNotifyCapabilityChangeApps:
5090 if (fNotifyClientArray)
5091 {
5092 IOPMInterestContext context;
5093
5094 context.responseArray = fResponseArray;
5095 context.notifyClients = fNotifyClientArray;
5096 context.serialNumber = fSerialNumber;
5097 context.messageType = kIOMessageCopyClientID;
5098 context.notifyType = kNotifyApps;
5099 context.isPreChange = fIsPreChange;
5100 context.enableTracing = false;
5101 context.us = this;
5102 context.maxTimeRequested = 0;
5103 context.stateNumber = fHeadNotePowerState;
5104 context.stateFlags = fHeadNotePowerArrayEntry->capabilityFlags;
5105 context.changeFlags = fHeadNoteChangeFlags;
5106 context.errorLog = "PM notification timeout (%s)\n";
5107
5108 applyToInterested(gIOAppPowerStateInterest, logAppTimeouts, (void *) &context);
5109 }
5110 break;
5111
5112 default:
5113 // kNotifyPriority, kNotifyCapabilityChangePriority
5114 // TODO: identify the priority client that has not acked
5115 PM_ERROR("PM priority notification timeout\n");
5116 if (gIOKitDebug & kIOLogDebugPower)
5117 {
5118 panic("PM priority notification timeout");
5119 }
5120 break;
5121 }
5122 }
5123
5124 if (fResponseArray)
5125 {
5126 fResponseArray->release();
5127 fResponseArray = NULL;
5128 }
5129 if (fNotifyClientArray)
5130 {
5131 fNotifyClientArray->release();
5132 fNotifyClientArray = NULL;
5133 }
5134 }
5135
5136 //*********************************************************************************
5137 // [protected] tellClientsWithResponse
5138 //
5139 // Notify registered applications and kernel clients that we are definitely
5140 // dropping power.
5141 //
5142 // Return true if we don't have to wait for acknowledgements
5143 //*********************************************************************************
5144
5145 bool IOService::tellClientsWithResponse ( int messageType )
5146 {
5147 IOPMInterestContext context;
5148 bool isRootDomain = IS_ROOT_DOMAIN;
5149
5150 PM_ASSERT_IN_GATE();
5151 assert( fResponseArray == NULL );
5152 assert( fNotifyClientArray == NULL );
5153
5154 RD_LOG("tellClientsWithResponse( %s, %d )\n",
5155 getIOMessageString(messageType), fOutOfBandParameter);
5156
5157 fResponseArray = OSArray::withCapacity( 1 );
5158 if (!fResponseArray)
5159 goto exit;
5160
5161 fResponseArray->setCapacityIncrement(8);
5162 if (++fSerialNumber == 0)
5163 fSerialNumber++;
5164
5165 context.responseArray = fResponseArray;
5166 context.notifyClients = 0;
5167 context.serialNumber = fSerialNumber;
5168 context.messageType = messageType;
5169 context.notifyType = fOutOfBandParameter;
5170 context.isPreChange = fIsPreChange;
5171 context.enableTracing = false;
5172 context.us = this;
5173 context.maxTimeRequested = 0;
5174 context.stateNumber = fHeadNotePowerState;
5175 context.stateFlags = fHeadNotePowerArrayEntry->capabilityFlags;
5176 context.changeFlags = fHeadNoteChangeFlags;
5177 context.messageFilter = (isRootDomain) ?
5178 OSMemberFunctionCast(
5179 IOPMMessageFilter,
5180 this,
5181 &IOPMrootDomain::systemMessageFilter) : 0;
5182
5183 switch ( fOutOfBandParameter ) {
5184 case kNotifyApps:
5185 applyToInterested( gIOAppPowerStateInterest,
5186 pmTellAppWithResponse, (void *) &context );
5187
5188 if (isRootDomain &&
5189 (fMachineState != kIOPM_OurChangeTellClientsPowerDown) &&
5190 (fMachineState != kIOPM_SyncTellClientsPowerDown))
5191 {
5192 // Notify capability app for tellChangeDown1()
5193 // but not for askChangeDown().
5194 context.notifyType = kNotifyCapabilityChangeApps;
5195 context.messageType = kIOMessageSystemCapabilityChange;
5196 applyToInterested( gIOAppPowerStateInterest,
5197 pmTellCapabilityAppWithResponse, (void *) &context );
5198 context.notifyType = fOutOfBandParameter;
5199 context.messageType = messageType;
5200 }
5201 context.maxTimeRequested = k30seconds;
5202
5203 applyToInterested( gIOGeneralInterest,
5204 pmTellClientWithResponse, (void *) &context );
5205
5206 fNotifyClientArray = context.notifyClients;
5207 break;
5208
5209 case kNotifyPriority:
5210 context.enableTracing = isRootDomain;
5211 applyToInterested( gIOPriorityPowerStateInterest,
5212 pmTellClientWithResponse, (void *) &context );
5213
5214 if (isRootDomain)
5215 {
5216 // Notify capability clients for tellChangeDown2().
5217 context.notifyType = kNotifyCapabilityChangePriority;
5218 context.messageType = kIOMessageSystemCapabilityChange;
5219 applyToInterested( gIOPriorityPowerStateInterest,
5220 pmTellCapabilityClientWithResponse, (void *) &context );
5221 }
5222 break;
5223
5224 case kNotifyCapabilityChangeApps:
5225 applyToInterested( gIOAppPowerStateInterest,
5226 pmTellCapabilityAppWithResponse, (void *) &context );
5227 fNotifyClientArray = context.notifyClients;
5228 context.maxTimeRequested = k30seconds;
5229 break;
5230
5231 case kNotifyCapabilityChangePriority:
5232 applyToInterested( gIOPriorityPowerStateInterest,
5233 pmTellCapabilityClientWithResponse, (void *) &context );
5234 break;
5235 }
5236
5237 // do we have to wait for somebody?
5238 if ( !checkForDone() )
5239 {
5240 OUR_PMLog(kPMLogStartAckTimer, context.maxTimeRequested, 0);
5241 if (context.enableTracing)
5242 getPMRootDomain()->traceDetail( context.maxTimeRequested / 1000 );
5243 start_ack_timer( context.maxTimeRequested / 1000, kMillisecondScale );
5244 return false;
5245 }
5246
5247 exit:
5248 // everybody responded
5249 if (fResponseArray)
5250 {
5251 fResponseArray->release();
5252 fResponseArray = NULL;
5253 }
5254 if (fNotifyClientArray)
5255 {
5256 fNotifyClientArray->release();
5257 fNotifyClientArray = NULL;
5258 }
5259
5260 return true;
5261 }
5262
5263 //*********************************************************************************
5264 // [static private] pmTellAppWithResponse
5265 //
5266 // We send a message to an application, and we expect a response, so we compute a
5267 // cookie we can identify the response with.
5268 //*********************************************************************************
5269
5270 void IOService::pmTellAppWithResponse ( OSObject * object, void * arg )
5271 {
5272 IOPMInterestContext * context = (IOPMInterestContext *) arg;
5273 IOServicePM * pwrMgt = context->us->pwrMgt;
5274 uint32_t msgIndex, msgRef, msgType;
5275 #if LOG_APP_RESPONSE_TIMES
5276 AbsoluteTime now;
5277 #endif
5278
5279 if (!OSDynamicCast(_IOServiceInterestNotifier, object))
5280 return;
5281
5282 if (context->messageFilter &&
5283 !context->messageFilter(context->us, object, context, 0, 0))
5284 {
5285 if (kIOLogDebugPower & gIOKitDebug)
5286 {
5287 // Log client pid/name and client array index.
5288 OSString * clientID = 0;
5289 context->us->messageClient(kIOMessageCopyClientID, object, &clientID);
5290 PM_LOG("%s DROP App %s, %s\n",
5291 context->us->getName(),
5292 getIOMessageString(context->messageType),
5293 clientID ? clientID->getCStringNoCopy() : "");
5294 if (clientID) clientID->release();
5295 }
5296 return;
5297 }
5298
5299 // Create client array (for tracking purposes) only if the service
5300 // has app clients. Usually only root domain does.
5301 if (0 == context->notifyClients)
5302 context->notifyClients = OSArray::withCapacity( 32 );
5303
5304 msgType = context->messageType;
5305 msgIndex = context->responseArray->getCount();
5306 msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
5307
5308 OUR_PMLog(kPMLogAppNotify, msgType, msgRef);
5309 if (kIOLogDebugPower & gIOKitDebug)
5310 {
5311 // Log client pid/name and client array index.
5312 OSString * clientID = 0;
5313 context->us->messageClient(kIOMessageCopyClientID, object, &clientID);
5314 PM_LOG("%s MESG App(%u) %s, %s\n",
5315 context->us->getName(),
5316 msgIndex, getIOMessageString(msgType),
5317 clientID ? clientID->getCStringNoCopy() : "");
5318 if (clientID) clientID->release();
5319 }
5320
5321 #if LOG_APP_RESPONSE_TIMES
5322 OSNumber * num;
5323 clock_get_uptime(&now);
5324 num = OSNumber::withNumber(AbsoluteTime_to_scalar(&now), sizeof(uint64_t) * 8);
5325 if (num)
5326 {
5327 context->responseArray->setObject(msgIndex, num);
5328 num->release();
5329 }
5330 else
5331 #endif
5332 context->responseArray->setObject(msgIndex, kOSBooleanFalse);
5333
5334 if (context->notifyClients)
5335 context->notifyClients->setObject(msgIndex, object);
5336
5337 context->us->messageClient(msgType, object, (void *) msgRef);
5338 }
5339
5340 //*********************************************************************************
5341 // [static private] pmTellClientWithResponse
5342 //
5343 // We send a message to an in-kernel client, and we expect a response,
5344 // so we compute a cookie we can identify the response with.
5345 //*********************************************************************************
5346
5347 void IOService::pmTellClientWithResponse ( OSObject * object, void * arg )
5348 {
5349 IOPowerStateChangeNotification notify;
5350 IOPMInterestContext * context = (IOPMInterestContext *) arg;
5351 OSObject * replied = kOSBooleanTrue;
5352 _IOServiceInterestNotifier * notifier;
5353 uint32_t msgIndex, msgRef, msgType;
5354 IOReturn retCode;
5355
5356 if (context->messageFilter &&
5357 !context->messageFilter(context->us, object, context, 0, 0))
5358 {
5359 if ((kIOLogDebugPower & gIOKitDebug) &&
5360 (OSDynamicCast(_IOServiceInterestNotifier, object)))
5361 {
5362 _IOServiceInterestNotifier *n = (_IOServiceInterestNotifier *) object;
5363 PM_LOG("%s DROP Client %s, notifier %p, handler %p\n",
5364 context->us->getName(),
5365 getIOMessageString(context->messageType),
5366 object, n->handler);
5367 }
5368 return;
5369 }
5370
5371 notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
5372 msgType = context->messageType;
5373 msgIndex = context->responseArray->getCount();
5374 msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
5375
5376 IOServicePM * pwrMgt = context->us->pwrMgt;
5377 if (gIOKitDebug & kIOLogPower) {
5378 OUR_PMLog(kPMLogClientNotify, msgRef, msgType);
5379 if (OSDynamicCast(IOService, object)) {
5380 const char *who = ((IOService *) object)->getName();
5381 gPlatform->PMLog(who, kPMLogClientNotify, (uintptr_t) object, 0);
5382 }
5383 else if (notifier) {
5384 OUR_PMLog(kPMLogClientNotify, (uintptr_t) notifier->handler, 0);
5385 }
5386 }
5387 if ((kIOLogDebugPower & gIOKitDebug) && notifier)
5388 {
5389 PM_LOG("%s MESG Client %s, notifier %p, handler %p\n",
5390 context->us->getName(),
5391 getIOMessageString(msgType),
5392 object, notifier->handler);
5393 }
5394
5395 notify.powerRef = (void *)(uintptr_t) msgRef;
5396 notify.returnValue = 0;
5397 notify.stateNumber = context->stateNumber;
5398 notify.stateFlags = context->stateFlags;
5399
5400 if (context->enableTracing && (notifier != 0))
5401 {
5402 uint32_t detail = ((msgIndex & 0xff) << 24) |
5403 ((msgType & 0xfff) << 12) |
5404 (((uintptr_t) notifier->handler) & 0xfff);
5405 getPMRootDomain()->traceDetail( detail );
5406 }
5407
5408 retCode = context->us->messageClient(msgType, object, (void *) &notify);
5409 if ( kIOReturnSuccess == retCode )
5410 {
5411 if ( 0 == notify.returnValue )
5412 {
5413 // client doesn't want time to respond
5414 OUR_PMLog(kPMLogClientAcknowledge, msgRef, (uintptr_t) object);
5415 }
5416 else
5417 {
5418 replied = kOSBooleanFalse;
5419 if ( notify.returnValue > context->maxTimeRequested )
5420 {
5421 if (notify.returnValue > kPriorityClientMaxWait)
5422 {
5423 context->maxTimeRequested = kPriorityClientMaxWait;
5424 PM_ERROR("%s: client %p returned %llu for %s\n",
5425 context->us->getName(),
5426 notifier ? (void *) notifier->handler : object,
5427 (uint64_t) notify.returnValue,
5428 getIOMessageString(msgType));
5429 }
5430 else
5431 context->maxTimeRequested = notify.returnValue;
5432 }
5433 }
5434 }
5435 else
5436 {
5437 // not a client of ours
5438 // so we won't be waiting for response
5439 OUR_PMLog(kPMLogClientAcknowledge, msgRef, 0);
5440 }
5441
5442 context->responseArray->setObject(msgIndex, replied);
5443 }
5444
5445 //*********************************************************************************
5446 // [static private] pmTellCapabilityAppWithResponse
5447 //*********************************************************************************
5448
5449 void IOService::pmTellCapabilityAppWithResponse ( OSObject * object, void * arg )
5450 {
5451 IOPMSystemCapabilityChangeParameters msgArg;
5452 IOPMInterestContext * context = (IOPMInterestContext *) arg;
5453 OSObject * replied = kOSBooleanTrue;
5454 IOServicePM * pwrMgt = context->us->pwrMgt;
5455 uint32_t msgIndex, msgRef, msgType;
5456 #if LOG_APP_RESPONSE_TIMES
5457 AbsoluteTime now;
5458 #endif
5459
5460 if (!OSDynamicCast(_IOServiceInterestNotifier, object))
5461 return;
5462
5463 memset(&msgArg, 0, sizeof(msgArg));
5464 if (context->messageFilter &&
5465 !context->messageFilter(context->us, object, context, &msgArg, &replied))
5466 {
5467 return;
5468 }
5469
5470 // Create client array (for tracking purposes) only if the service
5471 // has app clients. Usually only root domain does.
5472 if (0 == context->notifyClients)
5473 context->notifyClients = OSArray::withCapacity( 32 );
5474
5475 msgType = context->messageType;
5476 msgIndex = context->responseArray->getCount();
5477 msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
5478
5479 OUR_PMLog(kPMLogAppNotify, msgType, msgRef);
5480 if (kIOLogDebugPower & gIOKitDebug)
5481 {
5482 // Log client pid/name and client array index.
5483 OSString * clientID = 0;
5484 context->us->messageClient(kIOMessageCopyClientID, object, &clientID);
5485 PM_LOG("%s MESG App(%u) %s, wait %u, %s\n",
5486 context->us->getName(),
5487 msgIndex, getIOMessageString(msgType),
5488 (replied != kOSBooleanTrue),
5489 clientID ? clientID->getCStringNoCopy() : "");
5490 if (clientID) clientID->release();
5491 }
5492
5493 msgArg.notifyRef = msgRef;
5494 msgArg.maxWaitForReply = 0;
5495
5496 if (replied == kOSBooleanTrue)
5497 {
5498 msgArg.notifyRef = 0;
5499 context->responseArray->setObject(msgIndex, kOSBooleanTrue);
5500 if (context->notifyClients)
5501 context->notifyClients->setObject(msgIndex, kOSBooleanTrue);
5502 }
5503 else
5504 {
5505 #if LOG_APP_RESPONSE_TIMES
5506 OSNumber * num;
5507 clock_get_uptime(&now);
5508 num = OSNumber::withNumber(AbsoluteTime_to_scalar(&now), sizeof(uint64_t) * 8);
5509 if (num)
5510 {
5511 context->responseArray->setObject(msgIndex, num);
5512 num->release();
5513 }
5514 else
5515 #endif
5516 context->responseArray->setObject(msgIndex, kOSBooleanFalse);
5517
5518 if (context->notifyClients)
5519 context->notifyClients->setObject(msgIndex, object);
5520 }
5521
5522 context->us->messageClient(msgType, object, (void *) &msgArg, sizeof(msgArg));
5523 }
5524
5525 //*********************************************************************************
5526 // [static private] pmTellCapabilityClientWithResponse
5527 //*********************************************************************************
5528
5529 void IOService::pmTellCapabilityClientWithResponse(
5530 OSObject * object, void * arg )
5531 {
5532 IOPMSystemCapabilityChangeParameters msgArg;
5533 IOPMInterestContext * context = (IOPMInterestContext *) arg;
5534 OSObject * replied = kOSBooleanTrue;
5535 _IOServiceInterestNotifier * notifier;
5536 uint32_t msgIndex, msgRef, msgType;
5537 IOReturn retCode;
5538
5539 memset(&msgArg, 0, sizeof(msgArg));
5540 if (context->messageFilter &&
5541 !context->messageFilter(context->us, object, context, &msgArg, 0))
5542 {
5543 if ((kIOLogDebugPower & gIOKitDebug) &&
5544 (OSDynamicCast(_IOServiceInterestNotifier, object)))
5545 {
5546 _IOServiceInterestNotifier *n = (_IOServiceInterestNotifier *) object;
5547 PM_LOG("%s DROP Client %s, notifier %p, handler %p\n",
5548 context->us->getName(),
5549 getIOMessageString(context->messageType),
5550 object, n->handler);
5551 }
5552 return;
5553 }
5554
5555 notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
5556 msgType = context->messageType;
5557 msgIndex = context->responseArray->getCount();
5558 msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
5559
5560 IOServicePM * pwrMgt = context->us->pwrMgt;
5561 if (gIOKitDebug & kIOLogPower) {
5562 OUR_PMLog(kPMLogClientNotify, msgRef, msgType);
5563 if (OSDynamicCast(IOService, object)) {
5564 const char *who = ((IOService *) object)->getName();
5565 gPlatform->PMLog(who, kPMLogClientNotify, (uintptr_t) object, 0);
5566 }
5567 else if (notifier) {
5568 OUR_PMLog(kPMLogClientNotify, (uintptr_t) notifier->handler, 0);
5569 }
5570 }
5571 if ((kIOLogDebugPower & gIOKitDebug) && notifier)
5572 {
5573 PM_LOG("%s MESG Client %s, notifier %p, handler %p\n",
5574 context->us->getName(),
5575 getIOMessageString(msgType),
5576 object, notifier->handler);
5577 }
5578
5579 msgArg.notifyRef = msgRef;
5580 msgArg.maxWaitForReply = 0;
5581
5582 if (context->enableTracing && (notifier != 0))
5583 {
5584 uint32_t detail = ((msgIndex & 0xff) << 24) |
5585 ((msgType & 0xfff) << 12) |
5586 (((uintptr_t) notifier->handler) & 0xfff);
5587 getPMRootDomain()->traceDetail( detail );
5588 }
5589
5590 retCode = context->us->messageClient(
5591 msgType, object, (void *) &msgArg, sizeof(msgArg));
5592
5593 if ( kIOReturnSuccess == retCode )
5594 {
5595 if ( 0 == msgArg.maxWaitForReply )
5596 {
5597 // client doesn't want time to respond
5598 OUR_PMLog(kPMLogClientAcknowledge, msgRef, (uintptr_t) object);
5599 }
5600 else
5601 {
5602 replied = kOSBooleanFalse;
5603 if ( msgArg.maxWaitForReply > context->maxTimeRequested )
5604 {
5605 if (msgArg.maxWaitForReply > kCapabilityClientMaxWait)
5606 {
5607 context->maxTimeRequested = kCapabilityClientMaxWait;
5608 PM_ERROR("%s: client %p returned %u for %s\n",
5609 context->us->getName(),
5610 notifier ? (void *) notifier->handler : object,
5611 msgArg.maxWaitForReply,
5612 getIOMessageString(msgType));
5613 }
5614 else
5615 context->maxTimeRequested = msgArg.maxWaitForReply;
5616 }
5617 }
5618 }
5619 else
5620 {
5621 // not a client of ours
5622 // so we won't be waiting for response
5623 OUR_PMLog(kPMLogClientAcknowledge, msgRef, 0);
5624 }
5625
5626 context->responseArray->setObject(msgIndex, replied);
5627 }
5628
5629 //*********************************************************************************
5630 // [public] tellNoChangeDown
5631 //
5632 // Notify registered applications and kernel clients that we are not
5633 // dropping power.
5634 //
5635 // Subclass can override this to send a different message type. Parameter is
5636 // the aborted destination state number.
5637 //*********************************************************************************
5638
5639 void IOService::tellNoChangeDown ( unsigned long )
5640 {
5641 return tellClients( kIOMessageDeviceWillNotPowerOff );
5642 }
5643
5644 //*********************************************************************************
5645 // [public] tellChangeUp
5646 //
5647 // Notify registered applications and kernel clients that we are raising power.
5648 //
5649 // Subclass can override this to send a different message type. Parameter is
5650 // the aborted destination state number.
5651 //*********************************************************************************
5652
5653 void IOService::tellChangeUp ( unsigned long )
5654 {
5655 return tellClients( kIOMessageDeviceHasPoweredOn );
5656 }
5657
5658 //*********************************************************************************
5659 // [protected] tellClients
5660 //
5661 // Notify registered applications and kernel clients of something.
5662 //*********************************************************************************
5663
5664 void IOService::tellClients ( int messageType )
5665 {
5666 IOPMInterestContext context;
5667
5668 RD_LOG("tellClients( %s )\n", getIOMessageString(messageType));
5669
5670 memset(&context, 0, sizeof(context));
5671 context.messageType = messageType;
5672 context.isPreChange = fIsPreChange;
5673 context.us = this;
5674 context.stateNumber = fHeadNotePowerState;
5675 context.stateFlags = fHeadNotePowerArrayEntry->capabilityFlags;
5676 context.changeFlags = fHeadNoteChangeFlags;
5677 context.messageFilter = (IS_ROOT_DOMAIN) ?
5678 OSMemberFunctionCast(
5679 IOPMMessageFilter,
5680 this,
5681 &IOPMrootDomain::systemMessageFilter) : 0;
5682
5683 context.notifyType = kNotifyPriority;
5684 applyToInterested( gIOPriorityPowerStateInterest,
5685 tellKernelClientApplier, (void *) &context );
5686
5687 context.notifyType = kNotifyApps;
5688 applyToInterested( gIOAppPowerStateInterest,
5689 tellAppClientApplier, (void *) &context );
5690
5691 applyToInterested( gIOGeneralInterest,
5692 tellKernelClientApplier, (void *) &context );
5693 }
5694
5695 //*********************************************************************************
5696 // [private] tellKernelClientApplier
5697 //
5698 // Message a kernel client.
5699 //*********************************************************************************
5700
5701 static void tellKernelClientApplier ( OSObject * object, void * arg )
5702 {
5703 IOPowerStateChangeNotification notify;
5704 IOPMInterestContext * context = (IOPMInterestContext *) arg;
5705
5706 if (context->messageFilter &&
5707 !context->messageFilter(context->us, object, context, 0, 0))
5708 {
5709 if ((kIOLogDebugPower & gIOKitDebug) &&
5710 (OSDynamicCast(_IOServiceInterestNotifier, object)))
5711 {
5712 _IOServiceInterestNotifier *n = (_IOServiceInterestNotifier *) object;
5713 PM_LOG("%s DROP Client %s, notifier %p, handler %p\n",
5714 context->us->getName(),
5715 IOService::getIOMessageString(context->messageType),
5716 object, n->handler);
5717 }
5718 return;
5719 }
5720
5721 notify.powerRef = (void *) 0;
5722 notify.returnValue = 0;
5723 notify.stateNumber = context->stateNumber;
5724 notify.stateFlags = context->stateFlags;
5725
5726 context->us->messageClient(context->messageType, object, &notify);
5727
5728 if ((kIOLogDebugPower & gIOKitDebug) &&
5729 (OSDynamicCast(_IOServiceInterestNotifier, object)))
5730 {
5731 _IOServiceInterestNotifier *n = (_IOServiceInterestNotifier *) object;
5732 PM_LOG("%s MESG Client %s, notifier %p, handler %p\n",
5733 context->us->getName(),
5734 IOService::getIOMessageString(context->messageType),
5735 object, n->handler);
5736 }
5737 }
5738
5739 //*********************************************************************************
5740 // [private] tellAppClientApplier
5741 //
5742 // Message a registered application.
5743 //*********************************************************************************
5744
5745 static void tellAppClientApplier ( OSObject * object, void * arg )
5746 {
5747 IOPMInterestContext * context = (IOPMInterestContext *) arg;
5748
5749 if (context->messageFilter &&
5750 !context->messageFilter(context->us, object, context, 0, 0))
5751 {
5752 if (kIOLogDebugPower & gIOKitDebug)
5753 {
5754 // Log client pid/name and client array index.
5755 OSString * clientID = 0;
5756 context->us->messageClient(kIOMessageCopyClientID, object, &clientID);
5757 PM_LOG("%s DROP App %s, %s\n",
5758 context->us->getName(),
5759 IOService::getIOMessageString(context->messageType),
5760 clientID ? clientID->getCStringNoCopy() : "");
5761 if (clientID) clientID->release();
5762 }
5763 return;
5764 }
5765
5766 if (kIOLogDebugPower & gIOKitDebug)
5767 {
5768 // Log client pid/name and client array index.
5769 OSString * clientID = 0;
5770 context->us->messageClient(kIOMessageCopyClientID, object, &clientID);
5771 PM_LOG("%s MESG App %s, %s\n",
5772 context->us->getName(),
5773 IOService::getIOMessageString(context->messageType),
5774 clientID ? clientID->getCStringNoCopy() : "");
5775 if (clientID) clientID->release();
5776 }
5777
5778 context->us->messageClient(context->messageType, object, 0);
5779 }
5780
5781 //*********************************************************************************
5782 // [private] checkForDone
5783 //*********************************************************************************
5784
5785 bool IOService::checkForDone ( void )
5786 {
5787 int i = 0;
5788 OSObject * theFlag;
5789
5790 if ( fResponseArray == NULL )
5791 {
5792 return true;
5793 }
5794
5795 for ( i = 0; ; i++ )
5796 {
5797 theFlag = fResponseArray->getObject(i);
5798 if ( theFlag == NULL )
5799 {
5800 break;
5801 }
5802 if ( kOSBooleanTrue != theFlag )
5803 {
5804 return false;
5805 }
5806 }
5807 return true;
5808 }
5809
5810 //*********************************************************************************
5811 // [public] responseValid
5812 //*********************************************************************************
5813
5814 bool IOService::responseValid ( uint32_t refcon, int pid )
5815 {
5816 UInt16 serialComponent;
5817 UInt16 ordinalComponent;
5818 OSObject * theFlag;
5819
5820 serialComponent = (refcon >> 16) & 0xFFFF;
5821 ordinalComponent = (refcon & 0xFFFF);
5822
5823 if ( serialComponent != fSerialNumber )
5824 {
5825 return false;
5826 }
5827
5828 if ( fResponseArray == NULL )
5829 {
5830 return false;
5831 }
5832
5833 theFlag = fResponseArray->getObject(ordinalComponent);
5834
5835 if ( theFlag == 0 )
5836 {
5837 return false;
5838 }
5839
5840 OSNumber * num;
5841 if ((num = OSDynamicCast(OSNumber, theFlag)))
5842 {
5843 #if LOG_APP_RESPONSE_TIMES
5844 AbsoluteTime now;
5845 AbsoluteTime start;
5846 uint64_t nsec;
5847 OSString *name = IOCopyLogNameForPID(pid);
5848
5849 clock_get_uptime(&now);
5850 AbsoluteTime_to_scalar(&start) = num->unsigned64BitValue();
5851 SUB_ABSOLUTETIME(&now, &start);
5852 absolutetime_to_nanoseconds(now, &nsec);
5853
5854 PMEventDetails *details = PMEventDetails::eventDetails(
5855 kIOPMEventTypeAppResponse, // type
5856 name ? name->getCStringNoCopy() : "", // who
5857 (uintptr_t)pid, // owner unique
5858 NULL, // interest name
5859 0, // old
5860 0, // new
5861 0, // result
5862 NS_TO_US(nsec)); // usec completion time
5863
5864 getPMRootDomain()->recordAndReleasePMEventGated( details );
5865
5866 if (kIOLogDebugPower & gIOKitDebug)
5867 {
5868 PM_LOG("Ack(%u) %u ms\n",
5869 (uint32_t) ordinalComponent,
5870 NS_TO_MS(nsec));
5871 }
5872
5873 // > 100 ms
5874 if (nsec > LOG_APP_RESPONSE_TIMES)
5875 {
5876 PM_LOG("PM response took %d ms (%s)\n", NS_TO_MS(nsec),
5877 name ? name->getCStringNoCopy() : "");
5878
5879 if (nsec > LOG_APP_RESPONSE_MSG_TRACER)
5880 {
5881 // TODO: populate the messageType argument
5882 getPMRootDomain()->pmStatsRecordApplicationResponse(
5883 gIOPMStatsApplicationResponseSlow,
5884 name ? name->getCStringNoCopy() : "", 0,
5885 NS_TO_MS(nsec), pid);
5886 }
5887 }
5888
5889 if (name)
5890 name->release();
5891 #endif
5892 theFlag = kOSBooleanFalse;
5893 }
5894
5895 if ( kOSBooleanFalse == theFlag )
5896 {
5897 fResponseArray->replaceObject(ordinalComponent, kOSBooleanTrue);
5898 }
5899
5900 return true;
5901 }
5902
5903 //*********************************************************************************
5904 // [public] allowPowerChange
5905 //
5906 // Our power state is about to lower, and we have notified applications
5907 // and kernel clients, and one of them has acknowledged. If this is the last to do
5908 // so, and all acknowledgements are positive, we continue with the power change.
5909 //*********************************************************************************
5910
5911 IOReturn IOService::allowPowerChange ( unsigned long refcon )
5912 {
5913 IOPMRequest * request;
5914
5915 if ( !initialized )
5916 {
5917 // we're unloading
5918 return kIOReturnSuccess;
5919 }
5920
5921 request = acquirePMRequest( this, kIOPMRequestTypeAllowPowerChange );
5922 if (!request)
5923 return kIOReturnNoMemory;
5924
5925 request->fArg0 = (void *) refcon;
5926 request->fArg1 = (void *) proc_selfpid();
5927 request->fArg2 = (void *) 0;
5928 submitPMRequest( request );
5929
5930 return kIOReturnSuccess;
5931 }
5932
5933 #ifndef __LP64__
5934 IOReturn IOService::serializedAllowPowerChange2 ( unsigned long refcon )
5935 {
5936 // [deprecated] public
5937 return kIOReturnUnsupported;
5938 }
5939 #endif /* !__LP64__ */
5940
5941 //*********************************************************************************
5942 // [public] cancelPowerChange
5943 //
5944 // Our power state is about to lower, and we have notified applications
5945 // and kernel clients, and one of them has vetoed the change. If this is the last
5946 // client to respond, we abandon the power change.
5947 //*********************************************************************************
5948
5949 IOReturn IOService::cancelPowerChange ( unsigned long refcon )
5950 {
5951 IOPMRequest * request;
5952 OSString * name;
5953
5954 if ( !initialized )
5955 {
5956 // we're unloading
5957 return kIOReturnSuccess;
5958 }
5959
5960 name = IOCopyLogNameForPID(proc_selfpid());
5961 PM_ERROR("PM notification cancel (%s)\n", name ? name->getCStringNoCopy() : "");
5962
5963 request = acquirePMRequest( this, kIOPMRequestTypeCancelPowerChange );
5964 if (!request)
5965 {
5966 if (name)
5967 name->release();
5968 return kIOReturnNoMemory;
5969 }
5970
5971 request->fArg0 = (void *) refcon;
5972 request->fArg1 = (void *) proc_selfpid();
5973 request->fArg2 = (void *) name;
5974 submitPMRequest( request );
5975
5976 return kIOReturnSuccess;
5977 }
5978
5979 #ifndef __LP64__
5980 IOReturn IOService::serializedCancelPowerChange2 ( unsigned long refcon )
5981 {
5982 // [deprecated] public
5983 return kIOReturnUnsupported;
5984 }
5985
5986 //*********************************************************************************
5987 // PM_Clamp_Timer_Expired
5988 //
5989 // called when clamp timer expires...set power state to 0.
5990 //*********************************************************************************
5991
5992 void IOService::PM_Clamp_Timer_Expired ( void )
5993 {
5994 }
5995
5996 //*********************************************************************************
5997 // clampPowerOn
5998 //
5999 // Set to highest available power state for a minimum of duration milliseconds
6000 //*********************************************************************************
6001
6002 void IOService::clampPowerOn ( unsigned long duration )
6003 {
6004 }
6005 #endif /* !__LP64__ */
6006
6007 // MARK: -
6008 // MARK: Driver Overrides
6009
6010 //*********************************************************************************
6011 // [public] setPowerState
6012 //
6013 // Does nothing here. This should be implemented in a subclass driver.
6014 //*********************************************************************************
6015
6016 IOReturn IOService::setPowerState (
6017 unsigned long powerStateOrdinal, IOService * whatDevice )
6018 {
6019 return IOPMNoErr;
6020 }
6021
6022 //*********************************************************************************
6023 // [public] maxCapabilityForDomainState
6024 //
6025 // Finds the highest power state in the array whose input power
6026 // requirement is equal to the input parameter. Where a more intelligent
6027 // decision is possible, override this in the subclassed driver.
6028 //*********************************************************************************
6029
6030 unsigned long IOService::maxCapabilityForDomainState ( IOPMPowerFlags domainState )
6031 {
6032 int i;
6033
6034 if (fNumberOfPowerStates == 0 )
6035 {
6036 return 0;
6037 }
6038 for ( i = fNumberOfPowerStates - 1; i >= 0; i-- )
6039 {
6040 if ( (domainState & fPowerStates[i].inputPowerFlags) ==
6041 fPowerStates[i].inputPowerFlags )
6042 {
6043 return i;
6044 }
6045 }
6046 return 0;
6047 }
6048
6049 //*********************************************************************************
6050 // [public] initialPowerStateForDomainState
6051 //
6052 // Finds the highest power state in the array whose input power
6053 // requirement is equal to the input parameter. Where a more intelligent
6054 // decision is possible, override this in the subclassed driver.
6055 //*********************************************************************************
6056
6057 unsigned long IOService::initialPowerStateForDomainState ( IOPMPowerFlags domainState )
6058 {
6059 int i;
6060
6061 if (fNumberOfPowerStates == 0 )
6062 {
6063 return 0;
6064 }
6065 for ( i = fNumberOfPowerStates - 1; i >= 0; i-- )
6066 {
6067 if ( (domainState & fPowerStates[i].inputPowerFlags) ==
6068 fPowerStates[i].inputPowerFlags )
6069 {
6070 return i;
6071 }
6072 }
6073 return 0;
6074 }
6075
6076 //*********************************************************************************
6077 // [public] powerStateForDomainState
6078 //
6079 // Finds the highest power state in the array whose input power
6080 // requirement is equal to the input parameter. Where a more intelligent
6081 // decision is possible, override this in the subclassed driver.
6082 //*********************************************************************************
6083
6084 unsigned long IOService::powerStateForDomainState ( IOPMPowerFlags domainState )
6085 {
6086 int i;
6087
6088 if (fNumberOfPowerStates == 0 )
6089 {
6090 return 0;
6091 }
6092 for ( i = fNumberOfPowerStates - 1; i >= 0; i-- )
6093 {
6094 if ( (domainState & fPowerStates[i].inputPowerFlags) ==
6095 fPowerStates[i].inputPowerFlags )
6096 {
6097 return i;
6098 }
6099 }
6100 return 0;
6101 }
6102
6103 #ifndef __LP64__
6104 //*********************************************************************************
6105 // [deprecated] didYouWakeSystem
6106 //
6107 // Does nothing here. This should be implemented in a subclass driver.
6108 //*********************************************************************************
6109
6110 bool IOService::didYouWakeSystem ( void )
6111 {
6112 return false;
6113 }
6114 #endif /* !__LP64__ */
6115
6116 //*********************************************************************************
6117 // [public] powerStateWillChangeTo
6118 //
6119 // Does nothing here. This should be implemented in a subclass driver.
6120 //*********************************************************************************
6121
6122 IOReturn IOService::powerStateWillChangeTo ( IOPMPowerFlags, unsigned long, IOService * )
6123 {
6124 return kIOPMAckImplied;
6125 }
6126
6127 //*********************************************************************************
6128 // [public] powerStateDidChangeTo
6129 //
6130 // Does nothing here. This should be implemented in a subclass driver.
6131 //*********************************************************************************
6132
6133 IOReturn IOService::powerStateDidChangeTo ( IOPMPowerFlags, unsigned long, IOService * )
6134 {
6135 return kIOPMAckImplied;
6136 }
6137
6138 //*********************************************************************************
6139 // [protected] powerChangeDone
6140 //
6141 // Called from PM work loop thread.
6142 // Does nothing here. This should be implemented in a subclass policy-maker.
6143 //*********************************************************************************
6144
6145 void IOService::powerChangeDone ( unsigned long )
6146 {
6147 }
6148
6149 #ifndef __LP64__
6150 //*********************************************************************************
6151 // [deprecated] newTemperature
6152 //
6153 // Does nothing here. This should be implemented in a subclass driver.
6154 //*********************************************************************************
6155
6156 IOReturn IOService::newTemperature ( long currentTemp, IOService * whichZone )
6157 {
6158 return IOPMNoErr;
6159 }
6160 #endif /* !__LP64__ */
6161
6162 //*********************************************************************************
6163 // [public] systemWillShutdown
6164 //
6165 // System shutdown and restart notification.
6166 //*********************************************************************************
6167
6168 void IOService::systemWillShutdown( IOOptionBits specifier )
6169 {
6170 IOPMrootDomain * rootDomain = IOService::getPMRootDomain();
6171 if (rootDomain)
6172 rootDomain->acknowledgeSystemWillShutdown( this );
6173 }
6174
6175 // MARK: -
6176 // MARK: PM State Machine
6177
6178 //*********************************************************************************
6179 // [private static] acquirePMRequest
6180 //*********************************************************************************
6181
6182 IOPMRequest *
6183 IOService::acquirePMRequest( IOService * target, IOOptionBits requestType,
6184 IOPMRequest * active )
6185 {
6186 IOPMRequest * request;
6187
6188 assert(target);
6189
6190 request = IOPMRequest::create();
6191 if (request)
6192 {
6193 request->init( target, requestType );
6194 if (active)
6195 {
6196 IOPMRequest * root = active->getRootRequest();
6197 if (root) request->attachRootRequest(root);
6198 }
6199 }
6200 else
6201 {
6202 PM_ERROR("%s: No memory for PM request type 0x%x\n",
6203 target->getName(), (uint32_t) requestType);
6204 }
6205 return request;
6206 }
6207
6208 //*********************************************************************************
6209 // [private static] releasePMRequest
6210 //*********************************************************************************
6211
6212 void IOService::releasePMRequest( IOPMRequest * request )
6213 {
6214 if (request)
6215 {
6216 request->reset();
6217 request->release();
6218 }
6219 }
6220
6221 //*********************************************************************************
6222 // [private] submitPMRequest
6223 //*********************************************************************************
6224
6225 void IOService::submitPMRequest( IOPMRequest * request )
6226 {
6227 assert( request );
6228 assert( gIOPMReplyQueue );
6229 assert( gIOPMRequestQueue );
6230
6231 PM_LOG1("[+ %02lx] %p [%p %s] %p %p %p\n",
6232 (long)request->getType(), request,
6233 request->getTarget(), request->getTarget()->getName(),
6234 request->fArg0, request->fArg1, request->fArg2);
6235
6236 if (request->isReplyType())
6237 gIOPMReplyQueue->queuePMRequest( request );
6238 else
6239 gIOPMRequestQueue->queuePMRequest( request );
6240 }
6241
6242 void IOService::submitPMRequest( IOPMRequest ** requests, IOItemCount count )
6243 {
6244 assert( requests );
6245 assert( count > 0 );
6246 assert( gIOPMRequestQueue );
6247
6248 for (IOItemCount i = 0; i < count; i++)
6249 {
6250 IOPMRequest * req = requests[i];
6251 PM_LOG1("[+ %02lx] %p [%p %s] %p %p %p\n",
6252 (long)req->getType(), req,
6253 req->getTarget(), req->getTarget()->getName(),
6254 req->fArg0, req->fArg1, req->fArg2);
6255 }
6256
6257 gIOPMRequestQueue->queuePMRequestChain( requests, count );
6258 }
6259
6260 //*********************************************************************************
6261 // [private] servicePMRequestQueue
6262 //
6263 // Called from IOPMRequestQueue::checkForWork().
6264 //*********************************************************************************
6265
6266 bool IOService::servicePMRequestQueue(
6267 IOPMRequest * request,
6268 IOPMRequestQueue * queue )
6269 {
6270 bool more;
6271
6272 if (initialized)
6273 {
6274 // Work queue will immediately execute the queue'd request if possible.
6275 // If execution blocks, the work queue will wait for a producer signal.
6276 // Only need to signal more when completing attached requests.
6277
6278 more = gIOPMWorkQueue->queuePMRequest(request, pwrMgt);
6279 return more;
6280 }
6281
6282 // Calling PM without PMinit() is not allowed, fail the request.
6283
6284 PM_LOG("%s: PM not initialized\n", getName());
6285 fAdjustPowerScheduled = false;
6286 more = gIOPMFreeQueue->queuePMRequest(request);
6287 if (more) gIOPMWorkQueue->incrementProducerCount();
6288 return more;
6289 }
6290
6291 //*********************************************************************************
6292 // [private] servicePMFreeQueue
6293 //
6294 // Called from IOPMCompletionQueue::checkForWork().
6295 //*********************************************************************************
6296
6297 bool IOService::servicePMFreeQueue(
6298 IOPMRequest * request,
6299 IOPMCompletionQueue * queue )
6300 {
6301 bool more = request->getNextRequest();
6302 IOPMRequest * root = request->getRootRequest();
6303
6304 if (root && (root != request))
6305 more = true;
6306 if (more)
6307 gIOPMWorkQueue->incrementProducerCount();
6308
6309 releasePMRequest( request );
6310 return more;
6311 }
6312
6313 //*********************************************************************************
6314 // [private] retirePMRequest
6315 //
6316 // Called by IOPMWorkQueue to retire a completed request.
6317 //*********************************************************************************
6318
6319 bool IOService::retirePMRequest( IOPMRequest * request, IOPMWorkQueue * queue )
6320 {
6321 assert(request && queue);
6322
6323 PM_LOG1("[- %02x] %p [%p %s] state %d, busy %d\n",
6324 request->getType(), request, this, getName(),
6325 fMachineState, gIOPMBusyCount);
6326
6327 // Catch requests created by idleTimerExpired().
6328
6329 if ((request->getType() == kIOPMRequestTypeActivityTickle) &&
6330 (request->fArg1 == (void *) (uintptr_t) false))
6331 {
6332 // Idle timer power drop request completed.
6333 // Restart the idle timer if deviceDesire can go lower, otherwise set
6334 // a flag so we know to restart idle timer when deviceDesire goes up.
6335
6336 if (fDeviceDesire > 0)
6337 {
6338 fActivityTickleCount = 0;
6339 clock_get_uptime(&fIdleTimerStartTime);
6340 start_PM_idle_timer();
6341 }
6342 else
6343 fIdleTimerStopped = true;
6344 }
6345
6346 // If the request is linked, then Work queue has already incremented its
6347 // producer count.
6348
6349 return (gIOPMFreeQueue->queuePMRequest( request ));
6350 }
6351
6352 //*********************************************************************************
6353 // [private] isPMBlocked
6354 //
6355 // Check if machine state transition is blocked.
6356 //*********************************************************************************
6357
6358 bool IOService::isPMBlocked ( IOPMRequest * request, int count )
6359 {
6360 int reason = 0;
6361
6362 do {
6363 if (kIOPM_Finished == fMachineState)
6364 break;
6365
6366 if (kIOPM_DriverThreadCallDone == fMachineState)
6367 {
6368 // 5 = kDriverCallInformPreChange
6369 // 6 = kDriverCallInformPostChange
6370 // 7 = kDriverCallSetPowerState
6371 if (fDriverCallBusy)
6372 reason = 5 + fDriverCallReason;
6373 break;
6374 }
6375
6376 // Waiting on driver's setPowerState() timeout.
6377 if (fDriverTimer)
6378 {
6379 reason = 1; break;
6380 }
6381
6382 // Child or interested driver acks pending.
6383 if (fHeadNotePendingAcks)
6384 {
6385 reason = 2; break;
6386 }
6387
6388 // Waiting on apps or priority power interest clients.
6389 if (fResponseArray)
6390 {
6391 reason = 3; break;
6392 }
6393
6394 // Waiting on settle timer expiration.
6395 if (fSettleTimeUS)
6396 {
6397 reason = 4; break;
6398 }
6399 } while (false);
6400
6401 fWaitReason = reason;
6402
6403 if (reason)
6404 {
6405 if (count)
6406 {
6407 PM_LOG1("[B %02x] %p [%p %s] state %d, reason %d\n",
6408 request->getType(), request, this, getName(),
6409 fMachineState, reason);
6410 }
6411
6412 return true;
6413 }
6414
6415 return false;
6416 }
6417
6418 //*********************************************************************************
6419 // [private] servicePMRequest
6420 //
6421 // Service a request from our work queue.
6422 //*********************************************************************************
6423
6424 bool IOService::servicePMRequest( IOPMRequest * request, IOPMWorkQueue * queue )
6425 {
6426 bool done = false;
6427 int loop = 0;
6428
6429 assert(request && queue);
6430
6431 while (isPMBlocked(request, loop++) == false)
6432 {
6433 PM_LOG1("[W %02x] %p [%p %s] state %d\n",
6434 request->getType(), request, this, getName(), fMachineState);
6435
6436 gIOPMRequest = request;
6437 gIOPMWorkCount++;
6438
6439 // Every PM machine states must be handled in one of the cases below.
6440
6441 switch ( fMachineState )
6442 {
6443 case kIOPM_Finished:
6444 executePMRequest( request );
6445 break;
6446
6447 case kIOPM_OurChangeTellClientsPowerDown:
6448 // Root domain might self cancel due to assertions.
6449 if (IS_ROOT_DOMAIN)
6450 {
6451 bool cancel = (bool) fDoNotPowerDown;
6452 getPMRootDomain()->askChangeDownDone(
6453 &fHeadNoteChangeFlags, &cancel);
6454 fDoNotPowerDown = cancel;
6455 }
6456
6457 // askChangeDown() done, was it vetoed?
6458 if (!fDoNotPowerDown)
6459 {
6460 if (IS_ROOT_DOMAIN) {
6461 PMEventDetails *details = PMEventDetails::eventDetails(
6462 kIOPMEventTypeAppNotificationsFinished,
6463 NULL,
6464 0,
6465 0);
6466
6467 getPMRootDomain()->recordAndReleasePMEventGated( details );
6468 }
6469
6470 // no, we can continue
6471 OurChangeTellClientsPowerDown();
6472 }
6473 else
6474 {
6475 if (IS_ROOT_DOMAIN) {
6476 PMEventDetails *details = PMEventDetails::eventDetails(
6477 kIOPMEventTypeSleepDone,
6478 NULL,
6479 1, /* reason: 1 == Ask clients succeeded */
6480 kIOReturnAborted); /* result */
6481
6482 getPMRootDomain()->recordAndReleasePMEventGated( details );
6483 }
6484
6485 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
6486 PM_ERROR("%s: idle cancel\n", fName);
6487 // yes, rescind the warning
6488 tellNoChangeDown(fHeadNotePowerState);
6489 // mark the change note un-actioned
6490 fHeadNoteChangeFlags |= kIOPMNotDone;
6491 // and we're done
6492 OurChangeFinish();
6493 }
6494 break;
6495
6496 case kIOPM_OurChangeTellPriorityClientsPowerDown:
6497 // tellChangeDown(kNotifyApps) done, was it cancelled?
6498 if (fDoNotPowerDown)
6499 {
6500 if (IS_ROOT_DOMAIN) {
6501 PMEventDetails *details = PMEventDetails::eventDetails(
6502 kIOPMEventTypeSleepDone,
6503 NULL,
6504 2, /* reason: 2 == Client cancelled wake */
6505 kIOReturnAborted); /* result */
6506
6507 getPMRootDomain()->recordAndReleasePMEventGated( details );
6508 }
6509 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
6510 PM_ERROR("%s: idle revert\n", fName);
6511 // no, tell clients we're back in the old state
6512 tellChangeUp(fCurrentPowerState);
6513 // mark the change note un-actioned
6514 fHeadNoteChangeFlags |= kIOPMNotDone;
6515 // and we're done
6516 OurChangeFinish();
6517 }
6518 else
6519 {
6520 if (IS_ROOT_DOMAIN) {
6521 PMEventDetails *details = PMEventDetails::eventDetails(
6522 kIOPMEventTypeAppNotificationsFinished,
6523 NULL,
6524 2, /* reason: 2 == TellPriorityClientsDone */
6525 kIOReturnSuccess); /* result */
6526
6527 getPMRootDomain()->recordAndReleasePMEventGated( details );
6528 }
6529 // yes, we can continue
6530 OurChangeTellPriorityClientsPowerDown();
6531 }
6532 break;
6533
6534 case kIOPM_OurChangeNotifyInterestedDriversWillChange:
6535 OurChangeNotifyInterestedDriversWillChange();
6536 break;
6537
6538 case kIOPM_OurChangeSetPowerState:
6539 OurChangeSetPowerState();
6540 break;
6541
6542 case kIOPM_OurChangeWaitForPowerSettle:
6543 OurChangeWaitForPowerSettle();
6544 break;
6545
6546 case kIOPM_OurChangeNotifyInterestedDriversDidChange:
6547 OurChangeNotifyInterestedDriversDidChange();
6548 break;
6549
6550 case kIOPM_OurChangeTellCapabilityDidChange:
6551 OurChangeTellCapabilityDidChange();
6552 break;
6553
6554 case kIOPM_OurChangeFinish:
6555 OurChangeFinish();
6556 break;
6557
6558 case kIOPM_ParentChangeTellPriorityClientsPowerDown:
6559 ParentChangeTellPriorityClientsPowerDown();
6560 break;
6561
6562 case kIOPM_ParentChangeNotifyInterestedDriversWillChange:
6563 ParentChangeNotifyInterestedDriversWillChange();
6564 break;
6565
6566 case kIOPM_ParentChangeSetPowerState:
6567 ParentChangeSetPowerState();
6568 break;
6569
6570 case kIOPM_ParentChangeWaitForPowerSettle:
6571 ParentChangeWaitForPowerSettle();
6572 break;
6573
6574 case kIOPM_ParentChangeNotifyInterestedDriversDidChange:
6575 ParentChangeNotifyInterestedDriversDidChange();
6576 break;
6577
6578 case kIOPM_ParentChangeTellCapabilityDidChange:
6579 ParentChangeTellCapabilityDidChange();
6580 break;
6581
6582 case kIOPM_ParentChangeAcknowledgePowerChange:
6583 ParentChangeAcknowledgePowerChange();
6584 break;
6585
6586 case kIOPM_DriverThreadCallDone:
6587 if (fDriverCallReason == kDriverCallSetPowerState)
6588 notifyControllingDriverDone();
6589 else
6590 notifyInterestedDriversDone();
6591 break;
6592
6593 case kIOPM_NotifyChildrenOrdered:
6594 notifyChildrenOrdered();
6595 break;
6596
6597 case kIOPM_NotifyChildrenDelayed:
6598 notifyChildrenDelayed();
6599 break;
6600
6601 case kIOPM_NotifyChildrenStart:
6602 PM_LOG2("%s: kIOPM_NotifyChildrenStart done\n", getName());
6603 MS_POP(); // from notifyInterestedDriversDone()
6604 notifyChildren();
6605 break;
6606
6607 case kIOPM_SyncTellClientsPowerDown:
6608 // Root domain might self cancel due to assertions.
6609 if (IS_ROOT_DOMAIN)
6610 {
6611 bool cancel = (bool) fDoNotPowerDown;
6612 getPMRootDomain()->askChangeDownDone(
6613 &fHeadNoteChangeFlags, &cancel);
6614 fDoNotPowerDown = cancel;
6615 }
6616 if (!fDoNotPowerDown)
6617 {
6618 fMachineState = kIOPM_SyncTellPriorityClientsPowerDown;
6619 fOutOfBandParameter = kNotifyApps;
6620 tellChangeDown(fHeadNotePowerState);
6621 }
6622 else
6623 {
6624 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
6625 PM_ERROR("%s: idle cancel\n", fName);
6626 tellNoChangeDown(fHeadNotePowerState);
6627 fHeadNoteChangeFlags |= kIOPMNotDone;
6628 OurChangeFinish();
6629 }
6630 break;
6631
6632 case kIOPM_SyncTellPriorityClientsPowerDown:
6633 if (!fDoNotPowerDown)
6634 {
6635 fMachineState = kIOPM_SyncNotifyWillChange;
6636 fOutOfBandParameter = kNotifyPriority;
6637 tellChangeDown(fHeadNotePowerState);
6638 }
6639 else
6640 {
6641 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
6642 PM_ERROR("%s: idle revert\n", fName);
6643 tellChangeUp(fCurrentPowerState);
6644 fHeadNoteChangeFlags |= kIOPMNotDone;
6645 OurChangeFinish();
6646 }
6647 break;
6648
6649 case kIOPM_SyncNotifyWillChange:
6650 if (kIOPMSyncNoChildNotify & fHeadNoteChangeFlags)
6651 {
6652 fMachineState = kIOPM_SyncFinish;
6653 continue;
6654 }
6655 fMachineState = kIOPM_SyncNotifyDidChange;
6656 fDriverCallReason = kDriverCallInformPreChange;
6657 notifyChildren();
6658 break;
6659
6660 case kIOPM_SyncNotifyDidChange:
6661 fIsPreChange = false;
6662
6663 if (fHeadNoteChangeFlags & kIOPMParentInitiated)
6664 fMachineState = kIOPM_SyncFinish;
6665 else
6666 fMachineState = kIOPM_SyncTellCapabilityDidChange;
6667
6668 fDriverCallReason = kDriverCallInformPostChange;
6669 notifyChildren();
6670 break;
6671
6672 case kIOPM_SyncTellCapabilityDidChange:
6673 tellSystemCapabilityChange( kIOPM_SyncFinish );
6674 break;
6675
6676 case kIOPM_SyncFinish:
6677 if (fHeadNoteChangeFlags & kIOPMParentInitiated)
6678 ParentChangeAcknowledgePowerChange();
6679 else
6680 OurChangeFinish();
6681 break;
6682
6683 case kIOPM_TellCapabilityChangeDone:
6684 if (fIsPreChange)
6685 {
6686 if (fOutOfBandParameter == kNotifyCapabilityChangePriority)
6687 {
6688 MS_POP(); // tellSystemCapabilityChange()
6689 continue;
6690 }
6691 fOutOfBandParameter = kNotifyCapabilityChangePriority;
6692 }
6693 else
6694 {
6695 if (fOutOfBandParameter == kNotifyCapabilityChangeApps)
6696 {
6697 MS_POP(); // tellSystemCapabilityChange()
6698 continue;
6699 }
6700 fOutOfBandParameter = kNotifyCapabilityChangeApps;
6701 }
6702 tellClientsWithResponse( fOutOfBandMessage );
6703 break;
6704
6705 default:
6706 panic("servicePMWorkQueue: unknown machine state %x",
6707 fMachineState);
6708 }
6709
6710 gIOPMRequest = 0;
6711
6712 if (fMachineState == kIOPM_Finished)
6713 {
6714 done = true;
6715 break;
6716 }
6717 }
6718
6719 return done;
6720 }
6721
6722 //*********************************************************************************
6723 // [private] executePMRequest
6724 //*********************************************************************************
6725
6726 void IOService::executePMRequest( IOPMRequest * request )
6727 {
6728 assert( kIOPM_Finished == fMachineState );
6729
6730 switch (request->getType())
6731 {
6732 case kIOPMRequestTypePMStop:
6733 handlePMstop( request );
6734 break;
6735
6736 case kIOPMRequestTypeAddPowerChild1:
6737 addPowerChild1( request );
6738 break;
6739
6740 case kIOPMRequestTypeAddPowerChild2:
6741 addPowerChild2( request );
6742 break;
6743
6744 case kIOPMRequestTypeAddPowerChild3:
6745 addPowerChild3( request );
6746 break;
6747
6748 case kIOPMRequestTypeRegisterPowerDriver:
6749 handleRegisterPowerDriver( request );
6750 break;
6751
6752 case kIOPMRequestTypeAdjustPowerState:
6753 fAdjustPowerScheduled = false;
6754 rebuildChildClampBits();
6755 adjustPowerState();
6756 break;
6757
6758 case kIOPMRequestTypePowerDomainWillChange:
6759 handlePowerDomainWillChangeTo( request );
6760 break;
6761
6762 case kIOPMRequestTypePowerDomainDidChange:
6763
6764 handlePowerDomainDidChangeTo( request );
6765 break;
6766
6767 case kIOPMRequestTypeRequestPowerState:
6768 case kIOPMRequestTypeRequestPowerStateOverride:
6769 handleRequestPowerState( request );
6770 break;
6771
6772 case kIOPMRequestTypePowerOverrideOnPriv:
6773 case kIOPMRequestTypePowerOverrideOffPriv:
6774 handlePowerOverrideChanged( request );
6775 break;
6776
6777 case kIOPMRequestTypeActivityTickle:
6778 handleActivityTickle( request );
6779 break;
6780
6781 case kIOPMRequestTypeSynchronizePowerTree:
6782 handleSynchronizePowerTree( request );
6783 break;
6784
6785 case kIOPMRequestTypeSetIdleTimerPeriod:
6786 {
6787 fIdleTimerPeriod = (uintptr_t) request->fArg0;
6788
6789 if ((false == fLockedFlags.PMStop) && (fIdleTimerPeriod > 0))
6790 {
6791 fActivityTickleCount = 0;
6792 clock_get_uptime(&fIdleTimerStartTime);
6793 start_PM_idle_timer();
6794 }
6795 }
6796 break;
6797
6798 default:
6799 panic("executePMRequest: unknown request type %x", request->getType());
6800 }
6801 }
6802
6803 //*********************************************************************************
6804 // [private] servicePMReplyQueue
6805 //*********************************************************************************
6806
6807 bool IOService::servicePMReplyQueue( IOPMRequest * request, IOPMRequestQueue * queue )
6808 {
6809 bool more = false;
6810
6811 assert( request && queue );
6812 assert( request->isReplyType() );
6813
6814 PM_LOG1("[A %02x] %p [%p %s] state %d\n",
6815 request->getType(), request, this, getName(), fMachineState);
6816
6817 switch ( request->getType() )
6818 {
6819 case kIOPMRequestTypeAllowPowerChange:
6820 case kIOPMRequestTypeCancelPowerChange:
6821 // Check if we are expecting this response.
6822 if (responseValid((uint32_t)(uintptr_t) request->fArg0,
6823 (int)(uintptr_t) request->fArg1))
6824 {
6825 if (kIOPMRequestTypeCancelPowerChange == request->getType())
6826 {
6827 // Clients are not allowed to cancel when kIOPMSkipAskPowerDown
6828 // flag is set. Only root domain will set this flag.
6829
6830 if ((fHeadNoteChangeFlags & kIOPMSkipAskPowerDown) == 0)
6831 {
6832 fDoNotPowerDown = true;
6833
6834 OSString * name = (OSString *) request->fArg2;
6835 getPMRootDomain()->pmStatsRecordApplicationResponse(
6836 gIOPMStatsApplicationResponseCancel,
6837 name ? name->getCStringNoCopy() : "", 0,
6838 0, (int)(uintptr_t) request->fArg1);
6839 }
6840 }
6841
6842 if (checkForDone())
6843 {
6844 stop_ack_timer();
6845 cleanClientResponses(false);
6846 more = true;
6847 }
6848 }
6849 // OSString containing app name in Arg2 must be released.
6850 if (request->getType() == kIOPMRequestTypeCancelPowerChange)
6851 {
6852 OSObject * obj = (OSObject *) request->fArg2;
6853 if (obj) obj->release();
6854 }
6855 break;
6856
6857 case kIOPMRequestTypeAckPowerChange:
6858 more = handleAcknowledgePowerChange( request );
6859 break;
6860
6861 case kIOPMRequestTypeAckSetPowerState:
6862 if (fDriverTimer == -1)
6863 {
6864 // driver acked while setPowerState() call is in-flight.
6865 // take this ack, return value from setPowerState() is irrelevant.
6866 OUR_PMLog(kPMLogDriverAcknowledgeSet,
6867 (uintptr_t) this, fDriverTimer);
6868 fDriverTimer = 0;
6869 }
6870 else if (fDriverTimer > 0)
6871 {
6872 // expected ack, stop the timer
6873 stop_ack_timer();
6874
6875 #if LOG_SETPOWER_TIMES
6876 uint64_t nsec = computeTimeDeltaNS(&fDriverCallStartTime);
6877 if (nsec > LOG_SETPOWER_TIMES)
6878 PM_LOG("%s::setPowerState(%p, %lu -> %lu) async took %d ms\n",
6879 fName, this, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
6880
6881 PMEventDetails *details = PMEventDetails::eventDetails(
6882 kIOPMEventTypeSetPowerStateDelayed, // type
6883 fName, // who
6884 (uintptr_t)this, // owner unique
6885 NULL, // interest name
6886 (uint8_t)getPowerState(), // old
6887 (uint8_t)fHeadNotePowerState, // new
6888 0, // result
6889 NS_TO_US(nsec)); // usec completion time
6890
6891 getPMRootDomain()->recordAndReleasePMEventGated( details );
6892 #endif
6893 OUR_PMLog(kPMLogDriverAcknowledgeSet, (uintptr_t) this, fDriverTimer);
6894 fDriverTimer = 0;
6895 more = true;
6896 }
6897 else
6898 {
6899 // unexpected ack
6900 OUR_PMLog(kPMLogAcknowledgeErr4, (uintptr_t) this, 0);
6901 }
6902 break;
6903
6904 case kIOPMRequestTypeInterestChanged:
6905 handleInterestChanged( request );
6906 more = true;
6907 break;
6908
6909 case kIOPMRequestTypeIdleCancel:
6910 if ((fMachineState == kIOPM_OurChangeTellClientsPowerDown)
6911 || (fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown)
6912 || (fMachineState == kIOPM_SyncTellClientsPowerDown)
6913 || (fMachineState == kIOPM_SyncTellPriorityClientsPowerDown))
6914 {
6915 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
6916 PM_LOG2("%s: cancel from machine state %d\n",
6917 getName(), fMachineState);
6918 fDoNotPowerDown = true;
6919 // Stop waiting for app replys.
6920 if ((fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown) ||
6921 (fMachineState == kIOPM_SyncTellPriorityClientsPowerDown))
6922 cleanClientResponses(false);
6923 more = true;
6924 }
6925 break;
6926
6927 case kIOPMRequestTypeChildNotifyDelayCancel:
6928 if (fMachineState == kIOPM_NotifyChildrenDelayed)
6929 {
6930 PM_LOG2("%s: delay notify cancelled\n", getName());
6931 notifyChildrenDelayed();
6932 }
6933 break;
6934
6935 default:
6936 panic("servicePMReplyQueue: unknown reply type %x",
6937 request->getType());
6938 }
6939
6940 more |= gIOPMFreeQueue->queuePMRequest(request);
6941 if (more)
6942 gIOPMWorkQueue->incrementProducerCount();
6943
6944 return more;
6945 }
6946
6947 //*********************************************************************************
6948 // [private] assertPMDriverCall / deassertPMDriverCall
6949 //*********************************************************************************
6950
6951 bool IOService::assertPMDriverCall(
6952 IOPMDriverCallEntry * entry,
6953 IOOptionBits options,
6954 IOPMinformee * inform )
6955 {
6956 IOService * target = 0;
6957 bool ok = false;
6958
6959 if (!initialized)
6960 return false;
6961
6962 PM_LOCK();
6963
6964 if (fLockedFlags.PMStop)
6965 {
6966 goto fail;
6967 }
6968
6969 if (((options & kIOPMADC_NoInactiveCheck) == 0) && isInactive())
6970 {
6971 goto fail;
6972 }
6973
6974 if (inform)
6975 {
6976 if (!inform->active)
6977 {
6978 goto fail;
6979 }
6980 target = inform->whatObject;
6981 if (target->isInactive())
6982 {
6983 goto fail;
6984 }
6985 }
6986
6987 entry->thread = current_thread();
6988 entry->target = target;
6989 queue_enter(&fPMDriverCallQueue, entry, IOPMDriverCallEntry *, link);
6990 ok = true;
6991
6992 fail:
6993 PM_UNLOCK();
6994
6995 return ok;
6996 }
6997
6998 void IOService::deassertPMDriverCall( IOPMDriverCallEntry * entry )
6999 {
7000 bool wakeup = false;
7001
7002 PM_LOCK();
7003
7004 assert( !queue_empty(&fPMDriverCallQueue) );
7005 queue_remove(&fPMDriverCallQueue, entry, IOPMDriverCallEntry *, link);
7006 if (fLockedFlags.PMDriverCallWait)
7007 {
7008 wakeup = true;
7009 }
7010
7011 PM_UNLOCK();
7012
7013 if (wakeup)
7014 PM_LOCK_WAKEUP(&fPMDriverCallQueue);
7015 }
7016
7017 void IOService::waitForPMDriverCall( IOService * target )
7018 {
7019 const IOPMDriverCallEntry * entry;
7020 thread_t thread = current_thread();
7021 AbsoluteTime deadline;
7022 int waitResult;
7023 bool log = true;
7024 bool wait;
7025
7026 do {
7027 wait = false;
7028 queue_iterate(&fPMDriverCallQueue, entry, const IOPMDriverCallEntry *, link)
7029 {
7030 // Target of interested driver call
7031 if (target && (target != entry->target))
7032 continue;
7033
7034 if (entry->thread == thread)
7035 {
7036 if (log)
7037 {
7038 PM_LOG("%s: %s(%s) on PM thread\n",
7039 fName, __FUNCTION__, target ? target->getName() : "");
7040 OSReportWithBacktrace("%s: %s(%s) on PM thread\n",
7041 fName, __FUNCTION__, target ? target->getName() : "");
7042 log = false;
7043 }
7044 continue;
7045 }
7046
7047 wait = true;
7048 break;
7049 }
7050
7051 if (wait)
7052 {
7053 fLockedFlags.PMDriverCallWait = true;
7054 clock_interval_to_deadline(15, kSecondScale, &deadline);
7055 waitResult = PM_LOCK_SLEEP(&fPMDriverCallQueue, deadline);
7056 fLockedFlags.PMDriverCallWait = false;
7057 if (THREAD_TIMED_OUT == waitResult)
7058 {
7059 PM_ERROR("%s: waitForPMDriverCall timeout\n", fName);
7060 wait = false;
7061 }
7062 }
7063 } while (wait);
7064 }
7065
7066 //*********************************************************************************
7067 // [private] Debug helpers
7068 //*********************************************************************************
7069
7070 const char * IOService::getIOMessageString( uint32_t msg )
7071 {
7072 #define MSG_ENTRY(x) {x, #x}
7073
7074 static const IONamedValue msgNames[] = {
7075 MSG_ENTRY( kIOMessageCanDevicePowerOff ),
7076 MSG_ENTRY( kIOMessageDeviceWillPowerOff ),
7077 MSG_ENTRY( kIOMessageDeviceWillNotPowerOff ),
7078 MSG_ENTRY( kIOMessageDeviceHasPoweredOn ),
7079 MSG_ENTRY( kIOMessageCanSystemPowerOff ),
7080 MSG_ENTRY( kIOMessageSystemWillPowerOff ),
7081 MSG_ENTRY( kIOMessageSystemWillNotPowerOff ),
7082 MSG_ENTRY( kIOMessageCanSystemSleep ),
7083 MSG_ENTRY( kIOMessageSystemWillSleep ),
7084 MSG_ENTRY( kIOMessageSystemWillNotSleep ),
7085 MSG_ENTRY( kIOMessageSystemHasPoweredOn ),
7086 MSG_ENTRY( kIOMessageSystemWillRestart ),
7087 MSG_ENTRY( kIOMessageSystemWillPowerOn ),
7088 MSG_ENTRY( kIOMessageSystemCapabilityChange )
7089 };
7090
7091 return IOFindNameForValue(msg, msgNames);
7092 }
7093
7094 // MARK: -
7095 // MARK: IOPMRequest
7096
7097 //*********************************************************************************
7098 // IOPMRequest Class
7099 //
7100 // Requests from PM clients, and also used for inter-object messaging within PM.
7101 //*********************************************************************************
7102
7103 OSDefineMetaClassAndStructors( IOPMRequest, IOCommand );
7104
7105 IOPMRequest * IOPMRequest::create( void )
7106 {
7107 IOPMRequest * me = OSTypeAlloc(IOPMRequest);
7108 if (me && !me->init(0, kIOPMRequestTypeInvalid))
7109 {
7110 me->release();
7111 me = 0;
7112 }
7113 return me;
7114 }
7115
7116 bool IOPMRequest::init( IOService * target, IOOptionBits type )
7117 {
7118 if (!IOCommand::init())
7119 return false;
7120
7121 fType = type;
7122 fTarget = target;
7123 fCompletionStatus = kIOReturnSuccess;
7124
7125 if (fTarget)
7126 fTarget->retain();
7127
7128 return true;
7129 }
7130
7131 void IOPMRequest::reset( void )
7132 {
7133 assert( fWorkWaitCount == 0 );
7134 assert( fFreeWaitCount == 0 );
7135
7136 detachNextRequest();
7137 detachRootRequest();
7138
7139 fType = kIOPMRequestTypeInvalid;
7140
7141 if (fCompletionAction)
7142 {
7143 fCompletionAction(fCompletionTarget, fCompletionParam, fCompletionStatus);
7144 }
7145
7146 if (fTarget)
7147 {
7148 fTarget->release();
7149 fTarget = 0;
7150 }
7151 }
7152
7153 bool IOPMRequest::attachNextRequest( IOPMRequest * next )
7154 {
7155 bool ok = false;
7156
7157 if (!fRequestNext)
7158 {
7159 // Postpone the execution of the next request after
7160 // this request.
7161 fRequestNext = next;
7162 fRequestNext->fWorkWaitCount++;
7163 #if LOG_REQUEST_ATTACH
7164 kprintf("Attached next: %p [0x%x] -> %p [0x%x, %u] %s\n",
7165 this, (uint32_t) fType, fRequestNext,
7166 (uint32_t) fRequestNext->fType,
7167 (uint32_t) fRequestNext->fWorkWaitCount,
7168 fTarget->getName());
7169 #endif
7170 ok = true;
7171 }
7172 return ok;
7173 }
7174
7175 bool IOPMRequest::detachNextRequest( void )
7176 {
7177 bool ok = false;
7178
7179 if (fRequestNext)
7180 {
7181 assert(fRequestNext->fWorkWaitCount);
7182 if (fRequestNext->fWorkWaitCount)
7183 fRequestNext->fWorkWaitCount--;
7184 #if LOG_REQUEST_ATTACH
7185 kprintf("Detached next: %p [0x%x] -> %p [0x%x, %u] %s\n",
7186 this, (uint32_t) fType, fRequestNext,
7187 (uint32_t) fRequestNext->fType,
7188 (uint32_t) fRequestNext->fWorkWaitCount,
7189 fTarget->getName());
7190 #endif
7191 fRequestNext = 0;
7192 ok = true;
7193 }
7194 return ok;
7195 }
7196
7197 bool IOPMRequest::attachRootRequest( IOPMRequest * root )
7198 {
7199 bool ok = false;
7200
7201 if (!fRequestRoot)
7202 {
7203 // Delay the completion of the root request after
7204 // this request.
7205 fRequestRoot = root;
7206 fRequestRoot->fFreeWaitCount++;
7207 #if LOG_REQUEST_ATTACH
7208 kprintf("Attached root: %p [0x%x] -> %p [0x%x, %u] %s\n",
7209 this, (uint32_t) fType, fRequestRoot,
7210 (uint32_t) fRequestRoot->fType,
7211 (uint32_t) fRequestRoot->fFreeWaitCount,
7212 fTarget->getName());
7213 #endif
7214 ok = true;
7215 }
7216 return ok;
7217 }
7218
7219 bool IOPMRequest::detachRootRequest( void )
7220 {
7221 bool ok = false;
7222
7223 if (fRequestRoot)
7224 {
7225 assert(fRequestRoot->fFreeWaitCount);
7226 if (fRequestRoot->fFreeWaitCount)
7227 fRequestRoot->fFreeWaitCount--;
7228 #if LOG_REQUEST_ATTACH
7229 kprintf("Detached root: %p [0x%x] -> %p [0x%x, %u] %s\n",
7230 this, (uint32_t) fType, fRequestRoot,
7231 (uint32_t) fRequestRoot->fType,
7232 (uint32_t) fRequestRoot->fFreeWaitCount,
7233 fTarget->getName());
7234 #endif
7235 fRequestRoot = 0;
7236 ok = true;
7237 }
7238 return ok;
7239 }
7240
7241 // MARK: -
7242 // MARK: IOPMRequestQueue
7243
7244 //*********************************************************************************
7245 // IOPMRequestQueue Class
7246 //
7247 // Global queues. Queues are created once and never released.
7248 //*********************************************************************************
7249
7250 OSDefineMetaClassAndStructors( IOPMRequestQueue, IOEventSource );
7251
7252 IOPMRequestQueue * IOPMRequestQueue::create( IOService * inOwner, Action inAction )
7253 {
7254 IOPMRequestQueue * me = OSTypeAlloc(IOPMRequestQueue);
7255 if (me && !me->init(inOwner, inAction))
7256 {
7257 me->release();
7258 me = 0;
7259 }
7260 return me;
7261 }
7262
7263 bool IOPMRequestQueue::init( IOService * inOwner, Action inAction )
7264 {
7265 if (!inAction || !IOEventSource::init(inOwner, (IOEventSourceAction)inAction))
7266 return false;
7267
7268 queue_init(&fQueue);
7269 fLock = IOLockAlloc();
7270 return (fLock != 0);
7271 }
7272
7273 void IOPMRequestQueue::free( void )
7274 {
7275 if (fLock)
7276 {
7277 IOLockFree(fLock);
7278 fLock = 0;
7279 }
7280 return IOEventSource::free();
7281 }
7282
7283 void IOPMRequestQueue::queuePMRequest( IOPMRequest * request )
7284 {
7285 assert(request);
7286 IOLockLock(fLock);
7287 queue_enter(&fQueue, request, IOPMRequest *, fCommandChain);
7288 IOLockUnlock(fLock);
7289 if (workLoop) signalWorkAvailable();
7290 }
7291
7292 void
7293 IOPMRequestQueue::queuePMRequestChain( IOPMRequest ** requests, IOItemCount count )
7294 {
7295 IOPMRequest * next;
7296
7297 assert(requests && count);
7298 IOLockLock(fLock);
7299 while (count--)
7300 {
7301 next = *requests;
7302 requests++;
7303 queue_enter(&fQueue, next, IOPMRequest *, fCommandChain);
7304 }
7305 IOLockUnlock(fLock);
7306 if (workLoop) signalWorkAvailable();
7307 }
7308
7309 bool IOPMRequestQueue::checkForWork( void )
7310 {
7311 Action dqAction = (Action) action;
7312 IOPMRequest * request;
7313 IOService * target;
7314 bool more = false;
7315
7316 IOLockLock( fLock );
7317
7318 while (!queue_empty(&fQueue))
7319 {
7320 queue_remove_first( &fQueue, request, IOPMRequest *, fCommandChain );
7321 IOLockUnlock( fLock );
7322 target = request->getTarget();
7323 assert(target);
7324 more |= (*dqAction)( target, request, this );
7325 IOLockLock( fLock );
7326 }
7327
7328 IOLockUnlock( fLock );
7329 return more;
7330 }
7331
7332 // MARK: -
7333 // MARK: IOPMWorkQueue
7334
7335 //*********************************************************************************
7336 // IOPMWorkQueue Class
7337 //
7338 // Queue of IOServicePM objects with busy IOPMRequest(s).
7339 //*********************************************************************************
7340
7341 OSDefineMetaClassAndStructors( IOPMWorkQueue, IOEventSource );
7342
7343 IOPMWorkQueue *
7344 IOPMWorkQueue::create( IOService * inOwner, Action work, Action retire )
7345 {
7346 IOPMWorkQueue * me = OSTypeAlloc(IOPMWorkQueue);
7347 if (me && !me->init(inOwner, work, retire))
7348 {
7349 me->release();
7350 me = 0;
7351 }
7352 return me;
7353 }
7354
7355 bool IOPMWorkQueue::init( IOService * inOwner, Action work, Action retire )
7356 {
7357 if (!work || !retire ||
7358 !IOEventSource::init(inOwner, (IOEventSourceAction)0))
7359 return false;
7360
7361 queue_init(&fWorkQueue);
7362
7363 fWorkAction = work;
7364 fRetireAction = retire;
7365 fConsumerCount = fProducerCount = 0;
7366
7367 return true;
7368 }
7369
7370 bool IOPMWorkQueue::queuePMRequest( IOPMRequest * request, IOServicePM * pwrMgt )
7371 {
7372 bool more = false;
7373 bool empty;
7374
7375 assert( request );
7376 assert( pwrMgt );
7377 assert( onThread() );
7378 assert( queue_next(&request->fCommandChain) ==
7379 queue_prev(&request->fCommandChain) );
7380
7381 gIOPMBusyCount++;
7382
7383 // Add new request to the tail of the per-service request queue.
7384 // Then immediately check the request queue to minimize latency
7385 // if the queue was empty.
7386
7387 empty = queue_empty(&pwrMgt->RequestHead);
7388 queue_enter(&pwrMgt->RequestHead, request, IOPMRequest *, fCommandChain);
7389 if (empty)
7390 {
7391 more = checkRequestQueue(&pwrMgt->RequestHead, &empty);
7392 if (!empty)
7393 {
7394 // New Request is blocked, add IOServicePM to work queue.
7395 assert( queue_next(&pwrMgt->WorkChain) ==
7396 queue_prev(&pwrMgt->WorkChain) );
7397
7398 queue_enter(&fWorkQueue, pwrMgt, IOServicePM *, WorkChain);
7399 fQueueLength++;
7400 PM_LOG3("IOPMWorkQueue: [%u] added %s@%p to queue\n",
7401 fQueueLength, pwrMgt->Name, pwrMgt);
7402 }
7403 }
7404
7405 return more;
7406 }
7407
7408 bool IOPMWorkQueue::checkRequestQueue( queue_head_t * queue, bool * empty )
7409 {
7410 IOPMRequest * request;
7411 IOService * target;
7412 bool more = false;
7413 bool done = false;
7414
7415 assert(!queue_empty(queue));
7416 do {
7417 request = (IOPMRequest *) queue_first(queue);
7418 if (request->isWorkBlocked())
7419 break; // cannot start, blocked on attached request
7420
7421 target = request->getTarget();
7422 done = (*fWorkAction)( target, request, this );
7423 if (!done)
7424 break; // work started, blocked on PM state machine
7425
7426 assert(gIOPMBusyCount > 0);
7427 if (gIOPMBusyCount)
7428 gIOPMBusyCount--;
7429
7430 queue_remove_first(queue, request, IOPMRequest *, fCommandChain);
7431 more |= (*fRetireAction)( target, request, this );
7432 done = queue_empty(queue);
7433 } while (!done);
7434
7435 *empty = done;
7436
7437 if (more)
7438 {
7439 // Retired request blocks another request, since the
7440 // blocked request may reside in the work queue, we
7441 // must bump the producer count to avoid work stall.
7442 fProducerCount++;
7443 }
7444
7445 return more;
7446 }
7447
7448 bool IOPMWorkQueue::checkForWork( void )
7449 {
7450 IOServicePM * entry;
7451 IOServicePM * next;
7452 bool more = false;
7453 bool empty;
7454
7455 #if WORK_QUEUE_STATS
7456 fStatCheckForWork++;
7457 #endif
7458
7459 // Each producer signal triggers a full iteration over
7460 // all IOServicePM entries in the work queue.
7461
7462 while (fConsumerCount != fProducerCount)
7463 {
7464 PM_LOG3("IOPMWorkQueue: checkForWork %u %u\n",
7465 fProducerCount, fConsumerCount);
7466
7467 fConsumerCount = fProducerCount;
7468
7469 #if WORK_QUEUE_STATS
7470 if (queue_empty(&fWorkQueue))
7471 {
7472 fStatQueueEmpty++;
7473 break;
7474 }
7475 fStatScanEntries++;
7476 uint32_t cachedWorkCount = gIOPMWorkCount;
7477 #endif
7478
7479 entry = (IOServicePM *) queue_first(&fWorkQueue);
7480 while (!queue_end(&fWorkQueue, (queue_entry_t) entry))
7481 {
7482 more |= checkRequestQueue(&entry->RequestHead, &empty);
7483
7484 // Get next entry, points to head if current entry is last.
7485 next = (IOServicePM *) queue_next(&entry->WorkChain);
7486
7487 // if request queue is empty, remove IOServicePM from queue.
7488 if (empty)
7489 {
7490 assert(fQueueLength);
7491 if (fQueueLength) fQueueLength--;
7492 PM_LOG3("IOPMWorkQueue: [%u] removed %s@%p from queue\n",
7493 fQueueLength, entry->Name, entry);
7494 queue_remove(&fWorkQueue, entry, IOServicePM *, WorkChain);
7495 }
7496 entry = next;
7497 }
7498
7499 #if WORK_QUEUE_STATS
7500 if (cachedWorkCount == gIOPMWorkCount)
7501 fStatNoWorkDone++;
7502 #endif
7503 }
7504
7505 return more;
7506 }
7507
7508 void IOPMWorkQueue::signalWorkAvailable( void )
7509 {
7510 fProducerCount++;
7511 IOEventSource::signalWorkAvailable();
7512 }
7513
7514 void IOPMWorkQueue::incrementProducerCount( void )
7515 {
7516 fProducerCount++;
7517 }
7518
7519 // MARK: -
7520 // MARK: IOPMCompletionQueue
7521
7522 //*********************************************************************************
7523 // IOPMCompletionQueue Class
7524 //*********************************************************************************
7525
7526 OSDefineMetaClassAndStructors( IOPMCompletionQueue, IOEventSource );
7527
7528 IOPMCompletionQueue *
7529 IOPMCompletionQueue::create( IOService * inOwner, Action inAction )
7530 {
7531 IOPMCompletionQueue * me = OSTypeAlloc(IOPMCompletionQueue);
7532 if (me && !me->init(inOwner, inAction))
7533 {
7534 me->release();
7535 me = 0;
7536 }
7537 return me;
7538 }
7539
7540 bool IOPMCompletionQueue::init( IOService * inOwner, Action inAction )
7541 {
7542 if (!inAction || !IOEventSource::init(inOwner, (IOEventSourceAction)inAction))
7543 return false;
7544
7545 queue_init(&fQueue);
7546 return true;
7547 }
7548
7549 bool IOPMCompletionQueue::queuePMRequest( IOPMRequest * request )
7550 {
7551 bool more;
7552
7553 assert(request);
7554 // unblock dependent request
7555 more = request->detachNextRequest();
7556 queue_enter(&fQueue, request, IOPMRequest *, fCommandChain);
7557 return more;
7558 }
7559
7560 bool IOPMCompletionQueue::checkForWork( void )
7561 {
7562 Action dqAction = (Action) action;
7563 IOPMRequest * request;
7564 IOPMRequest * next;
7565 IOService * target;
7566 bool more = false;
7567
7568 request = (IOPMRequest *) queue_first(&fQueue);
7569 while (!queue_end(&fQueue, (queue_entry_t) request))
7570 {
7571 next = (IOPMRequest *) queue_next(&request->fCommandChain);
7572 if (!request->isFreeBlocked())
7573 {
7574 queue_remove(&fQueue, request, IOPMRequest *, fCommandChain);
7575 target = request->getTarget();
7576 assert(target);
7577 more |= (*dqAction)( target, request, this );
7578 }
7579 request = next;
7580 }
7581
7582 return more;
7583 }
7584
7585 // MARK: -
7586 // MARK: IOServicePM
7587
7588 OSDefineMetaClassAndStructors(IOServicePM, OSObject)
7589
7590 //*********************************************************************************
7591 // serialize
7592 //
7593 // Serialize IOServicePM for debugging.
7594 //*********************************************************************************
7595
7596 static void
7597 setPMProperty( OSDictionary * dict, const char * key, uint64_t value )
7598 {
7599 OSNumber * num = OSNumber::withNumber(value, sizeof(value) * 8);
7600 if (num)
7601 {
7602 dict->setObject(key, num);
7603 num->release();
7604 }
7605 }
7606
7607 IOReturn IOServicePM::gatedSerialize( OSSerialize * s )
7608 {
7609 OSDictionary * dict;
7610 bool ok = false;
7611 int dictSize = 5;
7612
7613 if (IdleTimerPeriod)
7614 dictSize += 4;
7615
7616 #if WORK_QUEUE_STATS
7617 if (gIOPMRootNode == ControllingDriver)
7618 dictSize += 4;
7619 #endif
7620
7621 if (PowerClients)
7622 dict = OSDictionary::withDictionary(
7623 PowerClients, PowerClients->getCount() + dictSize);
7624 else
7625 dict = OSDictionary::withCapacity(dictSize);
7626
7627 if (dict)
7628 {
7629 setPMProperty(dict, "CurrentPowerState", CurrentPowerState);
7630 if (NumberOfPowerStates)
7631 setPMProperty(dict, "MaxPowerState", NumberOfPowerStates-1);
7632 if (DesiredPowerState != CurrentPowerState)
7633 setPMProperty(dict, "DesiredPowerState", DesiredPowerState);
7634 if (kIOPM_Finished != MachineState)
7635 setPMProperty(dict, "MachineState", MachineState);
7636 if (DeviceOverrideEnabled)
7637 dict->setObject("PowerOverrideOn", kOSBooleanTrue);
7638
7639 if (IdleTimerPeriod)
7640 {
7641 AbsoluteTime now;
7642 AbsoluteTime delta;
7643 uint64_t nsecs;
7644
7645 clock_get_uptime(&now);
7646
7647 // The idle timer period in milliseconds.
7648 setPMProperty(dict, "IdleTimerPeriod", IdleTimerPeriod * 1000ULL);
7649
7650 // The number of activity tickles recorded since device idle
7651 setPMProperty(dict, "ActivityTickles", ActivityTickleCount);
7652
7653 if (AbsoluteTime_to_scalar(&DeviceActiveTimestamp))
7654 {
7655 // The number of milliseconds since the last activity tickle.
7656 delta = now;
7657 SUB_ABSOLUTETIME(&delta, &DeviceActiveTimestamp);
7658 absolutetime_to_nanoseconds(delta, &nsecs);
7659 setPMProperty(dict, "TimeSinceLastTickle", NS_TO_MS(nsecs));
7660 }
7661
7662 if (AbsoluteTime_to_scalar(&IdleTimerStartTime))
7663 {
7664 // The number of milliseconds since the last device idle.
7665 delta = now;
7666 SUB_ABSOLUTETIME(&delta, &IdleTimerStartTime);
7667 absolutetime_to_nanoseconds(delta, &nsecs);
7668 setPMProperty(dict, "TimeSinceDeviceIdle", NS_TO_MS(nsecs));
7669 }
7670 }
7671
7672 #if WORK_QUEUE_STATS
7673 if (gIOPMRootNode == Owner)
7674 {
7675 setPMProperty(dict, "WQ-CheckForWork",
7676 gIOPMWorkQueue->fStatCheckForWork);
7677 setPMProperty(dict, "WQ-ScanEntries",
7678 gIOPMWorkQueue->fStatScanEntries);
7679 setPMProperty(dict, "WQ-QueueEmpty",
7680 gIOPMWorkQueue->fStatQueueEmpty);
7681 setPMProperty(dict, "WQ-NoWorkDone",
7682 gIOPMWorkQueue->fStatNoWorkDone);
7683 }
7684 #endif
7685
7686 ok = dict->serialize(s);
7687 dict->release();
7688 }
7689
7690 return (ok ? kIOReturnSuccess : kIOReturnNoMemory);
7691 }
7692
7693 bool IOServicePM::serialize( OSSerialize * s ) const
7694 {
7695 IOReturn ret = kIOReturnNotReady;
7696
7697 if (gIOPMWorkLoop)
7698 {
7699 ret = gIOPMWorkLoop->runAction(
7700 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOServicePM::gatedSerialize),
7701 (OSObject *) this, (void *) s);
7702 }
7703
7704 return (kIOReturnSuccess == ret);
7705 }
7706
7707 PMEventDetails* PMEventDetails::eventDetails(uint32_t type,
7708 const char *ownerName,
7709 uintptr_t ownerUnique,
7710 const char *interestName,
7711 uint8_t oldState,
7712 uint8_t newState,
7713 uint32_t result,
7714 uint32_t elapsedTimeUS) {
7715
7716 PMEventDetails *myself;
7717 myself = new PMEventDetails;
7718
7719 if(myself) {
7720 myself->eventType = type;
7721 myself->ownerName = ownerName;
7722 myself->ownerUnique = ownerUnique;
7723 myself->interestName = interestName;
7724 myself->oldState = oldState;
7725 myself->newState = newState;
7726 myself->result = result;
7727 myself->elapsedTimeUS = elapsedTimeUS;
7728
7729 myself->eventClassifier = kIOPMEventClassDriverEvent;
7730 }
7731
7732 return myself;
7733 }
7734
7735
7736 PMEventDetails* PMEventDetails::eventDetails(uint32_t type,
7737 const char *uuid,
7738 uint32_t reason,
7739 uint32_t result) {
7740
7741 PMEventDetails *myself;
7742 myself = new PMEventDetails;
7743
7744 if(myself) {
7745 myself->eventType = type;
7746 myself->uuid = uuid;
7747 myself->reason = reason;
7748 myself->result = result;
7749
7750 myself->eventClassifier = kIOPMEventClassSystemEvent;
7751 }
7752
7753 return myself;
7754 }
7755