]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOServicePM.cpp
xnu-1699.24.23.tar.gz
[apple/xnu.git] / iokit / Kernel / IOServicePM.cpp
CommitLineData
1c79356b 1/*
2d21ac55 2 * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b 27 */
91447636 28
6d2010ae
A
29//#undef IOASSERT
30//#define IOASSERT 1
31
91447636 32#include <IOKit/assert.h>
91447636
A
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>
6d2010ae 38#include <IOKit/IOEventSource.h>
1c79356b 39#include <IOKit/IOWorkLoop.h>
2d21ac55 40#include <IOKit/IOCommand.h>
1c79356b 41
2d21ac55 42#include <IOKit/pwr_mgt/IOPMlog.h>
91447636
A
43#include <IOKit/pwr_mgt/IOPMinformee.h>
44#include <IOKit/pwr_mgt/IOPMinformeeList.h>
91447636
A
45#include <IOKit/pwr_mgt/IOPowerConnection.h>
46#include <IOKit/pwr_mgt/RootDomain.h>
6d2010ae 47#include <IOKit/pwr_mgt/IOPMPrivate.h>
9bccf70c 48
2d21ac55 49#include <sys/proc.h>
6d2010ae 50#include <libkern/OSDebug.h>
0c530ab8 51
91447636
A
52// Required for notification instrumentation
53#include "IOServicePrivate.h"
2d21ac55
A
54#include "IOServicePMPrivate.h"
55#include "IOKitKernelInternal.h"
9bccf70c 56
2d21ac55 57static void settle_timer_expired(thread_call_param_t, thread_call_param_t);
6d2010ae 58static void idle_timer_expired(thread_call_param_t, thread_call_param_t);
b0d623f7
A
59static void tellKernelClientApplier(OSObject * object, void * arg);
60static void tellAppClientApplier(OSObject * object, void * arg);
9bccf70c 61
2d21ac55
A
62static uint64_t computeTimeDeltaNS( const AbsoluteTime * start )
63{
64 AbsoluteTime now;
65 uint64_t nsec;
9bccf70c 66
2d21ac55
A
67 clock_get_uptime(&now);
68 SUB_ABSOLUTETIME(&now, start);
69 absolutetime_to_nanoseconds(now, &nsec);
70 return nsec;
71}
1c79356b 72
b0d623f7 73#if PM_VARS_SUPPORT
2d21ac55 74OSDefineMetaClassAndStructors(IOPMprot, OSObject)
b0d623f7 75#endif
1c79356b 76
6d2010ae
A
77// Container class for recording system power events
78OSDefineMetaClassAndStructors( PMEventDetails, OSObject );
79
80//******************************************************************************
2d21ac55 81// Globals
6d2010ae 82//******************************************************************************
1c79356b 83
b0d623f7
A
84static bool gIOPMInitialized = false;
85static uint32_t gIOPMBusyCount = 0;
6d2010ae 86static uint32_t gIOPMWorkCount = 0;
b0d623f7
A
87static IOWorkLoop * gIOPMWorkLoop = 0;
88static IOPMRequestQueue * gIOPMRequestQueue = 0;
89static IOPMRequestQueue * gIOPMReplyQueue = 0;
6d2010ae 90static IOPMWorkQueue * gIOPMWorkQueue = 0;
b0d623f7
A
91static IOPMCompletionQueue * gIOPMFreeQueue = 0;
92static IOPMRequest * gIOPMRequest = 0;
93static IOPlatformExpert * gPlatform = 0;
94static IOService * gIOPMRootNode = 0;
95
96static const OSSymbol * gIOPMPowerClientDevice = 0;
97static const OSSymbol * gIOPMPowerClientDriver = 0;
98static const OSSymbol * gIOPMPowerClientChildProxy = 0;
99static const OSSymbol * gIOPMPowerClientChildren = 0;
100
101static uint32_t getPMRequestType( void )
102{
103 uint32_t type = kIOPMRequestTypeInvalid;
104 if (gIOPMRequest)
105 type = gIOPMRequest->getType();
106 return type;
107}
1c79356b 108
6d2010ae 109//******************************************************************************
2d21ac55 110// Macros
6d2010ae 111//******************************************************************************
1c79356b 112
7e4a7d39 113#define PM_ERROR(x...) do { kprintf(x); IOLog(x); } while (false)
6d2010ae
A
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)
55e303ae 123
6d2010ae
A
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)
1c79356b 134
2d21ac55
A
135#define PM_ASSERT_IN_GATE(x) \
136do { \
137 assert(gIOPMWorkLoop->inGate()); \
138} while(false)
1c79356b 139
b0d623f7
A
140#define PM_LOCK() IOLockLock(fPMLock)
141#define PM_UNLOCK() IOLockUnlock(fPMLock)
6d2010ae 142#define PM_LOCK_SLEEP(event, dl) IOLockSleepDeadline(fPMLock, event, dl, THREAD_UNINT)
b0d623f7 143#define PM_LOCK_WAKEUP(event) IOLockWakeup(fPMLock, event, false)
2d21ac55 144
b0d623f7
A
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"
2d21ac55
A
151
152#define OUR_PMLog(t, a, b) \
b0d623f7 153 do { gPlatform->PMLog( fName, t, a, b); } while(0)
2d21ac55 154
b0d623f7 155#define NS_TO_MS(nsec) ((int)((nsec) / 1000000ULL))
6d2010ae 156#define NS_TO_US(nsec) ((int)((nsec) / 1000ULL))
2d21ac55 157
593a1d5f 158#if CONFIG_EMBEDDED
b0d623f7 159#define SUPPORT_IDLE_CANCEL 1
593a1d5f
A
160#endif
161
b0d623f7
A
162#define kIOPMPowerStateMax 0xFFFFFFFF
163
6d2010ae
A
164#define IS_PM_ROOT (this == gIOPMRootNode)
165#define IS_ROOT_DOMAIN (getPMRootDomain() == this)
7e4a7d39
A
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
7e4a7d39
A
176enum {
177 kReserveDomainPower = 1
178};
b0d623f7 179
6d2010ae
A
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
2d21ac55
A
200//*********************************************************************************
201// PM machine states
6d2010ae
A
202//
203// Check kgmacros after modifying machine states.
2d21ac55 204//*********************************************************************************
1c79356b 205
2d21ac55 206enum {
6d2010ae
A
207 kIOPM_Finished = 0,
208
2d21ac55
A
209 kIOPM_OurChangeTellClientsPowerDown = 1,
210 kIOPM_OurChangeTellPriorityClientsPowerDown = 2,
211 kIOPM_OurChangeNotifyInterestedDriversWillChange = 3,
212 kIOPM_OurChangeSetPowerState = 4,
213 kIOPM_OurChangeWaitForPowerSettle = 5,
214 kIOPM_OurChangeNotifyInterestedDriversDidChange = 6,
6d2010ae
A
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,
b0d623f7 232 kIOPM_SyncNotifyDidChange = 23,
6d2010ae
A
233 kIOPM_SyncTellCapabilityDidChange = 24,
234 kIOPM_SyncFinish = 25,
235 kIOPM_TellCapabilityChangeDone = 26,
236 kIOPM_DriverThreadCallDone = 27,
237
238 kIOPM_BadMachineState = 0xFFFFFFFF
2d21ac55
A
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 ==
1c79356b 294 This is how a power change initiated by the subclass device is handled:
2d21ac55
A
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 ==
309How 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 ==
323How 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
405Note all parent requested changes need to acknowledge the power has changed to the parent when done.
406 */
1c79356b 407
2d21ac55 408//*********************************************************************************
b0d623f7 409// [public] PMinit
2d21ac55
A
410//
411// Initialize power management.
412//*********************************************************************************
1c79356b
A
413
414void IOService::PMinit ( void )
415{
2d21ac55
A
416 if ( !initialized )
417 {
418 if ( !gIOPMInitialized )
419 {
b0d623f7 420 gPlatform = getPlatform();
6d2010ae
A
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 }
2d21ac55 449
6d2010ae
A
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 }
2d21ac55 463
6d2010ae
A
464 if (gIOPMWorkLoop->addEventSource(gIOPMFreeQueue) !=
465 kIOReturnSuccess)
466 {
467 gIOPMFreeQueue->release();
468 gIOPMFreeQueue = 0;
469 }
2d21ac55 470
6d2010ae
A
471 gIOPMPowerClientDevice =
472 OSSymbol::withCStringNoCopy( "DevicePowerState" );
2d21ac55 473
6d2010ae
A
474 gIOPMPowerClientDriver =
475 OSSymbol::withCStringNoCopy( "DriverPowerState" );
2d21ac55 476
6d2010ae
A
477 gIOPMPowerClientChildProxy =
478 OSSymbol::withCStringNoCopy( "ChildProxyPowerState" );
b0d623f7 479
6d2010ae
A
480 gIOPMPowerClientChildren =
481 OSSymbol::withCStringNoCopy( "ChildrenPowerState" );
482 }
2d21ac55 483
6d2010ae
A
484 if (gIOPMRequestQueue && gIOPMReplyQueue && gIOPMFreeQueue)
485 gIOPMInitialized = true;
486 }
487 if (!gIOPMInitialized)
488 return;
2d21ac55
A
489
490 pwrMgt = new IOServicePM;
491 pwrMgt->init();
492 setProperty(kPwrMgtKey, pwrMgt);
493
6d2010ae
A
494 queue_init(&pwrMgt->WorkChain);
495 queue_init(&pwrMgt->RequestHead);
496 queue_init(&pwrMgt->PMDriverCallQueue);
497
498 fOwner = this;
2d21ac55
A
499 fPMLock = IOLockAlloc();
500 fInterestedDrivers = new IOPMinformeeList;
501 fInterestedDrivers->initialize();
502 fDesiredPowerState = 0;
2d21ac55 503 fDeviceDesire = 0;
6d2010ae
A
504 fInitialPowerChange = true;
505 fInitialSetPowerState = true;
506 fPreviousRequestPowerFlags = 0;
507 fDeviceOverrideEnabled = false;
2d21ac55 508 fMachineState = kIOPM_Finished;
6d2010ae 509 fSavedMachineState = kIOPM_BadMachineState;
cf7d32b8 510 fIdleTimerMinPowerState = 0;
2d21ac55 511 fActivityLock = IOLockAlloc();
2d21ac55
A
512 fStrictTreeOrder = false;
513 fActivityTicklePowerState = -1;
514 fControllingDriver = NULL;
515 fPowerStates = NULL;
516 fNumberOfPowerStates = 0;
517 fCurrentPowerState = 0;
518 fParentsCurrentPowerFlags = 0;
6d2010ae 519 fMaxPowerState = 0;
2d21ac55 520 fName = getName();
2d21ac55
A
521 fParentsKnowState = false;
522 fSerialNumber = 0;
523 fResponseArray = NULL;
b0d623f7 524 fNotifyClientArray = NULL;
2d21ac55 525 fCurrentPowerConsumption = kIOPMUnknown;
b0d623f7 526 fOverrideMaxPowerState = kIOPMPowerStateMax;
2d21ac55 527
b0d623f7 528 if (!gIOPMRootNode && (getParentEntry(gIOPowerPlane) == getRegistryRoot()))
55e303ae 529 {
b0d623f7
A
530 gIOPMRootNode = this;
531 fParentsKnowState = true;
1c79356b 532 }
2d21ac55
A
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);
6d2010ae
A
538 fIdleTimer = thread_call_allocate(
539 &idle_timer_expired, (thread_call_param_t)this);
540 fDriverCallEntry = thread_call_allocate(
2d21ac55 541 (thread_call_func_t) &IOService::pmDriverCallout, this);
6d2010ae
A
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 }
2d21ac55
A
552
553#if PM_VARS_SUPPORT
554 IOPMprot * prot = new IOPMprot;
555 if (prot)
556 {
557 prot->init();
558 prot->ourName = fName;
b0d623f7 559 prot->thePlatform = gPlatform;
2d21ac55
A
560 fPMVars = prot;
561 pm_vars = prot;
562 }
563#else
6d2010ae 564 pm_vars = (void *) (uintptr_t) true;
2d21ac55
A
565#endif
566
1c79356b
A
567 initialized = true;
568 }
569}
570
0b4e3aa0 571//*********************************************************************************
b0d623f7 572// [private] PMfree
0b4e3aa0 573//
7e4a7d39 574// Free the data created by PMinit. Only called from IOService::free().
0b4e3aa0 575//*********************************************************************************
2d21ac55 576
0b4e3aa0
A
577void IOService::PMfree ( void )
578{
6d2010ae 579 initialized = false;
2d21ac55
A
580 pm_vars = 0;
581
582 if ( pwrMgt )
6d2010ae
A
583 {
584 assert(fMachineState == kIOPM_Finished);
585 assert(fInsertInterestSet == NULL);
586 assert(fRemoveInterestSet == NULL);
2d21ac55 587 assert(fNotifyChildArray == NULL);
6d2010ae
A
588 assert(queue_empty(&pwrMgt->RequestHead));
589 assert(queue_empty(&fPMDriverCallQueue));
2d21ac55 590
2d21ac55
A
591 if ( fSettleTimer ) {
592 thread_call_cancel(fSettleTimer);
593 thread_call_free(fSettleTimer);
594 fSettleTimer = NULL;
0b4e3aa0 595 }
2d21ac55
A
596 if ( fAckTimer ) {
597 thread_call_cancel(fAckTimer);
598 thread_call_free(fAckTimer);
599 fAckTimer = NULL;
0b4e3aa0 600 }
6d2010ae
A
601 if ( fIdleTimer ) {
602 thread_call_cancel(fIdleTimer);
603 thread_call_free(fIdleTimer);
604 fIdleTimer = NULL;
605 }
2d21ac55
A
606 if ( fDriverCallEntry ) {
607 thread_call_free(fDriverCallEntry);
608 fDriverCallEntry = NULL;
0b4e3aa0 609 }
2d21ac55
A
610 if ( fPMLock ) {
611 IOLockFree(fPMLock);
612 fPMLock = NULL;
0b4e3aa0 613 }
2d21ac55
A
614 if ( fActivityLock ) {
615 IOLockFree(fActivityLock);
616 fActivityLock = NULL;
0b4e3aa0 617 }
6d2010ae
A
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 }
2d21ac55
A
627 if ( fResponseArray ) {
628 fResponseArray->release();
629 fResponseArray = NULL;
0b4e3aa0 630 }
b0d623f7
A
631 if ( fNotifyClientArray ) {
632 fNotifyClientArray->release();
633 fNotifyClientArray = NULL;
634 }
2d21ac55 635 if (fPowerStates && fNumberOfPowerStates) {
6d2010ae 636 IODelete(fPowerStates, IOPMPSEntry, fNumberOfPowerStates);
2d21ac55
A
637 fNumberOfPowerStates = 0;
638 fPowerStates = NULL;
0b4e3aa0 639 }
6d2010ae
A
640 if (fPowerClients) {
641 fPowerClients->release();
642 fPowerClients = 0;
643 }
2d21ac55
A
644
645#if PM_VARS_SUPPORT
6d2010ae
A
646 if (fPMVars)
647 {
648 fPMVars->release();
649 fPMVars = 0;
650 }
2d21ac55
A
651#endif
652
653 pwrMgt->release();
6d2010ae 654 pwrMgt = 0;
0b4e3aa0
A
655 }
656}
657
2d21ac55 658//*********************************************************************************
b0d623f7 659// [public] joinPMtree
2d21ac55
A
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
671void IOService::joinPMtree ( IOService * driver )
672{
b0d623f7 673 IOPlatformExpert * platform;
2d21ac55
A
674
675 platform = getPlatform();
676 assert(platform != 0);
677 platform->PMRegisterDevice(this, driver);
678}
0b4e3aa0 679
b0d623f7 680#ifndef __LP64__
1c79356b 681//*********************************************************************************
b0d623f7 682// [deprecated] youAreRoot
1c79356b 683//
2d21ac55 684// Power Managment is informing us that we are the root power domain.
2d21ac55
A
685//*********************************************************************************
686
687IOReturn IOService::youAreRoot ( void )
688{
2d21ac55
A
689 return IOPMNoErr;
690}
b0d623f7 691#endif /* !__LP64__ */
2d21ac55
A
692
693//*********************************************************************************
b0d623f7 694// [public] PMstop
2d21ac55
A
695//
696// Immediately stop driver callouts. Schedule an async stop request to detach
697// from power plane.
1c79356b 698//*********************************************************************************
2d21ac55 699
1c79356b
A
700void IOService::PMstop ( void )
701{
6d2010ae 702 IOPMRequest * request;
2d21ac55 703
6d2010ae
A
704 if (!initialized)
705 return;
2d21ac55 706
6d2010ae 707 PM_LOCK();
2d21ac55 708
6d2010ae 709 if (fLockedFlags.PMStop)
b0d623f7 710 {
6d2010ae
A
711 PM_LOG2("%s: PMstop() already stopped\n", fName);
712 PM_UNLOCK();
713 return;
b0d623f7 714 }
6d2010ae
A
715
716 // Inhibit future driver calls.
717 fLockedFlags.PMStop = true;
718
719 // Wait for all prior driver calls to finish.
720 waitForPMDriverCall();
721
2d21ac55
A
722 PM_UNLOCK();
723
6d2010ae
A
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 }
2d21ac55
A
731}
732
733//*********************************************************************************
b0d623f7 734// [private] handlePMstop
2d21ac55 735//
b0d623f7 736// Disconnect the node from all parents and children in the power plane.
2d21ac55
A
737//*********************************************************************************
738
739void IOService::handlePMstop ( IOPMRequest * request )
740{
6d2010ae 741 OSIterator * iter;
2d21ac55 742 OSObject * next;
1c79356b 743 IOPowerConnection * connection;
2d21ac55
A
744 IOService * theChild;
745 IOService * theParent;
1c79356b 746
2d21ac55 747 PM_ASSERT_IN_GATE();
6d2010ae 748 PM_LOG2("%s: %p %s start\n", getName(), this, __FUNCTION__);
1c79356b 749
2d21ac55
A
750 // remove the property
751 removeProperty(kPwrMgtKey);
752
753 // detach parents
754 iter = getParentIterator(gIOPowerPlane);
755 if ( iter )
55e303ae 756 {
2d21ac55 757 while ( (next = iter->getNextObject()) )
55e303ae 758 {
2d21ac55 759 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
55e303ae 760 {
0b4e3aa0 761 theParent = (IOService *)connection->copyParentEntry(gIOPowerPlane);
2d21ac55 762 if ( theParent )
55e303ae 763 {
0b4e3aa0
A
764 theParent->removePowerChild(connection);
765 theParent->release();
766 }
1c79356b
A
767 }
768 }
769 iter->release();
770 }
55e303ae 771
2d21ac55
A
772 // detach IOConnections
773 detachAbove( gIOPowerPlane );
1c79356b 774
2d21ac55
A
775 // no more power state changes
776 fParentsKnowState = false;
1c79356b 777
2d21ac55
A
778 // detach children
779 iter = getChildIterator(gIOPowerPlane);
780 if ( iter )
55e303ae 781 {
2d21ac55 782 while ( (next = iter->getNextObject()) )
55e303ae 783 {
2d21ac55 784 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
55e303ae 785 {
0b4e3aa0 786 theChild = ((IOService *)(connection->copyChildEntry(gIOPowerPlane)));
2d21ac55 787 if ( theChild )
55e303ae
A
788 {
789 // detach nub from child
2d21ac55 790 connection->detachFromChild(theChild, gIOPowerPlane);
0b4e3aa0
A
791 theChild->release();
792 }
55e303ae 793 // detach us from nub
2d21ac55 794 detachFromChild(connection, gIOPowerPlane);
1c79356b
A
795 }
796 }
797 iter->release();
798 }
1c79356b 799
0b4e3aa0
A
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
2d21ac55 808 if ( fInterestedDrivers )
0b4e3aa0 809 {
6d2010ae 810 IOPMinformeeList * list = fInterestedDrivers;
2d21ac55 811 IOPMinformee * item;
1c79356b 812
6d2010ae
A
813 PM_LOCK();
814 while ((item = list->firstInList()))
815 {
816 list->removeFromList(item->whatObject);
817 }
818 PM_UNLOCK();
819 }
2d21ac55 820
6d2010ae
A
821 // Tell idleTimerExpired() to ignore idle timer.
822 fIdleTimerPeriod = 0;
823 if (fIdleTimer && thread_call_cancel(fIdleTimer))
824 release();
1c79356b 825
6d2010ae 826 PM_LOG2("%s: %p %s done\n", getName(), this, __FUNCTION__);
2d21ac55 827}
1c79356b
A
828
829//*********************************************************************************
b0d623f7 830// [public] addPowerChild
1c79356b 831//
2d21ac55 832// Power Management is informing us who our children are.
1c79356b 833//*********************************************************************************
2d21ac55
A
834
835IOReturn IOService::addPowerChild ( IOService * child )
1c79356b 836{
2d21ac55
A
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
b0d623f7 848 OUR_PMLog( kPMLogAddChild, (uintptr_t) child, 0 );
2d21ac55
A
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 {
6d2010ae 872 PM_LOG("%s: %s (%p) is already a child\n",
2d21ac55
A
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
b0d623f7
A
905 requests[0]->attachNextRequest( requests[1] );
906 requests[1]->attachNextRequest( requests[2] );
2d21ac55
A
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);
1c79356b 925
2d21ac55
A
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]);
1c79356b 930
b0d623f7 931 // Silent failure, to prevent platform drivers from adding the child
2d21ac55 932 // to the root domain.
b0d623f7
A
933
934 return kIOReturnSuccess;
2d21ac55 935}
1c79356b
A
936
937//*********************************************************************************
2d21ac55 938// [private] addPowerChild1
1c79356b 939//
b0d623f7 940// Step 1/3 of adding a power child. Called on the power parent.
1c79356b 941//*********************************************************************************
1c79356b 942
2d21ac55
A
943void 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();
b0d623f7 950 OUR_PMLog( kPMLogMakeUsable, kPMLogMakeUsable, 0 );
2d21ac55
A
951
952 if (fControllingDriver && inPlane(gIOPowerPlane) && fParentsKnowState)
953 {
954 tempDesire = fNumberOfPowerStates - 1;
955 }
956
6d2010ae 957 if (tempDesire && (IS_PM_ROOT || (fMaxPowerState >= tempDesire)))
2d21ac55 958 {
b0d623f7 959 adjustPowerState(tempDesire);
2d21ac55
A
960 }
961}
1c79356b
A
962
963//*********************************************************************************
2d21ac55 964// [private] addPowerChild2
1c79356b 965//
b0d623f7
A
966// Step 2/3 of adding a power child. Called on the joining child.
967// Execution blocked behind addPowerChild1.
1c79356b 968//*********************************************************************************
2d21ac55
A
969
970void IOService::addPowerChild2 ( IOPMRequest * request )
1c79356b 971{
2d21ac55
A
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 {
6d2010ae 984 PM_LOG("%s: addPowerChild2 not in power plane\n", getName());
2d21ac55
A
985 return;
986 }
1c79356b 987
b0d623f7
A
988 // Parent will be waiting for us to complete this stage.
989 // It is safe to directly access parent's vars.
0b4e3aa0 990
2d21ac55
A
991 knowsState = (parent->fPowerStates) && (parent->fParentsKnowState);
992 powerState = parent->fCurrentPowerState;
1c79356b 993
2d21ac55 994 if (knowsState)
6d2010ae 995 powerFlags = parent->fPowerStates[powerState].outputPowerFlags;
2d21ac55
A
996 else
997 powerFlags = 0;
1c79356b 998
2d21ac55
A
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 )
55e303ae 1008 {
6d2010ae 1009 fMaxPowerState = fControllingDriver->maxCapabilityForDomainState(fParentsCurrentPowerFlags);
55e303ae 1010 // initially change into the state we are already in
2d21ac55 1011 tempDesire = fControllingDriver->initialPowerStateForDomainState(fParentsCurrentPowerFlags);
6d2010ae 1012 fPreviousRequestPowerFlags = (IOPMPowerFlags)(-1);
b0d623f7 1013 adjustPowerState(tempDesire);
1c79356b 1014 }
b0d623f7 1015
6d2010ae 1016 getPMRootDomain()->tagPowerPlaneService(this, &fPMActions);
1c79356b
A
1017}
1018
1c79356b 1019//*********************************************************************************
2d21ac55 1020// [private] addPowerChild3
1c79356b 1021//
b0d623f7
A
1022// Step 3/3 of adding a power child. Called on the parent.
1023// Execution blocked behind addPowerChild2.
1c79356b 1024//*********************************************************************************
1c79356b 1025
2d21ac55
A
1026void IOService::addPowerChild3 ( IOPMRequest * request )
1027{
1028 IOPowerConnection * connection = (IOPowerConnection *) request->fArg0;
1029 IOService * child;
b0d623f7 1030 IOPMrootDomain * rootDomain = getPMRootDomain();
2d21ac55
A
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 {
6d2010ae 1039 PM_LOG1("%s: strict PM order enforced\n", getName());
2d21ac55
A
1040 fStrictTreeOrder = true;
1041 }
1042
b0d623f7
A
1043 if (rootDomain)
1044 rootDomain->joinAggressiveness( child );
2d21ac55
A
1045 }
1046 else
1047 {
6d2010ae 1048 PM_LOG("%s: addPowerChild3 not in power plane\n", getName());
2d21ac55 1049 }
1c79356b 1050
2d21ac55
A
1051 connection->release();
1052}
1c79356b 1053
b0d623f7 1054#ifndef __LP64__
2d21ac55 1055//*********************************************************************************
b0d623f7 1056// [deprecated] setPowerParent
2d21ac55
A
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//*********************************************************************************
1c79356b 1063
2d21ac55
A
1064IOReturn IOService::setPowerParent (
1065 IOPowerConnection * theParent, bool stateKnown, IOPMPowerFlags powerFlags )
1066{
1067 return kIOReturnUnsupported;
1c79356b 1068}
b0d623f7 1069#endif /* !__LP64__ */
1c79356b 1070
2d21ac55 1071//*********************************************************************************
b0d623f7 1072// [public] removePowerChild
1c79356b 1073//
2d21ac55
A
1074// Called on a parent whose child is being removed by PMstop().
1075//*********************************************************************************
1076
0b4e3aa0
A
1077IOReturn IOService::removePowerChild ( IOPowerConnection * theNub )
1078{
2d21ac55 1079 IORegistryEntry * theChild;
0b4e3aa0 1080
2d21ac55
A
1081 PM_ASSERT_IN_GATE();
1082 OUR_PMLog( kPMLogRemoveChild, 0, 0 );
1c79356b 1083
0b4e3aa0 1084 theNub->retain();
b0d623f7 1085
55e303ae
A
1086 // detach nub from child
1087 theChild = theNub->copyChildEntry(gIOPowerPlane);
2d21ac55 1088 if ( theChild )
55e303ae 1089 {
0b4e3aa0
A
1090 theNub->detachFromChild(theChild, gIOPowerPlane);
1091 theChild->release();
1092 }
55e303ae 1093 // detach from the nub
2d21ac55
A
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();
6d2010ae
A
1110
1111 // Request unblocked, work queue
1112 // should re-scan all busy requests.
1113 gIOPMWorkQueue->incrementProducerCount();
2d21ac55
A
1114 }
1115 }
1116 }
90556fb8 1117
2d21ac55 1118 theNub->release();
1c79356b 1119
b0d623f7
A
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)
2d21ac55
A
1124 {
1125 IOPMRequest * request;
2d21ac55
A
1126 request = acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState );
1127 if (request)
1128 {
1129 submitPMRequest( request );
b0d623f7 1130 fAdjustPowerScheduled = true;
2d21ac55
A
1131 }
1132 }
1c79356b
A
1133
1134 return IOPMNoErr;
1135}
1136
1c79356b 1137//*********************************************************************************
b0d623f7 1138// [public] registerPowerDriver
1c79356b
A
1139//
1140// A driver has called us volunteering to control power to our device.
1c79356b
A
1141//*********************************************************************************
1142
2d21ac55
A
1143IOReturn IOService::registerPowerDriver (
1144 IOService * powerDriver,
1145 IOPMPowerState * powerStates,
1146 unsigned long numberOfStates )
1c79356b 1147{
6d2010ae
A
1148 IOPMRequest * request;
1149 IOPMPSEntry * powerStatesCopy = 0;
55e303ae 1150
2d21ac55
A
1151 if (!initialized)
1152 return IOPMNotYetInitialized;
1c79356b 1153
2d21ac55
A
1154 // Validate arguments.
1155 if (!powerStates || (numberOfStates < 2))
1156 {
1157 OUR_PMLog(kPMLogControllingDriverErr5, numberOfStates, 0);
1158 return kIOReturnBadArgument;
1159 }
1c79356b 1160
b0d623f7 1161 if (!powerDriver || !powerDriver->initialized)
2d21ac55
A
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.
6d2010ae 1175 powerStatesCopy = IONew(IOPMPSEntry, numberOfStates);
2d21ac55
A
1176 if (!powerStatesCopy)
1177 break;
1178
6d2010ae
A
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 }
2d21ac55
A
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)
6d2010ae 1204 IODelete(powerStatesCopy, IOPMPSEntry, numberOfStates);
2d21ac55 1205 return kIOReturnNoMemory;
1c79356b
A
1206}
1207
1208//*********************************************************************************
2d21ac55
A
1209// [private] handleRegisterPowerDriver
1210//*********************************************************************************
1211
1212void IOService::handleRegisterPowerDriver ( IOPMRequest * request )
1213{
6d2010ae
A
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;
2d21ac55
A
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,
6d2010ae 1230 (unsigned long) kIOPMPowerStateVersion1);
2d21ac55
A
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++ ) {
6d2010ae 1240 fOutputPowerCharacterFlags |= fPowerStates[i].outputPowerFlags;
2d21ac55
A
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
b0d623f7
A
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 }
2d21ac55
A
1287
1288 if ( inPlane(gIOPowerPlane) && fParentsKnowState )
1289 {
1290 unsigned long tempDesire;
6d2010ae 1291 fMaxPowerState = fControllingDriver->maxCapabilityForDomainState(fParentsCurrentPowerFlags);
2d21ac55
A
1292 // initially change into the state we are already in
1293 tempDesire = fControllingDriver->initialPowerStateForDomainState(fParentsCurrentPowerFlags);
b0d623f7 1294 adjustPowerState(tempDesire);
2d21ac55
A
1295 }
1296 }
1297 else
1298 {
1299 OUR_PMLog(kPMLogControllingDriverErr2, numberOfStates, 0);
6d2010ae 1300 IODelete(powerStates, IOPMPSEntry, numberOfStates);
2d21ac55
A
1301 }
1302
1303 powerDriver->release();
1304}
1305
1306//*********************************************************************************
b0d623f7 1307// [public] registerInterestedDriver
1c79356b
A
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
2d21ac55 1315IOPMPowerFlags IOService::registerInterestedDriver ( IOService * driver )
1c79356b 1316{
6d2010ae
A
1317 IOPMRequest * request;
1318 bool signal;
2d21ac55 1319
6d2010ae
A
1320 if (!driver || !initialized || !fInterestedDrivers)
1321 return 0;
2d21ac55 1322
6d2010ae
A
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();
2d21ac55 1334
6d2010ae
A
1335 if (signal)
1336 {
1337 request = acquirePMRequest( this, kIOPMRequestTypeInterestChanged );
1338 if (request)
1339 submitPMRequest( request );
1340 }
1c79356b 1341
6d2010ae
A
1342 // This return value cannot be trusted, but return a value
1343 // for those clients that care.
1c79356b 1344
2d21ac55
A
1345 OUR_PMLog(kPMLogInterestedDriver, kIOPMDeviceUsable, 2);
1346 return kIOPMDeviceUsable;
1347}
1c79356b 1348
2d21ac55 1349//*********************************************************************************
b0d623f7 1350// [public] deRegisterInterestedDriver
2d21ac55 1351//*********************************************************************************
1c79356b 1352
2d21ac55
A
1353IOReturn IOService::deRegisterInterestedDriver ( IOService * driver )
1354{
6d2010ae 1355 IOPMinformeeList * list;
2d21ac55 1356 IOPMinformee * item;
6d2010ae
A
1357 IOPMRequest * request;
1358 bool signal;
2d21ac55 1359
6d2010ae
A
1360 if (!driver)
1361 return kIOReturnBadArgument;
1362 if (!initialized || !fInterestedDrivers)
1363 return IOPMNotPowerManaged;
2d21ac55 1364
6d2010ae
A
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);
2d21ac55 1374
6d2010ae
A
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();
1c79356b 1384
6d2010ae
A
1385 if (signal)
1386 {
1387 request = acquirePMRequest( this, kIOPMRequestTypeInterestChanged );
1388 if (request)
1389 submitPMRequest( request );
1390 }
55e303ae 1391
6d2010ae 1392 return IOPMNoErr;
1c79356b
A
1393}
1394
1c79356b 1395//*********************************************************************************
2d21ac55 1396// [private] handleInterestChanged
1c79356b 1397//
2d21ac55 1398// Handle interest added or removed.
1c79356b 1399//*********************************************************************************
2d21ac55
A
1400
1401void IOService::handleInterestChanged( IOPMRequest * request )
1c79356b 1402{
6d2010ae 1403 IOService * driver;
2d21ac55 1404 IOPMinformee * informee;
6d2010ae 1405 IOPMinformeeList * list = fInterestedDrivers;
2d21ac55 1406
6d2010ae 1407 PM_LOCK();
2d21ac55 1408
6d2010ae
A
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 }
1c79356b 1422
6d2010ae
A
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 }
1c79356b 1443
6d2010ae 1444 PM_UNLOCK();
1c79356b
A
1445}
1446
1c79356b 1447//*********************************************************************************
b0d623f7 1448// [public] acknowledgePowerChange
1c79356b
A
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
1461IOReturn IOService::acknowledgePowerChange ( IOService * whichObject )
1462{
2d21ac55
A
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)
2d21ac55 1472 return kIOReturnNoMemory;
2d21ac55
A
1473
1474 whichObject->retain();
1475 request->fArg0 = whichObject;
1476
1477 submitPMRequest( request );
1478 return IOPMNoErr;
1479}
1480
1481//*********************************************************************************
1482// [private] handleAcknowledgePowerChange
1483//*********************************************************************************
1484
1485bool 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);
1c79356b 1496
55e303ae 1497 // one of our interested drivers?
2d21ac55
A
1498 informee = fInterestedDrivers->findItem( whichObject );
1499 if ( informee == NULL )
55e303ae 1500 {
2d21ac55 1501 if ( !isChild(whichObject, gIOPowerPlane) )
55e303ae 1502 {
2d21ac55
A
1503 OUR_PMLog(kPMLogAcknowledgeErr1, 0, 0);
1504 goto no_err;
55e303ae 1505 } else {
2d21ac55 1506 OUR_PMLog(kPMLogChildAcknowledge, fHeadNotePendingAcks, 0);
55e303ae
A
1507 }
1508 } else {
2d21ac55 1509 OUR_PMLog(kPMLogDriverAcknowledge, fHeadNotePendingAcks, 0);
55e303ae 1510 }
2d21ac55
A
1511
1512 if ( fHeadNotePendingAcks != 0 )
55e303ae 1513 {
2d21ac55
A
1514 assert(fPowerStates != NULL);
1515
55e303ae 1516 // yes, make sure we're expecting acks
2d21ac55 1517 if ( informee != NULL )
55e303ae
A
1518 {
1519 // it's an interested driver
1520 // make sure we're expecting this ack
2d21ac55 1521 if ( informee->timer != 0 )
55e303ae 1522 {
2d21ac55
A
1523#if LOG_SETPOWER_TIMES
1524 if (informee->timer > 0)
55e303ae 1525 {
2d21ac55
A
1526 uint64_t nsec = computeTimeDeltaNS(&informee->startTime);
1527 if (nsec > LOG_SETPOWER_TIMES)
6d2010ae 1528 PM_LOG("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) async took %d ms\n",
2d21ac55
A
1529 informee->whatObject->getName(),
1530 (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
1531 informee->whatObject,
6d2010ae
A
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 );
55e303ae 1547 }
2d21ac55
A
1548#endif
1549 // mark it acked
1550 informee->timer = 0;
1551 // that's one fewer to worry about
1552 fHeadNotePendingAcks--;
55e303ae
A
1553 } else {
1554 // this driver has already acked
2d21ac55 1555 OUR_PMLog(kPMLogAcknowledgeErr2, 0, 0);
55e303ae
A
1556 }
1557 } else {
1558 // it's a child
1559 // make sure we're expecting this ack
2d21ac55 1560 if ( ((IOPowerConnection *)whichObject)->getAwaitingAck() )
55e303ae
A
1561 {
1562 // that's one fewer to worry about
2d21ac55 1563 fHeadNotePendingAcks--;
0b4e3aa0
A
1564 ((IOPowerConnection *)whichObject)->setAwaitingAck(false);
1565 theChild = (IOService *)whichObject->copyChildEntry(gIOPowerPlane);
2d21ac55 1566 if ( theChild )
55e303ae 1567 {
0b4e3aa0
A
1568 childPower = theChild->currentPowerConsumption();
1569 theChild->release();
1570 }
2d21ac55 1571 if ( childPower == kIOPMUnknown )
55e303ae 1572 {
b0d623f7 1573 fHeadNotePowerArrayEntry->staticPower = kIOPMUnknown;
55e303ae 1574 } else {
b0d623f7 1575 if (fHeadNotePowerArrayEntry->staticPower != kIOPMUnknown)
55e303ae 1576 {
b0d623f7 1577 fHeadNotePowerArrayEntry->staticPower += childPower;
0b4e3aa0
A
1578 }
1579 }
0b4e3aa0 1580 }
55e303ae 1581 }
2d21ac55
A
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 }
55e303ae 1589 } else {
2d21ac55 1590 OUR_PMLog(kPMLogAcknowledgeErr3, 0, 0); // not expecting anybody to ack
1c79356b 1591 }
2d21ac55
A
1592
1593no_err:
1594 if (whichObject)
1595 whichObject->release();
1596
1597 return all_acked;
1c79356b
A
1598}
1599
1600//*********************************************************************************
b0d623f7 1601// [public] acknowledgeSetPowerState
1c79356b
A
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
1608IOReturn IOService::acknowledgeSetPowerState ( void )
1609{
2d21ac55 1610 IOPMRequest * request;
9bccf70c 1611
2d21ac55
A
1612 if (!initialized)
1613 return IOPMNotYetInitialized;
91447636 1614
2d21ac55
A
1615 request = acquirePMRequest( this, kIOPMRequestTypeAckSetPowerState );
1616 if (!request)
2d21ac55 1617 return kIOReturnNoMemory;
1c79356b 1618
2d21ac55
A
1619 submitPMRequest( request );
1620 return kIOReturnSuccess;
1621}
1c79356b
A
1622
1623//*********************************************************************************
2d21ac55 1624// [private] adjustPowerState
1c79356b
A
1625//*********************************************************************************
1626
b0d623f7 1627void IOService::adjustPowerState ( uint32_t clamp )
1c79356b 1628{
2d21ac55 1629 PM_ASSERT_IN_GATE();
b0d623f7
A
1630 computeDesiredState(clamp);
1631 if (fControllingDriver && fParentsKnowState && inPlane(gIOPowerPlane))
2d21ac55 1632 {
6d2010ae
A
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
b0d623f7 1642 startPowerChange(
6d2010ae 1643 /* flags */ changeFlags,
b0d623f7
A
1644 /* power state */ fDesiredPowerState,
1645 /* domain flags */ 0,
1646 /* connection */ 0,
1647 /* parent flags */ 0);
2d21ac55 1648 }
b0d623f7
A
1649}
1650
1651//*********************************************************************************
1652// [public] synchronizePowerTree
1653//*********************************************************************************
1654
6d2010ae
A
1655IOReturn IOService::synchronizePowerTree (
1656 IOOptionBits options,
1657 IOService * notifyRoot )
b0d623f7 1658{
6d2010ae 1659 IOPMRequest * request_c = 0;
b0d623f7
A
1660 IOPMRequest * request_s;
1661
1662 if (this != getPMRootDomain())
1663 return kIOReturnBadArgument;
1664 if (!initialized)
1665 return kIOPMNotYetInitialized;
1666
6d2010ae
A
1667 if (notifyRoot)
1668 {
1669 IOPMRequest * nr;
b0d623f7 1670
6d2010ae
A
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 }
b0d623f7 1677
6d2010ae
A
1678 request_s = acquirePMRequest( this, kIOPMRequestTypeSynchronizePowerTree );
1679 if (!request_s)
1680 goto error_no_memory;
b0d623f7 1681
6d2010ae
A
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;
b0d623f7
A
1691 submitPMRequest(request_s);
1692
1693 return kIOReturnSuccess;
1694
1695error_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
6d2010ae 1705void IOService::handleSynchronizePowerTree ( IOPMRequest * request )
b0d623f7
A
1706{
1707 PM_ASSERT_IN_GATE();
1708 if (fControllingDriver && fParentsKnowState && inPlane(gIOPowerPlane) &&
1709 (fCurrentPowerState == fNumberOfPowerStates - 1))
2d21ac55 1710 {
6d2010ae
A
1711 IOOptionBits options = (uintptr_t) request->fArg0;
1712
b0d623f7 1713 startPowerChange(
6d2010ae
A
1714 /* flags */ kIOPMSelfInitiated | kIOPMSynchronize |
1715 (options & kIOPMSyncNoChildNotify),
b0d623f7
A
1716 /* power state */ fCurrentPowerState,
1717 /* domain flags */ 0,
1718 /* connection */ 0,
1719 /* parent flags */ 0);
2d21ac55 1720 }
1c79356b
A
1721}
1722
b0d623f7 1723#ifndef __LP64__
1c79356b 1724//*********************************************************************************
b0d623f7 1725// [deprecated] powerDomainWillChangeTo
1c79356b
A
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
2d21ac55
A
1734IOReturn IOService::powerDomainWillChangeTo (
1735 IOPMPowerFlags newPowerFlags,
1736 IOPowerConnection * whichParent )
1c79356b 1737{
2d21ac55
A
1738 assert(false);
1739 return kIOReturnUnsupported;
1740}
b0d623f7 1741#endif /* !__LP64__ */
1c79356b 1742
2d21ac55
A
1743//*********************************************************************************
1744// [private] handlePowerDomainWillChangeTo
1745//*********************************************************************************
1c79356b 1746
2d21ac55
A
1747void IOService::handlePowerDomainWillChangeTo ( IOPMRequest * request )
1748{
6d2010ae
A
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;
2d21ac55
A
1760
1761 PM_ASSERT_IN_GATE();
b0d623f7 1762 OUR_PMLog(kPMLogWillChange, parentPowerFlags, 0);
2d21ac55 1763
cf7d32b8 1764 if (!inPlane(gIOPowerPlane) || !whichParent || !whichParent->getAwaitingAck())
2d21ac55 1765 {
6d2010ae 1766 PM_LOG("%s::%s not in power tree\n", getName(), __FUNCTION__);
cf7d32b8 1767 goto exit_no_ack;
2d21ac55 1768 }
1c79356b 1769
2d21ac55 1770 savedParentsKnowState = fParentsKnowState;
0b4e3aa0 1771
b0d623f7
A
1772 // Combine parents' output power flags.
1773
2d21ac55 1774 combinedPowerFlags = 0;
1c79356b 1775
2d21ac55
A
1776 iter = getParentIterator(gIOPowerPlane);
1777 if ( iter )
55e303ae 1778 {
2d21ac55 1779 while ( (next = iter->getNextObject()) )
55e303ae 1780 {
2d21ac55 1781 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
55e303ae 1782 {
2d21ac55 1783 if ( connection == whichParent )
b0d623f7 1784 combinedPowerFlags |= parentPowerFlags;
2d21ac55 1785 else
1c79356b 1786 combinedPowerFlags |= connection->parentCurrentPowerFlags();
1c79356b
A
1787 }
1788 }
1789 iter->release();
1790 }
2d21ac55 1791
b0d623f7
A
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
6d2010ae 1795 if ( fControllingDriver && !fInitialPowerChange )
55e303ae 1796 {
2d21ac55
A
1797 newPowerState = fControllingDriver->maxCapabilityForDomainState(
1798 combinedPowerFlags);
1799
b0d623f7
A
1800 // Absorb parent's kIOPMSynchronize flag.
1801 myChangeFlags = kIOPMParentInitiated | kIOPMDomainWillChange |
1802 (parentChangeFlags & kIOPMSynchronize);
1803
1804 result = startPowerChange(
1805 /* flags */ myChangeFlags,
2d21ac55 1806 /* power state */ newPowerState,
b0d623f7 1807 /* domain flags */ combinedPowerFlags,
2d21ac55 1808 /* connection */ whichParent,
b0d623f7 1809 /* parent flags */ parentPowerFlags);
2d21ac55
A
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
b0d623f7 1816 if (parentChangeFlags & kIOPMDomainPowerDrop)
2d21ac55 1817 {
b0d623f7 1818 setParentInfo(parentPowerFlags, whichParent, true);
2d21ac55 1819 }
1c79356b 1820
2d21ac55 1821 // Parent is expecting an ACK from us. If we did not embark on a state
b0d623f7 1822 // transition, i.e. startPowerChange() returned IOPMAckImplied. We are
2d21ac55
A
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
cf7d32b8
A
1837exit_no_ack:
1838 // Drop the retain from notifyChild().
1839 if (whichParent) whichParent->release();
2d21ac55 1840}
1c79356b 1841
b0d623f7 1842#ifndef __LP64__
1c79356b 1843//*********************************************************************************
b0d623f7 1844// [deprecated] powerDomainDidChangeTo
1c79356b
A
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
2d21ac55
A
1853IOReturn IOService::powerDomainDidChangeTo (
1854 IOPMPowerFlags newPowerFlags,
1855 IOPowerConnection * whichParent )
1c79356b 1856{
2d21ac55
A
1857 assert(false);
1858 return kIOReturnUnsupported;
1859}
b0d623f7 1860#endif /* !__LP64__ */
1c79356b 1861
2d21ac55
A
1862//*********************************************************************************
1863// [private] handlePowerDomainDidChangeTo
1864//*********************************************************************************
1c79356b 1865
2d21ac55
A
1866void IOService::handlePowerDomainDidChangeTo ( IOPMRequest * request )
1867{
6d2010ae
A
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;
2d21ac55
A
1876
1877 PM_ASSERT_IN_GATE();
b0d623f7 1878 OUR_PMLog(kPMLogDidChange, parentPowerFlags, 0);
2d21ac55 1879
cf7d32b8 1880 if (!inPlane(gIOPowerPlane) || !whichParent || !whichParent->getAwaitingAck())
2d21ac55 1881 {
6d2010ae 1882 PM_LOG("%s::%s not in power tree\n", getName(), __FUNCTION__);
cf7d32b8 1883 goto exit_no_ack;
2d21ac55 1884 }
0b4e3aa0 1885
2d21ac55 1886 savedParentsKnowState = fParentsKnowState;
0b4e3aa0 1887
b0d623f7 1888 setParentInfo(parentPowerFlags, whichParent, true);
2d21ac55
A
1889
1890 if ( fControllingDriver )
1891 {
1892 newPowerState = fControllingDriver->maxCapabilityForDomainState(
1893 fParentsCurrentPowerFlags);
1894
6d2010ae 1895 if (fInitialPowerChange)
b0d623f7
A
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,
2d21ac55 1908 /* power state */ newPowerState,
b0d623f7 1909 /* domain flags */ fParentsCurrentPowerFlags,
2d21ac55 1910 /* connection */ whichParent,
b0d623f7 1911 /* parent flags */ 0);
2d21ac55 1912 }
0b4e3aa0 1913
2d21ac55 1914 // Parent is expecting an ACK from us. If we did not embark on a state
b0d623f7 1915 // transition, i.e. startPowerChange() returned IOPMAckImplied. We are
2d21ac55
A
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
b0d623f7 1930 // If the parent registers its power driver late, then this is the
2d21ac55
A
1931 // first opportunity to tell our parent about our desire.
1932
1933 if (!savedParentsKnowState && fParentsKnowState)
1934 {
6d2010ae 1935 PM_LOG1("%s::powerDomainDidChangeTo parentsKnowState = true\n",
2d21ac55 1936 getName());
7e4a7d39 1937 requestDomainPower( fDesiredPowerState );
2d21ac55 1938 }
cf7d32b8
A
1939
1940exit_no_ack:
1941 // Drop the retain from notifyChild().
1942 if (whichParent) whichParent->release();
2d21ac55 1943}
0b4e3aa0
A
1944
1945//*********************************************************************************
2d21ac55 1946// [private] setParentInfo
0b4e3aa0
A
1947//
1948// Set our connection data for one specific parent, and then combine all the parent
1949// data together.
1950//*********************************************************************************
2d21ac55
A
1951
1952void IOService::setParentInfo (
1953 IOPMPowerFlags newPowerFlags,
1954 IOPowerConnection * whichParent,
1955 bool knowsState )
0b4e3aa0 1956{
2d21ac55
A
1957 OSIterator * iter;
1958 OSObject * next;
1959 IOPowerConnection * conn;
1c79356b 1960
2d21ac55
A
1961 PM_ASSERT_IN_GATE();
1962
1963 // set our connection data
1964 whichParent->setParentCurrentPowerFlags(newPowerFlags);
1965 whichParent->setParentKnowsState(knowsState);
0b4e3aa0 1966
55e303ae 1967 // recompute our parent info
2d21ac55
A
1968 fParentsCurrentPowerFlags = 0;
1969 fParentsKnowState = true;
1c79356b
A
1970
1971 iter = getParentIterator(gIOPowerPlane);
2d21ac55 1972 if ( iter )
55e303ae 1973 {
2d21ac55 1974 while ( (next = iter->getNextObject()) )
55e303ae 1975 {
2d21ac55 1976 if ( (conn = OSDynamicCast(IOPowerConnection, next)) )
55e303ae 1977 {
2d21ac55
A
1978 fParentsKnowState &= conn->parentKnowsState();
1979 fParentsCurrentPowerFlags |= conn->parentCurrentPowerFlags();
1c79356b
A
1980 }
1981 }
1982 iter->release();
1983 }
1c79356b
A
1984}
1985
90556fb8 1986//*********************************************************************************
2d21ac55 1987// [private] rebuildChildClampBits
90556fb8
A
1988//
1989// The ChildClamp bits (kIOPMChildClamp & kIOPMChildClamp2) in our capabilityFlags
2d21ac55
A
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.
90556fb8
A
1994//*********************************************************************************
1995
2d21ac55 1996void IOService::rebuildChildClampBits ( void )
90556fb8 1997{
2d21ac55
A
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.
90556fb8 2006
2d21ac55 2007 for ( i = 0; i < fNumberOfPowerStates; i++ )
55e303ae 2008 {
2d21ac55 2009 fPowerStates[i].capabilityFlags &= ~(kIOPMChildClamp | kIOPMChildClamp2);
90556fb8
A
2010 }
2011
b0d623f7
A
2012 if (!inPlane(gIOPowerPlane))
2013 return;
2014
2d21ac55
A
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.
90556fb8
A
2018
2019 iter = getChildIterator(gIOPowerPlane);
2d21ac55 2020 if ( iter )
90556fb8 2021 {
2d21ac55 2022 while ( (next = iter->getNextObject()) )
90556fb8 2023 {
2d21ac55 2024 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
90556fb8 2025 {
2d21ac55
A
2026 if (connection->getReadyFlag() == false)
2027 {
6d2010ae 2028 PM_LOG3("[%s] %s: connection not ready\n",
2d21ac55
A
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 }
90556fb8
A
2041 }
2042 }
2043 iter->release();
2044 }
90556fb8
A
2045}
2046
1c79356b 2047//*********************************************************************************
b0d623f7 2048// [public] requestPowerDomainState
1c79356b 2049//
7e4a7d39 2050// Called on a power parent when a child's power requirement changes.
1c79356b 2051//*********************************************************************************
2d21ac55 2052
7e4a7d39
A
2053IOReturn IOService::requestPowerDomainState(
2054 IOPMPowerFlags childRequestPowerFlags,
2055 IOPowerConnection * childConnection,
2056 unsigned long specification )
1c79356b 2057{
6d2010ae 2058 IOPMPowerStateIndex ps;
7e4a7d39
A
2059 IOPMPowerFlags outputPowerFlags;
2060 IOService * child;
2061 IOPMRequest * subRequest;
2062 bool preventIdle, preventSleep;
2063 bool adjustPower = false;
2d21ac55
A
2064
2065 if (!initialized)
2066 return IOPMNotYetInitialized;
2067
2068 if (gIOPMWorkLoop->onThread() == false)
2069 {
6d2010ae 2070 PM_LOG("%s::requestPowerDomainState\n", getName());
2d21ac55
A
2071 return kIOReturnSuccess;
2072 }
1c79356b 2073
7e4a7d39 2074 OUR_PMLog(kPMLogRequestDomain, childRequestPowerFlags, specification);
1c79356b 2075
7e4a7d39 2076 if (!isChild(childConnection, gIOPowerPlane))
2d21ac55
A
2077 return kIOReturnNotAttached;
2078
7e4a7d39 2079 if (!fControllingDriver || !fNumberOfPowerStates)
6d2010ae 2080 return kIOReturnNotReady;
2d21ac55 2081
7e4a7d39 2082 child = (IOService *) childConnection->getChildEntry(gIOPowerPlane);
2d21ac55 2083 assert(child);
1c79356b 2084
7e4a7d39
A
2085 preventIdle = ((childRequestPowerFlags & kIOPMPreventIdleSleep) != 0);
2086 preventSleep = ((childRequestPowerFlags & kIOPMPreventSystemSleep) != 0);
2087 childRequestPowerFlags &= ~(kIOPMPreventIdleSleep | kIOPMPreventSystemSleep);
1c79356b 2088
7e4a7d39
A
2089 // Merge in the power flags contributed by this power parent
2090 // at its current or impending power state.
1c79356b 2091
6d2010ae 2092 outputPowerFlags = fPowerStates[fCurrentPowerState].outputPowerFlags;
060df5ea 2093 if (fMachineState != kIOPM_Finished)
7e4a7d39 2094 {
6d2010ae 2095 if (IS_POWER_DROP && !IS_ROOT_DOMAIN)
7e4a7d39
A
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
6d2010ae 2106 // re-evaluate the parent's power state.
7e4a7d39
A
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
6d2010ae 2116 PM_LOG1("%s: power drop cancelled in state %u by %s\n",
7e4a7d39
A
2117 getName(), fMachineState, child->getName());
2118 }
2119 else
2120 {
2121 // Beyond cancellation point, report the impending state.
2122 outputPowerFlags =
6d2010ae 2123 fPowerStates[fHeadNotePowerState].outputPowerFlags;
7e4a7d39
A
2124 }
2125 }
060df5ea 2126 else if (IS_POWER_RISE)
7e4a7d39
A
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;
1c79356b 2140
7e4a7d39 2141 // Map child's requested power flags to one of our power state.
1c79356b 2142
7e4a7d39
A
2143 for (ps = 0; ps < fNumberOfPowerStates; ps++)
2144 {
6d2010ae 2145 if ((fPowerStates[ps].outputPowerFlags & childRequestPowerFlags) ==
7e4a7d39
A
2146 (fOutputPowerCharacterFlags & childRequestPowerFlags))
2147 break;
2148 }
2149 if (ps >= fNumberOfPowerStates)
2150 {
2151 ps = 0; // should never happen
1c79356b
A
2152 }
2153
7e4a7d39
A
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 {
6d2010ae 2167 PM_LOG("requestPowerDomainState[%s]: %s, init %d, %u->%u\n",
7e4a7d39
A
2168 getName(), child->getName(),
2169 !childConnection->childHasRequestedPower(),
2170 (uint32_t) childConnection->getDesiredDomainState(),
2171 (uint32_t) ps);
2172 }
2173#endif
0b4e3aa0 2174
2d21ac55 2175 // Record the child's desires on the connection.
593a1d5f 2176#if SUPPORT_IDLE_CANCEL
7e4a7d39 2177 bool attemptCancel = (preventIdle && !childConnection->getPreventIdleSleepFlag());
593a1d5f 2178#endif
7e4a7d39
A
2179 childConnection->setChildHasRequestedPower();
2180 childConnection->setDesiredDomainState( ps );
2181 childConnection->setPreventIdleSleepFlag( preventIdle );
2182 childConnection->setPreventSystemSleepFlag( preventSleep );
2d21ac55 2183
b0d623f7
A
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.
2d21ac55 2187
6d2010ae 2188 if (adjustPower && !fDeviceOverrideEnabled &&
7e4a7d39 2189 (!fAdjustPowerScheduled || gIOPMRequest->getRootRequest()))
b0d623f7 2190 {
7e4a7d39
A
2191 subRequest = acquirePMRequest(
2192 this, kIOPMRequestTypeAdjustPowerState, gIOPMRequest );
2193 if (subRequest)
2d21ac55 2194 {
7e4a7d39 2195 submitPMRequest( subRequest );
b0d623f7 2196 fAdjustPowerScheduled = true;
2d21ac55 2197 }
7e4a7d39
A
2198 }
2199
593a1d5f
A
2200#if SUPPORT_IDLE_CANCEL
2201 if (attemptCancel)
2202 {
7e4a7d39
A
2203 subRequest = acquirePMRequest( this, kIOPMRequestTypeIdleCancel );
2204 if (subRequest)
593a1d5f 2205 {
7e4a7d39 2206 submitPMRequest( subRequest );
593a1d5f
A
2207 }
2208 }
2209#endif
1c79356b 2210
7e4a7d39 2211 return kIOReturnSuccess;
2d21ac55 2212}
1c79356b
A
2213
2214//*********************************************************************************
b0d623f7 2215// [public] temporaryPowerClampOn
1c79356b
A
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
2223IOReturn IOService::temporaryPowerClampOn ( void )
2224{
b0d623f7 2225 return requestPowerState( gIOPMPowerClientChildProxy, kIOPMPowerStateMax );
1c79356b
A
2226}
2227
1c79356b 2228//*********************************************************************************
b0d623f7 2229// [public] makeUsable
1c79356b
A
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
2240IOReturn IOService::makeUsable ( void )
2241{
2d21ac55 2242 OUR_PMLog(kPMLogMakeUsable, 0, 0);
b0d623f7
A
2243 return requestPowerState( gIOPMPowerClientDevice, kIOPMPowerStateMax );
2244}
2d21ac55 2245
b0d623f7
A
2246//*********************************************************************************
2247// [public] currentCapability
2248//*********************************************************************************
2d21ac55 2249
b0d623f7
A
2250IOPMPowerFlags IOService::currentCapability ( void )
2251{
2252 if (!initialized)
2253 return IOPMNotPowerManaged;
2254
2255 return fCurrentCapabilityFlags;
1c79356b
A
2256}
2257
2d21ac55 2258//*********************************************************************************
b0d623f7 2259// [public] changePowerStateTo
0c530ab8 2260//
b0d623f7
A
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.
2d21ac55 2264//*********************************************************************************
0c530ab8 2265
b0d623f7 2266IOReturn IOService::changePowerStateTo ( unsigned long ordinal )
0c530ab8 2267{
b0d623f7
A
2268 OUR_PMLog(kPMLogChangeStateTo, ordinal, 0);
2269 return requestPowerState( gIOPMPowerClientDriver, ordinal );
0c530ab8
A
2270}
2271
1c79356b 2272//*********************************************************************************
b0d623f7
A
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.
1c79356b
A
2278//*********************************************************************************
2279
b0d623f7 2280IOReturn IOService::changePowerStateToPriv ( unsigned long ordinal )
1c79356b 2281{
b0d623f7
A
2282 OUR_PMLog(kPMLogChangeStateToPriv, ordinal, 0);
2283 return requestPowerState( gIOPMPowerClientDevice, ordinal );
2d21ac55 2284}
1c79356b
A
2285
2286//*********************************************************************************
b0d623f7 2287// [protected] changePowerStateWithOverrideTo
1c79356b 2288//
b0d623f7
A
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.
1c79356b
A
2293//*********************************************************************************
2294
b0d623f7 2295IOReturn IOService::changePowerStateWithOverrideTo ( unsigned long ordinal )
1c79356b 2296{
2d21ac55 2297 IOPMRequest * request;
1c79356b 2298
2d21ac55 2299 if (!initialized)
b0d623f7 2300 return kIOPMNotYetInitialized;
2d21ac55 2301
b0d623f7 2302 OUR_PMLog(kPMLogChangeStateToPriv, ordinal, 0);
2d21ac55 2303
b0d623f7 2304 request = acquirePMRequest( this, kIOPMRequestTypeRequestPowerStateOverride );
2d21ac55
A
2305 if (!request)
2306 return kIOReturnNoMemory;
2307
b0d623f7
A
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
1c79356b 2316
b0d623f7
A
2317 // Prevent needless downwards power transitions by clamping power
2318 // until the scheduled request is executed.
2d21ac55 2319
b0d623f7 2320 if (gIOPMWorkLoop->inGate() && (ordinal < fNumberOfPowerStates))
2d21ac55
A
2321 {
2322 fTempClampPowerState = max(fTempClampPowerState, ordinal);
2323 fTempClampCount++;
6d2010ae
A
2324 fOverrideMaxPowerState = ordinal;
2325 request->fArg2 = (void *) (uintptr_t) true;
2d21ac55
A
2326 }
2327
2328 submitPMRequest( request );
1c79356b
A
2329 return IOPMNoErr;
2330}
2331
2332//*********************************************************************************
b0d623f7 2333// [private] requestPowerState
1c79356b
A
2334//*********************************************************************************
2335
b0d623f7
A
2336IOReturn IOService::requestPowerState (
2337 const OSSymbol * client,
2338 uint32_t state )
1c79356b 2339{
2d21ac55 2340 IOPMRequest * request;
1c79356b 2341
b0d623f7
A
2342 if (!client)
2343 return kIOReturnBadArgument;
2d21ac55 2344 if (!initialized)
b0d623f7 2345 return kIOPMNotYetInitialized;
2d21ac55 2346
b0d623f7 2347 request = acquirePMRequest( this, kIOPMRequestTypeRequestPowerState );
2d21ac55
A
2348 if (!request)
2349 return kIOReturnNoMemory;
2350
b0d623f7
A
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
2d21ac55 2359
b0d623f7
A
2360 // Prevent needless downwards power transitions by clamping power
2361 // until the scheduled request is executed.
2d21ac55 2362
b0d623f7 2363 if (gIOPMWorkLoop->inGate() && (state < fNumberOfPowerStates))
2d21ac55 2364 {
b0d623f7 2365 fTempClampPowerState = max(fTempClampPowerState, state);
2d21ac55 2366 fTempClampCount++;
6d2010ae 2367 request->fArg2 = (void *) (uintptr_t) true;
2d21ac55 2368 }
1c79356b 2369
2d21ac55 2370 submitPMRequest( request );
1c79356b
A
2371 return IOPMNoErr;
2372}
2373
2d21ac55 2374//*********************************************************************************
b0d623f7 2375// [private] handleRequestPowerState
2d21ac55
A
2376//*********************************************************************************
2377
b0d623f7 2378void IOService::handleRequestPowerState ( IOPMRequest * request )
2d21ac55 2379{
b0d623f7
A
2380 const OSSymbol * client = (const OSSymbol *) request->fArg1;
2381 uint32_t state = (uint32_t)(uintptr_t) request->fArg0;
2d21ac55
A
2382
2383 PM_ASSERT_IN_GATE();
b0d623f7 2384 if (request->fArg2)
2d21ac55
A
2385 {
2386 assert(fTempClampCount != 0);
b0d623f7
A
2387 if (fTempClampCount) fTempClampCount--;
2388 if (!fTempClampCount) fTempClampPowerState = 0;
2d21ac55
A
2389 }
2390
b0d623f7
A
2391 if (fNumberOfPowerStates && (state >= fNumberOfPowerStates))
2392 state = fNumberOfPowerStates - 1;
2393
6d2010ae
A
2394 // The power suppression due to changePowerStateWithOverrideTo() expires
2395 // upon the next "device" power request - changePowerStateToPriv().
b0d623f7
A
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
2417void 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
2438void IOService::removePowerClient( const OSSymbol * client )
2439{
2440 if (fPowerClients && client)
2441 fPowerClients->removeObject(client);
2442}
2443
2444uint32_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;
2d21ac55 2454}
1c79356b 2455
6d2010ae
A
2456//*********************************************************************************
2457// [protected] powerOverrideOnPriv
2458//*********************************************************************************
2459
2460IOReturn 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
2485IOReturn 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
2510void 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
1c79356b 2527//*********************************************************************************
2d21ac55 2528// [private] computeDesiredState
1c79356b
A
2529//*********************************************************************************
2530
b0d623f7 2531void IOService::computeDesiredState ( unsigned long localClamp )
1c79356b 2532{
2d21ac55
A
2533 OSIterator * iter;
2534 OSObject * next;
2535 IOPowerConnection * connection;
b0d623f7
A
2536 uint32_t desiredState = 0;
2537 uint32_t newPowerState = 0;
2538 bool hasChildren = false;
2d21ac55 2539
b0d623f7 2540 // Desired power state is always 0 without a controlling driver.
2d21ac55 2541
b0d623f7
A
2542 if (!fNumberOfPowerStates)
2543 {
2544 fDesiredPowerState = 0;
6d2010ae 2545 //PM_LOG("%s::%s no controlling driver\n", getName(), __FUNCTION__);
b0d623f7
A
2546 return;
2547 }
2d21ac55 2548
b0d623f7 2549 // Examine the children's desired power state.
1c79356b 2550
b0d623f7
A
2551 iter = getChildIterator(gIOPowerPlane);
2552 if (iter)
55e303ae 2553 {
b0d623f7 2554 while ((next = iter->getNextObject()))
55e303ae 2555 {
b0d623f7 2556 if ((connection = OSDynamicCast(IOPowerConnection, next)))
55e303ae 2557 {
b0d623f7 2558 if (connection->getReadyFlag() == false)
55e303ae 2559 {
6d2010ae 2560 PM_LOG3("[%s] %s: connection not ready\n",
b0d623f7
A
2561 getName(), __FUNCTION__);
2562 continue;
1c79356b 2563 }
b0d623f7
A
2564 if (connection->childHasRequestedPower())
2565 hasChildren = true;
2566 if (connection->getDesiredDomainState() > desiredState)
2567 desiredState = connection->getDesiredDomainState();
1c79356b 2568 }
1c79356b 2569 }
b0d623f7
A
2570 iter->release();
2571 }
2572 if (hasChildren)
2573 updatePowerClient(gIOPMPowerClientChildren, desiredState);
2574 else
2575 removePowerClient(gIOPMPowerClientChildren);
2d21ac55 2576
b0d623f7
A
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.
6d2010ae 2586 if ((fDeviceOverrideEnabled ||
b0d623f7
A
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);
6d2010ae 2598 PM_LOG1(" %u %s\n",
b0d623f7
A
2599 desiredState, client->getCStringNoCopy());
2600
2601 newPowerState = max(newPowerState, desiredState);
2602
2603 if (client == gIOPMPowerClientDevice)
2604 fDeviceDesire = desiredState;
2605 }
2606 iter->release();
1c79356b
A
2607 }
2608
b0d623f7
A
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);
2d21ac55 2617
2d21ac55
A
2618 // Limit check against number of power states.
2619
b0d623f7
A
2620 if (newPowerState >= fNumberOfPowerStates)
2621 newPowerState = fNumberOfPowerStates - 1;
2622
2623 fDesiredPowerState = newPowerState;
2624
6d2010ae 2625 PM_LOG1(" temp %u, clamp %u, current %u, new %u\n",
b0d623f7
A
2626 (uint32_t) localClamp, (uint32_t) fTempClampPowerState,
2627 (uint32_t) fCurrentPowerState, newPowerState);
1c79356b 2628
b0d623f7 2629 // Restart idle timer if stopped and device desire has increased.
2d21ac55 2630
b0d623f7 2631 if (fDeviceDesire && fIdleTimerStopped)
2d21ac55 2632 {
b0d623f7
A
2633 fIdleTimerStopped = false;
2634 fActivityTickleCount = 0;
2635 clock_get_uptime(&fIdleTimerStartTime);
2d21ac55
A
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
b0d623f7 2645 if ((getPMRequestType() != kIOPMRequestTypeActivityTickle) &&
2d21ac55
A
2646 (fActivityTicklePowerState != -1))
2647 {
2648 IOLockLock(fActivityLock);
2649 fActivityTicklePowerState = -1;
2650 IOLockUnlock(fActivityLock);
2651 }
2d21ac55 2652}
1c79356b
A
2653
2654//*********************************************************************************
b0d623f7 2655// [public] currentPowerConsumption
1c79356b
A
2656//
2657//*********************************************************************************
2658
2659unsigned long IOService::currentPowerConsumption ( void )
2660{
2d21ac55 2661 if (!initialized)
0b4e3aa0 2662 return kIOPMUnknown;
2d21ac55
A
2663
2664 return fCurrentPowerConsumption;
2665}
2666
2667//*********************************************************************************
b0d623f7 2668// [deprecated] getPMworkloop
2d21ac55
A
2669//*********************************************************************************
2670
2671IOWorkLoop * IOService::getPMworkloop ( void )
2672{
2673 return gIOPMWorkLoop;
1c79356b
A
2674}
2675
6d2010ae
A
2676#if NOT_YET
2677
1c79356b 2678//*********************************************************************************
6d2010ae
A
2679// Power Parent/Children Applier
2680//*********************************************************************************
2681
2682static void
2683applyToPowerChildren(
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
2716static void
2717applyToPowerParent(
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.
2d21ac55
A
2762// The tickle with parameter kIOPMSubclassPolicy is ignored here and
2763// should be intercepted by a subclass.
1c79356b
A
2764//*********************************************************************************
2765
55e303ae 2766bool IOService::activityTickle ( unsigned long type, unsigned long stateNumber )
1c79356b 2767{
2d21ac55
A
2768 IOPMRequest * request;
2769 bool noPowerChange = true;
e7c99d92 2770
2d21ac55
A
2771 if ( initialized && stateNumber && (type == kIOPMSuperclassPolicy1) )
2772 {
2773 IOLockLock(fActivityLock);
e7c99d92 2774
2d21ac55 2775 // Record device activity for the idle timer handler.
e7c99d92 2776
6d2010ae 2777 fDeviceWasActive = true;
b0d623f7 2778 fActivityTickleCount++;
2d21ac55 2779 clock_get_uptime(&fDeviceActiveTimestamp);
55e303ae 2780
6d2010ae 2781 PM_ACTION_0(actionActivityTickle);
b0d623f7 2782
2d21ac55
A
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.
1c79356b 2786
2d21ac55
A
2787 if (fActivityTicklePowerState < (long)stateNumber)
2788 {
2789 fActivityTicklePowerState = stateNumber;
2790 noPowerChange = false;
1c79356b 2791
2d21ac55
A
2792 request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
2793 if (request)
2794 {
2795 request->fArg0 = (void *) stateNumber; // power state
6d2010ae 2796 request->fArg1 = (void *) (uintptr_t) true; // power rise
2d21ac55
A
2797 submitPMRequest(request);
2798 }
2799 }
1c79356b 2800
2d21ac55
A
2801 IOLockUnlock(fActivityLock);
2802 }
1c79356b 2803
2d21ac55
A
2804 // Returns false if the activityTickle might cause a transition to a
2805 // higher powered state, true otherwise.
2806
2807 return noPowerChange;
2808}
1c79356b
A
2809
2810//*********************************************************************************
b0d623f7
A
2811// [private] handleActivityTickle
2812//*********************************************************************************
2813
2814void 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
6d2010ae 2845//******************************************************************************
b0d623f7 2846// [public] setIdleTimerPeriod
1c79356b 2847//
6d2010ae
A
2848// A subclass policy-maker is using our standard idleness detection service.
2849// Start the idle timer. Period is in seconds.
2850//******************************************************************************
1c79356b 2851
2d21ac55 2852IOReturn IOService::setIdleTimerPeriod ( unsigned long period )
1c79356b 2853{
b0d623f7 2854 if (!initialized)
2d21ac55
A
2855 return IOPMNotYetInitialized;
2856
6d2010ae 2857 OUR_PMLog(kPMLogSetIdleTimerPeriod, period, fIdleTimerPeriod);
1c79356b 2858
b0d623f7
A
2859 IOPMRequest * request =
2860 acquirePMRequest( this, kIOPMRequestTypeSetIdleTimerPeriod );
2861 if (!request)
2862 return kIOReturnNoMemory;
1c79356b 2863
b0d623f7
A
2864 request->fArg0 = (void *) period;
2865 submitPMRequest( request );
2d21ac55 2866
6d2010ae 2867 return kIOReturnSuccess;
1c79356b
A
2868}
2869
91447636 2870//******************************************************************************
b0d623f7 2871// [public] nextIdleTimeout
91447636
A
2872//
2873// Returns how many "seconds from now" the device should idle into its
2874// next lowest power state.
2875//******************************************************************************
2d21ac55 2876
91447636
A
2877SInt32 IOService::nextIdleTimeout(
2878 AbsoluteTime currentTime,
2879 AbsoluteTime lastActivity,
2880 unsigned int powerState)
2881{
6d2010ae
A
2882 AbsoluteTime delta;
2883 UInt64 delta_ns;
2884 SInt32 delta_secs;
2885 SInt32 delay_secs;
1c79356b 2886
91447636
A
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.
b0d623f7 2896 if (delta_secs < (int) fIdleTimerPeriod)
2d21ac55 2897 delay_secs = (int) fIdleTimerPeriod - delta_secs;
91447636 2898 else
2d21ac55 2899 delay_secs = (int) fIdleTimerPeriod;
91447636
A
2900
2901 return (SInt32)delay_secs;
2902}
2903
6d2010ae 2904//*********************************************************************************
b0d623f7 2905// [public] start_PM_idle_timer
6d2010ae 2906//*********************************************************************************
2d21ac55 2907
1c79356b
A
2908void IOService::start_PM_idle_timer ( void )
2909{
6d2010ae
A
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;
e7c99d92 2915
6d2010ae 2916 if (!initialized || !fIdleTimerPeriod)
2d21ac55
A
2917 return;
2918
2919 IOLockLock(fActivityLock);
e7c99d92
A
2920
2921 clock_get_uptime(&uptime);
6d2010ae 2922
91447636 2923 // Subclasses may modify idle sleep algorithm
2d21ac55 2924 idle_in = nextIdleTimeout(uptime, fDeviceActiveTimestamp, fCurrentPowerState);
e7c99d92 2925
91447636 2926 // Check for out-of range responses
2d21ac55 2927 if (idle_in > maxTimeout)
55e303ae 2928 {
91447636
A
2929 // use standard implementation
2930 idle_in = IOService::nextIdleTimeout(uptime,
2d21ac55
A
2931 fDeviceActiveTimestamp,
2932 fCurrentPowerState);
2933 } else if (idle_in < minTimeout) {
2934 idle_in = fIdleTimerPeriod;
e7c99d92
A
2935 }
2936
2d21ac55 2937 IOLockUnlock(fActivityLock);
e7c99d92 2938
6d2010ae
A
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
2950static void
2951idle_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();
1c79356b
A
2963}
2964
1c79356b 2965//*********************************************************************************
b0d623f7 2966// [private] idleTimerExpired
1c79356b 2967//
6d2010ae 2968// The idle timer has expired. If there has been activity since the last
1c79356b
A
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
6d2010ae 2973void IOService::idleTimerExpired( void )
1c79356b 2974{
2d21ac55
A
2975 IOPMRequest * request;
2976 bool restartTimer = true;
2977
b0d623f7 2978 if ( !initialized || !fIdleTimerPeriod || fLockedFlags.PMStop )
55e303ae 2979 return;
1c79356b 2980
2d21ac55 2981 IOLockLock(fActivityLock);
1c79356b 2982
2d21ac55 2983 // Check for device activity (tickles) over last timer period.
1c79356b 2984
6d2010ae 2985 if (fDeviceWasActive)
2d21ac55
A
2986 {
2987 // Device was active - do not drop power, restart timer.
6d2010ae 2988 fDeviceWasActive = false;
2d21ac55
A
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.
1c79356b 2996
2d21ac55
A
2997 if (fActivityTicklePowerState > 0)
2998 {
2999 fActivityTicklePowerState--;
3000 }
1c79356b 3001
2d21ac55
A
3002 request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
3003 if (request)
3004 {
3005 request->fArg0 = (void *) 0; // power state (irrelevant)
6d2010ae 3006 request->fArg1 = (void *) (uintptr_t) false; // power drop
2d21ac55 3007 submitPMRequest( request );
1c79356b 3008
2d21ac55
A
3009 // Do not restart timer until after the tickle request has been
3010 // processed.
91447636 3011
2d21ac55
A
3012 restartTimer = false;
3013 }
1c79356b 3014 }
2d21ac55
A
3015
3016 IOLockUnlock(fActivityLock);
3017
3018 if (restartTimer)
3019 start_PM_idle_timer();
1c79356b
A
3020}
3021
b0d623f7 3022#ifndef __LP64__
2d21ac55 3023//*********************************************************************************
b0d623f7
A
3024// [deprecated] PM_idle_timer_expiration
3025//*********************************************************************************
3026
3027void IOService::PM_idle_timer_expiration ( void )
3028{
3029}
3030
3031//*********************************************************************************
3032// [deprecated] command_received
2d21ac55
A
3033//*********************************************************************************
3034
3035void IOService::command_received ( void *statePtr , void *, void * , void * )
3036{
3037}
b0d623f7 3038#endif /* !__LP64__ */
1c79356b
A
3039
3040//*********************************************************************************
b0d623f7 3041// [public] setAggressiveness
1c79356b
A
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
3047IOReturn IOService::setAggressiveness ( unsigned long type, unsigned long newLevel )
3048{
b0d623f7 3049 return kIOReturnSuccess;
1c79356b
A
3050}
3051
3052//*********************************************************************************
b0d623f7 3053// [public] getAggressiveness
1c79356b
A
3054//
3055// Called by the user client.
3056//*********************************************************************************
3057
3058IOReturn IOService::getAggressiveness ( unsigned long type, unsigned long * currentLevel )
3059{
b0d623f7 3060 IOPMrootDomain * rootDomain = getPMRootDomain();
55e303ae 3061
b0d623f7
A
3062 if (!rootDomain)
3063 return kIOReturnNotReady;
3064
3065 return rootDomain->getAggressiveness( type, currentLevel );
1c79356b
A
3066}
3067
3068//*********************************************************************************
2d21ac55
A
3069// [public] getPowerState
3070//
3071//*********************************************************************************
3072
3073UInt32 IOService::getPowerState ( void )
3074{
3075 if (!initialized)
3076 return 0;
3077
3078 return fCurrentPowerState;
3079}
3080
b0d623f7 3081#ifndef __LP64__
2d21ac55 3082//*********************************************************************************
b0d623f7 3083// [deprecated] systemWake
1c79356b
A
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
3089IOReturn IOService::systemWake ( void )
3090{
2d21ac55
A
3091 OSIterator * iter;
3092 OSObject * next;
3093 IOPowerConnection * connection;
3094 IOService * theChild;
1c79356b 3095
1c79356b 3096 iter = getChildIterator(gIOPowerPlane);
2d21ac55 3097 if ( iter )
55e303ae 3098 {
2d21ac55 3099 while ( (next = iter->getNextObject()) )
55e303ae 3100 {
2d21ac55 3101 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
55e303ae 3102 {
2d21ac55
A
3103 if (connection->getReadyFlag() == false)
3104 {
6d2010ae 3105 PM_LOG3("[%s] %s: connection not ready\n",
2d21ac55
A
3106 getName(), __FUNCTION__);
3107 continue;
3108 }
3109
0b4e3aa0 3110 theChild = (IOService *)connection->copyChildEntry(gIOPowerPlane);
2d21ac55 3111 if ( theChild )
55e303ae 3112 {
0b4e3aa0 3113 theChild->systemWake();
55e303ae 3114 theChild->release();
0b4e3aa0 3115 }
1c79356b
A
3116 }
3117 }
3118 iter->release();
3119 }
3120
2d21ac55 3121 if ( fControllingDriver != NULL )
55e303ae 3122 {
2d21ac55 3123 if ( fControllingDriver->didYouWakeSystem() )
55e303ae 3124 {
1c79356b
A
3125 makeUsable();
3126 }
3127 }
3128
3129 return IOPMNoErr;
3130}
3131
1c79356b 3132//*********************************************************************************
b0d623f7 3133// [deprecated] temperatureCriticalForZone
1c79356b
A
3134//*********************************************************************************
3135
3136IOReturn IOService::temperatureCriticalForZone ( IOService * whichZone )
3137{
2d21ac55
A
3138 IOService * theParent;
3139 IOService * theNub;
0b4e3aa0 3140
2d21ac55 3141 OUR_PMLog(kPMLogCriticalTemp, 0, 0);
1c79356b 3142
6d2010ae 3143 if ( inPlane(gIOPowerPlane) && !IS_PM_ROOT )
55e303ae 3144 {
0b4e3aa0 3145 theNub = (IOService *)copyParentEntry(gIOPowerPlane);
2d21ac55 3146 if ( theNub )
55e303ae 3147 {
0b4e3aa0
A
3148 theParent = (IOService *)theNub->copyParentEntry(gIOPowerPlane);
3149 theNub->release();
2d21ac55 3150 if ( theParent )
55e303ae 3151 {
0b4e3aa0
A
3152 theParent->temperatureCriticalForZone(whichZone);
3153 theParent->release();
3154 }
3155 }
1c79356b
A
3156 }
3157 return IOPMNoErr;
3158}
b0d623f7 3159#endif /* !__LP64__ */
1c79356b 3160
6d2010ae
A
3161// MARK: -
3162// MARK: Power Change (Common)
1c79356b
A
3163
3164//*********************************************************************************
b0d623f7 3165// [private] startPowerChange
6d2010ae
A
3166//
3167// All power state changes starts here.
1c79356b
A
3168//*********************************************************************************
3169
6d2010ae
A
3170IOReturn IOService::startPowerChange(
3171 IOPMPowerChangeFlags changeFlags,
3172 IOPMPowerStateIndex powerState,
3173 IOPMPowerFlags domainFlags,
3174 IOPowerConnection * parentConnection,
3175 IOPMPowerFlags parentFlags )
2d21ac55 3176{
2d21ac55
A
3177 PM_ASSERT_IN_GATE();
3178 assert( fMachineState == kIOPM_Finished );
b0d623f7 3179 assert( powerState < fNumberOfPowerStates );
2d21ac55 3180
b0d623f7 3181 if (powerState >= fNumberOfPowerStates)
55e303ae 3182 return IOPMAckImplied;
1c79356b 3183
6d2010ae
A
3184 fIsPreChange = true;
3185 PM_ACTION_2(actionPowerChangeOverride, &powerState, &changeFlags);
b7266188 3186
6d2010ae 3187 // Forks to either Driver or Parent initiated power change paths.
2d21ac55 3188
6d2010ae 3189 fHeadNoteChangeFlags = changeFlags;
b0d623f7
A
3190 fHeadNotePowerState = powerState;
3191 fHeadNotePowerArrayEntry = &fPowerStates[ powerState ];
3192 fHeadNoteParentConnection = NULL;
1c79356b 3193
6d2010ae 3194 if (changeFlags & kIOPMSelfInitiated)
2d21ac55 3195 {
b0d623f7
A
3196 if (changeFlags & kIOPMSynchronize)
3197 OurSyncStart();
3198 else
3199 OurChangeStart();
2d21ac55
A
3200 return 0;
3201 }
3202 else
3203 {
b0d623f7
A
3204 assert(changeFlags & kIOPMParentInitiated);
3205 fHeadNoteDomainFlags = domainFlags;
3206 fHeadNoteParentFlags = parentFlags;
3207 fHeadNoteParentConnection = parentConnection;
3208 return ParentChangeStart();
2d21ac55
A
3209 }
3210}
1c79356b 3211
2d21ac55
A
3212//*********************************************************************************
3213// [private] notifyInterestedDrivers
3214//*********************************************************************************
3215
3216bool IOService::notifyInterestedDrivers ( void )
3217{
6d2010ae
A
3218 IOPMinformee * informee;
3219 IOPMinformeeList * list = fInterestedDrivers;
3220 DriverCallParam * param;
3221 IOItemCount count;
2d21ac55 3222
6d2010ae
A
3223 PM_ASSERT_IN_GATE();
3224 assert( fDriverCallParamCount == 0 );
3225 assert( fHeadNotePendingAcks == 0 );
2d21ac55 3226
b0d623f7
A
3227 fHeadNotePendingAcks = 0;
3228
6d2010ae
A
3229 count = list->numberOfItems();
3230 if (!count)
3231 goto done; // no interested drivers
2d21ac55 3232
6d2010ae
A
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.
2d21ac55 3237
6d2010ae
A
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 }
2d21ac55 3248
6d2010ae
A
3249 param = IONew(DriverCallParam, count);
3250 if (!param)
3251 goto done; // no memory
2d21ac55 3252
6d2010ae
A
3253 fDriverCallParamPtr = (void *) param;
3254 fDriverCallParamSlots = count;
3255 }
2d21ac55 3256
6d2010ae
A
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();
2d21ac55 3264 informee = list->nextInList( informee );
6d2010ae 3265 }
2d21ac55 3266
6d2010ae
A
3267 fDriverCallParamCount = count;
3268 fHeadNotePendingAcks = count;
2d21ac55 3269
6d2010ae
A
3270 // Block state machine and wait for callout completion.
3271 assert(!fDriverCallBusy);
3272 fDriverCallBusy = true;
3273 thread_call_enter( fDriverCallEntry );
3274 return true;
2d21ac55
A
3275
3276done:
6d2010ae
A
3277 // Return false if there are no interested drivers or could not schedule
3278 // callout thread due to error.
3279 return false;
2d21ac55
A
3280}
3281
3282//*********************************************************************************
3283// [private] notifyInterestedDriversDone
3284//*********************************************************************************
3285
3286void IOService::notifyInterestedDriversDone ( void )
3287{
6d2010ae
A
3288 IOPMinformee * informee;
3289 IOItemCount count;
3290 DriverCallParam * param;
3291 IOReturn result;
2d21ac55
A
3292
3293 PM_ASSERT_IN_GATE();
6d2010ae
A
3294 assert( fDriverCallBusy == false );
3295 assert( fMachineState == kIOPM_DriverThreadCallDone );
3296
2d21ac55
A
3297 param = (DriverCallParam *) fDriverCallParamPtr;
3298 count = fDriverCallParamCount;
3299
2d21ac55
A
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 {
b0d623f7
A
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;
2d21ac55
A
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
6d2010ae
A
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.
2d21ac55 3357
6d2010ae
A
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 }
2d21ac55
A
3369}
3370
3371//*********************************************************************************
3372// [private] notifyChildren
3373//*********************************************************************************
3374
3375void IOService::notifyChildren ( void )
3376{
3377 OSIterator * iter;
3378 OSObject * next;
3379 IOPowerConnection * connection;
3380 OSArray * children = 0;
6d2010ae
A
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 }
1c79356b 3392
2d21ac55
A
3393 if (fStrictTreeOrder)
3394 children = OSArray::withCapacity(8);
1c79356b 3395
2d21ac55 3396 // Sum child power consumption in notifyChild()
b0d623f7 3397 fHeadNotePowerArrayEntry->staticPower = 0;
2d21ac55
A
3398
3399 iter = getChildIterator(gIOPowerPlane);
3400 if ( iter )
3401 {
3402 while ((next = iter->getNextObject()))
55e303ae 3403 {
2d21ac55
A
3404 if ((connection = OSDynamicCast(IOPowerConnection, next)))
3405 {
3406 if (connection->getReadyFlag() == false)
3407 {
6d2010ae 3408 PM_LOG3("[%s] %s: connection not ready\n",
2d21ac55
A
3409 getName(), __FUNCTION__);
3410 continue;
3411 }
3412
6d2010ae
A
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)
2d21ac55
A
3435 children->setObject( connection );
3436 else
6d2010ae 3437 notifyChild( connection );
2d21ac55 3438 }
1c79356b 3439 }
2d21ac55 3440 iter->release();
1c79356b
A
3441 }
3442
6d2010ae
A
3443 if (children && (children->getCount() == 0))
3444 {
3445 children->release();
3446 children = 0;
3447 }
2d21ac55
A
3448 if (children)
3449 {
6d2010ae
A
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 }
2d21ac55
A
3467 }
3468}
1c79356b 3469
2d21ac55 3470//*********************************************************************************
6d2010ae 3471// [private] notifyChildrenOrdered
2d21ac55 3472//*********************************************************************************
1c79356b 3473
6d2010ae 3474void IOService::notifyChildrenOrdered ( void )
2d21ac55
A
3475{
3476 PM_ASSERT_IN_GATE();
3477 assert(fNotifyChildArray);
6d2010ae 3478 assert(fMachineState == kIOPM_NotifyChildrenOrdered);
2d21ac55 3479
b0d623f7 3480 // Notify one child, wait for it to ack, then repeat for next child.
2d21ac55
A
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);
6d2010ae 3494 notifyChild( connection );
2d21ac55
A
3495 }
3496 else
3497 {
3498 fNotifyChildArray->release();
3499 fNotifyChildArray = 0;
6d2010ae
A
3500
3501 MS_POP(); // pushed by notifyChildren()
2d21ac55 3502 }
1c79356b
A
3503}
3504
6d2010ae
A
3505//*********************************************************************************
3506// [private] notifyChildrenDelayed
3507//*********************************************************************************
3508
3509void 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
1c79356b 3537//*********************************************************************************
2d21ac55 3538// [private] notifyAll
1c79356b
A
3539//*********************************************************************************
3540
6d2010ae 3541IOReturn IOService::notifyAll ( uint32_t nextMS )
1c79356b 3542{
2d21ac55 3543 // Save the next machine_state to be restored by notifyInterestedDriversDone()
1c79356b 3544
2d21ac55 3545 PM_ASSERT_IN_GATE();
6d2010ae 3546 MS_PUSH(nextMS);
2d21ac55 3547 fMachineState = kIOPM_DriverThreadCallDone;
6d2010ae 3548 fDriverCallReason = fIsPreChange ?
2d21ac55 3549 kDriverCallInformPreChange : kDriverCallInformPostChange;
6601e61a 3550
2d21ac55
A
3551 if (!notifyInterestedDrivers())
3552 notifyInterestedDriversDone();
55e303ae 3553
2d21ac55
A
3554 return IOPMWillAckLater;
3555}
0c530ab8 3556
2d21ac55
A
3557//*********************************************************************************
3558// [private, static] pmDriverCallout
3559//
3560// Thread call context
3561//*********************************************************************************
0c530ab8 3562
2d21ac55
A
3563IOReturn IOService::actionDriverCalloutDone (
3564 OSObject * target,
3565 void * arg0, void * arg1,
3566 void * arg2, void * arg3 )
3567{
6d2010ae 3568 IOServicePM * pwrMgt = (IOServicePM *) arg0;
0c530ab8 3569
6d2010ae
A
3570 assert( fDriverCallBusy );
3571 fDriverCallBusy = false;
1c79356b 3572
6d2010ae
A
3573 assert(gIOPMWorkQueue);
3574 gIOPMWorkQueue->signalWorkAvailable();
1c79356b 3575
6d2010ae 3576 return kIOReturnSuccess;
2d21ac55 3577}
1c79356b 3578
2d21ac55
A
3579void 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:
b0d623f7
A
3594 panic("IOService::pmDriverCallout bad machine state %x",
3595 from->fDriverCallReason);
2d21ac55
A
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
3609void IOService::driverSetPowerState ( void )
3610{
6d2010ae
A
3611 IOPMPowerStateIndex powerState;
3612 DriverCallParam * param;
3613 IOPMDriverCallEntry callEntry;
2d21ac55 3614 AbsoluteTime end;
6d2010ae
A
3615 IOReturn result;
3616 uint32_t oldPowerState = getPowerState();
2d21ac55 3617
6d2010ae
A
3618 assert( fDriverCallBusy );
3619 assert( fDriverCallParamPtr );
3620 assert( fDriverCallParamCount == 1 );
2d21ac55 3621
6d2010ae
A
3622 param = (DriverCallParam *) fDriverCallParamPtr;
3623 powerState = fHeadNotePowerState;
2d21ac55 3624
6d2010ae
A
3625 if (assertPMDriverCall(&callEntry))
3626 {
3627 OUR_PMLog( kPMLogProgramHardware, (uintptr_t) this, powerState);
2d21ac55 3628 clock_get_uptime(&fDriverCallStartTime);
6d2010ae 3629 result = fControllingDriver->setPowerState( powerState, this );
2d21ac55 3630 clock_get_uptime(&end);
6d2010ae
A
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 }
2d21ac55
A
3640
3641#if LOG_SETPOWER_TIMES
3642 if ((result == IOPMAckImplied) || (result < 0))
55e303ae 3643 {
2d21ac55 3644 uint64_t nsec;
0c530ab8 3645
2d21ac55
A
3646 SUB_ABSOLUTETIME(&end, &fDriverCallStartTime);
3647 absolutetime_to_nanoseconds(end, &nsec);
3648 if (nsec > LOG_SETPOWER_TIMES)
6d2010ae 3649 PM_LOG("%s::setPowerState(%p, %lu -> %lu) took %d ms\n",
2d21ac55 3650 fName, this, fCurrentPowerState, powerState, NS_TO_MS(nsec));
6d2010ae
A
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 );
1c79356b 3663 }
2d21ac55 3664#endif
6d2010ae
A
3665 }
3666 else
3667 result = kIOPMAckImplied;
1c79356b 3668
6d2010ae 3669 param->Result = result;
2d21ac55 3670}
55e303ae 3671
2d21ac55
A
3672//*********************************************************************************
3673// [private] driverInformPowerChange
3674//
3675// Thread call context
3676//*********************************************************************************
0c530ab8 3677
2d21ac55
A
3678void IOService::driverInformPowerChange ( void )
3679{
6d2010ae
A
3680 IOPMinformee * informee;
3681 IOService * driver;
3682 DriverCallParam * param;
3683 IOPMDriverCallEntry callEntry;
3684 IOPMPowerFlags powerFlags;
3685 IOPMPowerStateIndex powerState;
2d21ac55 3686 AbsoluteTime end;
6d2010ae
A
3687 IOReturn result;
3688 IOItemCount count;
2d21ac55 3689
6d2010ae
A
3690 assert( fDriverCallBusy );
3691 assert( fDriverCallParamPtr );
3692 assert( fDriverCallParamCount );
2d21ac55 3693
6d2010ae
A
3694 param = (DriverCallParam *) fDriverCallParamPtr;
3695 count = fDriverCallParamCount;
2d21ac55 3696
6d2010ae
A
3697 powerFlags = fHeadNotePowerArrayEntry->capabilityFlags;
3698 powerState = fHeadNotePowerState;
2d21ac55 3699
6d2010ae
A
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);
2d21ac55 3710 clock_get_uptime(&informee->startTime);
6d2010ae 3711 result = driver->powerStateWillChangeTo(powerFlags, powerState, this);
2d21ac55 3712 clock_get_uptime(&end);
6d2010ae
A
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);
2d21ac55
A
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)
6d2010ae 3734 PM_LOG("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) took %d ms\n",
2d21ac55
A
3735 driver->getName(),
3736 (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
3737 driver, fName, fCurrentPowerState, powerState, NS_TO_MS(nsec));
6d2010ae
A
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 );
2d21ac55
A
3754 }
3755#endif
6d2010ae
A
3756 }
3757 else
3758 result = kIOPMAckImplied;
0c530ab8 3759
6d2010ae
A
3760 param->Result = result;
3761 param++;
3762 }
1c79356b
A
3763}
3764
1c79356b 3765//*********************************************************************************
2d21ac55 3766// [private] notifyChild
1c79356b
A
3767//
3768// Notify a power domain child of an upcoming power change.
1c79356b
A
3769// If the object acknowledges the current change, we return TRUE.
3770//*********************************************************************************
3771
6d2010ae 3772bool IOService::notifyChild ( IOPowerConnection * theNub )
1c79356b 3773{
6d2010ae
A
3774 IOReturn ret = IOPMAckImplied;
3775 unsigned long childPower;
3776 IOService * theChild;
3777 IOPMRequest * childRequest;
3778 IOPMPowerChangeFlags requestArg2;
3779 int requestType;
2d21ac55
A
3780
3781 PM_ASSERT_IN_GATE();
3a60a9f5 3782 theChild = (IOService *)(theNub->copyChildEntry(gIOPowerPlane));
2d21ac55 3783 if (!theChild)
55e303ae 3784 {
2d21ac55 3785 assert(false);
0b4e3aa0 3786 return true;
55e303ae 3787 }
2d21ac55 3788
3a60a9f5
A
3789 // Unless the child handles the notification immediately and returns
3790 // kIOPMAckImplied, we'll be awaiting their acknowledgement later.
2d21ac55 3791 fHeadNotePendingAcks++;
3a60a9f5 3792 theNub->setAwaitingAck(true);
b0d623f7 3793
6d2010ae 3794 requestArg2 = fHeadNoteChangeFlags;
b0d623f7
A
3795 if (fHeadNotePowerState < fCurrentPowerState)
3796 requestArg2 |= kIOPMDomainPowerDrop;
3797
6d2010ae 3798 requestType = fIsPreChange ?
b0d623f7
A
3799 kIOPMRequestTypePowerDomainWillChange :
3800 kIOPMRequestTypePowerDomainDidChange;
2d21ac55
A
3801
3802 childRequest = acquirePMRequest( theChild, requestType );
3803 if (childRequest)
3804 {
cf7d32b8 3805 theNub->retain();
6d2010ae 3806 childRequest->fArg0 = (void *) fHeadNotePowerArrayEntry->outputPowerFlags;
2d21ac55 3807 childRequest->fArg1 = (void *) theNub;
b0d623f7 3808 childRequest->fArg2 = (void *) requestArg2;
2d21ac55 3809 theChild->submitPMRequest( childRequest );
b0d623f7 3810 ret = IOPMWillAckLater;
2d21ac55
A
3811 }
3812 else
3813 {
b0d623f7 3814 ret = IOPMAckImplied;
2d21ac55
A
3815 fHeadNotePendingAcks--;
3816 theNub->setAwaitingAck(false);
0b4e3aa0 3817 childPower = theChild->currentPowerConsumption();
2d21ac55 3818 if ( childPower == kIOPMUnknown )
55e303ae 3819 {
b0d623f7 3820 fHeadNotePowerArrayEntry->staticPower = kIOPMUnknown;
55e303ae 3821 } else {
b0d623f7
A
3822 if (fHeadNotePowerArrayEntry->staticPower != kIOPMUnknown )
3823 fHeadNotePowerArrayEntry->staticPower += childPower;
0b4e3aa0 3824 }
55e303ae 3825 }
55e303ae 3826
2d21ac55 3827 theChild->release();
b0d623f7 3828 return (IOPMAckImplied == ret);
1c79356b
A
3829}
3830
6d2010ae
A
3831//*********************************************************************************
3832// [private] notifyControllingDriver
3833//*********************************************************************************
3834
3835bool 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
3880void 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
3939void 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 {
7ee9d059
A
4022 if ((fHeadNoteChangeFlags & kIOPMPowerSuppressed) &&
4023 (fHeadNotePowerState != fCurrentPowerState) &&
4024 (fHeadNotePowerState == fDesiredPowerState))
4025 {
4026 // Power changed, and desired power state restored.
4027 // Clear any prior power desire while in suppressed state.
4028 requestDomainPower(fHeadNotePowerState);
4029 }
4030
6d2010ae
A
4031 // did power raise?
4032 if ( fCurrentPowerState < fHeadNotePowerState )
4033 {
4034 // yes, inform clients and apps
4035 tellChangeUp (fHeadNotePowerState);
4036 }
4037 // either way
4038 prevPowerState = fCurrentPowerState;
4039 fCurrentPowerState = fHeadNotePowerState;
4040#if PM_VARS_SUPPORT
4041 fPMVars->myCurrentState = fCurrentPowerState;
4042#endif
4043 fMaxPowerState = fControllingDriver->maxCapabilityForDomainState(fHeadNoteDomainFlags);
4044
4045 OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, 0);
4046 PM_ACTION_2(actionPowerChangeDone,
4047 fHeadNotePowerState, fHeadNoteChangeFlags);
4048 callAction = true;
4049
4050 powerStatePtr = &fPowerStates[fCurrentPowerState];
4051 fCurrentCapabilityFlags = powerStatePtr->capabilityFlags;
4052 if (fCurrentCapabilityFlags & kIOPMStaticPowerValid)
4053 fCurrentPowerConsumption = powerStatePtr->staticPower;
4054
4055 // inform subclass policy-maker
4056 if (fPCDFunctionOverride && fParentsKnowState &&
4057 assertPMDriverCall(&callEntry, kIOPMADC_NoInactiveCheck))
4058 {
4059 powerChangeDone(prevPowerState);
4060 deassertPMDriverCall(&callEntry);
4061 }
4062 }
4063 }
4064
4065 // When power rises enough to satisfy the tickle's desire for more power,
4066 // the condition preventing idle-timer from dropping power is removed.
4067
4068 if (fCurrentPowerState >= fIdleTimerMinPowerState)
4069 {
4070 fIdleTimerMinPowerState = 0;
4071 }
4072
4073 if (!callAction)
4074 {
4075 PM_ACTION_2(actionPowerChangeDone,
4076 fHeadNotePowerState, fHeadNoteChangeFlags);
4077 }
4078}
4079
7e4a7d39
A
4080// MARK: -
4081// MARK: Power Change Initiated by Driver
4082
4083//*********************************************************************************
4084// [private] OurChangeStart
4085//
4086// Begin the processing of a power change initiated by us.
4087//*********************************************************************************
4088
4089void IOService::OurChangeStart ( void )
4090{
4091 PM_ASSERT_IN_GATE();
4092 OUR_PMLog( kPMLogStartDeviceChange, fHeadNotePowerState, fCurrentPowerState );
4093
6d2010ae 4094 // fMaxPowerState is our maximum possible power state based on the current
7e4a7d39
A
4095 // power state of our parents. If we are trying to raise power beyond the
4096 // maximum, send an async request for more power to all parents.
4097
6d2010ae 4098 if (!IS_PM_ROOT && (fMaxPowerState < fHeadNotePowerState))
7e4a7d39 4099 {
6d2010ae 4100 fHeadNoteChangeFlags |= kIOPMNotDone;
7e4a7d39
A
4101 requestDomainPower(fHeadNotePowerState);
4102 OurChangeFinish();
4103 return;
4104 }
4105
4106 // Redundant power changes skips to the end of the state machine.
4107
6d2010ae 4108 if (!fInitialPowerChange && (fHeadNotePowerState == fCurrentPowerState))
7e4a7d39
A
4109 {
4110 OurChangeFinish();
4111 return;
4112 }
6d2010ae 4113 fInitialPowerChange = false;
7e4a7d39 4114
7e4a7d39
A
4115 // Change started, but may not complete...
4116 // Can be canceled (power drop) or deferred (power rise).
4117
6d2010ae 4118 PM_ACTION_2(actionPowerChangeStart, fHeadNotePowerState, &fHeadNoteChangeFlags);
7e4a7d39
A
4119
4120 // Two separate paths, depending if power is being raised or lowered.
4121 // Lowering power is subject to approval by clients of this service.
4122
4123 if (IS_POWER_DROP)
4124 {
7e4a7d39
A
4125 fDoNotPowerDown = false;
4126
6d2010ae
A
4127 // Ask for persmission to drop power state
4128 fMachineState = kIOPM_OurChangeTellClientsPowerDown;
7e4a7d39 4129 fOutOfBandParameter = kNotifyApps;
6d2010ae 4130 askChangeDown(fHeadNotePowerState);
7e4a7d39
A
4131 }
4132 else
4133 {
4134 // This service is raising power and parents are able to support the
4135 // new power state. However a parent may have already committed to
4136 // drop power, which might force this object to temporarily drop power.
4137 // This results in "oscillations" before the state machines converge
4138 // to a steady state.
4139 //
4140 // To prevent this, a child must make a power reservation against all
4141 // parents before raising power. If the reservation fails, indicating
4142 // that the child will be unable to sustain the higher power state,
4143 // then the child will signal the parent to adjust power, and the child
4144 // will defer its power change.
4145
7e4a7d39
A
4146 IOReturn ret;
4147
4148 // Reserve parent power necessary to achieve fHeadNotePowerState.
4149 ret = requestDomainPower( fHeadNotePowerState, kReserveDomainPower );
4150 if (ret != kIOReturnSuccess)
4151 {
4152 // Reservation failed, defer power rise.
6d2010ae 4153 fHeadNoteChangeFlags |= kIOPMNotDone;
7e4a7d39
A
4154 OurChangeFinish();
4155 return;
4156 }
6d2010ae
A
4157
4158 OurChangeTellCapabilityWillChange();
7e4a7d39
A
4159 }
4160}
4161
4162//*********************************************************************************
4163
4164struct IOPMRequestDomainPowerContext {
4165 IOService * child; // the requesting child
4166 IOPMPowerFlags requestPowerFlags; // power flags requested by child
4167};
4168
4169static void
4170requestDomainPowerApplier(
4171 IORegistryEntry * entry,
4172 void * inContext )
4173{
4174 IOPowerConnection * connection;
4175 IOService * parent;
4176 IOPMRequestDomainPowerContext * context;
4177
4178 if ((connection = OSDynamicCast(IOPowerConnection, entry)) == 0)
4179 return;
4180 parent = (IOService *) connection->copyParentEntry(gIOPowerPlane);
4181 if (!parent)
4182 return;
4183
4184 assert(inContext);
4185 context = (IOPMRequestDomainPowerContext *) inContext;
4186
4187 if (connection->parentKnowsState() && connection->getReadyFlag())
4188 {
4189 parent->requestPowerDomainState(
4190 context->requestPowerFlags,
4191 connection,
4192 IOPMLowestState);
4193 }
4194
4195 parent->release();
4196}
4197
4198//*********************************************************************************
4199// [private] requestDomainPower
4200//*********************************************************************************
4201
4202IOReturn IOService::requestDomainPower(
6d2010ae
A
4203 IOPMPowerStateIndex ourPowerState,
4204 IOOptionBits options )
7e4a7d39 4205{
6d2010ae 4206 const IOPMPSEntry * powerStateEntry;
7e4a7d39 4207 IOPMPowerFlags requestPowerFlags;
6d2010ae 4208 IOPMPowerStateIndex maxPowerState;
7e4a7d39
A
4209 IOPMRequestDomainPowerContext context;
4210
4211 PM_ASSERT_IN_GATE();
4212 assert(ourPowerState < fNumberOfPowerStates);
4213 if (ourPowerState >= fNumberOfPowerStates)
4214 return kIOReturnBadArgument;
6d2010ae 4215 if (IS_PM_ROOT)
7e4a7d39
A
4216 return kIOReturnSuccess;
4217
4218 // Fetch the input power flags for the requested power state.
4219 // Parent request is stated in terms of required power flags.
4220
4221 powerStateEntry = &fPowerStates[ourPowerState];
6d2010ae 4222 requestPowerFlags = powerStateEntry->inputPowerFlags;
7e4a7d39
A
4223
4224 if (powerStateEntry->capabilityFlags & (kIOPMChildClamp | kIOPMPreventIdleSleep))
4225 requestPowerFlags |= kIOPMPreventIdleSleep;
4226 if (powerStateEntry->capabilityFlags & (kIOPMChildClamp2 | kIOPMPreventSystemSleep))
4227 requestPowerFlags |= kIOPMPreventSystemSleep;
4228
4229 // Disregard the "previous request" for power reservation.
4230
4231 if (((options & kReserveDomainPower) == 0) &&
6d2010ae 4232 (fPreviousRequestPowerFlags == requestPowerFlags))
7e4a7d39
A
4233 {
4234 // skip if domain already knows our requirements
4235 goto done;
4236 }
6d2010ae 4237 fPreviousRequestPowerFlags = requestPowerFlags;
7e4a7d39
A
4238
4239 context.child = this;
4240 context.requestPowerFlags = requestPowerFlags;
4241 fHeadNoteDomainTargetFlags = 0;
4242 applyToParents(requestDomainPowerApplier, &context, gIOPowerPlane);
4243
4244 if (options & kReserveDomainPower)
4245 {
4246 maxPowerState = fControllingDriver->maxCapabilityForDomainState(
4247 fHeadNoteDomainTargetFlags );
4248
4249 if (maxPowerState < fHeadNotePowerState)
4250 {
6d2010ae 4251 PM_LOG1("%s: power desired %u:0x%x got %u:0x%x\n",
7e4a7d39
A
4252 getName(),
4253 (uint32_t) ourPowerState, (uint32_t) requestPowerFlags,
4254 (uint32_t) maxPowerState, (uint32_t) fHeadNoteDomainTargetFlags);
4255 return kIOReturnNoPower;
4256 }
4257 }
4258
4259done:
4260 return kIOReturnSuccess;
4261}
4262
4263//*********************************************************************************
4264// [private] OurSyncStart
4265//*********************************************************************************
4266
4267void IOService::OurSyncStart ( void )
4268{
4269 PM_ASSERT_IN_GATE();
4270
6d2010ae 4271 if (fInitialPowerChange)
7e4a7d39
A
4272 return;
4273
6d2010ae
A
4274 PM_ACTION_2(actionPowerChangeStart, fHeadNotePowerState, &fHeadNoteChangeFlags);
4275
4276 if (fHeadNoteChangeFlags & kIOPMNotDone)
4277 {
4278 OurChangeFinish();
4279 return;
4280 }
7e4a7d39 4281
6d2010ae
A
4282 if (fHeadNoteChangeFlags & kIOPMSyncTellPowerDown)
4283 {
4284 fDoNotPowerDown = false;
7e4a7d39 4285
6d2010ae
A
4286 // Ask for permission to drop power state
4287 fMachineState = kIOPM_SyncTellClientsPowerDown;
4288 fOutOfBandParameter = kNotifyApps;
4289 askChangeDown(fHeadNotePowerState);
4290 }
4291 else
4292 {
4293 // Only inform capability app and clients.
4294 tellSystemCapabilityChange( kIOPM_SyncNotifyWillChange );
4295 }
7e4a7d39
A
4296}
4297
1c79356b 4298//*********************************************************************************
2d21ac55 4299// [private] OurChangeTellClientsPowerDown
1c79356b 4300//
6d2010ae
A
4301// All applications and kernel clients have acknowledged our permission to drop
4302// power. Here we notify them that we will lower the power and wait for acks.
1c79356b
A
4303//*********************************************************************************
4304
55e303ae 4305void IOService::OurChangeTellClientsPowerDown ( void )
0b4e3aa0 4306{
2d21ac55 4307 fMachineState = kIOPM_OurChangeTellPriorityClientsPowerDown;
b0d623f7 4308 tellChangeDown1(fHeadNotePowerState);
0b4e3aa0
A
4309}
4310
0b4e3aa0 4311//*********************************************************************************
2d21ac55 4312// [private] OurChangeTellPriorityClientsPowerDown
0b4e3aa0 4313//
6d2010ae
A
4314// All applications and kernel clients have acknowledged our intention to drop
4315// power. Here we notify "priority" clients that we are lowering power.
0b4e3aa0
A
4316//*********************************************************************************
4317
55e303ae 4318void IOService::OurChangeTellPriorityClientsPowerDown ( void )
1c79356b 4319{
2d21ac55 4320 fMachineState = kIOPM_OurChangeNotifyInterestedDriversWillChange;
b0d623f7 4321 tellChangeDown2(fHeadNotePowerState);
1c79356b
A
4322}
4323
6d2010ae
A
4324//*********************************************************************************
4325// [private] OurChangeTellCapabilityWillChange
4326//
4327// Extra stage for root domain to notify apps and drivers about the
4328// system capability change when raising power state.
4329//*********************************************************************************
4330
4331void IOService::OurChangeTellCapabilityWillChange ( void )
4332{
4333 if (!IS_ROOT_DOMAIN)
4334 return OurChangeNotifyInterestedDriversWillChange();
4335
4336 tellSystemCapabilityChange( kIOPM_OurChangeNotifyInterestedDriversWillChange );
4337}
4338
1c79356b 4339//*********************************************************************************
2d21ac55 4340// [private] OurChangeNotifyInterestedDriversWillChange
1c79356b 4341//
6d2010ae
A
4342// All applications and kernel clients have acknowledged our power state change.
4343// Here we notify interested drivers pre-change.
1c79356b
A
4344//*********************************************************************************
4345
55e303ae 4346void IOService::OurChangeNotifyInterestedDriversWillChange ( void )
1c79356b 4347{
6d2010ae 4348 IOPMrootDomain * rootDomain;
b0d623f7
A
4349 if ((rootDomain = getPMRootDomain()) == this)
4350 {
6d2010ae
A
4351 if (IS_POWER_DROP)
4352 {
4353 rootDomain->tracePoint( kIOPMTracePointSleepWillChangeInterests );
4354
4355 PMEventDetails *details = PMEventDetails::eventDetails(
4356 kIOPMEventTypeAppNotificationsFinished,
4357 NULL,
4358 100,
4359 kIOReturnSuccess);
4360 rootDomain->recordAndReleasePMEventGated( details );
4361 }
4362 else
4363 rootDomain->tracePoint( kIOPMTracePointWakeWillChangeInterests );
b0d623f7
A
4364 }
4365
6d2010ae 4366 notifyAll( kIOPM_OurChangeSetPowerState );
1c79356b
A
4367}
4368
1c79356b 4369//*********************************************************************************
2d21ac55 4370// [private] OurChangeSetPowerState
1c79356b 4371//
6d2010ae
A
4372// Instruct our controlling driver to program the hardware for the power state
4373// change. Wait for async completions.
1c79356b
A
4374//*********************************************************************************
4375
55e303ae 4376void IOService::OurChangeSetPowerState ( void )
1c79356b 4377{
6d2010ae
A
4378 MS_PUSH( kIOPM_OurChangeWaitForPowerSettle );
4379 fMachineState = kIOPM_DriverThreadCallDone;
4380 fDriverCallReason = kDriverCallSetPowerState;
55e303ae 4381
6d2010ae
A
4382 if (notifyControllingDriver() == false)
4383 notifyControllingDriverDone();
1c79356b
A
4384}
4385
1c79356b 4386//*********************************************************************************
2d21ac55 4387// [private] OurChangeWaitForPowerSettle
1c79356b 4388//
6d2010ae
A
4389// Our controlling driver has completed the power state change we initiated.
4390// Wait for the driver specified settle time to expire.
1c79356b
A
4391//*********************************************************************************
4392
6d2010ae 4393void IOService::OurChangeWaitForPowerSettle ( void )
1c79356b 4394{
6d2010ae 4395 fMachineState = kIOPM_OurChangeNotifyInterestedDriversDidChange;
7e4a7d39 4396 startSettleTimer();
1c79356b
A
4397}
4398
1c79356b 4399//*********************************************************************************
2d21ac55 4400// [private] OurChangeNotifyInterestedDriversDidChange
1c79356b 4401//
6d2010ae
A
4402// Power has settled on a power change we initiated. Here we notify
4403// all our interested drivers post-change.
1c79356b
A
4404//*********************************************************************************
4405
55e303ae 4406void IOService::OurChangeNotifyInterestedDriversDidChange ( void )
1c79356b 4407{
6d2010ae
A
4408 IOPMrootDomain * rootDomain;
4409 if ((rootDomain = getPMRootDomain()) == this)
4410 {
4411 rootDomain->tracePoint( IS_POWER_DROP ?
4412 kIOPMTracePointSleepDidChangeInterests :
4413 kIOPMTracePointWakeDidChangeInterests );
4414 }
4415
4416 notifyAll( kIOPM_OurChangeTellCapabilityDidChange );
4417}
4418
4419//*********************************************************************************
4420// [private] OurChangeTellCapabilityDidChange
4421//
4422// For root domain to notify capability power-change.
4423//*********************************************************************************
4424
4425void IOService::OurChangeTellCapabilityDidChange ( void )
4426{
4427 if (!IS_ROOT_DOMAIN)
4428 return OurChangeFinish();
4429
4430 getPMRootDomain()->tracePoint( IS_POWER_DROP ?
4431 kIOPMTracePointSleepCapabilityClients :
4432 kIOPMTracePointWakeCapabilityClients );
4433
4434 tellSystemCapabilityChange( kIOPM_OurChangeFinish );
1c79356b
A
4435}
4436
1c79356b 4437//*********************************************************************************
2d21ac55 4438// [private] OurChangeFinish
1c79356b 4439//
6d2010ae 4440// Done with this self-induced power state change.
1c79356b
A
4441//*********************************************************************************
4442
55e303ae 4443void IOService::OurChangeFinish ( void )
1c79356b
A
4444{
4445 all_done();
4446}
4447
7e4a7d39
A
4448// MARK: -
4449// MARK: Power Change Initiated by Parent
0b4e3aa0 4450
1c79356b 4451//*********************************************************************************
7e4a7d39 4452// [private] ParentChangeStart
1c79356b 4453//
7e4a7d39 4454// Here we begin the processing of a power change initiated by our parent.
1c79356b
A
4455//*********************************************************************************
4456
7e4a7d39 4457IOReturn IOService::ParentChangeStart ( void )
1c79356b 4458{
7e4a7d39
A
4459 PM_ASSERT_IN_GATE();
4460 OUR_PMLog( kPMLogStartParentChange, fHeadNotePowerState, fCurrentPowerState );
4461
4462 // Power domain is lowering power
4463 if ( fHeadNotePowerState < fCurrentPowerState )
b0d623f7 4464 {
7e4a7d39
A
4465 // TODO: redundant? See handlePowerDomainWillChangeTo()
4466 setParentInfo( fHeadNoteParentFlags, fHeadNoteParentConnection, true );
b0d623f7 4467
6d2010ae 4468 PM_ACTION_2(actionPowerChangeStart, fHeadNotePowerState, &fHeadNoteChangeFlags);
1c79356b 4469
6d2010ae
A
4470 // Tell apps and kernel clients
4471 fInitialPowerChange = false;
4472 fMachineState = kIOPM_ParentChangeTellPriorityClientsPowerDown;
7e4a7d39
A
4473 tellChangeDown1(fHeadNotePowerState);
4474 return IOPMWillAckLater;
4475 }
4476
4477 // Power domain is raising power
4478 if ( fHeadNotePowerState > fCurrentPowerState )
4479 {
4480 if ( fDesiredPowerState > fCurrentPowerState )
4481 {
4482 if ( fDesiredPowerState < fHeadNotePowerState )
4483 {
4484 // We power up, but not all the way
4485 fHeadNotePowerState = fDesiredPowerState;
4486 fHeadNotePowerArrayEntry = &fPowerStates[fDesiredPowerState];
4487 OUR_PMLog(kPMLogAmendParentChange, fHeadNotePowerState, 0);
4488 }
4489 } else {
4490 // We don't need to change
4491 fHeadNotePowerState = fCurrentPowerState;
4492 fHeadNotePowerArrayEntry = &fPowerStates[fCurrentPowerState];
4493 OUR_PMLog(kPMLogAmendParentChange, fHeadNotePowerState, 0);
4494 }
4495 }
4496
6d2010ae 4497 if ( fHeadNoteChangeFlags & kIOPMDomainDidChange )
7e4a7d39
A
4498 {
4499 if ( fHeadNotePowerState > fCurrentPowerState )
4500 {
6d2010ae
A
4501 PM_ACTION_2(actionPowerChangeStart,
4502 fHeadNotePowerState, &fHeadNoteChangeFlags);
7e4a7d39
A
4503
4504 // Parent did change up - start our change up
6d2010ae
A
4505 fInitialPowerChange = false;
4506 ParentChangeTellCapabilityWillChange();
7e4a7d39
A
4507 return IOPMWillAckLater;
4508 }
6d2010ae 4509 else if (fHeadNoteChangeFlags & kIOPMSynchronize)
7e4a7d39
A
4510 {
4511 // We do not need to change power state, but notify
4512 // children to propagate tree synchronization.
4513 fMachineState = kIOPM_SyncNotifyDidChange;
4514 fDriverCallReason = kDriverCallInformPreChange;
4515 notifyChildren();
4516 return IOPMWillAckLater;
4517 }
4518 }
4519
4520 all_done();
4521 return IOPMAckImplied;
4522}
4523
4524//*********************************************************************************
6d2010ae 4525// [private] ParentChangeTellPriorityClientsPowerDown
7e4a7d39 4526//
6d2010ae
A
4527// All applications and kernel clients have acknowledged our intention to drop
4528// power. Here we notify "priority" clients that we are lowering power.
7e4a7d39
A
4529//*********************************************************************************
4530
6d2010ae 4531void IOService::ParentChangeTellPriorityClientsPowerDown ( void )
7e4a7d39 4532{
6d2010ae 4533 fMachineState = kIOPM_ParentChangeNotifyInterestedDriversWillChange;
7e4a7d39
A
4534 tellChangeDown2(fHeadNotePowerState);
4535}
4536
4537//*********************************************************************************
6d2010ae 4538// [private] ParentChangeTellCapabilityWillChange
7e4a7d39 4539//
6d2010ae
A
4540// All (legacy) applications and kernel clients have acknowledged, extra stage for
4541// root domain to notify apps and drivers about the system capability change.
7e4a7d39
A
4542//*********************************************************************************
4543
6d2010ae 4544void IOService::ParentChangeTellCapabilityWillChange ( void )
7e4a7d39 4545{
6d2010ae
A
4546 if (!IS_ROOT_DOMAIN)
4547 return ParentChangeNotifyInterestedDriversWillChange();
7e4a7d39 4548
6d2010ae 4549 tellSystemCapabilityChange( kIOPM_ParentChangeNotifyInterestedDriversWillChange );
7e4a7d39
A
4550}
4551
4552//*********************************************************************************
6d2010ae 4553// [private] ParentChangeNotifyInterestedDriversWillChange
7e4a7d39 4554//
6d2010ae
A
4555// All applications and kernel clients have acknowledged our power state change.
4556// Here we notify interested drivers pre-change.
1c79356b
A
4557//*********************************************************************************
4558
6d2010ae 4559void IOService::ParentChangeNotifyInterestedDriversWillChange ( void )
1c79356b 4560{
6d2010ae
A
4561 notifyAll( kIOPM_ParentChangeSetPowerState );
4562}
1c79356b 4563
6d2010ae
A
4564//*********************************************************************************
4565// [private] ParentChangeSetPowerState
4566//
4567// Instruct our controlling driver to program the hardware for the power state
4568// change. Wait for async completions.
4569//*********************************************************************************
4570
4571void IOService::ParentChangeSetPowerState ( void )
4572{
4573 MS_PUSH( kIOPM_ParentChangeWaitForPowerSettle );
4574 fMachineState = kIOPM_DriverThreadCallDone;
4575 fDriverCallReason = kDriverCallSetPowerState;
4576
4577 if (notifyControllingDriver() == false)
4578 notifyControllingDriverDone();
1c79356b
A
4579}
4580
1c79356b 4581//*********************************************************************************
6d2010ae 4582// [private] ParentChangeWaitForPowerSettle
1c79356b 4583//
6d2010ae
A
4584// Our controlling driver has completed the power state change initiated by our
4585// parent. Wait for the driver specified settle time to expire.
1c79356b
A
4586//*********************************************************************************
4587
6d2010ae 4588void IOService::ParentChangeWaitForPowerSettle ( void )
1c79356b 4589{
6d2010ae 4590 fMachineState = kIOPM_ParentChangeNotifyInterestedDriversDidChange;
7e4a7d39 4591 startSettleTimer();
1c79356b
A
4592}
4593
1c79356b 4594//*********************************************************************************
6d2010ae
A
4595// [private] ParentChangeNotifyInterestedDriversDidChange
4596//
4597// Power has settled on a power change initiated by our parent. Here we notify
4598// all our interested drivers post-change.
4599//*********************************************************************************
4600
4601void IOService::ParentChangeNotifyInterestedDriversDidChange ( void )
4602{
4603 notifyAll( kIOPM_ParentChangeTellCapabilityDidChange );
4604}
4605
4606//*********************************************************************************
4607// [private] ParentChangeTellCapabilityDidChange
1c79356b 4608//
6d2010ae 4609// For root domain to notify capability power-change.
1c79356b
A
4610//*********************************************************************************
4611
6d2010ae 4612void IOService::ParentChangeTellCapabilityDidChange ( void )
1c79356b 4613{
6d2010ae
A
4614 if (!IS_ROOT_DOMAIN)
4615 return ParentChangeAcknowledgePowerChange();
4616
4617 tellSystemCapabilityChange( kIOPM_ParentChangeAcknowledgePowerChange );
1c79356b
A
4618}
4619
1c79356b 4620//*********************************************************************************
b0d623f7 4621// [private] ParentAcknowledgePowerChange
1c79356b 4622//
6d2010ae 4623// Acknowledge our power parent that our power change is done.
1c79356b
A
4624//*********************************************************************************
4625
6d2010ae 4626void IOService::ParentChangeAcknowledgePowerChange ( void )
1c79356b 4627{
2d21ac55
A
4628 IORegistryEntry * nub;
4629 IOService * parent;
4630
b0d623f7 4631 nub = fHeadNoteParentConnection;
55e303ae 4632 nub->retain();
1c79356b 4633 all_done();
0b4e3aa0 4634 parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
2d21ac55 4635 if ( parent )
55e303ae 4636 {
0b4e3aa0
A
4637 parent->acknowledgePowerChange((IOService *)nub);
4638 parent->release();
4639 }
4640 nub->release();
1c79356b
A
4641}
4642
6d2010ae
A
4643// MARK: -
4644// MARK: Ack and Settle timers
4645
1c79356b 4646//*********************************************************************************
6d2010ae 4647// [private] settleTimerExpired
1c79356b 4648//
6d2010ae
A
4649// Power has settled after our last change. Notify interested parties that
4650// there is a new power state.
1c79356b
A
4651//*********************************************************************************
4652
6d2010ae 4653void IOService::settleTimerExpired( void )
1c79356b 4654{
6d2010ae
A
4655 fSettleTimeUS = 0;
4656 gIOPMWorkQueue->signalWorkAvailable();
1c79356b
A
4657}
4658
1c79356b 4659//*********************************************************************************
6d2010ae 4660// settle_timer_expired
1c79356b 4661//
6d2010ae 4662// Holds a retain while the settle timer callout is in flight.
1c79356b
A
4663//*********************************************************************************
4664
7e4a7d39
A
4665static void
4666settle_timer_expired( thread_call_param_t arg0, thread_call_param_t arg1 )
1c79356b 4667{
7e4a7d39
A
4668 IOService * me = (IOService *) arg0;
4669
6d2010ae 4670 if (gIOPMWorkLoop && gIOPMWorkQueue)
7e4a7d39
A
4671 {
4672 gIOPMWorkLoop->runAction(
4673 OSMemberFunctionCast(IOWorkLoop::Action, me, &IOService::settleTimerExpired),
4674 me);
7e4a7d39
A
4675 }
4676 me->release();
4677}
4678
4679//*********************************************************************************
4680// [private] startSettleTimer
4681//
4682// Calculate a power-settling delay in microseconds and start a timer.
4683//*********************************************************************************
4684
4685void IOService::startSettleTimer( void )
4686{
4687 AbsoluteTime deadline;
6d2010ae 4688 IOPMPowerStateIndex i;
7e4a7d39
A
4689 uint32_t settleTime = 0;
4690 boolean_t pending;
2d21ac55
A
4691
4692 PM_ASSERT_IN_GATE();
1c79356b 4693
2d21ac55 4694 i = fCurrentPowerState;
55e303ae 4695
7e4a7d39 4696 // lowering power
b0d623f7 4697 if ( fHeadNotePowerState < fCurrentPowerState )
55e303ae 4698 {
b0d623f7 4699 while ( i > fHeadNotePowerState )
55e303ae 4700 {
7e4a7d39 4701 settleTime += (uint32_t) fPowerStates[i].settleDownTime;
1c79356b
A
4702 i--;
4703 }
4704 }
4705
7e4a7d39 4706 // raising power
b0d623f7 4707 if ( fHeadNotePowerState > fCurrentPowerState )
55e303ae 4708 {
b0d623f7 4709 while ( i < fHeadNotePowerState )
55e303ae 4710 {
7e4a7d39 4711 settleTime += (uint32_t) fPowerStates[i+1].settleUpTime;
1c79356b
A
4712 i++;
4713 }
4714 }
4715
7e4a7d39
A
4716 if (settleTime)
4717 {
4718 retain();
4719 clock_interval_to_deadline(settleTime, kMicrosecondScale, &deadline);
4720 pending = thread_call_enter_delayed(fSettleTimer, deadline);
4721 if (pending) release();
4722 }
1c79356b
A
4723}
4724
4725//*********************************************************************************
7e4a7d39 4726// [private] ackTimerTick
1c79356b
A
4727//
4728// The acknowledgement timeout periodic timer has ticked.
4729// If we are awaiting acks for a power change notification,
4730// we decrement the timer word of each interested driver which hasn't acked.
4731// If a timer word becomes zero, we pretend the driver aknowledged.
4732// If we are waiting for the controlling driver to change the power
4733// state of the hardware, we decrement its timer word, and if it becomes
4734// zero, we pretend the driver acknowledged.
2d21ac55
A
4735//
4736// Returns true if the timer tick made it possible to advance to the next
4737// machine state, false otherwise.
1c79356b
A
4738//*********************************************************************************
4739
b0d623f7 4740#ifndef __LP64__
1c79356b
A
4741void IOService::ack_timer_ticked ( void )
4742{
2d21ac55
A
4743 assert(false);
4744}
b0d623f7 4745#endif /* !__LP64__ */
1c79356b 4746
2d21ac55
A
4747bool IOService::ackTimerTick( void )
4748{
4749 IOPMinformee * nextObject;
4750 bool done = false;
1c79356b 4751
2d21ac55
A
4752 PM_ASSERT_IN_GATE();
4753 switch (fMachineState) {
55e303ae 4754 case kIOPM_OurChangeWaitForPowerSettle:
6d2010ae 4755 case kIOPM_ParentChangeWaitForPowerSettle:
2d21ac55
A
4756 // are we waiting for controlling driver to acknowledge?
4757 if ( fDriverTimer > 0 )
4758 {
4759 // yes, decrement timer tick
4760 fDriverTimer--;
4761 if ( fDriverTimer == 0 )
55e303ae 4762 {
2d21ac55
A
4763 // controlling driver is tardy
4764 uint64_t nsec = computeTimeDeltaNS(&fDriverCallStartTime);
4765 OUR_PMLog(kPMLogCtrlDriverTardy, 0, 0);
4766 setProperty(kIOPMTardyAckSPSKey, kOSBooleanTrue);
4767 PM_ERROR("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms\n",
b0d623f7 4768 fName, this, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
2d21ac55 4769
6d2010ae
A
4770#if LOG_SETPOWER_TIMES
4771 PMEventDetails *details = PMEventDetails::eventDetails(
4772 kIOPMEventTypeSetPowerStateDelayed, // type
4773 fName, // who
4774 (uintptr_t)this, // owner unique
4775 NULL, // interest name
4776 (uint8_t)getPowerState(), // old
4777 0, // new
4778 kIOReturnTimeout, // result
4779 NS_TO_US(nsec)); // usec completion time
4780
4781 getPMRootDomain()->recordAndReleasePMEventGated( details );
4782#endif
4783
2d21ac55
A
4784 if (gIOKitDebug & kIOLogDebugPower)
4785 {
4786 panic("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms",
b0d623f7 4787 fName, this, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
2d21ac55
A
4788 }
4789 else
4790 {
4791 // Unblock state machine and pretend driver has acked.
4792 done = true;
4793 }
55e303ae
A
4794 } else {
4795 // still waiting, set timer again
1c79356b 4796 start_ack_timer();
1c79356b
A
4797 }
4798 }
1c79356b
A
4799 break;
4800
6d2010ae 4801 case kIOPM_NotifyChildrenStart:
55e303ae 4802 // are we waiting for interested parties to acknowledge?
2d21ac55 4803 if ( fHeadNotePendingAcks != 0 )
55e303ae
A
4804 {
4805 // yes, go through the list of interested drivers
2d21ac55 4806 nextObject = fInterestedDrivers->firstInList();
55e303ae 4807 // and check each one
2d21ac55 4808 while ( nextObject != NULL )
55e303ae 4809 {
2d21ac55 4810 if ( nextObject->timer > 0 )
55e303ae 4811 {
2d21ac55 4812 nextObject->timer--;
55e303ae 4813 // this one should have acked by now
2d21ac55 4814 if ( nextObject->timer == 0 )
55e303ae 4815 {
2d21ac55
A
4816 uint64_t nsec = computeTimeDeltaNS(&nextObject->startTime);
4817 OUR_PMLog(kPMLogIntDriverTardy, 0, 0);
4818 nextObject->whatObject->setProperty(kIOPMTardyAckPSCKey, kOSBooleanTrue);
4819 PM_ERROR("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) timed out after %d ms\n",
4820 nextObject->whatObject->getName(),
4821 (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
b0d623f7 4822 nextObject->whatObject, fName, fCurrentPowerState, fHeadNotePowerState,
2d21ac55
A
4823 NS_TO_MS(nsec));
4824
6d2010ae
A
4825#if LOG_SETPOWER_TIMES
4826 uint16_t logType = (fDriverCallReason == kDriverCallInformPreChange)
4827 ? kIOPMEventTypePSWillChangeTo
4828 : kIOPMEventTypePSDidChangeTo;
4829
4830 PMEventDetails *details = PMEventDetails::eventDetails(
4831 logType, // type
4832 fName, // who
4833 (uintptr_t)this, // owner unique
4834 nextObject->whatObject->getName(), // interest name
4835 (uint8_t)fCurrentPowerState, // old
4836 (uint8_t)fHeadNotePowerState, // new
4837 kIOReturnTimeout, // result
4838 NS_TO_US(nsec)); // usec completion time
4839
4840 getPMRootDomain()->recordAndReleasePMEventGated( details );
4841#endif
4842
2d21ac55
A
4843 // Pretend driver has acked.
4844 fHeadNotePendingAcks--;
1c79356b
A
4845 }
4846 }
2d21ac55 4847 nextObject = fInterestedDrivers->nextInList(nextObject);
1c79356b 4848 }
55e303ae
A
4849
4850 // is that the last?
2d21ac55 4851 if ( fHeadNotePendingAcks == 0 )
55e303ae 4852 {
55e303ae 4853 // yes, we can continue
2d21ac55 4854 done = true;
55e303ae
A
4855 } else {
4856 // no, set timer again
1c79356b 4857 start_ack_timer();
1c79356b 4858 }
1c79356b
A
4859 }
4860 break;
4861
6d2010ae 4862 // TODO: aggreggate this
55e303ae 4863 case kIOPM_OurChangeTellClientsPowerDown:
55e303ae 4864 case kIOPM_OurChangeTellPriorityClientsPowerDown:
55e303ae 4865 case kIOPM_OurChangeNotifyInterestedDriversWillChange:
6d2010ae
A
4866 case kIOPM_ParentChangeTellPriorityClientsPowerDown:
4867 case kIOPM_ParentChangeNotifyInterestedDriversWillChange:
4868 case kIOPM_SyncTellClientsPowerDown:
4869 case kIOPM_SyncTellPriorityClientsPowerDown:
4870 case kIOPM_SyncNotifyWillChange:
4871 case kIOPM_TellCapabilityChangeDone:
2d21ac55
A
4872 // apps didn't respond in time
4873 cleanClientResponses(true);
4874 OUR_PMLog(kPMLogClientTardy, 0, 1);
593a1d5f 4875 // tardy equates to approval
2d21ac55 4876 done = true;
1c79356b 4877 break;
2d21ac55 4878
1c79356b 4879 default:
6d2010ae 4880 PM_LOG1("%s: unexpected ack timer tick (state = %d)\n",
2d21ac55 4881 getName(), fMachineState);
1c79356b
A
4882 break;
4883 }
2d21ac55 4884 return done;
1c79356b
A
4885}
4886
1c79356b 4887//*********************************************************************************
2d21ac55 4888// [private] start_ack_timer
1c79356b
A
4889//*********************************************************************************
4890
4891void IOService::start_ack_timer ( void )
4892{
2d21ac55 4893 start_ack_timer( ACK_TIMER_PERIOD, kNanosecondScale );
1c79356b
A
4894}
4895
2d21ac55
A
4896void IOService::start_ack_timer ( UInt32 interval, UInt32 scale )
4897{
4898 AbsoluteTime deadline;
4899 boolean_t pending;
4900
4901 clock_interval_to_deadline(interval, scale, &deadline);
4902
4903 retain();
4904 pending = thread_call_enter_delayed(fAckTimer, deadline);
4905 if (pending) release();
4906}
1c79356b
A
4907
4908//*********************************************************************************
2d21ac55 4909// [private] stop_ack_timer
1c79356b
A
4910//*********************************************************************************
4911
4912void IOService::stop_ack_timer ( void )
4913{
2d21ac55 4914 boolean_t pending;
1c79356b 4915
2d21ac55
A
4916 pending = thread_call_cancel(fAckTimer);
4917 if (pending) release();
4918}
1c79356b
A
4919
4920//*********************************************************************************
b0d623f7 4921// [static] actionAckTimerExpired
1c79356b 4922//
2d21ac55 4923// Inside PM work loop's gate.
1c79356b
A
4924//*********************************************************************************
4925
2d21ac55
A
4926IOReturn
4927IOService::actionAckTimerExpired (
4928 OSObject * target,
4929 void * arg0, void * arg1,
4930 void * arg2, void * arg3 )
1c79356b 4931{
2d21ac55
A
4932 IOService * me = (IOService *) target;
4933 bool done;
1c79356b 4934
2d21ac55
A
4935 // done will be true if the timer tick unblocks the machine state,
4936 // otherwise no need to signal the work loop.
1c79356b 4937
2d21ac55 4938 done = me->ackTimerTick();
6d2010ae
A
4939 if (done && gIOPMWorkQueue)
4940 gIOPMWorkQueue->signalWorkAvailable();
1c79356b 4941
2d21ac55
A
4942 return kIOReturnSuccess;
4943}
1c79356b
A
4944
4945//*********************************************************************************
2d21ac55 4946// ack_timer_expired
1c79356b 4947//
2d21ac55 4948// Thread call function. Holds a retain while the callout is in flight.
1c79356b
A
4949//*********************************************************************************
4950
2d21ac55
A
4951void
4952IOService::ack_timer_expired ( thread_call_param_t arg0, thread_call_param_t arg1 )
1c79356b 4953{
2d21ac55 4954 IOService * me = (IOService *) arg0;
55e303ae 4955
2d21ac55
A
4956 if (gIOPMWorkLoop)
4957 {
4958 gIOPMWorkLoop->runAction(&actionAckTimerExpired, me);
4959 }
4960 me->release();
1c79356b
A
4961}
4962
6d2010ae
A
4963// MARK: -
4964// MARK: Client Messaging
1c79356b 4965
1c79356b 4966//*********************************************************************************
6d2010ae 4967// [private] tellSystemCapabilityChange
1c79356b
A
4968//*********************************************************************************
4969
6d2010ae 4970void IOService::tellSystemCapabilityChange( uint32_t nextMS )
1c79356b 4971{
6d2010ae
A
4972 MS_PUSH( nextMS );
4973 fMachineState = kIOPM_TellCapabilityChangeDone;
4974 fOutOfBandMessage = kIOMessageSystemCapabilityChange;
2d21ac55 4975
6d2010ae
A
4976 if (fIsPreChange)
4977 {
4978 // Notify app first on pre-change.
4979 fOutOfBandParameter = kNotifyCapabilityChangeApps;
4980 }
4981 else
4982 {
4983 // Notify kernel clients first on post-change.
4984 fOutOfBandParameter = kNotifyCapabilityChangePriority;
4985 }
1c79356b 4986
6d2010ae 4987 tellClientsWithResponse( fOutOfBandMessage );
1c79356b
A
4988}
4989
1c79356b 4990//*********************************************************************************
b0d623f7 4991// [public] askChangeDown
1c79356b
A
4992//
4993// Ask registered applications and kernel clients if we can change to a lower
4994// power state.
4995//
4996// Subclass can override this to send a different message type. Parameter is
4997// the destination state number.
4998//
4999// Return true if we don't have to wait for acknowledgements
5000//*********************************************************************************
5001
0b4e3aa0 5002bool IOService::askChangeDown ( unsigned long stateNum )
1c79356b 5003{
2d21ac55 5004 return tellClientsWithResponse( kIOMessageCanDevicePowerOff );
1c79356b
A
5005}
5006
0b4e3aa0 5007//*********************************************************************************
b0d623f7 5008// [private] tellChangeDown1
0b4e3aa0
A
5009//
5010// Notify registered applications and kernel clients that we are definitely
5011// dropping power.
5012//
5013// Return true if we don't have to wait for acknowledgements
5014//*********************************************************************************
5015
5016bool IOService::tellChangeDown1 ( unsigned long stateNum )
5017{
2d21ac55 5018 fOutOfBandParameter = kNotifyApps;
0b4e3aa0
A
5019 return tellChangeDown(stateNum);
5020}
5021
0b4e3aa0 5022//*********************************************************************************
b0d623f7 5023// [private] tellChangeDown2
0b4e3aa0
A
5024//
5025// Notify priority clients that we are definitely dropping power.
5026//
5027// Return true if we don't have to wait for acknowledgements
5028//*********************************************************************************
5029
5030bool IOService::tellChangeDown2 ( unsigned long stateNum )
5031{
2d21ac55 5032 fOutOfBandParameter = kNotifyPriority;
0b4e3aa0
A
5033 return tellChangeDown(stateNum);
5034}
5035
1c79356b 5036//*********************************************************************************
b0d623f7 5037// [public] tellChangeDown
1c79356b
A
5038//
5039// Notify registered applications and kernel clients that we are definitely
5040// dropping power.
5041//
5042// Subclass can override this to send a different message type. Parameter is
5043// the destination state number.
5044//
5045// Return true if we don't have to wait for acknowledgements
5046//*********************************************************************************
5047
0b4e3aa0 5048bool IOService::tellChangeDown ( unsigned long stateNum )
1c79356b 5049{
2d21ac55
A
5050 return tellClientsWithResponse( kIOMessageDeviceWillPowerOff );
5051}
5052
5053//*********************************************************************************
5054// cleanClientResponses
5055//
5056//*********************************************************************************
5057
b0d623f7 5058static void logAppTimeouts ( OSObject * object, void * arg )
2d21ac55 5059{
b0d623f7
A
5060 IOPMInterestContext * context = (IOPMInterestContext *) arg;
5061 OSObject * flag;
5062 unsigned int clientIndex;
2d21ac55 5063
b0d623f7
A
5064 if (OSDynamicCast(_IOServiceInterestNotifier, object))
5065 {
5066 // Discover the 'counter' value or index assigned to this client
5067 // when it was notified, by searching for the array index of the
5068 // client in an array holding the cached interested clients.
5069
5070 clientIndex = context->notifyClients->getNextIndexOfObject(object, 0);
5071
5072 if ((clientIndex != (unsigned int) -1) &&
6d2010ae 5073 (flag = context->responseArray->getObject(clientIndex)) &&
b0d623f7 5074 (flag != kOSBooleanTrue))
2d21ac55
A
5075 {
5076 OSString * clientID = 0;
6d2010ae 5077 context->us->messageClient(context->messageType, object, &clientID);
b0d623f7
A
5078 PM_ERROR(context->errorLog, clientID ? clientID->getCStringNoCopy() : "");
5079
5080 // TODO: record message type if possible
5081 IOService::getPMRootDomain()->pmStatsRecordApplicationResponse(
5082 gIOPMStatsApplicationResponseTimedOut,
5083 clientID ? clientID->getCStringNoCopy() : "",
5084 0, (30*1000), -1);
5085
2d21ac55
A
5086 if (clientID)
5087 clientID->release();
5088 }
2d21ac55 5089 }
1c79356b
A
5090}
5091
2d21ac55
A
5092void IOService::cleanClientResponses ( bool logErrors )
5093{
6d2010ae
A
5094 if (logErrors && fResponseArray)
5095 {
2d21ac55
A
5096 switch ( fOutOfBandParameter ) {
5097 case kNotifyApps:
6d2010ae
A
5098 case kNotifyCapabilityChangeApps:
5099 if (fNotifyClientArray)
5100 {
5101 IOPMInterestContext context;
5102
5103 context.responseArray = fResponseArray;
5104 context.notifyClients = fNotifyClientArray;
5105 context.serialNumber = fSerialNumber;
5106 context.messageType = kIOMessageCopyClientID;
5107 context.notifyType = kNotifyApps;
5108 context.isPreChange = fIsPreChange;
5109 context.enableTracing = false;
5110 context.us = this;
5111 context.maxTimeRequested = 0;
5112 context.stateNumber = fHeadNotePowerState;
5113 context.stateFlags = fHeadNotePowerArrayEntry->capabilityFlags;
5114 context.changeFlags = fHeadNoteChangeFlags;
5115 context.errorLog = "PM notification timeout (%s)\n";
5116
5117 applyToInterested(gIOAppPowerStateInterest, logAppTimeouts, (void *) &context);
5118 }
5119 break;
5120
2d21ac55 5121 default:
6d2010ae
A
5122 // kNotifyPriority, kNotifyCapabilityChangePriority
5123 // TODO: identify the priority client that has not acked
5124 PM_ERROR("PM priority notification timeout\n");
5125 if (gIOKitDebug & kIOLogDebugPower)
5126 {
5127 panic("PM priority notification timeout");
5128 }
2d21ac55
A
5129 break;
5130 }
5131 }
5132
b0d623f7 5133 if (fResponseArray)
2d21ac55 5134 {
2d21ac55
A
5135 fResponseArray->release();
5136 fResponseArray = NULL;
5137 }
b0d623f7
A
5138 if (fNotifyClientArray)
5139 {
5140 fNotifyClientArray->release();
5141 fNotifyClientArray = NULL;
5142 }
2d21ac55 5143}
1c79356b
A
5144
5145//*********************************************************************************
b0d623f7 5146// [protected] tellClientsWithResponse
1c79356b
A
5147//
5148// Notify registered applications and kernel clients that we are definitely
5149// dropping power.
5150//
5151// Return true if we don't have to wait for acknowledgements
5152//*********************************************************************************
5153
6d2010ae 5154bool IOService::tellClientsWithResponse ( int messageType )
1c79356b 5155{
b0d623f7 5156 IOPMInterestContext context;
6d2010ae 5157 bool isRootDomain = IS_ROOT_DOMAIN;
2d21ac55
A
5158
5159 PM_ASSERT_IN_GATE();
b0d623f7
A
5160 assert( fResponseArray == NULL );
5161 assert( fNotifyClientArray == NULL );
1c79356b 5162
6d2010ae
A
5163 RD_LOG("tellClientsWithResponse( %s, %d )\n",
5164 getIOMessageString(messageType), fOutOfBandParameter);
5165
2d21ac55 5166 fResponseArray = OSArray::withCapacity( 1 );
b0d623f7
A
5167 if (!fResponseArray)
5168 goto exit;
5169
5170 fResponseArray->setCapacityIncrement(8);
6d2010ae
A
5171 if (++fSerialNumber == 0)
5172 fSerialNumber++;
b0d623f7 5173
6d2010ae 5174 context.responseArray = fResponseArray;
b0d623f7
A
5175 context.notifyClients = 0;
5176 context.serialNumber = fSerialNumber;
6d2010ae
A
5177 context.messageType = messageType;
5178 context.notifyType = fOutOfBandParameter;
5179 context.isPreChange = fIsPreChange;
5180 context.enableTracing = false;
b0d623f7
A
5181 context.us = this;
5182 context.maxTimeRequested = 0;
5183 context.stateNumber = fHeadNotePowerState;
5184 context.stateFlags = fHeadNotePowerArrayEntry->capabilityFlags;
6d2010ae
A
5185 context.changeFlags = fHeadNoteChangeFlags;
5186 context.messageFilter = (isRootDomain) ?
5187 OSMemberFunctionCast(
5188 IOPMMessageFilter,
5189 this,
5190 &IOPMrootDomain::systemMessageFilter) : 0;
0b4e3aa0 5191
2d21ac55 5192 switch ( fOutOfBandParameter ) {
0b4e3aa0 5193 case kNotifyApps:
b0d623f7
A
5194 applyToInterested( gIOAppPowerStateInterest,
5195 pmTellAppWithResponse, (void *) &context );
6d2010ae
A
5196
5197 if (isRootDomain &&
5198 (fMachineState != kIOPM_OurChangeTellClientsPowerDown) &&
5199 (fMachineState != kIOPM_SyncTellClientsPowerDown))
5200 {
5201 // Notify capability app for tellChangeDown1()
5202 // but not for askChangeDown().
5203 context.notifyType = kNotifyCapabilityChangeApps;
5204 context.messageType = kIOMessageSystemCapabilityChange;
5205 applyToInterested( gIOAppPowerStateInterest,
5206 pmTellCapabilityAppWithResponse, (void *) &context );
5207 context.notifyType = fOutOfBandParameter;
5208 context.messageType = messageType;
5209 }
5210 context.maxTimeRequested = k30seconds;
b0d623f7
A
5211
5212 applyToInterested( gIOGeneralInterest,
5213 pmTellClientWithResponse, (void *) &context );
6d2010ae
A
5214
5215 fNotifyClientArray = context.notifyClients;
0b4e3aa0 5216 break;
b0d623f7 5217
0b4e3aa0 5218 case kNotifyPriority:
6d2010ae 5219 context.enableTracing = isRootDomain;
b0d623f7
A
5220 applyToInterested( gIOPriorityPowerStateInterest,
5221 pmTellClientWithResponse, (void *) &context );
6d2010ae
A
5222
5223 if (isRootDomain)
5224 {
5225 // Notify capability clients for tellChangeDown2().
5226 context.notifyType = kNotifyCapabilityChangePriority;
5227 context.messageType = kIOMessageSystemCapabilityChange;
5228 applyToInterested( gIOPriorityPowerStateInterest,
5229 pmTellCapabilityClientWithResponse, (void *) &context );
5230 }
5231 break;
5232
5233 case kNotifyCapabilityChangeApps:
5234 applyToInterested( gIOAppPowerStateInterest,
5235 pmTellCapabilityAppWithResponse, (void *) &context );
5236 fNotifyClientArray = context.notifyClients;
5237 context.maxTimeRequested = k30seconds;
5238 break;
5239
5240 case kNotifyCapabilityChangePriority:
5241 applyToInterested( gIOPriorityPowerStateInterest,
5242 pmTellCapabilityClientWithResponse, (void *) &context );
0b4e3aa0
A
5243 break;
5244 }
b0d623f7 5245
55e303ae 5246 // do we have to wait for somebody?
2d21ac55 5247 if ( !checkForDone() )
55e303ae 5248 {
b0d623f7 5249 OUR_PMLog(kPMLogStartAckTimer, context.maxTimeRequested, 0);
6d2010ae
A
5250 if (context.enableTracing)
5251 getPMRootDomain()->traceDetail( context.maxTimeRequested / 1000 );
b0d623f7 5252 start_ack_timer( context.maxTimeRequested / 1000, kMillisecondScale );
1c79356b
A
5253 return false;
5254 }
2d21ac55 5255
b0d623f7 5256exit:
55e303ae 5257 // everybody responded
b0d623f7
A
5258 if (fResponseArray)
5259 {
5260 fResponseArray->release();
5261 fResponseArray = NULL;
5262 }
5263 if (fNotifyClientArray)
5264 {
5265 fNotifyClientArray->release();
5266 fNotifyClientArray = NULL;
5267 }
5268
1c79356b
A
5269 return true;
5270}
5271
1c79356b 5272//*********************************************************************************
2d21ac55 5273// [static private] pmTellAppWithResponse
1c79356b
A
5274//
5275// We send a message to an application, and we expect a response, so we compute a
5276// cookie we can identify the response with.
5277//*********************************************************************************
2d21ac55 5278
b0d623f7 5279void IOService::pmTellAppWithResponse ( OSObject * object, void * arg )
1c79356b 5280{
6d2010ae 5281 IOPMInterestContext * context = (IOPMInterestContext *) arg;
b0d623f7 5282 IOServicePM * pwrMgt = context->us->pwrMgt;
6d2010ae
A
5283 uint32_t msgIndex, msgRef, msgType;
5284#if LOG_APP_RESPONSE_TIMES
b0d623f7 5285 AbsoluteTime now;
6d2010ae 5286#endif
91447636 5287
b0d623f7 5288 if (!OSDynamicCast(_IOServiceInterestNotifier, object))
6d2010ae
A
5289 return;
5290
5291 if (context->messageFilter &&
5292 !context->messageFilter(context->us, object, context, 0, 0))
55e303ae 5293 {
6d2010ae
A
5294 if (kIOLogDebugPower & gIOKitDebug)
5295 {
5296 // Log client pid/name and client array index.
5297 OSString * clientID = 0;
5298 context->us->messageClient(kIOMessageCopyClientID, object, &clientID);
5299 PM_LOG("%s DROP App %s, %s\n",
5300 context->us->getName(),
5301 getIOMessageString(context->messageType),
5302 clientID ? clientID->getCStringNoCopy() : "");
5303 if (clientID) clientID->release();
5304 }
b0d623f7
A
5305 return;
5306 }
2d21ac55 5307
6d2010ae
A
5308 // Create client array (for tracking purposes) only if the service
5309 // has app clients. Usually only root domain does.
b0d623f7 5310 if (0 == context->notifyClients)
b0d623f7 5311 context->notifyClients = OSArray::withCapacity( 32 );
6d2010ae
A
5312
5313 msgType = context->messageType;
5314 msgIndex = context->responseArray->getCount();
5315 msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
5316
5317 OUR_PMLog(kPMLogAppNotify, msgType, msgRef);
5318 if (kIOLogDebugPower & gIOKitDebug)
5319 {
5320 // Log client pid/name and client array index.
5321 OSString * clientID = 0;
5322 context->us->messageClient(kIOMessageCopyClientID, object, &clientID);
5323 PM_LOG("%s MESG App(%u) %s, %s\n",
5324 context->us->getName(),
5325 msgIndex, getIOMessageString(msgType),
5326 clientID ? clientID->getCStringNoCopy() : "");
5327 if (clientID) clientID->release();
b0d623f7
A
5328 }
5329
6d2010ae
A
5330#if LOG_APP_RESPONSE_TIMES
5331 OSNumber * num;
5332 clock_get_uptime(&now);
5333 num = OSNumber::withNumber(AbsoluteTime_to_scalar(&now), sizeof(uint64_t) * 8);
5334 if (num)
b0d623f7 5335 {
6d2010ae
A
5336 context->responseArray->setObject(msgIndex, num);
5337 num->release();
b0d623f7
A
5338 }
5339 else
6d2010ae
A
5340#endif
5341 context->responseArray->setObject(msgIndex, kOSBooleanFalse);
5342
5343 if (context->notifyClients)
5344 context->notifyClients->setObject(msgIndex, object);
5345
5346 context->us->messageClient(msgType, object, (void *) msgRef);
5347}
5348
5349//*********************************************************************************
5350// [static private] pmTellClientWithResponse
5351//
5352// We send a message to an in-kernel client, and we expect a response,
5353// so we compute a cookie we can identify the response with.
5354//*********************************************************************************
5355
5356void IOService::pmTellClientWithResponse ( OSObject * object, void * arg )
5357{
5358 IOPowerStateChangeNotification notify;
5359 IOPMInterestContext * context = (IOPMInterestContext *) arg;
5360 OSObject * replied = kOSBooleanTrue;
5361 _IOServiceInterestNotifier * notifier;
5362 uint32_t msgIndex, msgRef, msgType;
5363 IOReturn retCode;
5364
5365 if (context->messageFilter &&
5366 !context->messageFilter(context->us, object, context, 0, 0))
b0d623f7 5367 {
6d2010ae
A
5368 if ((kIOLogDebugPower & gIOKitDebug) &&
5369 (OSDynamicCast(_IOServiceInterestNotifier, object)))
5370 {
5371 _IOServiceInterestNotifier *n = (_IOServiceInterestNotifier *) object;
5372 PM_LOG("%s DROP Client %s, notifier %p, handler %p\n",
5373 context->us->getName(),
5374 getIOMessageString(context->messageType),
5375 object, n->handler);
5376 }
5377 return;
5378 }
b0d623f7 5379
6d2010ae
A
5380 notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
5381 msgType = context->messageType;
5382 msgIndex = context->responseArray->getCount();
5383 msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
5384
5385 IOServicePM * pwrMgt = context->us->pwrMgt;
5386 if (gIOKitDebug & kIOLogPower) {
5387 OUR_PMLog(kPMLogClientNotify, msgRef, msgType);
5388 if (OSDynamicCast(IOService, object)) {
5389 const char *who = ((IOService *) object)->getName();
5390 gPlatform->PMLog(who, kPMLogClientNotify, (uintptr_t) object, 0);
5391 }
5392 else if (notifier) {
5393 OUR_PMLog(kPMLogClientNotify, (uintptr_t) notifier->handler, 0);
5394 }
5395 }
5396 if ((kIOLogDebugPower & gIOKitDebug) && notifier)
5397 {
5398 PM_LOG("%s MESG Client %s, notifier %p, handler %p\n",
5399 context->us->getName(),
5400 getIOMessageString(msgType),
5401 object, notifier->handler);
5402 }
5403
5404 notify.powerRef = (void *)(uintptr_t) msgRef;
5405 notify.returnValue = 0;
5406 notify.stateNumber = context->stateNumber;
5407 notify.stateFlags = context->stateFlags;
5408
5409 if (context->enableTracing && (notifier != 0))
5410 {
5411 uint32_t detail = ((msgIndex & 0xff) << 24) |
5412 ((msgType & 0xfff) << 12) |
5413 (((uintptr_t) notifier->handler) & 0xfff);
5414 getPMRootDomain()->traceDetail( detail );
5415 }
5416
5417 retCode = context->us->messageClient(msgType, object, (void *) &notify);
5418 if ( kIOReturnSuccess == retCode )
5419 {
5420 if ( 0 == notify.returnValue )
b0d623f7 5421 {
6d2010ae
A
5422 // client doesn't want time to respond
5423 OUR_PMLog(kPMLogClientAcknowledge, msgRef, (uintptr_t) object);
5424 }
5425 else
5426 {
5427 replied = kOSBooleanFalse;
5428 if ( notify.returnValue > context->maxTimeRequested )
5429 {
5430 if (notify.returnValue > kPriorityClientMaxWait)
5431 {
5432 context->maxTimeRequested = kPriorityClientMaxWait;
5433 PM_ERROR("%s: client %p returned %llu for %s\n",
5434 context->us->getName(),
5435 notifier ? (void *) notifier->handler : object,
5436 (uint64_t) notify.returnValue,
5437 getIOMessageString(msgType));
5438 }
5439 else
5440 context->maxTimeRequested = notify.returnValue;
5441 }
b0d623f7 5442 }
6d2010ae
A
5443 }
5444 else
5445 {
5446 // not a client of ours
5447 // so we won't be waiting for response
5448 OUR_PMLog(kPMLogClientAcknowledge, msgRef, 0);
5449 }
5450
5451 context->responseArray->setObject(msgIndex, replied);
5452}
5453
5454//*********************************************************************************
5455// [static private] pmTellCapabilityAppWithResponse
5456//*********************************************************************************
2d21ac55 5457
6d2010ae
A
5458void IOService::pmTellCapabilityAppWithResponse ( OSObject * object, void * arg )
5459{
5460 IOPMSystemCapabilityChangeParameters msgArg;
5461 IOPMInterestContext * context = (IOPMInterestContext *) arg;
5462 OSObject * replied = kOSBooleanTrue;
5463 IOServicePM * pwrMgt = context->us->pwrMgt;
5464 uint32_t msgIndex, msgRef, msgType;
5465#if LOG_APP_RESPONSE_TIMES
5466 AbsoluteTime now;
5467#endif
5468
5469 if (!OSDynamicCast(_IOServiceInterestNotifier, object))
5470 return;
5471
5472 memset(&msgArg, 0, sizeof(msgArg));
5473 if (context->messageFilter &&
5474 !context->messageFilter(context->us, object, context, &msgArg, &replied))
5475 {
5476 return;
5477 }
5478
5479 // Create client array (for tracking purposes) only if the service
5480 // has app clients. Usually only root domain does.
5481 if (0 == context->notifyClients)
5482 context->notifyClients = OSArray::withCapacity( 32 );
5483
5484 msgType = context->messageType;
5485 msgIndex = context->responseArray->getCount();
5486 msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
5487
5488 OUR_PMLog(kPMLogAppNotify, msgType, msgRef);
5489 if (kIOLogDebugPower & gIOKitDebug)
5490 {
5491 // Log client pid/name and client array index.
5492 OSString * clientID = 0;
5493 context->us->messageClient(kIOMessageCopyClientID, object, &clientID);
5494 PM_LOG("%s MESG App(%u) %s, wait %u, %s\n",
5495 context->us->getName(),
5496 msgIndex, getIOMessageString(msgType),
5497 (replied != kOSBooleanTrue),
5498 clientID ? clientID->getCStringNoCopy() : "");
5499 if (clientID) clientID->release();
5500 }
5501
5502 msgArg.notifyRef = msgRef;
5503 msgArg.maxWaitForReply = 0;
5504
5505 if (replied == kOSBooleanTrue)
5506 {
5507 msgArg.notifyRef = 0;
5508 context->responseArray->setObject(msgIndex, kOSBooleanTrue);
5509 if (context->notifyClients)
5510 context->notifyClients->setObject(msgIndex, kOSBooleanTrue);
5511 }
5512 else
5513 {
2d21ac55
A
5514#if LOG_APP_RESPONSE_TIMES
5515 OSNumber * num;
5516 clock_get_uptime(&now);
5517 num = OSNumber::withNumber(AbsoluteTime_to_scalar(&now), sizeof(uint64_t) * 8);
5518 if (num)
5519 {
6d2010ae 5520 context->responseArray->setObject(msgIndex, num);
2d21ac55
A
5521 num->release();
5522 }
5523 else
5524#endif
6d2010ae 5525 context->responseArray->setObject(msgIndex, kOSBooleanFalse);
2d21ac55 5526
6d2010ae
A
5527 if (context->notifyClients)
5528 context->notifyClients->setObject(msgIndex, object);
1c79356b 5529 }
b0d623f7 5530
6d2010ae 5531 context->us->messageClient(msgType, object, (void *) &msgArg, sizeof(msgArg));
1c79356b
A
5532}
5533
1c79356b 5534//*********************************************************************************
6d2010ae 5535// [static private] pmTellCapabilityClientWithResponse
1c79356b 5536//*********************************************************************************
2d21ac55 5537
6d2010ae
A
5538void IOService::pmTellCapabilityClientWithResponse(
5539 OSObject * object, void * arg )
1c79356b 5540{
6d2010ae 5541 IOPMSystemCapabilityChangeParameters msgArg;
b0d623f7 5542 IOPMInterestContext * context = (IOPMInterestContext *) arg;
6d2010ae
A
5543 OSObject * replied = kOSBooleanTrue;
5544 _IOServiceInterestNotifier * notifier;
5545 uint32_t msgIndex, msgRef, msgType;
b0d623f7 5546 IOReturn retCode;
2d21ac55 5547
6d2010ae
A
5548 memset(&msgArg, 0, sizeof(msgArg));
5549 if (context->messageFilter &&
5550 !context->messageFilter(context->us, object, context, &msgArg, 0))
5551 {
5552 if ((kIOLogDebugPower & gIOKitDebug) &&
5553 (OSDynamicCast(_IOServiceInterestNotifier, object)))
5554 {
5555 _IOServiceInterestNotifier *n = (_IOServiceInterestNotifier *) object;
5556 PM_LOG("%s DROP Client %s, notifier %p, handler %p\n",
5557 context->us->getName(),
5558 getIOMessageString(context->messageType),
5559 object, n->handler);
5560 }
b0d623f7 5561 return;
6d2010ae 5562 }
0b4e3aa0 5563
6d2010ae
A
5564 notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
5565 msgType = context->messageType;
5566 msgIndex = context->responseArray->getCount();
5567 msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
b0d623f7
A
5568
5569 IOServicePM * pwrMgt = context->us->pwrMgt;
91447636 5570 if (gIOKitDebug & kIOLogPower) {
6d2010ae 5571 OUR_PMLog(kPMLogClientNotify, msgRef, msgType);
2d21ac55
A
5572 if (OSDynamicCast(IOService, object)) {
5573 const char *who = ((IOService *) object)->getName();
6d2010ae
A
5574 gPlatform->PMLog(who, kPMLogClientNotify, (uintptr_t) object, 0);
5575 }
5576 else if (notifier) {
5577 OUR_PMLog(kPMLogClientNotify, (uintptr_t) notifier->handler, 0);
2d21ac55 5578 }
91447636 5579 }
6d2010ae
A
5580 if ((kIOLogDebugPower & gIOKitDebug) && notifier)
5581 {
5582 PM_LOG("%s MESG Client %s, notifier %p, handler %p\n",
5583 context->us->getName(),
5584 getIOMessageString(msgType),
5585 object, notifier->handler);
5586 }
91447636 5587
6d2010ae
A
5588 msgArg.notifyRef = msgRef;
5589 msgArg.maxWaitForReply = 0;
5590
5591 if (context->enableTracing && (notifier != 0))
5592 {
5593 uint32_t detail = ((msgIndex & 0xff) << 24) |
5594 ((msgType & 0xfff) << 12) |
5595 (((uintptr_t) notifier->handler) & 0xfff);
5596 getPMRootDomain()->traceDetail( detail );
5597 }
5598
5599 retCode = context->us->messageClient(
5600 msgType, object, (void *) &msgArg, sizeof(msgArg));
5601
5602 if ( kIOReturnSuccess == retCode )
55e303ae 5603 {
6d2010ae 5604 if ( 0 == msgArg.maxWaitForReply )
55e303ae
A
5605 {
5606 // client doesn't want time to respond
6d2010ae
A
5607 OUR_PMLog(kPMLogClientAcknowledge, msgRef, (uintptr_t) object);
5608 }
5609 else
5610 {
5611 replied = kOSBooleanFalse;
5612 if ( msgArg.maxWaitForReply > context->maxTimeRequested )
55e303ae 5613 {
6d2010ae 5614 if (msgArg.maxWaitForReply > kCapabilityClientMaxWait)
55e303ae 5615 {
6d2010ae
A
5616 context->maxTimeRequested = kCapabilityClientMaxWait;
5617 PM_ERROR("%s: client %p returned %u for %s\n",
5618 context->us->getName(),
5619 notifier ? (void *) notifier->handler : object,
5620 msgArg.maxWaitForReply,
5621 getIOMessageString(msgType));
1c79356b 5622 }
6d2010ae
A
5623 else
5624 context->maxTimeRequested = msgArg.maxWaitForReply;
1c79356b 5625 }
1c79356b 5626 }
6d2010ae
A
5627 }
5628 else
5629 {
55e303ae 5630 // not a client of ours
55e303ae 5631 // so we won't be waiting for response
6d2010ae 5632 OUR_PMLog(kPMLogClientAcknowledge, msgRef, 0);
1c79356b 5633 }
6d2010ae
A
5634
5635 context->responseArray->setObject(msgIndex, replied);
1c79356b
A
5636}
5637
1c79356b 5638//*********************************************************************************
b0d623f7 5639// [public] tellNoChangeDown
1c79356b
A
5640//
5641// Notify registered applications and kernel clients that we are not
5642// dropping power.
5643//
5644// Subclass can override this to send a different message type. Parameter is
5645// the aborted destination state number.
5646//*********************************************************************************
5647
5648void IOService::tellNoChangeDown ( unsigned long )
5649{
2d21ac55 5650 return tellClients( kIOMessageDeviceWillNotPowerOff );
1c79356b
A
5651}
5652
1c79356b 5653//*********************************************************************************
b0d623f7 5654// [public] tellChangeUp
1c79356b
A
5655//
5656// Notify registered applications and kernel clients that we are raising power.
5657//
5658// Subclass can override this to send a different message type. Parameter is
5659// the aborted destination state number.
5660//*********************************************************************************
5661
5662void IOService::tellChangeUp ( unsigned long )
5663{
2d21ac55 5664 return tellClients( kIOMessageDeviceHasPoweredOn );
1c79356b
A
5665}
5666
1c79356b 5667//*********************************************************************************
b0d623f7 5668// [protected] tellClients
1c79356b
A
5669//
5670// Notify registered applications and kernel clients of something.
5671//*********************************************************************************
5672
5673void IOService::tellClients ( int messageType )
b0d623f7
A
5674{
5675 IOPMInterestContext context;
1c79356b 5676
6d2010ae
A
5677 RD_LOG("tellClients( %s )\n", getIOMessageString(messageType));
5678
5679 memset(&context, 0, sizeof(context));
5680 context.messageType = messageType;
5681 context.isPreChange = fIsPreChange;
5682 context.us = this;
5683 context.stateNumber = fHeadNotePowerState;
5684 context.stateFlags = fHeadNotePowerArrayEntry->capabilityFlags;
5685 context.changeFlags = fHeadNoteChangeFlags;
5686 context.messageFilter = (IS_ROOT_DOMAIN) ?
5687 OSMemberFunctionCast(
5688 IOPMMessageFilter,
5689 this,
5690 &IOPMrootDomain::systemMessageFilter) : 0;
5691
5692 context.notifyType = kNotifyPriority;
b0d623f7
A
5693 applyToInterested( gIOPriorityPowerStateInterest,
5694 tellKernelClientApplier, (void *) &context );
6d2010ae
A
5695
5696 context.notifyType = kNotifyApps;
b0d623f7
A
5697 applyToInterested( gIOAppPowerStateInterest,
5698 tellAppClientApplier, (void *) &context );
5699
5700 applyToInterested( gIOGeneralInterest,
5701 tellKernelClientApplier, (void *) &context );
1c79356b
A
5702}
5703
1c79356b 5704//*********************************************************************************
b0d623f7 5705// [private] tellKernelClientApplier
1c79356b 5706//
b0d623f7 5707// Message a kernel client.
1c79356b 5708//*********************************************************************************
2d21ac55 5709
b0d623f7 5710static void tellKernelClientApplier ( OSObject * object, void * arg )
1c79356b 5711{
2d21ac55 5712 IOPowerStateChangeNotification notify;
6d2010ae 5713 IOPMInterestContext * context = (IOPMInterestContext *) arg;
1c79356b 5714
6d2010ae
A
5715 if (context->messageFilter &&
5716 !context->messageFilter(context->us, object, context, 0, 0))
5717 {
5718 if ((kIOLogDebugPower & gIOKitDebug) &&
5719 (OSDynamicCast(_IOServiceInterestNotifier, object)))
5720 {
5721 _IOServiceInterestNotifier *n = (_IOServiceInterestNotifier *) object;
5722 PM_LOG("%s DROP Client %s, notifier %p, handler %p\n",
5723 context->us->getName(),
5724 IOService::getIOMessageString(context->messageType),
5725 object, n->handler);
5726 }
b0d623f7 5727 return;
6d2010ae 5728 }
b0d623f7
A
5729
5730 notify.powerRef = (void *) 0;
0b4e3aa0 5731 notify.returnValue = 0;
b0d623f7
A
5732 notify.stateNumber = context->stateNumber;
5733 notify.stateFlags = context->stateFlags;
5734
6d2010ae
A
5735 context->us->messageClient(context->messageType, object, &notify);
5736
5737 if ((kIOLogDebugPower & gIOKitDebug) &&
5738 (OSDynamicCast(_IOServiceInterestNotifier, object)))
5739 {
5740 _IOServiceInterestNotifier *n = (_IOServiceInterestNotifier *) object;
5741 PM_LOG("%s MESG Client %s, notifier %p, handler %p\n",
5742 context->us->getName(),
5743 IOService::getIOMessageString(context->messageType),
5744 object, n->handler);
5745 }
b0d623f7
A
5746}
5747
5748//*********************************************************************************
5749// [private] tellAppClientApplier
5750//
5751// Message a registered application.
5752//*********************************************************************************
5753
5754static void tellAppClientApplier ( OSObject * object, void * arg )
5755{
6d2010ae 5756 IOPMInterestContext * context = (IOPMInterestContext *) arg;
b0d623f7 5757
6d2010ae
A
5758 if (context->messageFilter &&
5759 !context->messageFilter(context->us, object, context, 0, 0))
5760 {
5761 if (kIOLogDebugPower & gIOKitDebug)
5762 {
5763 // Log client pid/name and client array index.
5764 OSString * clientID = 0;
5765 context->us->messageClient(kIOMessageCopyClientID, object, &clientID);
5766 PM_LOG("%s DROP App %s, %s\n",
5767 context->us->getName(),
5768 IOService::getIOMessageString(context->messageType),
5769 clientID ? clientID->getCStringNoCopy() : "");
5770 if (clientID) clientID->release();
5771 }
b0d623f7 5772 return;
6d2010ae
A
5773 }
5774
5775 if (kIOLogDebugPower & gIOKitDebug)
5776 {
5777 // Log client pid/name and client array index.
5778 OSString * clientID = 0;
5779 context->us->messageClient(kIOMessageCopyClientID, object, &clientID);
5780 PM_LOG("%s MESG App %s, %s\n",
5781 context->us->getName(),
5782 IOService::getIOMessageString(context->messageType),
5783 clientID ? clientID->getCStringNoCopy() : "");
5784 if (clientID) clientID->release();
5785 }
0b4e3aa0 5786
6d2010ae 5787 context->us->messageClient(context->messageType, object, 0);
1c79356b
A
5788}
5789
2d21ac55
A
5790//*********************************************************************************
5791// [private] checkForDone
5792//*********************************************************************************
1c79356b 5793
1c79356b
A
5794bool IOService::checkForDone ( void )
5795{
2d21ac55
A
5796 int i = 0;
5797 OSObject * theFlag;
1c79356b 5798
2d21ac55 5799 if ( fResponseArray == NULL )
55e303ae 5800 {
1c79356b
A
5801 return true;
5802 }
55e303ae 5803
2d21ac55 5804 for ( i = 0; ; i++ )
55e303ae 5805 {
2d21ac55
A
5806 theFlag = fResponseArray->getObject(i);
5807 if ( theFlag == NULL )
55e303ae 5808 {
1c79356b
A
5809 break;
5810 }
2d21ac55 5811 if ( kOSBooleanTrue != theFlag )
55e303ae 5812 {
1c79356b
A
5813 return false;
5814 }
5815 }
1c79356b
A
5816 return true;
5817}
5818
2d21ac55
A
5819//*********************************************************************************
5820// [public] responseValid
5821//*********************************************************************************
1c79356b 5822
6d2010ae 5823bool IOService::responseValid ( uint32_t refcon, int pid )
2d21ac55
A
5824{
5825 UInt16 serialComponent;
5826 UInt16 ordinalComponent;
5827 OSObject * theFlag;
2d21ac55
A
5828
5829 serialComponent = (refcon >> 16) & 0xFFFF;
5830 ordinalComponent = (refcon & 0xFFFF);
5831
5832 if ( serialComponent != fSerialNumber )
55e303ae 5833 {
1c79356b
A
5834 return false;
5835 }
5836
2d21ac55 5837 if ( fResponseArray == NULL )
55e303ae 5838 {
1c79356b
A
5839 return false;
5840 }
5841
2d21ac55 5842 theFlag = fResponseArray->getObject(ordinalComponent);
1c79356b 5843
2d21ac55 5844 if ( theFlag == 0 )
55e303ae 5845 {
1c79356b
A
5846 return false;
5847 }
2d21ac55
A
5848
5849 OSNumber * num;
5850 if ((num = OSDynamicCast(OSNumber, theFlag)))
5851 {
5852#if LOG_APP_RESPONSE_TIMES
5853 AbsoluteTime now;
5854 AbsoluteTime start;
6d2010ae
A
5855 uint64_t nsec;
5856 OSString *name = IOCopyLogNameForPID(pid);
2d21ac55
A
5857
5858 clock_get_uptime(&now);
5859 AbsoluteTime_to_scalar(&start) = num->unsigned64BitValue();
5860 SUB_ABSOLUTETIME(&now, &start);
5861 absolutetime_to_nanoseconds(now, &nsec);
6d2010ae
A
5862
5863 PMEventDetails *details = PMEventDetails::eventDetails(
5864 kIOPMEventTypeAppResponse, // type
5865 name ? name->getCStringNoCopy() : "", // who
5866 (uintptr_t)pid, // owner unique
5867 NULL, // interest name
5868 0, // old
5869 0, // new
5870 0, // result
5871 NS_TO_US(nsec)); // usec completion time
5872
5873 getPMRootDomain()->recordAndReleasePMEventGated( details );
5874
5875 if (kIOLogDebugPower & gIOKitDebug)
5876 {
5877 PM_LOG("Ack(%u) %u ms\n",
5878 (uint32_t) ordinalComponent,
5879 NS_TO_MS(nsec));
5880 }
2d21ac55
A
5881
5882 // > 100 ms
5883 if (nsec > LOG_APP_RESPONSE_TIMES)
5884 {
6d2010ae 5885 PM_LOG("PM response took %d ms (%s)\n", NS_TO_MS(nsec),
2d21ac55 5886 name ? name->getCStringNoCopy() : "");
b0d623f7
A
5887
5888 if (nsec > LOG_APP_RESPONSE_MSG_TRACER)
5889 {
5890 // TODO: populate the messageType argument
5891 getPMRootDomain()->pmStatsRecordApplicationResponse(
5892 gIOPMStatsApplicationResponseSlow,
5893 name ? name->getCStringNoCopy() : "", 0,
5894 NS_TO_MS(nsec), pid);
6d2010ae 5895 }
2d21ac55 5896 }
6d2010ae
A
5897
5898 if (name)
5899 name->release();
2d21ac55
A
5900#endif
5901 theFlag = kOSBooleanFalse;
5902 }
5903
5904 if ( kOSBooleanFalse == theFlag )
55e303ae 5905 {
2d21ac55 5906 fResponseArray->replaceObject(ordinalComponent, kOSBooleanTrue);
1c79356b
A
5907 }
5908
1c79356b
A
5909 return true;
5910}
5911
2d21ac55 5912//*********************************************************************************
b0d623f7 5913// [public] allowPowerChange
1c79356b
A
5914//
5915// Our power state is about to lower, and we have notified applications
5916// and kernel clients, and one of them has acknowledged. If this is the last to do
5917// so, and all acknowledgements are positive, we continue with the power change.
2d21ac55
A
5918//*********************************************************************************
5919
1c79356b
A
5920IOReturn IOService::allowPowerChange ( unsigned long refcon )
5921{
2d21ac55
A
5922 IOPMRequest * request;
5923
5924 if ( !initialized )
55e303ae
A
5925 {
5926 // we're unloading
5927 return kIOReturnSuccess;
1c79356b
A
5928 }
5929
2d21ac55
A
5930 request = acquirePMRequest( this, kIOPMRequestTypeAllowPowerChange );
5931 if (!request)
2d21ac55 5932 return kIOReturnNoMemory;
2d21ac55
A
5933
5934 request->fArg0 = (void *) refcon;
5935 request->fArg1 = (void *) proc_selfpid();
6d2010ae 5936 request->fArg2 = (void *) 0;
2d21ac55
A
5937 submitPMRequest( request );
5938
5939 return kIOReturnSuccess;
1c79356b 5940}
2d21ac55 5941
b0d623f7 5942#ifndef __LP64__
1c79356b
A
5943IOReturn IOService::serializedAllowPowerChange2 ( unsigned long refcon )
5944{
2d21ac55
A
5945 // [deprecated] public
5946 return kIOReturnUnsupported;
1c79356b 5947}
b0d623f7 5948#endif /* !__LP64__ */
1c79356b 5949
2d21ac55 5950//*********************************************************************************
b0d623f7 5951// [public] cancelPowerChange
1c79356b
A
5952//
5953// Our power state is about to lower, and we have notified applications
5954// and kernel clients, and one of them has vetoed the change. If this is the last
5955// client to respond, we abandon the power change.
2d21ac55
A
5956//*********************************************************************************
5957
1c79356b
A
5958IOReturn IOService::cancelPowerChange ( unsigned long refcon )
5959{
b0d623f7
A
5960 IOPMRequest * request;
5961 OSString * name;
2d21ac55
A
5962
5963 if ( !initialized )
55e303ae
A
5964 {
5965 // we're unloading
5966 return kIOReturnSuccess;
1c79356b
A
5967 }
5968
b0d623f7 5969 name = IOCopyLogNameForPID(proc_selfpid());
593a1d5f 5970 PM_ERROR("PM notification cancel (%s)\n", name ? name->getCStringNoCopy() : "");
593a1d5f 5971
2d21ac55
A
5972 request = acquirePMRequest( this, kIOPMRequestTypeCancelPowerChange );
5973 if (!request)
b0d623f7
A
5974 {
5975 if (name)
5976 name->release();
5977 return kIOReturnNoMemory;
5978 }
2d21ac55 5979
b0d623f7
A
5980 request->fArg0 = (void *) refcon;
5981 request->fArg1 = (void *) proc_selfpid();
5982 request->fArg2 = (void *) name;
5983 submitPMRequest( request );
2d21ac55 5984
b0d623f7 5985 return kIOReturnSuccess;
1c79356b
A
5986}
5987
b0d623f7 5988#ifndef __LP64__
1c79356b
A
5989IOReturn IOService::serializedCancelPowerChange2 ( unsigned long refcon )
5990{
2d21ac55
A
5991 // [deprecated] public
5992 return kIOReturnUnsupported;
1c79356b
A
5993}
5994
1c79356b
A
5995//*********************************************************************************
5996// PM_Clamp_Timer_Expired
5997//
5998// called when clamp timer expires...set power state to 0.
5999//*********************************************************************************
6000
2d21ac55 6001void IOService::PM_Clamp_Timer_Expired ( void )
1c79356b 6002{
1c79356b
A
6003}
6004
2d21ac55 6005//*********************************************************************************
91447636 6006// clampPowerOn
1c79356b 6007//
91447636 6008// Set to highest available power state for a minimum of duration milliseconds
2d21ac55 6009//*********************************************************************************
91447636 6010
2d21ac55 6011void IOService::clampPowerOn ( unsigned long duration )
1c79356b 6012{
91447636 6013}
b0d623f7 6014#endif /* !__LP64__ */
1c79356b 6015
6d2010ae
A
6016// MARK: -
6017// MARK: Driver Overrides
6018
1c79356b 6019//*********************************************************************************
b0d623f7 6020// [public] setPowerState
1c79356b
A
6021//
6022// Does nothing here. This should be implemented in a subclass driver.
6023//*********************************************************************************
6024
2d21ac55
A
6025IOReturn IOService::setPowerState (
6026 unsigned long powerStateOrdinal, IOService * whatDevice )
1c79356b
A
6027{
6028 return IOPMNoErr;
6029}
6030
1c79356b 6031//*********************************************************************************
b0d623f7 6032// [public] maxCapabilityForDomainState
1c79356b
A
6033//
6034// Finds the highest power state in the array whose input power
6035// requirement is equal to the input parameter. Where a more intelligent
6036// decision is possible, override this in the subclassed driver.
6037//*********************************************************************************
6038
6039unsigned long IOService::maxCapabilityForDomainState ( IOPMPowerFlags domainState )
6040{
6041 int i;
6042
2d21ac55 6043 if (fNumberOfPowerStates == 0 )
55e303ae 6044 {
1c79356b
A
6045 return 0;
6046 }
2d21ac55 6047 for ( i = fNumberOfPowerStates - 1; i >= 0; i-- )
55e303ae 6048 {
6d2010ae
A
6049 if ( (domainState & fPowerStates[i].inputPowerFlags) ==
6050 fPowerStates[i].inputPowerFlags )
55e303ae 6051 {
1c79356b
A
6052 return i;
6053 }
6054 }
6055 return 0;
6056}
6057
1c79356b 6058//*********************************************************************************
b0d623f7 6059// [public] initialPowerStateForDomainState
1c79356b
A
6060//
6061// Finds the highest power state in the array whose input power
6062// requirement is equal to the input parameter. Where a more intelligent
6063// decision is possible, override this in the subclassed driver.
6064//*********************************************************************************
6065
6066unsigned long IOService::initialPowerStateForDomainState ( IOPMPowerFlags domainState )
6067{
55e303ae 6068 int i;
1c79356b 6069
2d21ac55 6070 if (fNumberOfPowerStates == 0 )
55e303ae
A
6071 {
6072 return 0;
6073 }
2d21ac55 6074 for ( i = fNumberOfPowerStates - 1; i >= 0; i-- )
55e303ae 6075 {
6d2010ae
A
6076 if ( (domainState & fPowerStates[i].inputPowerFlags) ==
6077 fPowerStates[i].inputPowerFlags )
55e303ae
A
6078 {
6079 return i;
6080 }
6081 }
6082 return 0;
1c79356b
A
6083}
6084
1c79356b 6085//*********************************************************************************
b0d623f7 6086// [public] powerStateForDomainState
1c79356b
A
6087//
6088// Finds the highest power state in the array whose input power
6089// requirement is equal to the input parameter. Where a more intelligent
6090// decision is possible, override this in the subclassed driver.
6091//*********************************************************************************
6092
6093unsigned long IOService::powerStateForDomainState ( IOPMPowerFlags domainState )
6094{
55e303ae 6095 int i;
1c79356b 6096
2d21ac55 6097 if (fNumberOfPowerStates == 0 )
55e303ae
A
6098 {
6099 return 0;
6100 }
2d21ac55 6101 for ( i = fNumberOfPowerStates - 1; i >= 0; i-- )
55e303ae 6102 {
6d2010ae
A
6103 if ( (domainState & fPowerStates[i].inputPowerFlags) ==
6104 fPowerStates[i].inputPowerFlags )
55e303ae
A
6105 {
6106 return i;
6107 }
6108 }
6109 return 0;
1c79356b
A
6110}
6111
b0d623f7 6112#ifndef __LP64__
1c79356b 6113//*********************************************************************************
b0d623f7 6114// [deprecated] didYouWakeSystem
1c79356b
A
6115//
6116// Does nothing here. This should be implemented in a subclass driver.
6117//*********************************************************************************
6118
b0d623f7 6119bool IOService::didYouWakeSystem ( void )
1c79356b
A
6120{
6121 return false;
6122}
b0d623f7 6123#endif /* !__LP64__ */
1c79356b 6124
1c79356b 6125//*********************************************************************************
b0d623f7 6126// [public] powerStateWillChangeTo
1c79356b
A
6127//
6128// Does nothing here. This should be implemented in a subclass driver.
6129//*********************************************************************************
6130
2d21ac55 6131IOReturn IOService::powerStateWillChangeTo ( IOPMPowerFlags, unsigned long, IOService * )
1c79356b 6132{
2d21ac55 6133 return kIOPMAckImplied;
1c79356b
A
6134}
6135
1c79356b 6136//*********************************************************************************
b0d623f7 6137// [public] powerStateDidChangeTo
1c79356b
A
6138//
6139// Does nothing here. This should be implemented in a subclass driver.
6140//*********************************************************************************
6141
2d21ac55 6142IOReturn IOService::powerStateDidChangeTo ( IOPMPowerFlags, unsigned long, IOService * )
1c79356b 6143{
2d21ac55 6144 return kIOPMAckImplied;
1c79356b
A
6145}
6146
1c79356b 6147//*********************************************************************************
b0d623f7 6148// [protected] powerChangeDone
1c79356b 6149//
2d21ac55 6150// Called from PM work loop thread.
1c79356b
A
6151// Does nothing here. This should be implemented in a subclass policy-maker.
6152//*********************************************************************************
6153
6154void IOService::powerChangeDone ( unsigned long )
6155{
6156}
6157
b0d623f7 6158#ifndef __LP64__
1c79356b 6159//*********************************************************************************
b0d623f7 6160// [deprecated] newTemperature
1c79356b
A
6161//
6162// Does nothing here. This should be implemented in a subclass driver.
6163//*********************************************************************************
6164
6165IOReturn IOService::newTemperature ( long currentTemp, IOService * whichZone )
1c79356b
A
6166{
6167 return IOPMNoErr;
6168}
b0d623f7 6169#endif /* !__LP64__ */
1c79356b 6170
2d21ac55 6171//*********************************************************************************
b0d623f7 6172// [public] systemWillShutdown
2d21ac55
A
6173//
6174// System shutdown and restart notification.
6175//*********************************************************************************
1c79356b 6176
2d21ac55
A
6177void IOService::systemWillShutdown( IOOptionBits specifier )
6178{
6179 IOPMrootDomain * rootDomain = IOService::getPMRootDomain();
6180 if (rootDomain)
6181 rootDomain->acknowledgeSystemWillShutdown( this );
6182}
1c79356b 6183
6d2010ae
A
6184// MARK: -
6185// MARK: PM State Machine
6186
1c79356b 6187//*********************************************************************************
2d21ac55
A
6188// [private static] acquirePMRequest
6189//*********************************************************************************
6190
6191IOPMRequest *
b0d623f7
A
6192IOService::acquirePMRequest( IOService * target, IOOptionBits requestType,
6193 IOPMRequest * active )
2d21ac55
A
6194{
6195 IOPMRequest * request;
6196
6197 assert(target);
6198
6199 request = IOPMRequest::create();
6200 if (request)
6201 {
6202 request->init( target, requestType );
b0d623f7
A
6203 if (active)
6204 {
6205 IOPMRequest * root = active->getRootRequest();
6206 if (root) request->attachRootRequest(root);
6207 }
6208 }
6209 else
6210 {
6211 PM_ERROR("%s: No memory for PM request type 0x%x\n",
6212 target->getName(), (uint32_t) requestType);
2d21ac55
A
6213 }
6214 return request;
6215}
6216
6217//*********************************************************************************
6218// [private static] releasePMRequest
6219//*********************************************************************************
6220
6221void IOService::releasePMRequest( IOPMRequest * request )
6222{
6223 if (request)
6224 {
6225 request->reset();
6226 request->release();
6227 }
6228}
6229
6230//*********************************************************************************
6231// [private] submitPMRequest
6232//*********************************************************************************
6233
6234void IOService::submitPMRequest( IOPMRequest * request )
6235{
6236 assert( request );
6237 assert( gIOPMReplyQueue );
6238 assert( gIOPMRequestQueue );
6239
6d2010ae 6240 PM_LOG1("[+ %02lx] %p [%p %s] %p %p %p\n",
b0d623f7 6241 (long)request->getType(), request,
2d21ac55
A
6242 request->getTarget(), request->getTarget()->getName(),
6243 request->fArg0, request->fArg1, request->fArg2);
6244
b0d623f7 6245 if (request->isReplyType())
2d21ac55
A
6246 gIOPMReplyQueue->queuePMRequest( request );
6247 else
6248 gIOPMRequestQueue->queuePMRequest( request );
6249}
6250
6251void IOService::submitPMRequest( IOPMRequest ** requests, IOItemCount count )
6252{
6253 assert( requests );
6254 assert( count > 0 );
6255 assert( gIOPMRequestQueue );
6256
6257 for (IOItemCount i = 0; i < count; i++)
6258 {
6259 IOPMRequest * req = requests[i];
6d2010ae 6260 PM_LOG1("[+ %02lx] %p [%p %s] %p %p %p\n",
b0d623f7 6261 (long)req->getType(), req,
2d21ac55
A
6262 req->getTarget(), req->getTarget()->getName(),
6263 req->fArg0, req->fArg1, req->fArg2);
6264 }
6265
6266 gIOPMRequestQueue->queuePMRequestChain( requests, count );
6267}
6268
6269//*********************************************************************************
6270// [private] servicePMRequestQueue
6d2010ae
A
6271//
6272// Called from IOPMRequestQueue::checkForWork().
2d21ac55
A
6273//*********************************************************************************
6274
6275bool IOService::servicePMRequestQueue(
6276 IOPMRequest * request,
6277 IOPMRequestQueue * queue )
6278{
6d2010ae 6279 bool more;
2d21ac55 6280
6d2010ae
A
6281 if (initialized)
6282 {
6283 // Work queue will immediately execute the queue'd request if possible.
6284 // If execution blocks, the work queue will wait for a producer signal.
6285 // Only need to signal more when completing attached requests.
2d21ac55 6286
6d2010ae
A
6287 more = gIOPMWorkQueue->queuePMRequest(request, pwrMgt);
6288 return more;
6289 }
2d21ac55 6290
6d2010ae 6291 // Calling PM without PMinit() is not allowed, fail the request.
2d21ac55 6292
6d2010ae 6293 PM_LOG("%s: PM not initialized\n", getName());
b0d623f7 6294 fAdjustPowerScheduled = false;
6d2010ae
A
6295 more = gIOPMFreeQueue->queuePMRequest(request);
6296 if (more) gIOPMWorkQueue->incrementProducerCount();
6297 return more;
2d21ac55
A
6298}
6299
6300//*********************************************************************************
6301// [private] servicePMFreeQueue
6302//
6d2010ae 6303// Called from IOPMCompletionQueue::checkForWork().
2d21ac55
A
6304//*********************************************************************************
6305
6306bool IOService::servicePMFreeQueue(
b0d623f7
A
6307 IOPMRequest * request,
6308 IOPMCompletionQueue * queue )
2d21ac55 6309{
b0d623f7
A
6310 bool more = request->getNextRequest();
6311 IOPMRequest * root = request->getRootRequest();
6312
6313 if (root && (root != request))
6314 more = true;
6d2010ae
A
6315 if (more)
6316 gIOPMWorkQueue->incrementProducerCount();
060df5ea 6317
2d21ac55
A
6318 releasePMRequest( request );
6319 return more;
6320}
6321
6322//*********************************************************************************
6323// [private] retirePMRequest
1c79356b 6324//
2d21ac55 6325// Called by IOPMWorkQueue to retire a completed request.
1c79356b 6326//*********************************************************************************
2d21ac55
A
6327
6328bool IOService::retirePMRequest( IOPMRequest * request, IOPMWorkQueue * queue )
1c79356b 6329{
2d21ac55 6330 assert(request && queue);
1c79356b 6331
6d2010ae 6332 PM_LOG1("[- %02x] %p [%p %s] state %d, busy %d\n",
2d21ac55
A
6333 request->getType(), request, this, getName(),
6334 fMachineState, gIOPMBusyCount);
91447636 6335
b0d623f7 6336 // Catch requests created by idleTimerExpired().
1c79356b 6337
2d21ac55 6338 if ((request->getType() == kIOPMRequestTypeActivityTickle) &&
6d2010ae 6339 (request->fArg1 == (void *) (uintptr_t) false))
2d21ac55
A
6340 {
6341 // Idle timer power drop request completed.
6342 // Restart the idle timer if deviceDesire can go lower, otherwise set
6343 // a flag so we know to restart idle timer when deviceDesire goes up.
1c79356b 6344
2d21ac55 6345 if (fDeviceDesire > 0)
b0d623f7
A
6346 {
6347 fActivityTickleCount = 0;
6348 clock_get_uptime(&fIdleTimerStartTime);
2d21ac55 6349 start_PM_idle_timer();
b0d623f7 6350 }
2d21ac55 6351 else
b0d623f7 6352 fIdleTimerStopped = true;
2d21ac55 6353 }
1c79356b 6354
6d2010ae
A
6355 // If the request is linked, then Work queue has already incremented its
6356 // producer count.
6357
6358 return (gIOPMFreeQueue->queuePMRequest( request ));
2d21ac55 6359}
1c79356b 6360
2d21ac55
A
6361//*********************************************************************************
6362// [private] isPMBlocked
6363//
6364// Check if machine state transition is blocked.
6365//*********************************************************************************
1c79356b 6366
2d21ac55
A
6367bool IOService::isPMBlocked ( IOPMRequest * request, int count )
6368{
6369 int reason = 0;
6370
6371 do {
6372 if (kIOPM_Finished == fMachineState)
6373 break;
6374
6375 if (kIOPM_DriverThreadCallDone == fMachineState)
6376 {
6377 // 5 = kDriverCallInformPreChange
6378 // 6 = kDriverCallInformPostChange
6379 // 7 = kDriverCallSetPowerState
6d2010ae
A
6380 if (fDriverCallBusy)
6381 reason = 5 + fDriverCallReason;
2d21ac55
A
6382 break;
6383 }
6384
6385 // Waiting on driver's setPowerState() timeout.
6386 if (fDriverTimer)
6387 {
6388 reason = 1; break;
6389 }
6390
6391 // Child or interested driver acks pending.
6392 if (fHeadNotePendingAcks)
6393 {
6394 reason = 2; break;
6395 }
6396
6397 // Waiting on apps or priority power interest clients.
6398 if (fResponseArray)
6399 {
6400 reason = 3; break;
6401 }
6402
6403 // Waiting on settle timer expiration.
6404 if (fSettleTimeUS)
6405 {
6406 reason = 4; break;
6407 }
6408 } while (false);
6409
6410 fWaitReason = reason;
6411
6412 if (reason)
6413 {
6414 if (count)
6415 {
6d2010ae 6416 PM_LOG1("[B %02x] %p [%p %s] state %d, reason %d\n",
2d21ac55
A
6417 request->getType(), request, this, getName(),
6418 fMachineState, reason);
6419 }
6420
6421 return true;
6422 }
1c79356b 6423
2d21ac55 6424 return false;
1c79356b
A
6425}
6426
2d21ac55
A
6427//*********************************************************************************
6428// [private] servicePMRequest
6429//
6430// Service a request from our work queue.
6431//*********************************************************************************
6432
6433bool IOService::servicePMRequest( IOPMRequest * request, IOPMWorkQueue * queue )
6434{
6435 bool done = false;
6436 int loop = 0;
6437
6438 assert(request && queue);
6439
6440 while (isPMBlocked(request, loop++) == false)
6441 {
6d2010ae 6442 PM_LOG1("[W %02x] %p [%p %s] state %d\n",
2d21ac55
A
6443 request->getType(), request, this, getName(), fMachineState);
6444
b0d623f7 6445 gIOPMRequest = request;
6d2010ae 6446 gIOPMWorkCount++;
2d21ac55
A
6447
6448 // Every PM machine states must be handled in one of the cases below.
6449
6450 switch ( fMachineState )
6451 {
6452 case kIOPM_Finished:
6453 executePMRequest( request );
6454 break;
6455
6456 case kIOPM_OurChangeTellClientsPowerDown:
6d2010ae
A
6457 // Root domain might self cancel due to assertions.
6458 if (IS_ROOT_DOMAIN)
6459 {
6460 bool cancel = (bool) fDoNotPowerDown;
6461 getPMRootDomain()->askChangeDownDone(
6462 &fHeadNoteChangeFlags, &cancel);
6463 fDoNotPowerDown = cancel;
6464 }
6465
6466 // askChangeDown() done, was it vetoed?
2d21ac55
A
6467 if (!fDoNotPowerDown)
6468 {
6d2010ae
A
6469 if (IS_ROOT_DOMAIN) {
6470 PMEventDetails *details = PMEventDetails::eventDetails(
6471 kIOPMEventTypeAppNotificationsFinished,
6472 NULL,
6473 0,
6474 0);
6475
6476 getPMRootDomain()->recordAndReleasePMEventGated( details );
6477 }
6478
2d21ac55
A
6479 // no, we can continue
6480 OurChangeTellClientsPowerDown();
6481 }
6482 else
6483 {
6d2010ae
A
6484 if (IS_ROOT_DOMAIN) {
6485 PMEventDetails *details = PMEventDetails::eventDetails(
6486 kIOPMEventTypeSleepDone,
6487 NULL,
6488 1, /* reason: 1 == Ask clients succeeded */
6489 kIOReturnAborted); /* result */
6490
6491 getPMRootDomain()->recordAndReleasePMEventGated( details );
6492 }
6493
593a1d5f
A
6494 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
6495 PM_ERROR("%s: idle cancel\n", fName);
2d21ac55 6496 // yes, rescind the warning
b0d623f7 6497 tellNoChangeDown(fHeadNotePowerState);
2d21ac55 6498 // mark the change note un-actioned
6d2010ae 6499 fHeadNoteChangeFlags |= kIOPMNotDone;
2d21ac55 6500 // and we're done
6d2010ae 6501 OurChangeFinish();
2d21ac55
A
6502 }
6503 break;
6504
6505 case kIOPM_OurChangeTellPriorityClientsPowerDown:
6d2010ae 6506 // tellChangeDown(kNotifyApps) done, was it cancelled?
593a1d5f
A
6507 if (fDoNotPowerDown)
6508 {
6d2010ae
A
6509 if (IS_ROOT_DOMAIN) {
6510 PMEventDetails *details = PMEventDetails::eventDetails(
6511 kIOPMEventTypeSleepDone,
6512 NULL,
6513 2, /* reason: 2 == Client cancelled wake */
6514 kIOReturnAborted); /* result */
6515
6516 getPMRootDomain()->recordAndReleasePMEventGated( details );
6517 }
593a1d5f
A
6518 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
6519 PM_ERROR("%s: idle revert\n", fName);
6520 // no, tell clients we're back in the old state
6521 tellChangeUp(fCurrentPowerState);
6522 // mark the change note un-actioned
6d2010ae 6523 fHeadNoteChangeFlags |= kIOPMNotDone;
593a1d5f 6524 // and we're done
6d2010ae 6525 OurChangeFinish();
593a1d5f
A
6526 }
6527 else
593a1d5f 6528 {
6d2010ae
A
6529 if (IS_ROOT_DOMAIN) {
6530 PMEventDetails *details = PMEventDetails::eventDetails(
6531 kIOPMEventTypeAppNotificationsFinished,
6532 NULL,
6533 2, /* reason: 2 == TellPriorityClientsDone */
6534 kIOReturnSuccess); /* result */
6535
6536 getPMRootDomain()->recordAndReleasePMEventGated( details );
6537 }
593a1d5f
A
6538 // yes, we can continue
6539 OurChangeTellPriorityClientsPowerDown();
6540 }
2d21ac55
A
6541 break;
6542
6543 case kIOPM_OurChangeNotifyInterestedDriversWillChange:
6544 OurChangeNotifyInterestedDriversWillChange();
6545 break;
6546
6547 case kIOPM_OurChangeSetPowerState:
6548 OurChangeSetPowerState();
6549 break;
6550
6551 case kIOPM_OurChangeWaitForPowerSettle:
6552 OurChangeWaitForPowerSettle();
6553 break;
6554
6555 case kIOPM_OurChangeNotifyInterestedDriversDidChange:
6556 OurChangeNotifyInterestedDriversDidChange();
6557 break;
6558
6d2010ae
A
6559 case kIOPM_OurChangeTellCapabilityDidChange:
6560 OurChangeTellCapabilityDidChange();
6561 break;
6562
2d21ac55
A
6563 case kIOPM_OurChangeFinish:
6564 OurChangeFinish();
6565 break;
6566
6d2010ae
A
6567 case kIOPM_ParentChangeTellPriorityClientsPowerDown:
6568 ParentChangeTellPriorityClientsPowerDown();
2d21ac55
A
6569 break;
6570
6d2010ae
A
6571 case kIOPM_ParentChangeNotifyInterestedDriversWillChange:
6572 ParentChangeNotifyInterestedDriversWillChange();
2d21ac55
A
6573 break;
6574
6d2010ae
A
6575 case kIOPM_ParentChangeSetPowerState:
6576 ParentChangeSetPowerState();
2d21ac55
A
6577 break;
6578
6d2010ae
A
6579 case kIOPM_ParentChangeWaitForPowerSettle:
6580 ParentChangeWaitForPowerSettle();
2d21ac55
A
6581 break;
6582
6d2010ae
A
6583 case kIOPM_ParentChangeNotifyInterestedDriversDidChange:
6584 ParentChangeNotifyInterestedDriversDidChange();
2d21ac55
A
6585 break;
6586
6d2010ae
A
6587 case kIOPM_ParentChangeTellCapabilityDidChange:
6588 ParentChangeTellCapabilityDidChange();
6589 break;
2d21ac55 6590
6d2010ae
A
6591 case kIOPM_ParentChangeAcknowledgePowerChange:
6592 ParentChangeAcknowledgePowerChange();
2d21ac55
A
6593 break;
6594
2d21ac55
A
6595 case kIOPM_DriverThreadCallDone:
6596 if (fDriverCallReason == kDriverCallSetPowerState)
6597 notifyControllingDriverDone();
6598 else
6599 notifyInterestedDriversDone();
6600 break;
6601
6d2010ae
A
6602 case kIOPM_NotifyChildrenOrdered:
6603 notifyChildrenOrdered();
6604 break;
6605
6606 case kIOPM_NotifyChildrenDelayed:
6607 notifyChildrenDelayed();
6608 break;
6609
6610 case kIOPM_NotifyChildrenStart:
6611 PM_LOG2("%s: kIOPM_NotifyChildrenStart done\n", getName());
6612 MS_POP(); // from notifyInterestedDriversDone()
6613 notifyChildren();
6614 break;
6615
6616 case kIOPM_SyncTellClientsPowerDown:
6617 // Root domain might self cancel due to assertions.
6618 if (IS_ROOT_DOMAIN)
6619 {
6620 bool cancel = (bool) fDoNotPowerDown;
6621 getPMRootDomain()->askChangeDownDone(
6622 &fHeadNoteChangeFlags, &cancel);
6623 fDoNotPowerDown = cancel;
6624 }
6625 if (!fDoNotPowerDown)
6626 {
6627 fMachineState = kIOPM_SyncTellPriorityClientsPowerDown;
6628 fOutOfBandParameter = kNotifyApps;
6629 tellChangeDown(fHeadNotePowerState);
6630 }
6631 else
6632 {
6633 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
6634 PM_ERROR("%s: idle cancel\n", fName);
6635 tellNoChangeDown(fHeadNotePowerState);
6636 fHeadNoteChangeFlags |= kIOPMNotDone;
6637 OurChangeFinish();
6638 }
6639 break;
6640
6641 case kIOPM_SyncTellPriorityClientsPowerDown:
6642 if (!fDoNotPowerDown)
6643 {
6644 fMachineState = kIOPM_SyncNotifyWillChange;
6645 fOutOfBandParameter = kNotifyPriority;
6646 tellChangeDown(fHeadNotePowerState);
6647 }
6648 else
6649 {
6650 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
6651 PM_ERROR("%s: idle revert\n", fName);
6652 tellChangeUp(fCurrentPowerState);
6653 fHeadNoteChangeFlags |= kIOPMNotDone;
6654 OurChangeFinish();
6655 }
2d21ac55
A
6656 break;
6657
6d2010ae
A
6658 case kIOPM_SyncNotifyWillChange:
6659 if (kIOPMSyncNoChildNotify & fHeadNoteChangeFlags)
6660 {
6661 fMachineState = kIOPM_SyncFinish;
6662 continue;
6663 }
6664 fMachineState = kIOPM_SyncNotifyDidChange;
6665 fDriverCallReason = kDriverCallInformPreChange;
6666 notifyChildren();
6667 break;
6668
b0d623f7 6669 case kIOPM_SyncNotifyDidChange:
6d2010ae
A
6670 fIsPreChange = false;
6671
6672 if (fHeadNoteChangeFlags & kIOPMParentInitiated)
6673 fMachineState = kIOPM_SyncFinish;
6674 else
6675 fMachineState = kIOPM_SyncTellCapabilityDidChange;
6676
b0d623f7
A
6677 fDriverCallReason = kDriverCallInformPostChange;
6678 notifyChildren();
6679 break;
6680
6d2010ae
A
6681 case kIOPM_SyncTellCapabilityDidChange:
6682 tellSystemCapabilityChange( kIOPM_SyncFinish );
6683 break;
6684
b0d623f7 6685 case kIOPM_SyncFinish:
6d2010ae
A
6686 if (fHeadNoteChangeFlags & kIOPMParentInitiated)
6687 ParentChangeAcknowledgePowerChange();
b0d623f7
A
6688 else
6689 OurChangeFinish();
6d2010ae
A
6690 break;
6691
6692 case kIOPM_TellCapabilityChangeDone:
6693 if (fIsPreChange)
6694 {
6695 if (fOutOfBandParameter == kNotifyCapabilityChangePriority)
6696 {
6697 MS_POP(); // tellSystemCapabilityChange()
6698 continue;
6699 }
6700 fOutOfBandParameter = kNotifyCapabilityChangePriority;
6701 }
6702 else
6703 {
6704 if (fOutOfBandParameter == kNotifyCapabilityChangeApps)
6705 {
6706 MS_POP(); // tellSystemCapabilityChange()
6707 continue;
6708 }
6709 fOutOfBandParameter = kNotifyCapabilityChangeApps;
6710 }
6711 tellClientsWithResponse( fOutOfBandMessage );
b0d623f7
A
6712 break;
6713
2d21ac55 6714 default:
b0d623f7
A
6715 panic("servicePMWorkQueue: unknown machine state %x",
6716 fMachineState);
2d21ac55
A
6717 }
6718
b0d623f7 6719 gIOPMRequest = 0;
2d21ac55
A
6720
6721 if (fMachineState == kIOPM_Finished)
6722 {
2d21ac55
A
6723 done = true;
6724 break;
6725 }
6726 }
1c79356b 6727
2d21ac55
A
6728 return done;
6729}
1c79356b 6730
1c79356b 6731//*********************************************************************************
2d21ac55
A
6732// [private] executePMRequest
6733//*********************************************************************************
6734
6735void IOService::executePMRequest( IOPMRequest * request )
6736{
6737 assert( kIOPM_Finished == fMachineState );
6738
6739 switch (request->getType())
6740 {
6741 case kIOPMRequestTypePMStop:
6742 handlePMstop( request );
6743 break;
6744
6745 case kIOPMRequestTypeAddPowerChild1:
6746 addPowerChild1( request );
6747 break;
6748
6749 case kIOPMRequestTypeAddPowerChild2:
6750 addPowerChild2( request );
6751 break;
6752
6753 case kIOPMRequestTypeAddPowerChild3:
6754 addPowerChild3( request );
6755 break;
6756
6757 case kIOPMRequestTypeRegisterPowerDriver:
6758 handleRegisterPowerDriver( request );
6759 break;
6760
6761 case kIOPMRequestTypeAdjustPowerState:
b0d623f7
A
6762 fAdjustPowerScheduled = false;
6763 rebuildChildClampBits();
2d21ac55
A
6764 adjustPowerState();
6765 break;
6766
2d21ac55
A
6767 case kIOPMRequestTypePowerDomainWillChange:
6768 handlePowerDomainWillChangeTo( request );
6769 break;
6770
6771 case kIOPMRequestTypePowerDomainDidChange:
6d2010ae 6772
2d21ac55
A
6773 handlePowerDomainDidChangeTo( request );
6774 break;
6775
b0d623f7
A
6776 case kIOPMRequestTypeRequestPowerState:
6777 case kIOPMRequestTypeRequestPowerStateOverride:
6778 handleRequestPowerState( request );
2d21ac55
A
6779 break;
6780
6781 case kIOPMRequestTypePowerOverrideOnPriv:
6782 case kIOPMRequestTypePowerOverrideOffPriv:
6783 handlePowerOverrideChanged( request );
6784 break;
6785
6786 case kIOPMRequestTypeActivityTickle:
b0d623f7
A
6787 handleActivityTickle( request );
6788 break;
2d21ac55 6789
b0d623f7
A
6790 case kIOPMRequestTypeSynchronizePowerTree:
6791 handleSynchronizePowerTree( request );
6792 break;
6793
6794 case kIOPMRequestTypeSetIdleTimerPeriod:
6795 {
b0d623f7
A
6796 fIdleTimerPeriod = (uintptr_t) request->fArg0;
6797
6d2010ae 6798 if ((false == fLockedFlags.PMStop) && (fIdleTimerPeriod > 0))
b0d623f7 6799 {
b0d623f7
A
6800 fActivityTickleCount = 0;
6801 clock_get_uptime(&fIdleTimerStartTime);
6802 start_PM_idle_timer();
6803 }
6804 }
6805 break;
2d21ac55
A
6806
6807 default:
b0d623f7 6808 panic("executePMRequest: unknown request type %x", request->getType());
2d21ac55
A
6809 }
6810}
6811
6812//*********************************************************************************
6813// [private] servicePMReplyQueue
6814//*********************************************************************************
6815
6816bool IOService::servicePMReplyQueue( IOPMRequest * request, IOPMRequestQueue * queue )
6817{
6818 bool more = false;
6819
6820 assert( request && queue );
b0d623f7 6821 assert( request->isReplyType() );
2d21ac55 6822
6d2010ae 6823 PM_LOG1("[A %02x] %p [%p %s] state %d\n",
2d21ac55
A
6824 request->getType(), request, this, getName(), fMachineState);
6825
6826 switch ( request->getType() )
6827 {
6828 case kIOPMRequestTypeAllowPowerChange:
6829 case kIOPMRequestTypeCancelPowerChange:
6830 // Check if we are expecting this response.
6d2010ae
A
6831 if (responseValid((uint32_t)(uintptr_t) request->fArg0,
6832 (int)(uintptr_t) request->fArg1))
2d21ac55
A
6833 {
6834 if (kIOPMRequestTypeCancelPowerChange == request->getType())
b0d623f7 6835 {
6d2010ae
A
6836 // Clients are not allowed to cancel when kIOPMSkipAskPowerDown
6837 // flag is set. Only root domain will set this flag.
6838
6839 if ((fHeadNoteChangeFlags & kIOPMSkipAskPowerDown) == 0)
6840 {
6841 fDoNotPowerDown = true;
b0d623f7 6842
6d2010ae
A
6843 OSString * name = (OSString *) request->fArg2;
6844 getPMRootDomain()->pmStatsRecordApplicationResponse(
6845 gIOPMStatsApplicationResponseCancel,
6846 name ? name->getCStringNoCopy() : "", 0,
6847 0, (int)(uintptr_t) request->fArg1);
6848 }
b0d623f7 6849 }
2d21ac55
A
6850
6851 if (checkForDone())
6852 {
6853 stop_ack_timer();
6d2010ae 6854 cleanClientResponses(false);
2d21ac55
A
6855 more = true;
6856 }
6857 }
b0d623f7
A
6858 // OSString containing app name in Arg2 must be released.
6859 if (request->getType() == kIOPMRequestTypeCancelPowerChange)
6860 {
6861 OSObject * obj = (OSObject *) request->fArg2;
6862 if (obj) obj->release();
6863 }
2d21ac55
A
6864 break;
6865
6866 case kIOPMRequestTypeAckPowerChange:
6867 more = handleAcknowledgePowerChange( request );
6868 break;
6869
6870 case kIOPMRequestTypeAckSetPowerState:
6871 if (fDriverTimer == -1)
6872 {
6873 // driver acked while setPowerState() call is in-flight.
6874 // take this ack, return value from setPowerState() is irrelevant.
6875 OUR_PMLog(kPMLogDriverAcknowledgeSet,
b0d623f7 6876 (uintptr_t) this, fDriverTimer);
2d21ac55
A
6877 fDriverTimer = 0;
6878 }
6879 else if (fDriverTimer > 0)
6880 {
6881 // expected ack, stop the timer
6882 stop_ack_timer();
6883
6884#if LOG_SETPOWER_TIMES
6885 uint64_t nsec = computeTimeDeltaNS(&fDriverCallStartTime);
6886 if (nsec > LOG_SETPOWER_TIMES)
6d2010ae 6887 PM_LOG("%s::setPowerState(%p, %lu -> %lu) async took %d ms\n",
b0d623f7 6888 fName, this, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
6d2010ae
A
6889
6890 PMEventDetails *details = PMEventDetails::eventDetails(
6891 kIOPMEventTypeSetPowerStateDelayed, // type
6892 fName, // who
6893 (uintptr_t)this, // owner unique
6894 NULL, // interest name
6895 (uint8_t)getPowerState(), // old
6896 (uint8_t)fHeadNotePowerState, // new
6897 0, // result
6898 NS_TO_US(nsec)); // usec completion time
6899
6900 getPMRootDomain()->recordAndReleasePMEventGated( details );
2d21ac55 6901#endif
b0d623f7 6902 OUR_PMLog(kPMLogDriverAcknowledgeSet, (uintptr_t) this, fDriverTimer);
2d21ac55
A
6903 fDriverTimer = 0;
6904 more = true;
6905 }
6906 else
6907 {
6908 // unexpected ack
b0d623f7 6909 OUR_PMLog(kPMLogAcknowledgeErr4, (uintptr_t) this, 0);
2d21ac55
A
6910 }
6911 break;
6912
6913 case kIOPMRequestTypeInterestChanged:
6914 handleInterestChanged( request );
6915 more = true;
6916 break;
6917
593a1d5f
A
6918 case kIOPMRequestTypeIdleCancel:
6919 if ((fMachineState == kIOPM_OurChangeTellClientsPowerDown)
6d2010ae
A
6920 || (fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown)
6921 || (fMachineState == kIOPM_SyncTellClientsPowerDown)
6922 || (fMachineState == kIOPM_SyncTellPriorityClientsPowerDown))
593a1d5f 6923 {
6d2010ae
A
6924 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
6925 PM_LOG2("%s: cancel from machine state %d\n",
6926 getName(), fMachineState);
593a1d5f 6927 fDoNotPowerDown = true;
6d2010ae
A
6928 // Stop waiting for app replys.
6929 if ((fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown) ||
6930 (fMachineState == kIOPM_SyncTellPriorityClientsPowerDown))
593a1d5f
A
6931 cleanClientResponses(false);
6932 more = true;
6933 }
6934 break;
593a1d5f 6935
6d2010ae
A
6936 case kIOPMRequestTypeChildNotifyDelayCancel:
6937 if (fMachineState == kIOPM_NotifyChildrenDelayed)
6938 {
6939 PM_LOG2("%s: delay notify cancelled\n", getName());
6940 notifyChildrenDelayed();
6941 }
6942 break;
6943
2d21ac55 6944 default:
b0d623f7
A
6945 panic("servicePMReplyQueue: unknown reply type %x",
6946 request->getType());
2d21ac55
A
6947 }
6948
6d2010ae
A
6949 more |= gIOPMFreeQueue->queuePMRequest(request);
6950 if (more)
6951 gIOPMWorkQueue->incrementProducerCount();
6952
2d21ac55
A
6953 return more;
6954}
6955
b0d623f7 6956//*********************************************************************************
6d2010ae 6957// [private] assertPMDriverCall / deassertPMDriverCall
b0d623f7
A
6958//*********************************************************************************
6959
6d2010ae
A
6960bool IOService::assertPMDriverCall(
6961 IOPMDriverCallEntry * entry,
6962 IOOptionBits options,
6963 IOPMinformee * inform )
b0d623f7 6964{
6d2010ae
A
6965 IOService * target = 0;
6966 bool ok = false;
6967
b0d623f7
A
6968 if (!initialized)
6969 return false;
6970
b0d623f7 6971 PM_LOCK();
6d2010ae 6972
b0d623f7
A
6973 if (fLockedFlags.PMStop)
6974 {
6d2010ae
A
6975 goto fail;
6976 }
6977
6978 if (((options & kIOPMADC_NoInactiveCheck) == 0) && isInactive())
6979 {
6980 goto fail;
6981 }
6982
6983 if (inform)
6984 {
6985 if (!inform->active)
6986 {
6987 goto fail;
6988 }
6989 target = inform->whatObject;
6990 if (target->isInactive())
6991 {
6992 goto fail;
6993 }
b0d623f7
A
6994 }
6995
6d2010ae
A
6996 entry->thread = current_thread();
6997 entry->target = target;
6998 queue_enter(&fPMDriverCallQueue, entry, IOPMDriverCallEntry *, link);
6999 ok = true;
7000
7001fail:
b0d623f7
A
7002 PM_UNLOCK();
7003
6d2010ae 7004 return ok;
b0d623f7
A
7005}
7006
6d2010ae 7007void IOService::deassertPMDriverCall( IOPMDriverCallEntry * entry )
b0d623f7 7008{
6d2010ae
A
7009 bool wakeup = false;
7010
b0d623f7 7011 PM_LOCK();
6d2010ae
A
7012
7013 assert( !queue_empty(&fPMDriverCallQueue) );
7014 queue_remove(&fPMDriverCallQueue, entry, IOPMDriverCallEntry *, link);
7015 if (fLockedFlags.PMDriverCallWait)
b0d623f7 7016 {
6d2010ae 7017 wakeup = true;
b0d623f7 7018 }
6d2010ae 7019
b0d623f7 7020 PM_UNLOCK();
6d2010ae
A
7021
7022 if (wakeup)
7023 PM_LOCK_WAKEUP(&fPMDriverCallQueue);
7024}
7025
7026void IOService::waitForPMDriverCall( IOService * target )
7027{
7028 const IOPMDriverCallEntry * entry;
7029 thread_t thread = current_thread();
7030 AbsoluteTime deadline;
7031 int waitResult;
7032 bool log = true;
7033 bool wait;
7034
7035 do {
7036 wait = false;
7037 queue_iterate(&fPMDriverCallQueue, entry, const IOPMDriverCallEntry *, link)
7038 {
7039 // Target of interested driver call
7040 if (target && (target != entry->target))
7041 continue;
7042
7043 if (entry->thread == thread)
7044 {
7045 if (log)
7046 {
7047 PM_LOG("%s: %s(%s) on PM thread\n",
7048 fName, __FUNCTION__, target ? target->getName() : "");
7049 OSReportWithBacktrace("%s: %s(%s) on PM thread\n",
7050 fName, __FUNCTION__, target ? target->getName() : "");
7051 log = false;
7052 }
7053 continue;
7054 }
7055
7056 wait = true;
7057 break;
7058 }
7059
7060 if (wait)
7061 {
7062 fLockedFlags.PMDriverCallWait = true;
7063 clock_interval_to_deadline(15, kSecondScale, &deadline);
7064 waitResult = PM_LOCK_SLEEP(&fPMDriverCallQueue, deadline);
7065 fLockedFlags.PMDriverCallWait = false;
7066 if (THREAD_TIMED_OUT == waitResult)
7067 {
7068 PM_ERROR("%s: waitForPMDriverCall timeout\n", fName);
7069 wait = false;
7070 }
7071 }
7072 } while (wait);
7073}
7074
7075//*********************************************************************************
7076// [private] Debug helpers
7077//*********************************************************************************
7078
7079const char * IOService::getIOMessageString( uint32_t msg )
7080{
7081#define MSG_ENTRY(x) {x, #x}
7082
7083 static const IONamedValue msgNames[] = {
7084 MSG_ENTRY( kIOMessageCanDevicePowerOff ),
7085 MSG_ENTRY( kIOMessageDeviceWillPowerOff ),
7086 MSG_ENTRY( kIOMessageDeviceWillNotPowerOff ),
7087 MSG_ENTRY( kIOMessageDeviceHasPoweredOn ),
7088 MSG_ENTRY( kIOMessageCanSystemPowerOff ),
7089 MSG_ENTRY( kIOMessageSystemWillPowerOff ),
7090 MSG_ENTRY( kIOMessageSystemWillNotPowerOff ),
7091 MSG_ENTRY( kIOMessageCanSystemSleep ),
7092 MSG_ENTRY( kIOMessageSystemWillSleep ),
7093 MSG_ENTRY( kIOMessageSystemWillNotSleep ),
7094 MSG_ENTRY( kIOMessageSystemHasPoweredOn ),
7095 MSG_ENTRY( kIOMessageSystemWillRestart ),
7096 MSG_ENTRY( kIOMessageSystemWillPowerOn ),
7097 MSG_ENTRY( kIOMessageSystemCapabilityChange )
7098 };
7099
7100 return IOFindNameForValue(msg, msgNames);
b0d623f7
A
7101}
7102
7e4a7d39
A
7103// MARK: -
7104// MARK: IOPMRequest
7105
2d21ac55
A
7106//*********************************************************************************
7107// IOPMRequest Class
7108//
7109// Requests from PM clients, and also used for inter-object messaging within PM.
7110//*********************************************************************************
7111
7112OSDefineMetaClassAndStructors( IOPMRequest, IOCommand );
7113
7114IOPMRequest * IOPMRequest::create( void )
7115{
7116 IOPMRequest * me = OSTypeAlloc(IOPMRequest);
7117 if (me && !me->init(0, kIOPMRequestTypeInvalid))
7118 {
7119 me->release();
7120 me = 0;
7121 }
7122 return me;
7123}
7124
7125bool IOPMRequest::init( IOService * target, IOOptionBits type )
7126{
7127 if (!IOCommand::init())
7128 return false;
7129
b0d623f7
A
7130 fType = type;
7131 fTarget = target;
7132 fCompletionStatus = kIOReturnSuccess;
2d21ac55
A
7133
7134 if (fTarget)
7135 fTarget->retain();
7136
7137 return true;
7138}
7139
7140void IOPMRequest::reset( void )
7141{
b0d623f7
A
7142 assert( fWorkWaitCount == 0 );
7143 assert( fFreeWaitCount == 0 );
7144
7145 detachNextRequest();
7146 detachRootRequest();
2d21ac55
A
7147
7148 fType = kIOPMRequestTypeInvalid;
7149
b0d623f7 7150 if (fCompletionAction)
2d21ac55 7151 {
b0d623f7
A
7152 fCompletionAction(fCompletionTarget, fCompletionParam, fCompletionStatus);
7153 }
2d21ac55
A
7154
7155 if (fTarget)
7156 {
7157 fTarget->release();
7158 fTarget = 0;
b0d623f7
A
7159 }
7160}
7161
6d2010ae 7162bool IOPMRequest::attachNextRequest( IOPMRequest * next )
b0d623f7 7163{
6d2010ae
A
7164 bool ok = false;
7165
b0d623f7
A
7166 if (!fRequestNext)
7167 {
7168 // Postpone the execution of the next request after
7169 // this request.
7170 fRequestNext = next;
7171 fRequestNext->fWorkWaitCount++;
7172#if LOG_REQUEST_ATTACH
7173 kprintf("Attached next: %p [0x%x] -> %p [0x%x, %u] %s\n",
7174 this, (uint32_t) fType, fRequestNext,
7175 (uint32_t) fRequestNext->fType,
7176 (uint32_t) fRequestNext->fWorkWaitCount,
7177 fTarget->getName());
7178#endif
6d2010ae 7179 ok = true;
b0d623f7 7180 }
6d2010ae 7181 return ok;
b0d623f7
A
7182}
7183
6d2010ae 7184bool IOPMRequest::detachNextRequest( void )
b0d623f7 7185{
6d2010ae
A
7186 bool ok = false;
7187
b0d623f7
A
7188 if (fRequestNext)
7189 {
7190 assert(fRequestNext->fWorkWaitCount);
7191 if (fRequestNext->fWorkWaitCount)
7192 fRequestNext->fWorkWaitCount--;
7193#if LOG_REQUEST_ATTACH
7194 kprintf("Detached next: %p [0x%x] -> %p [0x%x, %u] %s\n",
7195 this, (uint32_t) fType, fRequestNext,
7196 (uint32_t) fRequestNext->fType,
7197 (uint32_t) fRequestNext->fWorkWaitCount,
7198 fTarget->getName());
7199#endif
7200 fRequestNext = 0;
6d2010ae 7201 ok = true;
b0d623f7 7202 }
6d2010ae 7203 return ok;
b0d623f7
A
7204}
7205
6d2010ae 7206bool IOPMRequest::attachRootRequest( IOPMRequest * root )
b0d623f7 7207{
6d2010ae
A
7208 bool ok = false;
7209
b0d623f7
A
7210 if (!fRequestRoot)
7211 {
7212 // Delay the completion of the root request after
7213 // this request.
7214 fRequestRoot = root;
7215 fRequestRoot->fFreeWaitCount++;
7216#if LOG_REQUEST_ATTACH
7217 kprintf("Attached root: %p [0x%x] -> %p [0x%x, %u] %s\n",
7218 this, (uint32_t) fType, fRequestRoot,
7219 (uint32_t) fRequestRoot->fType,
7220 (uint32_t) fRequestRoot->fFreeWaitCount,
7221 fTarget->getName());
7222#endif
6d2010ae 7223 ok = true;
b0d623f7 7224 }
6d2010ae 7225 return ok;
b0d623f7
A
7226}
7227
6d2010ae 7228bool IOPMRequest::detachRootRequest( void )
b0d623f7 7229{
6d2010ae
A
7230 bool ok = false;
7231
b0d623f7
A
7232 if (fRequestRoot)
7233 {
7234 assert(fRequestRoot->fFreeWaitCount);
7235 if (fRequestRoot->fFreeWaitCount)
7236 fRequestRoot->fFreeWaitCount--;
7237#if LOG_REQUEST_ATTACH
7238 kprintf("Detached root: %p [0x%x] -> %p [0x%x, %u] %s\n",
7239 this, (uint32_t) fType, fRequestRoot,
7240 (uint32_t) fRequestRoot->fType,
7241 (uint32_t) fRequestRoot->fFreeWaitCount,
7242 fTarget->getName());
7243#endif
7244 fRequestRoot = 0;
6d2010ae 7245 ok = true;
b0d623f7 7246 }
6d2010ae 7247 return ok;
2d21ac55
A
7248}
7249
7e4a7d39
A
7250// MARK: -
7251// MARK: IOPMRequestQueue
7252
2d21ac55
A
7253//*********************************************************************************
7254// IOPMRequestQueue Class
1c79356b 7255//
6d2010ae 7256// Global queues. Queues are created once and never released.
1c79356b 7257//*********************************************************************************
2d21ac55
A
7258
7259OSDefineMetaClassAndStructors( IOPMRequestQueue, IOEventSource );
7260
7261IOPMRequestQueue * IOPMRequestQueue::create( IOService * inOwner, Action inAction )
1c79356b 7262{
2d21ac55
A
7263 IOPMRequestQueue * me = OSTypeAlloc(IOPMRequestQueue);
7264 if (me && !me->init(inOwner, inAction))
7265 {
7266 me->release();
7267 me = 0;
7268 }
7269 return me;
7270}
1c79356b 7271
2d21ac55
A
7272bool IOPMRequestQueue::init( IOService * inOwner, Action inAction )
7273{
7274 if (!inAction || !IOEventSource::init(inOwner, (IOEventSourceAction)inAction))
1c79356b
A
7275 return false;
7276
2d21ac55
A
7277 queue_init(&fQueue);
7278 fLock = IOLockAlloc();
7279 return (fLock != 0);
7280}
1c79356b 7281
2d21ac55
A
7282void IOPMRequestQueue::free( void )
7283{
7284 if (fLock)
7285 {
7286 IOLockFree(fLock);
7287 fLock = 0;
7288 }
7289 return IOEventSource::free();
7290}
1c79356b 7291
2d21ac55
A
7292void IOPMRequestQueue::queuePMRequest( IOPMRequest * request )
7293{
7294 assert(request);
7295 IOLockLock(fLock);
7296 queue_enter(&fQueue, request, IOPMRequest *, fCommandChain);
7297 IOLockUnlock(fLock);
7298 if (workLoop) signalWorkAvailable();
7299}
1c79356b 7300
2d21ac55
A
7301void
7302IOPMRequestQueue::queuePMRequestChain( IOPMRequest ** requests, IOItemCount count )
7303{
7304 IOPMRequest * next;
7305
7306 assert(requests && count);
7307 IOLockLock(fLock);
7308 while (count--)
7309 {
7310 next = *requests;
7311 requests++;
7312 queue_enter(&fQueue, next, IOPMRequest *, fCommandChain);
7313 }
7314 IOLockUnlock(fLock);
7315 if (workLoop) signalWorkAvailable();
7316}
7317
7318bool IOPMRequestQueue::checkForWork( void )
7319{
7320 Action dqAction = (Action) action;
7321 IOPMRequest * request;
7322 IOService * target;
7323 bool more = false;
7324
7325 IOLockLock( fLock );
7326
7327 while (!queue_empty(&fQueue))
7328 {
7329 queue_remove_first( &fQueue, request, IOPMRequest *, fCommandChain );
7330 IOLockUnlock( fLock );
7331 target = request->getTarget();
7332 assert(target);
7333 more |= (*dqAction)( target, request, this );
7334 IOLockLock( fLock );
7335 }
7336
7337 IOLockUnlock( fLock );
7338 return more;
7339}
7340
7e4a7d39
A
7341// MARK: -
7342// MARK: IOPMWorkQueue
7343
2d21ac55
A
7344//*********************************************************************************
7345// IOPMWorkQueue Class
7346//
6d2010ae 7347// Queue of IOServicePM objects with busy IOPMRequest(s).
2d21ac55 7348//*********************************************************************************
1c79356b 7349
2d21ac55 7350OSDefineMetaClassAndStructors( IOPMWorkQueue, IOEventSource );
1c79356b 7351
2d21ac55
A
7352IOPMWorkQueue *
7353IOPMWorkQueue::create( IOService * inOwner, Action work, Action retire )
7354{
7355 IOPMWorkQueue * me = OSTypeAlloc(IOPMWorkQueue);
7356 if (me && !me->init(inOwner, work, retire))
7357 {
7358 me->release();
7359 me = 0;
7360 }
7361 return me;
7362}
7363
7364bool IOPMWorkQueue::init( IOService * inOwner, Action work, Action retire )
7365{
7366 if (!work || !retire ||
7367 !IOEventSource::init(inOwner, (IOEventSourceAction)0))
7368 return false;
7369
7370 queue_init(&fWorkQueue);
7371
6d2010ae
A
7372 fWorkAction = work;
7373 fRetireAction = retire;
7374 fConsumerCount = fProducerCount = 0;
2d21ac55
A
7375
7376 return true;
7377}
7378
6d2010ae 7379bool IOPMWorkQueue::queuePMRequest( IOPMRequest * request, IOServicePM * pwrMgt )
2d21ac55 7380{
6d2010ae
A
7381 bool more = false;
7382 bool empty;
7383
2d21ac55 7384 assert( request );
6d2010ae 7385 assert( pwrMgt );
2d21ac55 7386 assert( onThread() );
6d2010ae
A
7387 assert( queue_next(&request->fCommandChain) ==
7388 queue_prev(&request->fCommandChain) );
2d21ac55
A
7389
7390 gIOPMBusyCount++;
6d2010ae
A
7391
7392 // Add new request to the tail of the per-service request queue.
7393 // Then immediately check the request queue to minimize latency
7394 // if the queue was empty.
7395
7396 empty = queue_empty(&pwrMgt->RequestHead);
7397 queue_enter(&pwrMgt->RequestHead, request, IOPMRequest *, fCommandChain);
7398 if (empty)
7399 {
7400 more = checkRequestQueue(&pwrMgt->RequestHead, &empty);
7401 if (!empty)
7402 {
7403 // New Request is blocked, add IOServicePM to work queue.
7404 assert( queue_next(&pwrMgt->WorkChain) ==
7405 queue_prev(&pwrMgt->WorkChain) );
7406
7407 queue_enter(&fWorkQueue, pwrMgt, IOServicePM *, WorkChain);
7408 fQueueLength++;
7409 PM_LOG3("IOPMWorkQueue: [%u] added %s@%p to queue\n",
7410 fQueueLength, pwrMgt->Name, pwrMgt);
7411 }
7412 }
7413
7414 return more;
2d21ac55
A
7415}
7416
6d2010ae 7417bool IOPMWorkQueue::checkRequestQueue( queue_head_t * queue, bool * empty )
2d21ac55
A
7418{
7419 IOPMRequest * request;
6d2010ae
A
7420 IOService * target;
7421 bool more = false;
7422 bool done = false;
2d21ac55 7423
6d2010ae
A
7424 assert(!queue_empty(queue));
7425 do {
7426 request = (IOPMRequest *) queue_first(queue);
7427 if (request->isWorkBlocked())
7428 break; // cannot start, blocked on attached request
2d21ac55 7429
6d2010ae
A
7430 target = request->getTarget();
7431 done = (*fWorkAction)( target, request, this );
7432 if (!done)
7433 break; // work started, blocked on PM state machine
7434
7435 assert(gIOPMBusyCount > 0);
7436 if (gIOPMBusyCount)
7437 gIOPMBusyCount--;
7438
7439 queue_remove_first(queue, request, IOPMRequest *, fCommandChain);
7440 more |= (*fRetireAction)( target, request, this );
7441 done = queue_empty(queue);
7442 } while (!done);
7443
7444 *empty = done;
7445
7446 if (more)
7447 {
7448 // Retired request blocks another request, since the
7449 // blocked request may reside in the work queue, we
7450 // must bump the producer count to avoid work stall.
7451 fProducerCount++;
7452 }
7453
7454 return more;
7455}
7456
7457bool IOPMWorkQueue::checkForWork( void )
7458{
7459 IOServicePM * entry;
7460 IOServicePM * next;
7461 bool more = false;
7462 bool empty;
7463
7464#if WORK_QUEUE_STATS
7465 fStatCheckForWork++;
7466#endif
7467
7468 // Each producer signal triggers a full iteration over
7469 // all IOServicePM entries in the work queue.
7470
7471 while (fConsumerCount != fProducerCount)
7472 {
7473 PM_LOG3("IOPMWorkQueue: checkForWork %u %u\n",
7474 fProducerCount, fConsumerCount);
7475
7476 fConsumerCount = fProducerCount;
7477
7478#if WORK_QUEUE_STATS
7479 if (queue_empty(&fWorkQueue))
7480 {
7481 fStatQueueEmpty++;
7482 break;
7483 }
7484 fStatScanEntries++;
7485 uint32_t cachedWorkCount = gIOPMWorkCount;
7486#endif
7487
7488 entry = (IOServicePM *) queue_first(&fWorkQueue);
7489 while (!queue_end(&fWorkQueue, (queue_entry_t) entry))
7490 {
7491 more |= checkRequestQueue(&entry->RequestHead, &empty);
7492
7493 // Get next entry, points to head if current entry is last.
7494 next = (IOServicePM *) queue_next(&entry->WorkChain);
7495
7496 // if request queue is empty, remove IOServicePM from queue.
7497 if (empty)
7498 {
7499 assert(fQueueLength);
7500 if (fQueueLength) fQueueLength--;
7501 PM_LOG3("IOPMWorkQueue: [%u] removed %s@%p from queue\n",
7502 fQueueLength, entry->Name, entry);
7503 queue_remove(&fWorkQueue, entry, IOServicePM *, WorkChain);
7504 }
7505 entry = next;
7506 }
7507
7508#if WORK_QUEUE_STATS
7509 if (cachedWorkCount == gIOPMWorkCount)
7510 fStatNoWorkDone++;
7511#endif
7512 }
7513
7514 return more;
7515}
7516
7517void IOPMWorkQueue::signalWorkAvailable( void )
7518{
7519 fProducerCount++;
7520 IOEventSource::signalWorkAvailable();
7521}
7522
7523void IOPMWorkQueue::incrementProducerCount( void )
7524{
7525 fProducerCount++;
2d21ac55
A
7526}
7527
7e4a7d39
A
7528// MARK: -
7529// MARK: IOPMCompletionQueue
7530
b0d623f7
A
7531//*********************************************************************************
7532// IOPMCompletionQueue Class
7533//*********************************************************************************
7534
7535OSDefineMetaClassAndStructors( IOPMCompletionQueue, IOEventSource );
7536
6d2010ae
A
7537IOPMCompletionQueue *
7538IOPMCompletionQueue::create( IOService * inOwner, Action inAction )
b0d623f7
A
7539{
7540 IOPMCompletionQueue * me = OSTypeAlloc(IOPMCompletionQueue);
7541 if (me && !me->init(inOwner, inAction))
7542 {
7543 me->release();
7544 me = 0;
7545 }
7546 return me;
7547}
7548
7549bool IOPMCompletionQueue::init( IOService * inOwner, Action inAction )
7550{
7551 if (!inAction || !IOEventSource::init(inOwner, (IOEventSourceAction)inAction))
7552 return false;
7553
7554 queue_init(&fQueue);
7555 return true;
7556}
7557
6d2010ae 7558bool IOPMCompletionQueue::queuePMRequest( IOPMRequest * request )
b0d623f7 7559{
6d2010ae
A
7560 bool more;
7561
b0d623f7 7562 assert(request);
6d2010ae
A
7563 // unblock dependent request
7564 more = request->detachNextRequest();
b0d623f7 7565 queue_enter(&fQueue, request, IOPMRequest *, fCommandChain);
6d2010ae 7566 return more;
b0d623f7
A
7567}
7568
7569bool IOPMCompletionQueue::checkForWork( void )
7570{
7571 Action dqAction = (Action) action;
7572 IOPMRequest * request;
6d2010ae 7573 IOPMRequest * next;
b0d623f7
A
7574 IOService * target;
7575 bool more = false;
b0d623f7 7576
6d2010ae
A
7577 request = (IOPMRequest *) queue_first(&fQueue);
7578 while (!queue_end(&fQueue, (queue_entry_t) request))
7579 {
7580 next = (IOPMRequest *) queue_next(&request->fCommandChain);
7581 if (!request->isFreeBlocked())
7582 {
7583 queue_remove(&fQueue, request, IOPMRequest *, fCommandChain);
7584 target = request->getTarget();
7585 assert(target);
7586 more |= (*dqAction)( target, request, this );
7587 }
7588 request = next;
7589 }
b0d623f7 7590
6d2010ae 7591 return more;
b0d623f7
A
7592}
7593
7e4a7d39
A
7594// MARK: -
7595// MARK: IOServicePM
7596
2d21ac55
A
7597OSDefineMetaClassAndStructors(IOServicePM, OSObject)
7598
7599//*********************************************************************************
7600// serialize
7601//
7602// Serialize IOServicePM for debugging.
7603//*********************************************************************************
7604
7605static void
b0d623f7 7606setPMProperty( OSDictionary * dict, const char * key, uint64_t value )
2d21ac55
A
7607{
7608 OSNumber * num = OSNumber::withNumber(value, sizeof(value) * 8);
7609 if (num)
7610 {
7611 dict->setObject(key, num);
7612 num->release();
7613 }
1c79356b
A
7614}
7615
b0d623f7 7616IOReturn IOServicePM::gatedSerialize( OSSerialize * s )
2d21ac55
A
7617{
7618 OSDictionary * dict;
7619 bool ok = false;
6d2010ae 7620 int dictSize = 5;
b0d623f7
A
7621
7622 if (IdleTimerPeriod)
7623 dictSize += 4;
7624
6d2010ae
A
7625#if WORK_QUEUE_STATS
7626 if (gIOPMRootNode == ControllingDriver)
7627 dictSize += 4;
7628#endif
7629
b0d623f7
A
7630 if (PowerClients)
7631 dict = OSDictionary::withDictionary(
7632 PowerClients, PowerClients->getCount() + dictSize);
7633 else
7634 dict = OSDictionary::withCapacity(dictSize);
2d21ac55 7635
2d21ac55
A
7636 if (dict)
7637 {
b0d623f7 7638 setPMProperty(dict, "CurrentPowerState", CurrentPowerState);
6d2010ae
A
7639 if (NumberOfPowerStates)
7640 setPMProperty(dict, "MaxPowerState", NumberOfPowerStates-1);
2d21ac55 7641 if (DesiredPowerState != CurrentPowerState)
b0d623f7 7642 setPMProperty(dict, "DesiredPowerState", DesiredPowerState);
2d21ac55 7643 if (kIOPM_Finished != MachineState)
b0d623f7 7644 setPMProperty(dict, "MachineState", MachineState);
6d2010ae 7645 if (DeviceOverrideEnabled)
b0d623f7
A
7646 dict->setObject("PowerOverrideOn", kOSBooleanTrue);
7647
7648 if (IdleTimerPeriod)
7649 {
7650 AbsoluteTime now;
7651 AbsoluteTime delta;
7652 uint64_t nsecs;
7653
7654 clock_get_uptime(&now);
7655
7656 // The idle timer period in milliseconds.
7657 setPMProperty(dict, "IdleTimerPeriod", IdleTimerPeriod * 1000ULL);
7658
7659 // The number of activity tickles recorded since device idle
7660 setPMProperty(dict, "ActivityTickles", ActivityTickleCount);
7661
7662 if (AbsoluteTime_to_scalar(&DeviceActiveTimestamp))
7663 {
7664 // The number of milliseconds since the last activity tickle.
7665 delta = now;
7666 SUB_ABSOLUTETIME(&delta, &DeviceActiveTimestamp);
7667 absolutetime_to_nanoseconds(delta, &nsecs);
6d2010ae 7668 setPMProperty(dict, "TimeSinceLastTickle", NS_TO_MS(nsecs));
b0d623f7
A
7669 }
7670
7671 if (AbsoluteTime_to_scalar(&IdleTimerStartTime))
7672 {
7673 // The number of milliseconds since the last device idle.
7674 delta = now;
7675 SUB_ABSOLUTETIME(&delta, &IdleTimerStartTime);
7676 absolutetime_to_nanoseconds(delta, &nsecs);
7677 setPMProperty(dict, "TimeSinceDeviceIdle", NS_TO_MS(nsecs));
7678 }
7679 }
2d21ac55 7680
6d2010ae
A
7681#if WORK_QUEUE_STATS
7682 if (gIOPMRootNode == Owner)
7683 {
7684 setPMProperty(dict, "WQ-CheckForWork",
7685 gIOPMWorkQueue->fStatCheckForWork);
7686 setPMProperty(dict, "WQ-ScanEntries",
7687 gIOPMWorkQueue->fStatScanEntries);
7688 setPMProperty(dict, "WQ-QueueEmpty",
7689 gIOPMWorkQueue->fStatQueueEmpty);
7690 setPMProperty(dict, "WQ-NoWorkDone",
7691 gIOPMWorkQueue->fStatNoWorkDone);
7692 }
7693#endif
7694
2d21ac55
A
7695 ok = dict->serialize(s);
7696 dict->release();
7697 }
7698
b0d623f7
A
7699 return (ok ? kIOReturnSuccess : kIOReturnNoMemory);
7700}
7701
7702bool IOServicePM::serialize( OSSerialize * s ) const
7703{
7704 IOReturn ret = kIOReturnNotReady;
7705
7706 if (gIOPMWorkLoop)
7707 {
7708 ret = gIOPMWorkLoop->runAction(
7709 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOServicePM::gatedSerialize),
7710 (OSObject *) this, (void *) s);
7711 }
7712
7713 return (kIOReturnSuccess == ret);
2d21ac55 7714}
6d2010ae
A
7715
7716PMEventDetails* PMEventDetails::eventDetails(uint32_t type,
7717 const char *ownerName,
7718 uintptr_t ownerUnique,
7719 const char *interestName,
7720 uint8_t oldState,
7721 uint8_t newState,
7722 uint32_t result,
7723 uint32_t elapsedTimeUS) {
7724
7725 PMEventDetails *myself;
7726 myself = new PMEventDetails;
7727
7728 if(myself) {
7729 myself->eventType = type;
7730 myself->ownerName = ownerName;
7731 myself->ownerUnique = ownerUnique;
7732 myself->interestName = interestName;
7733 myself->oldState = oldState;
7734 myself->newState = newState;
7735 myself->result = result;
7736 myself->elapsedTimeUS = elapsedTimeUS;
7737
7738 myself->eventClassifier = kIOPMEventClassDriverEvent;
7739 }
7740
7741 return myself;
7742}
7743
7744
7745PMEventDetails* PMEventDetails::eventDetails(uint32_t type,
7746 const char *uuid,
7747 uint32_t reason,
7748 uint32_t result) {
7749
7750 PMEventDetails *myself;
7751 myself = new PMEventDetails;
7752
7753 if(myself) {
7754 myself->eventType = type;
7755 myself->uuid = uuid;
7756 myself->reason = reason;
7757 myself->result = result;
7758
7759 myself->eventClassifier = kIOPMEventClassSystemEvent;
7760 }
7761
7762 return myself;
7763}
7764