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