]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOServicePM.cpp
xnu-1228.7.58.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
A
28
29#include <IOKit/assert.h>
91447636
A
30#include <IOKit/IOKitDebug.h>
31#include <IOKit/IOLib.h>
32#include <IOKit/IOMessage.h>
33#include <IOKit/IOPlatformExpert.h>
34#include <IOKit/IOService.h>
1c79356b
A
35#include <IOKit/IOTimerEventSource.h>
36#include <IOKit/IOWorkLoop.h>
2d21ac55 37#include <IOKit/IOCommand.h>
1c79356b 38
2d21ac55 39#include <IOKit/pwr_mgt/IOPMlog.h>
91447636
A
40#include <IOKit/pwr_mgt/IOPMinformee.h>
41#include <IOKit/pwr_mgt/IOPMinformeeList.h>
91447636
A
42#include <IOKit/pwr_mgt/IOPowerConnection.h>
43#include <IOKit/pwr_mgt/RootDomain.h>
9bccf70c 44
2d21ac55 45#include <sys/proc.h>
0c530ab8 46
91447636
A
47// Required for notification instrumentation
48#include "IOServicePrivate.h"
2d21ac55
A
49#include "IOServicePMPrivate.h"
50#include "IOKitKernelInternal.h"
9bccf70c 51
2d21ac55
A
52static void settle_timer_expired(thread_call_param_t, thread_call_param_t);
53static void PM_idle_timer_expired(OSObject *, IOTimerEventSource *);
54void tellAppWithResponse(OSObject * object, void * context) { /*empty*/ }
55void tellClientWithResponse(OSObject * object, void * context) { /*empty*/ }
56void tellClient(OSObject * object, void * context);
57IOReturn serializedAllowPowerChange(OSObject *, void *, void *, void *, void *);
9bccf70c 58
2d21ac55
A
59static uint64_t computeTimeDeltaNS( const AbsoluteTime * start )
60{
61 AbsoluteTime now;
62 uint64_t nsec;
9bccf70c 63
2d21ac55
A
64 clock_get_uptime(&now);
65 SUB_ABSOLUTETIME(&now, start);
66 absolutetime_to_nanoseconds(now, &nsec);
67 return nsec;
68}
1c79356b 69
2d21ac55 70OSDefineMetaClassAndStructors(IOPMprot, OSObject)
1c79356b 71
2d21ac55
A
72// log setPowerStates longer than (ns):
73#define LOG_SETPOWER_TIMES (50ULL * 1000ULL * 1000ULL)
74// log app responses longer than (ns):
75#define LOG_APP_RESPONSE_TIMES (100ULL * 1000ULL * 1000ULL)
1c79356b 76
2d21ac55
A
77//*********************************************************************************
78// Globals
79//*********************************************************************************
1c79356b 80
2d21ac55
A
81static bool gIOPMInitialized = false;
82static IOItemCount gIOPMBusyCount = 0;
83static IOWorkLoop * gIOPMWorkLoop = 0;
84static IOPMRequestQueue * gIOPMRequestQueue = 0;
85static IOPMRequestQueue * gIOPMReplyQueue = 0;
86static IOPMRequestQueue * gIOPMFreeQueue = 0;
1c79356b 87
2d21ac55
A
88//*********************************************************************************
89// Macros
90//*********************************************************************************
1c79356b 91
2d21ac55
A
92#define PM_ERROR(x...) do { kprintf(x); IOLog(x); } while (false)
93#define PM_DEBUG(x...) do { kprintf(x); } while (false)
0b4e3aa0 94
2d21ac55
A
95#define PM_TRACE(x...) do { \
96 if (kIOLogDebugPower & gIOKitDebug) kprintf(x); } while (false)
55e303ae 97
2d21ac55 98#define PM_CONNECT(x...)
1c79356b 99
2d21ac55
A
100#define PM_ASSERT_IN_GATE(x) \
101do { \
102 assert(gIOPMWorkLoop->inGate()); \
103} while(false)
1c79356b 104
2d21ac55
A
105#define PM_LOCK() IOLockLock(fPMLock)
106#define PM_UNLOCK() IOLockUnlock(fPMLock)
107
108#define ns_per_us 1000
109#define k30seconds (30*1000000)
110#define kMinAckTimeoutTicks (10*1000000)
111#define kIOPMTardyAckSPSKey "IOPMTardyAckSetPowerState"
112#define kIOPMTardyAckPSCKey "IOPMTardyAckPowerStateChange"
113#define kPwrMgtKey "IOPowerManagement"
114
115#define OUR_PMLog(t, a, b) \
116 do { fPlatform->PMLog( fName, t, a, b); } while(0)
117
118#define NS_TO_MS(nsec) ((int)((nsec) / 1000000ULL))
119
120//*********************************************************************************
121// PM machine states
122//*********************************************************************************
1c79356b 123
2d21ac55
A
124enum {
125 kIOPM_OurChangeTellClientsPowerDown = 1,
126 kIOPM_OurChangeTellPriorityClientsPowerDown = 2,
127 kIOPM_OurChangeNotifyInterestedDriversWillChange = 3,
128 kIOPM_OurChangeSetPowerState = 4,
129 kIOPM_OurChangeWaitForPowerSettle = 5,
130 kIOPM_OurChangeNotifyInterestedDriversDidChange = 6,
131 kIOPM_OurChangeFinish = 7,
132 kIOPM_ParentDownTellPriorityClientsPowerDown = 8,
133 kIOPM_ParentDownNotifyInterestedDriversWillChange = 9,
134 /* 10 not used */
135 kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange = 11,
136 kIOPM_ParentDownSetPowerState = 12,
137 kIOPM_ParentDownWaitForPowerSettle = 13,
138 kIOPM_ParentDownAcknowledgeChange = 14,
139 kIOPM_ParentUpSetPowerState = 15,
140 /* 16 not used */
141 kIOPM_ParentUpWaitForSettleTime = 17,
142 kIOPM_ParentUpNotifyInterestedDriversDidChange = 18,
143 kIOPM_ParentUpAcknowledgePowerChange = 19,
144 kIOPM_Finished = 20,
145 kIOPM_DriverThreadCallDone = 21,
146 kIOPM_NotifyChildrenDone = 22
147};
148
149
150 /*
151 Power Management defines a few roles that drivers can play in their own,
152 and other drivers', power management. We briefly define those here.
153
154 Many drivers implement their policy maker and power controller within the same
155 IOService object, but that is not required.
156
157== Policy Maker ==
158 * Virtual IOService PM methods a "policy maker" may implement
159 * maxCapabilityForDomainState()
160 * initialPowerStateForDomainState()
161 * powerStateForDomainState()
162
163 * Virtual IOService PM methods a "policy maker" may CALL
164 * PMinit()
165
166== Power Controller ==
167 * Virtual IOService PM methods a "power controller" may implement
168 * setPowerState()
169
170 * Virtual IOService PM methods a "power controller" may CALL
171 * joinPMtree()
172 * registerPowerDriver()
173
174=======================
175 There are two different kinds of power state changes.
176 * One is initiated by a subclassed device object which has either decided
177 to change power state, or its controlling driver has suggested it, or
178 some other driver wants to use the idle device and has asked it to become
179 usable.
180 * The second kind of power state change is initiated by the power domain
181 parent.
182 The two are handled through different code paths.
183
184 We maintain a queue of "change notifications," or change notes.
185 * Usually the queue is empty.
186 * When it isn't, usually there is one change note in it
187 * It's possible to have more than one power state change pending at one
188 time, so a queue is implemented.
189 Example:
190 * The subclass device decides it's idle and initiates a change to a lower
191 power state. This causes interested parties to be notified, but they
192 don't all acknowledge right away. This causes the change note to sit
193 in the queue until all the acks are received. During this time, the
194 device decides it isn't idle anymore and wants to raise power back up
195 again. This change can't be started, however, because the previous one
196 isn't complete yet, so the second one waits in the queue. During this
197 time, the parent decides to lower or raise the power state of the entire
198 power domain and notifies the device, and that notification goes into
199 the queue, too, and can't be actioned until the others are.
200
201 == SelfInitiated ==
1c79356b 202 This is how a power change initiated by the subclass device is handled:
2d21ac55
A
203 -> First, all interested parties are notified of the change via their
204 powerStateWillChangeTo method. If they all don't acknowledge via return
205 code, then we have to wait. If they do, or when they finally all
206 acknowledge via our acknowledgePowerChange method, then we can continue.
207 -> We call the controlling driver, instructing it to change to the new state
208 -> Then we wait for power to settle. If there is no settling-time, or after
209 it has passed,
210 -> we notify interested parties again, this time via their
211 powerStateDidChangeTo methods.
212 -> When they have all acked, we're done.
213 If we lowered power and don't need the power domain to be in its current power
214 state, we suggest to the parent that it lower the power domain state.
215
216 == PowerDomainDownInitiated ==
217How a change to a lower power domain state initiated by the parent is handled:
218 -> First, we figure out what power state we will be in when the new domain
219 state is reached.
220 -> Then all interested parties are notified that we are moving to that new
221 state.
222 -> When they have acknowledged, we call the controlling driver to assume
223 that state and we wait for power to settle.
224 -> Then we acknowledge our preparedness to our parent. When all its
225 interested parties have acknowledged,
226 -> it lowers power and then notifies its interested parties again.
227 -> When we get this call, we notify our interested parties that the power
228 state has changed, and when they have all acknowledged, we're done.
229
230 == PowerDomainUpInitiated ==
231How a change to a higher power domain state initiated by the parent is handled:
232 -> We figure out what power state we will be in when the new domain state is
233 reached.
234 -> If it is different from our current state we acknowledge the parent.
235 -> When all the parent's interested parties have acknowledged, it raises
236 power in the domain and waits for power to settle.
237 -> Then it notifies everyone that the new state has been reached.
238 -> When we get this call, we call the controlling driver, instructing it to
239 assume the new state, and wait for power to settle.
240 -> Then we notify our interested parties. When they all acknowledge we are
241 done.
242
243 In either of the two power domain state cases above, it is possible that we
244 will not be changing state even though the domain is.
245 Examples:
246 * A change to a lower domain state may not affect us because we are already
247 in a low enough state,
248 * We will not take advantage of a change to a higher domain state, because
249 we have no need of the higher power. In such cases, there is nothing to
250 do but acknowledge the parent. So when the parent calls our
251 powerDomainWillChange method, and we decide that we will not be changing
252 state, we merely acknowledge the parent, via return code, and wait.
253 When the parent subsequently calls powerStateDidChange, we acknowledge again
254 via return code, and the change is complete.
255
256 == 4 Paths Through State Machine ==
257 Power state changes are processed in a state machine, and since there are four
258 varieties of power state changes, there are four major paths through the state
259 machine.
260
261 == 5. No Need To change ==
262 The fourth is nearly trivial. In this path, the parent is changing the domain
263 state, but we are not changing the device state. The change starts when the
264 parent calls powerDomainWillChange. All we do is acknowledge the parent. When
265 the parent calls powerStateDidChange, we acknowledge the parent again, and
266 we're done.
267
268 == 1. OurChange Down == XXX gvdl
269 The first is fairly simple. It starts:
270 * when a power domain child calls requestPowerDomainState and we decide to
271 change power states to accomodate the child,
272 * or if our power-controlling driver calls changePowerStateTo,
273 * or if some other driver which is using our device calls makeUsable,
274 * or if a subclassed object calls changePowerStateToPriv.
275 These are all power changes initiated by us, not forced upon us by the parent.
276
277 -> We start by notifying interested parties.
278 -> If they all acknowledge via return code, we can go on to state
279 "msSetPowerState".
280 -> Otherwise, we start the ack timer and wait for the stragglers to
281 acknowlege by calling acknowledgePowerChange.
282 -> We move on to state "msSetPowerState" when all the
283 stragglers have acknowledged, or when the ack timer expires on
284 all those which didn't acknowledge.
285 In "msSetPowerState" we call the power-controlling driver to change the
286 power state of the hardware.
287 -> If it returns saying it has done so, we go on to state
288 "msWaitForPowerSettle".
289 -> Otherwise, we have to wait for it, so we set the ack timer and wait.
290 -> When it calls acknowledgeSetPowerState, or when the ack timer
291 expires, we go on.
292 In "msWaitForPowerSettle", we look in the power state array to see if
293 there is any settle time required when changing from our current state to the
294 new state.
295 -> If not, we go right away to "msNotifyInterestedDriversDidChange".
296 -> Otherwise, we set the settle timer and wait. When it expires, we move on.
297 In "msNotifyInterestedDriversDidChange" state, we notify all our
298 interested parties via their powerStateDidChange methods that we have finished
299 changing power state.
300 -> If they all acknowledge via return code, we move on to "msFinish".
301 -> Otherwise we set the ack timer and wait. When they have all
302 acknowledged, or when the ack timer has expired for those that didn't,
303 we move on to "msFinish".
304 In "msFinish" we remove the used change note from the head of the queue
305 and start the next one if one exists.
306
307 == 2. Parent Change Down ==
308 Start at Stage 2 of OurChange Down XXX gvdl
309
310 == 3. Change Up ==
311 Start at Stage 4 of OurChange Down XXX gvdl
312
313Note all parent requested changes need to acknowledge the power has changed to the parent when done.
314 */
1c79356b 315
2d21ac55
A
316//*********************************************************************************
317// [public virtual] PMinit
318//
319// Initialize power management.
320//*********************************************************************************
1c79356b
A
321
322void IOService::PMinit ( void )
323{
2d21ac55
A
324 if ( !initialized )
325 {
326 if ( !gIOPMInitialized )
327 {
328 gIOPMWorkLoop = IOWorkLoop::workLoop();
329 if (gIOPMWorkLoop)
330 {
331 gIOPMRequestQueue = IOPMRequestQueue::create(
332 this, OSMemberFunctionCast(IOPMRequestQueue::Action,
333 this, &IOService::servicePMRequestQueue));
334
335 gIOPMReplyQueue = IOPMRequestQueue::create(
336 this, OSMemberFunctionCast(IOPMRequestQueue::Action,
337 this, &IOService::servicePMReplyQueue));
338
339 gIOPMFreeQueue = IOPMRequestQueue::create(
340 this, OSMemberFunctionCast(IOPMRequestQueue::Action,
341 this, &IOService::servicePMFreeQueue));
342
343 if (gIOPMWorkLoop->addEventSource(gIOPMRequestQueue) !=
344 kIOReturnSuccess)
345 {
346 gIOPMRequestQueue->release();
347 gIOPMRequestQueue = 0;
348 }
349
350 if (gIOPMWorkLoop->addEventSource(gIOPMReplyQueue) !=
351 kIOReturnSuccess)
352 {
353 gIOPMReplyQueue->release();
354 gIOPMReplyQueue = 0;
355 }
356
357 if (gIOPMWorkLoop->addEventSource(gIOPMFreeQueue) !=
358 kIOReturnSuccess)
359 {
360 gIOPMFreeQueue->release();
361 gIOPMFreeQueue = 0;
362 }
363 }
364
365 if (gIOPMRequestQueue && gIOPMReplyQueue && gIOPMFreeQueue)
366 gIOPMInitialized = true;
367 }
368 if (!gIOPMInitialized)
369 return;
370
371 pwrMgt = new IOServicePM;
372 pwrMgt->init();
373 setProperty(kPwrMgtKey, pwrMgt);
374
375 fOwner = this;
376 fWeAreRoot = false;
377 fPMLock = IOLockAlloc();
378 fInterestedDrivers = new IOPMinformeeList;
379 fInterestedDrivers->initialize();
380 fDesiredPowerState = 0;
381 fDriverDesire = 0;
382 fDeviceDesire = 0;
383 fInitialChange = true;
384 fNeedToBecomeUsable = false;
385 fPreviousRequest = 0;
386 fDeviceOverrides = false;
387 fMachineState = kIOPM_Finished;
388 fIdleTimerEventSource = NULL;
cf7d32b8 389 fIdleTimerMinPowerState = 0;
2d21ac55
A
390 fActivityLock = IOLockAlloc();
391 fClampOn = false;
392 fStrictTreeOrder = false;
393 fActivityTicklePowerState = -1;
394 fControllingDriver = NULL;
395 fPowerStates = NULL;
396 fNumberOfPowerStates = 0;
397 fCurrentPowerState = 0;
398 fParentsCurrentPowerFlags = 0;
399 fMaxCapability = 0;
400 fName = getName();
401 fPlatform = getPlatform();
402 fParentsKnowState = false;
403 fSerialNumber = 0;
404 fResponseArray = NULL;
405 fDoNotPowerDown = true;
406 fCurrentPowerConsumption = kIOPMUnknown;
407
408 for (unsigned int i = 0; i <= kMaxType; i++)
55e303ae 409 {
2d21ac55
A
410 fAggressivenessValue[i] = 0;
411 fAggressivenessValid[i] = false;
1c79356b 412 }
2d21ac55
A
413
414 fAckTimer = thread_call_allocate(
415 &IOService::ack_timer_expired, (thread_call_param_t)this);
416 fSettleTimer = thread_call_allocate(
417 &settle_timer_expired, (thread_call_param_t)this);
418 fDriverCallEntry = thread_call_allocate(
419 (thread_call_func_t) &IOService::pmDriverCallout, this);
420 assert(fDriverCallEntry);
421
422#if PM_VARS_SUPPORT
423 IOPMprot * prot = new IOPMprot;
424 if (prot)
425 {
426 prot->init();
427 prot->ourName = fName;
428 prot->thePlatform = fPlatform;
429 fPMVars = prot;
430 pm_vars = prot;
431 }
432#else
433 pm_vars = (IOPMprot *) true;
434#endif
435
1c79356b
A
436 initialized = true;
437 }
438}
439
0b4e3aa0 440//*********************************************************************************
2d21ac55 441// [public] PMfree
0b4e3aa0
A
442//
443// Free up the data created in PMinit, if it exists.
444//*********************************************************************************
2d21ac55 445
0b4e3aa0
A
446void IOService::PMfree ( void )
447{
2d21ac55
A
448 initialized = false;
449 pm_vars = 0;
450
451 if ( pwrMgt )
452 {
453 assert(fMachineState == kIOPM_Finished);
454 assert(fInsertInterestSet == NULL);
455 assert(fRemoveInterestSet == NULL);
456 assert(fNotifyChildArray == NULL);
457
458 if ( fIdleTimerEventSource != NULL ) {
459 getPMworkloop()->removeEventSource(fIdleTimerEventSource);
460 fIdleTimerEventSource->release();
461 fIdleTimerEventSource = NULL;
0b4e3aa0 462 }
2d21ac55
A
463 if ( fSettleTimer ) {
464 thread_call_cancel(fSettleTimer);
465 thread_call_free(fSettleTimer);
466 fSettleTimer = NULL;
0b4e3aa0 467 }
2d21ac55
A
468 if ( fAckTimer ) {
469 thread_call_cancel(fAckTimer);
470 thread_call_free(fAckTimer);
471 fAckTimer = NULL;
0b4e3aa0 472 }
2d21ac55
A
473 if ( fDriverCallEntry ) {
474 thread_call_free(fDriverCallEntry);
475 fDriverCallEntry = NULL;
0b4e3aa0 476 }
2d21ac55
A
477 if ( fPMLock ) {
478 IOLockFree(fPMLock);
479 fPMLock = NULL;
0b4e3aa0 480 }
2d21ac55
A
481 if ( fActivityLock ) {
482 IOLockFree(fActivityLock);
483 fActivityLock = NULL;
0b4e3aa0 484 }
2d21ac55
A
485 if ( fInterestedDrivers ) {
486 fInterestedDrivers->release();
487 fInterestedDrivers = NULL;
488 }
489 if ( fPMWorkQueue ) {
490 getPMworkloop()->removeEventSource(fPMWorkQueue);
491 fPMWorkQueue->release();
492 fPMWorkQueue = 0;
493 }
494 if (fDriverCallParamSlots && fDriverCallParamPtr) {
495 IODelete(fDriverCallParamPtr, DriverCallParam, fDriverCallParamSlots);
496 fDriverCallParamPtr = 0;
497 fDriverCallParamSlots = 0;
498 }
499 if ( fResponseArray ) {
500 fResponseArray->release();
501 fResponseArray = NULL;
0b4e3aa0 502 }
2d21ac55
A
503 if (fPowerStates && fNumberOfPowerStates) {
504 IODelete(fPowerStates, IOPMPowerState, fNumberOfPowerStates);
505 fNumberOfPowerStates = 0;
506 fPowerStates = NULL;
0b4e3aa0 507 }
2d21ac55
A
508
509#if PM_VARS_SUPPORT
510 if (fPMVars)
511 {
512 fPMVars->release();
513 fPMVars = 0;
514 }
515#endif
516
517 pwrMgt->release();
518 pwrMgt = 0;
0b4e3aa0
A
519 }
520}
521
2d21ac55
A
522//*********************************************************************************
523// [public virtual] joinPMtree
524//
525// A policy-maker calls its nub here when initializing, to be attached into
526// the power management hierarchy. The default function is to call the
527// platform expert, which knows how to do it. This method is overridden
528// by a nub subclass which may either know how to do it, or may need to
529// take other action.
530//
531// This may be the only "power management" method used in a nub,
532// meaning it may not be initialized for power management.
533//*********************************************************************************
534
535void IOService::joinPMtree ( IOService * driver )
536{
537 IOPlatformExpert * platform;
538
539 platform = getPlatform();
540 assert(platform != 0);
541 platform->PMRegisterDevice(this, driver);
542}
0b4e3aa0 543
1c79356b 544//*********************************************************************************
2d21ac55 545// [public virtual] youAreRoot
1c79356b 546//
2d21ac55
A
547// Power Managment is informing us that we are the root power domain.
548// The only difference between us and any other power domain is that
549// we have no parent and therefore never call it.
550//*********************************************************************************
551
552IOReturn IOService::youAreRoot ( void )
553{
554 fWeAreRoot = true;
555 fParentsKnowState = true;
556 attachToParent( getRegistryRoot(), gIOPowerPlane );
557 return IOPMNoErr;
558}
559
560//*********************************************************************************
561// [public virtual] PMstop
562//
563// Immediately stop driver callouts. Schedule an async stop request to detach
564// from power plane.
1c79356b 565//*********************************************************************************
2d21ac55 566
1c79356b
A
567void IOService::PMstop ( void )
568{
2d21ac55
A
569 IOPMRequest * request;
570
571 if (!initialized)
572 return;
573
574 // Schedule an async PMstop request, but immediately stop any further
575 // calls to the controlling or interested drivers. This device will
576 // continue to exist in the power plane and participate in power state
577 // changes until the PMstop async request is processed.
578
579 PM_LOCK();
580 fWillPMStop = true;
581 if (fDriverCallBusy)
582 PM_DEBUG("%s::PMstop() driver call busy\n", getName());
583 PM_UNLOCK();
584
585 request = acquirePMRequest( this, kIOPMRequestTypePMStop );
586 if (request)
587 {
588 PM_TRACE("[%s] %p PMstop\n", getName(), this);
589 submitPMRequest( request );
590 }
591}
592
593//*********************************************************************************
594// handlePMstop
595//
596// Disconnect the node from its parents and children in the Power Plane.
597//*********************************************************************************
598
599void IOService::handlePMstop ( IOPMRequest * request )
600{
601 OSIterator * iter;
602 OSObject * next;
1c79356b 603 IOPowerConnection * connection;
2d21ac55
A
604 IOService * theChild;
605 IOService * theParent;
1c79356b 606
2d21ac55
A
607 PM_ASSERT_IN_GATE();
608 PM_TRACE("[%s] %p %s start\n", getName(), this, __FUNCTION__);
1c79356b 609
2d21ac55
A
610 // remove the property
611 removeProperty(kPwrMgtKey);
612
613 // detach parents
614 iter = getParentIterator(gIOPowerPlane);
615 if ( iter )
55e303ae 616 {
2d21ac55 617 while ( (next = iter->getNextObject()) )
55e303ae 618 {
2d21ac55 619 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
55e303ae 620 {
0b4e3aa0 621 theParent = (IOService *)connection->copyParentEntry(gIOPowerPlane);
2d21ac55 622 if ( theParent )
55e303ae 623 {
0b4e3aa0
A
624 theParent->removePowerChild(connection);
625 theParent->release();
626 }
1c79356b
A
627 }
628 }
629 iter->release();
630 }
55e303ae 631
2d21ac55
A
632 // detach IOConnections
633 detachAbove( gIOPowerPlane );
1c79356b 634
2d21ac55
A
635 // no more power state changes
636 fParentsKnowState = false;
1c79356b 637
2d21ac55
A
638 // detach children
639 iter = getChildIterator(gIOPowerPlane);
640 if ( iter )
55e303ae 641 {
2d21ac55 642 while ( (next = iter->getNextObject()) )
55e303ae 643 {
2d21ac55 644 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
55e303ae 645 {
0b4e3aa0 646 theChild = ((IOService *)(connection->copyChildEntry(gIOPowerPlane)));
2d21ac55 647 if ( theChild )
55e303ae
A
648 {
649 // detach nub from child
2d21ac55 650 connection->detachFromChild(theChild, gIOPowerPlane);
0b4e3aa0
A
651 theChild->release();
652 }
55e303ae 653 // detach us from nub
2d21ac55 654 detachFromChild(connection, gIOPowerPlane);
1c79356b
A
655 }
656 }
657 iter->release();
658 }
1c79356b 659
0b4e3aa0
A
660 // Remove all interested drivers from the list, including the power
661 // controlling driver.
662 //
663 // Usually, the controlling driver and the policy-maker functionality
664 // are implemented by the same object, and without the deregistration,
665 // the object will be holding an extra retain on itself, and cannot
666 // be freed.
667
2d21ac55 668 if ( fInterestedDrivers )
0b4e3aa0 669 {
2d21ac55
A
670 IOPMinformeeList * list = fInterestedDrivers;
671 IOPMinformee * item;
1c79356b 672
2d21ac55
A
673 PM_LOCK();
674 while ((item = list->firstInList()))
675 {
676 list->removeFromList(item->whatObject);
677 }
678 PM_UNLOCK();
679 }
680
681 // Tell PM_idle_timer_expiration() to ignore idle timer.
682 fIdleTimerPeriod = 0;
1c79356b 683
2d21ac55
A
684 fWillPMStop = false;
685 PM_TRACE("[%s] %p %s done\n", getName(), this, __FUNCTION__);
686}
1c79356b
A
687
688//*********************************************************************************
2d21ac55 689// [public virtual] addPowerChild
1c79356b 690//
2d21ac55 691// Power Management is informing us who our children are.
1c79356b 692//*********************************************************************************
2d21ac55
A
693
694IOReturn IOService::addPowerChild ( IOService * child )
1c79356b 695{
2d21ac55
A
696 IOPowerConnection * connection = 0;
697 IOPMRequest * requests[3] = {0, 0, 0};
698 OSIterator * iter;
699 bool ok = true;
700
701 if (!child)
702 return kIOReturnBadArgument;
703
704 if (!initialized || !child->initialized)
705 return IOPMNotYetInitialized;
706
707 OUR_PMLog( kPMLogAddChild, 0, 0 );
708
709 do {
710 // Is this child already one of our children?
711
712 iter = child->getParentIterator( gIOPowerPlane );
713 if ( iter )
714 {
715 IORegistryEntry * entry;
716 OSObject * next;
717
718 while ((next = iter->getNextObject()))
719 {
720 if ((entry = OSDynamicCast(IORegistryEntry, next)) &&
721 isChild(entry, gIOPowerPlane))
722 {
723 ok = false;
724 break;
725 }
726 }
727 iter->release();
728 }
729 if (!ok)
730 {
731 PM_DEBUG("[%s] %s (%p) is already a child\n",
732 getName(), child->getName(), child);
733 break;
734 }
735
736 // Add the child to the power plane immediately, but the
737 // joining connection is marked as not ready.
738 // We want the child to appear in the power plane before
739 // returning to the caller, but don't want the caller to
740 // block on the PM work loop.
741
742 connection = new IOPowerConnection;
743 if (!connection)
744 break;
745
746 // Create a chain of PM requests to perform the bottom-half
747 // work from the PM work loop.
748
749 requests[0] = acquirePMRequest(
750 /* target */ this,
751 /* type */ kIOPMRequestTypeAddPowerChild1 );
752
753 requests[1] = acquirePMRequest(
754 /* target */ child,
755 /* type */ kIOPMRequestTypeAddPowerChild2 );
756
757 requests[2] = acquirePMRequest(
758 /* target */ this,
759 /* type */ kIOPMRequestTypeAddPowerChild3 );
760
761 if (!requests[0] || !requests[1] || !requests[2])
762 break;
763
764 requests[0]->setParentRequest( requests[1] );
765 requests[1]->setParentRequest( requests[2] );
766
767 connection->init();
768 connection->start(this);
769 connection->setAwaitingAck(false);
770 connection->setReadyFlag(false);
771
772 attachToChild( connection, gIOPowerPlane );
773 connection->attachToChild( child, gIOPowerPlane );
774
775 // connection needs to be released
776 requests[0]->fArg0 = connection;
777 requests[1]->fArg0 = connection;
778 requests[2]->fArg0 = connection;
779
780 submitPMRequest( requests, 3 );
781 return kIOReturnSuccess;
782 }
783 while (false);
1c79356b 784
2d21ac55
A
785 if (connection) connection->release();
786 if (requests[0]) releasePMRequest(requests[0]);
787 if (requests[1]) releasePMRequest(requests[1]);
788 if (requests[2]) releasePMRequest(requests[2]);
1c79356b 789
2d21ac55
A
790 // silent failure, to prevent platform drivers from adding the child
791 // to the root domain.
792 return IOPMNoErr;
793}
1c79356b
A
794
795//*********************************************************************************
2d21ac55 796// [private] addPowerChild1
1c79356b 797//
2d21ac55 798// Called on the power parent.
1c79356b 799//*********************************************************************************
1c79356b 800
2d21ac55
A
801void IOService::addPowerChild1 ( IOPMRequest * request )
802{
803 unsigned long tempDesire = 0;
804
805 // Make us temporary usable before adding the child.
806
807 PM_ASSERT_IN_GATE();
808 OUR_PMLog( kPMLogMakeUsable, kPMLogMakeUsable, fDeviceDesire );
809
810 if (fControllingDriver && inPlane(gIOPowerPlane) && fParentsKnowState)
811 {
812 tempDesire = fNumberOfPowerStates - 1;
813 }
814
815 if (tempDesire && (fWeAreRoot || (fMaxCapability >= tempDesire)))
816 {
817 computeDesiredState( tempDesire );
818 changeState();
819 }
820}
1c79356b
A
821
822//*********************************************************************************
2d21ac55 823// [private] addPowerChild2
1c79356b 824//
2d21ac55 825// Called on the joining child. Blocked behind addPowerChild1.
1c79356b 826//*********************************************************************************
2d21ac55
A
827
828void IOService::addPowerChild2 ( IOPMRequest * request )
1c79356b 829{
2d21ac55
A
830 IOPowerConnection * connection = (IOPowerConnection *) request->fArg0;
831 IOService * parent;
832 IOPMPowerFlags powerFlags;
833 bool knowsState;
834 unsigned long powerState;
835 unsigned long tempDesire;
836
837 PM_ASSERT_IN_GATE();
838 parent = (IOService *) connection->getParentEntry(gIOPowerPlane);
839
840 if (!parent || !inPlane(gIOPowerPlane))
841 {
842 PM_DEBUG("[%s] addPowerChild2 not in power plane\n", getName());
843 return;
844 }
1c79356b 845
2d21ac55
A
846 // Parent will be waiting for us to complete this stage, safe to
847 // directly access parent's vars.
0b4e3aa0 848
2d21ac55
A
849 knowsState = (parent->fPowerStates) && (parent->fParentsKnowState);
850 powerState = parent->fCurrentPowerState;
1c79356b 851
2d21ac55
A
852 if (knowsState)
853 powerFlags = parent->fPowerStates[powerState].outputPowerCharacter;
854 else
855 powerFlags = 0;
1c79356b 856
2d21ac55
A
857 // Set our power parent.
858
859 OUR_PMLog(kPMLogSetParent, knowsState, powerFlags);
860
861 setParentInfo( powerFlags, connection, knowsState );
862
863 connection->setReadyFlag(true);
864
865 if ( fControllingDriver && fParentsKnowState )
55e303ae 866 {
2d21ac55 867 fMaxCapability = fControllingDriver->maxCapabilityForDomainState(fParentsCurrentPowerFlags);
55e303ae 868 // initially change into the state we are already in
2d21ac55
A
869 tempDesire = fControllingDriver->initialPowerStateForDomainState(fParentsCurrentPowerFlags);
870 computeDesiredState(tempDesire);
871 fPreviousRequest = 0xffffffff;
1c79356b 872 changeState();
1c79356b 873 }
1c79356b
A
874}
875
1c79356b 876//*********************************************************************************
2d21ac55 877// [private] addPowerChild3
1c79356b 878//
2d21ac55 879// Called on the parent. Blocked behind addPowerChild2.
1c79356b 880//*********************************************************************************
1c79356b 881
2d21ac55
A
882void IOService::addPowerChild3 ( IOPMRequest * request )
883{
884 IOPowerConnection * connection = (IOPowerConnection *) request->fArg0;
885 IOService * child;
886 unsigned int i;
887
888 PM_ASSERT_IN_GATE();
889 child = (IOService *) connection->getChildEntry(gIOPowerPlane);
890
891 if (child && inPlane(gIOPowerPlane))
892 {
893 if (child->getProperty("IOPMStrictTreeOrder"))
894 {
895 PM_DEBUG("[%s] strict ordering enforced\n", getName());
896 fStrictTreeOrder = true;
897 }
898
899 for (i = 0; i <= kMaxType; i++)
900 {
901 if ( fAggressivenessValid[i] )
902 {
903 child->setAggressiveness(i, fAggressivenessValue[i]);
904 }
905 }
906 }
907 else
908 {
909 PM_DEBUG("[%s] addPowerChild3 not in power plane\n", getName());
910 }
1c79356b 911
2d21ac55
A
912 connection->release();
913}
1c79356b 914
2d21ac55
A
915//*********************************************************************************
916// [public virtual deprecated] setPowerParent
917//
918// Power Management is informing us who our parent is.
919// If we have a controlling driver, find out, given our newly-informed
920// power domain state, what state it would be in, and then tell it
921// to assume that state.
922//*********************************************************************************
1c79356b 923
2d21ac55
A
924IOReturn IOService::setPowerParent (
925 IOPowerConnection * theParent, bool stateKnown, IOPMPowerFlags powerFlags )
926{
927 return kIOReturnUnsupported;
1c79356b
A
928}
929
2d21ac55
A
930//*********************************************************************************
931// [public virtual] removePowerChild
1c79356b 932//
2d21ac55
A
933// Called on a parent whose child is being removed by PMstop().
934//*********************************************************************************
935
0b4e3aa0
A
936IOReturn IOService::removePowerChild ( IOPowerConnection * theNub )
937{
2d21ac55 938 IORegistryEntry * theChild;
0b4e3aa0 939
2d21ac55
A
940 PM_ASSERT_IN_GATE();
941 OUR_PMLog( kPMLogRemoveChild, 0, 0 );
1c79356b 942
0b4e3aa0
A
943 theNub->retain();
944
55e303ae
A
945 // detach nub from child
946 theChild = theNub->copyChildEntry(gIOPowerPlane);
2d21ac55 947 if ( theChild )
55e303ae 948 {
0b4e3aa0
A
949 theNub->detachFromChild(theChild, gIOPowerPlane);
950 theChild->release();
951 }
55e303ae 952 // detach from the nub
2d21ac55
A
953 detachFromChild(theNub, gIOPowerPlane);
954
955 // Are we awaiting an ack from this child?
956 if ( theNub->getAwaitingAck() )
957 {
958 // yes, pretend we got one
959 theNub->setAwaitingAck(false);
960 if (fHeadNotePendingAcks != 0 )
961 {
962 // that's one fewer ack to worry about
963 fHeadNotePendingAcks--;
964
965 // is that the last?
966 if ( fHeadNotePendingAcks == 0 )
967 {
968 stop_ack_timer();
969 }
970 }
971 }
90556fb8 972
2d21ac55 973 theNub->release();
1c79356b 974
2d21ac55
A
975 // Schedule a request to re-scan child desires and clamp bits.
976 if (!fWillAdjustPowerState)
977 {
978 IOPMRequest * request;
1c79356b 979
2d21ac55
A
980 request = acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState );
981 if (request)
982 {
983 submitPMRequest( request );
984 fWillAdjustPowerState = true;
985 }
986 }
1c79356b
A
987
988 return IOPMNoErr;
989}
990
1c79356b 991//*********************************************************************************
2d21ac55 992// [public virtual] registerPowerDriver
1c79356b
A
993//
994// A driver has called us volunteering to control power to our device.
1c79356b
A
995//*********************************************************************************
996
2d21ac55
A
997IOReturn IOService::registerPowerDriver (
998 IOService * powerDriver,
999 IOPMPowerState * powerStates,
1000 unsigned long numberOfStates )
1c79356b 1001{
2d21ac55
A
1002 IOPMRequest * request;
1003 IOPMPowerState * powerStatesCopy = 0;
55e303ae 1004
2d21ac55
A
1005 if (!initialized)
1006 return IOPMNotYetInitialized;
1c79356b 1007
2d21ac55
A
1008 // Validate arguments.
1009 if (!powerStates || (numberOfStates < 2))
1010 {
1011 OUR_PMLog(kPMLogControllingDriverErr5, numberOfStates, 0);
1012 return kIOReturnBadArgument;
1013 }
1c79356b 1014
2d21ac55
A
1015 if (!powerDriver)
1016 {
1017 OUR_PMLog(kPMLogControllingDriverErr4, 0, 0);
1018 return kIOReturnBadArgument;
1019 }
1020
1021 if (powerStates[0].version != kIOPMPowerStateVersion1)
1022 {
1023 OUR_PMLog(kPMLogControllingDriverErr1, powerStates[0].version, 0);
1024 return kIOReturnBadArgument;
1025 }
1026
1027 do {
1028 // Make a copy of the supplied power state array.
1029 powerStatesCopy = IONew(IOPMPowerState, numberOfStates);
1030 if (!powerStatesCopy)
1031 break;
1032
1033 bcopy( powerStates, powerStatesCopy,
1034 sizeof(IOPMPowerState) * numberOfStates );
1035
1036 request = acquirePMRequest( this, kIOPMRequestTypeRegisterPowerDriver );
1037 if (!request)
1038 break;
1039
1040 powerDriver->retain();
1041 request->fArg0 = (void *) powerDriver;
1042 request->fArg1 = (void *) powerStatesCopy;
1043 request->fArg2 = (void *) numberOfStates;
1044
1045 submitPMRequest( request );
1046 return kIOReturnSuccess;
1047 }
1048 while (false);
1049
1050 if (powerStatesCopy)
1051 IODelete(powerStatesCopy, IOPMPowerState, numberOfStates);
1052 return kIOReturnNoMemory;
1c79356b
A
1053}
1054
1055//*********************************************************************************
2d21ac55
A
1056// [private] handleRegisterPowerDriver
1057//*********************************************************************************
1058
1059void IOService::handleRegisterPowerDriver ( IOPMRequest * request )
1060{
1061 IOService * powerDriver = (IOService *) request->fArg0;
1062 IOPMPowerState * powerStates = (IOPMPowerState *) request->fArg1;
1063 unsigned long numberOfStates = (unsigned long) request->fArg2;
1064 unsigned long i;
1065 IOService * root;
1066
1067 PM_ASSERT_IN_GATE();
1068 assert(powerStates);
1069 assert(powerDriver);
1070 assert(numberOfStates > 1);
1071
1072 if ( !fNumberOfPowerStates )
1073 {
1074 OUR_PMLog(kPMLogControllingDriver,
1075 (unsigned long) numberOfStates,
1076 (unsigned long) powerStates[0].version);
1077
1078 fPowerStates = powerStates;
1079 fNumberOfPowerStates = numberOfStates;
1080 fControllingDriver = powerDriver;
1081 fCurrentCapabilityFlags = fPowerStates[0].capabilityFlags;
1082
1083 // make a mask of all the character bits we know about
1084 fOutputPowerCharacterFlags = 0;
1085 for ( i = 0; i < numberOfStates; i++ ) {
1086 fOutputPowerCharacterFlags |= fPowerStates[i].outputPowerCharacter;
1087 }
1088
1089 // Register powerDriver as interested, unless already done.
1090 // We don't want to register the default implementation since
1091 // it does nothing. One ramification of not always registering
1092 // is the one fewer retain count held.
1093
1094 root = getPlatform()->getProvider();
1095 assert(root);
1096 if (!root ||
1097 ((OSMemberFunctionCast(void (*)(void),
1098 root, &IOService::powerStateDidChangeTo)) !=
1099 ((OSMemberFunctionCast(void (*)(void),
1100 this, &IOService::powerStateDidChangeTo)))) ||
1101 ((OSMemberFunctionCast(void (*)(void),
1102 root, &IOService::powerStateWillChangeTo)) !=
1103 ((OSMemberFunctionCast(void (*)(void),
1104 this, &IOService::powerStateWillChangeTo)))))
1105 {
1106 if (fInterestedDrivers->findItem(powerDriver) == NULL)
1107 {
1108 PM_LOCK();
1109 fInterestedDrivers->appendNewInformee(powerDriver);
1110 PM_UNLOCK();
1111 }
1112 }
1113
1114 if ( fNeedToBecomeUsable ) {
1115 fNeedToBecomeUsable = false;
1116 fDeviceDesire = fNumberOfPowerStates - 1;
1117 }
1118
1119 if ( inPlane(gIOPowerPlane) && fParentsKnowState )
1120 {
1121 unsigned long tempDesire;
1122 fMaxCapability = fControllingDriver->maxCapabilityForDomainState(fParentsCurrentPowerFlags);
1123 // initially change into the state we are already in
1124 tempDesire = fControllingDriver->initialPowerStateForDomainState(fParentsCurrentPowerFlags);
1125 computeDesiredState(tempDesire);
1126 changeState();
1127 }
1128 }
1129 else
1130 {
1131 OUR_PMLog(kPMLogControllingDriverErr2, numberOfStates, 0);
1132 IODelete(powerStates, IOPMPowerState, numberOfStates);
1133 }
1134
1135 powerDriver->release();
1136}
1137
1138//*********************************************************************************
1139// [public virtual] registerInterestedDriver
1c79356b
A
1140//
1141// Add the caller to our list of interested drivers and return our current
1142// power state. If we don't have a power-controlling driver yet, we will
1143// call this interested driver again later when we do get a driver and find
1144// out what the current power state of the device is.
1145//*********************************************************************************
1146
2d21ac55 1147IOPMPowerFlags IOService::registerInterestedDriver ( IOService * driver )
1c79356b 1148{
2d21ac55
A
1149 IOPMRequest * request;
1150 bool signal;
1151
1152 if (!initialized || !fInterestedDrivers)
1153 return IOPMNotPowerManaged;
1154
1155 PM_LOCK();
1156 signal = (!fInsertInterestSet && !fRemoveInterestSet);
1157 if (fInsertInterestSet == NULL)
1158 fInsertInterestSet = OSSet::withCapacity(4);
1159 if (fInsertInterestSet)
1160 fInsertInterestSet->setObject(driver);
1161 PM_UNLOCK();
1162
1163 if (signal)
1164 {
1165 request = acquirePMRequest( this, kIOPMRequestTypeInterestChanged );
1166 if (request)
1167 submitPMRequest( request );
1168 }
1c79356b 1169
2d21ac55
A
1170 // This return value cannot be trusted, but return a value
1171 // for those clients that care.
1c79356b 1172
2d21ac55
A
1173 OUR_PMLog(kPMLogInterestedDriver, kIOPMDeviceUsable, 2);
1174 return kIOPMDeviceUsable;
1175}
1c79356b 1176
2d21ac55
A
1177//*********************************************************************************
1178// [public virtual] deRegisterInterestedDriver
1179//*********************************************************************************
1c79356b 1180
2d21ac55
A
1181IOReturn IOService::deRegisterInterestedDriver ( IOService * driver )
1182{
1183 IOPMinformeeList * list;
1184 IOPMinformee * item;
1185 IOPMRequest * request;
1186 bool signal;
1187
1188 if (!initialized || !fInterestedDrivers)
1189 return IOPMNotPowerManaged;
1190
1191 PM_LOCK();
1192 signal = (!fRemoveInterestSet && !fInsertInterestSet);
1193 if (fRemoveInterestSet == NULL)
1194 fRemoveInterestSet = OSSet::withCapacity(4);
1195 if (fRemoveInterestSet)
1196 {
1197 fRemoveInterestSet->setObject(driver);
1198
1199 list = fInterestedDrivers;
1200 item = list->findItem(driver);
1201 if (item && item->active)
1202 {
1203 item->active = false;
1204 }
1205 if (fDriverCallBusy)
1206 PM_DEBUG("%s::deRegisterInterestedDriver() driver call busy\n", getName());
1207 }
1208 PM_UNLOCK();
1c79356b 1209
2d21ac55
A
1210 if (signal)
1211 {
1212 request = acquirePMRequest( this, kIOPMRequestTypeInterestChanged );
1213 if (request)
1214 submitPMRequest( request );
1215 }
55e303ae 1216
2d21ac55 1217 return IOPMNoErr;
1c79356b
A
1218}
1219
1c79356b 1220//*********************************************************************************
2d21ac55 1221// [private] handleInterestChanged
1c79356b 1222//
2d21ac55 1223// Handle interest added or removed.
1c79356b 1224//*********************************************************************************
2d21ac55
A
1225
1226void IOService::handleInterestChanged( IOPMRequest * request )
1c79356b 1227{
2d21ac55
A
1228 IOService * driver;
1229 IOPMinformee * informee;
1230 IOPMinformeeList * list = fInterestedDrivers;
1231
1232 PM_LOCK();
1233
1234 if (fInsertInterestSet)
1235 {
1236 while ((driver = (IOService *) fInsertInterestSet->getAnyObject()))
1237 {
1238 if ((list->findItem(driver) == NULL) &&
1239 (!fRemoveInterestSet ||
1240 !fRemoveInterestSet->containsObject(driver)))
1241 {
1242 informee = list->appendNewInformee(driver);
1243 }
1244 fInsertInterestSet->removeObject(driver);
1245 }
1246 fInsertInterestSet->release();
1247 fInsertInterestSet = 0;
1248 }
1c79356b 1249
2d21ac55
A
1250 if (fRemoveInterestSet)
1251 {
1252 while ((driver = (IOService *) fRemoveInterestSet->getAnyObject()))
1253 {
1254 informee = list->findItem(driver);
1255 if (informee)
1256 {
1257 if (fHeadNotePendingAcks && informee->timer)
1258 {
1259 informee->timer = 0;
1260 fHeadNotePendingAcks--;
1261 }
1262 list->removeFromList(driver);
1263 }
1264 fRemoveInterestSet->removeObject(driver);
1265 }
1266 fRemoveInterestSet->release();
1267 fRemoveInterestSet = 0;
1268 }
1c79356b 1269
2d21ac55 1270 PM_UNLOCK();
1c79356b
A
1271}
1272
1c79356b 1273//*********************************************************************************
2d21ac55 1274// [public virtual] acknowledgePowerChange
1c79356b
A
1275//
1276// After we notified one of the interested drivers or a power-domain child
1277// of an impending change in power, it has called to say it is now
1278// prepared for the change. If this object is the last to
1279// acknowledge this change, we take whatever action we have been waiting
1280// for.
1281// That may include acknowledging to our parent. In this case, we do it
1282// last of all to insure that this doesn't cause the parent to call us some-
1283// where else and alter data we are relying on here (like the very existance
1284// of a "current change note".)
1285//*********************************************************************************
1286
1287IOReturn IOService::acknowledgePowerChange ( IOService * whichObject )
1288{
2d21ac55
A
1289 IOPMRequest * request;
1290
1291 if (!initialized)
1292 return IOPMNotYetInitialized;
1293 if (!whichObject)
1294 return kIOReturnBadArgument;
1295
1296 request = acquirePMRequest( this, kIOPMRequestTypeAckPowerChange );
1297 if (!request)
1298 {
1299 PM_ERROR("%s::%s no memory\n", getName(), __FUNCTION__);
1300 return kIOReturnNoMemory;
1301 }
1302
1303 whichObject->retain();
1304 request->fArg0 = whichObject;
1305
1306 submitPMRequest( request );
1307 return IOPMNoErr;
1308}
1309
1310//*********************************************************************************
1311// [private] handleAcknowledgePowerChange
1312//*********************************************************************************
1313
1314bool IOService::handleAcknowledgePowerChange ( IOPMRequest * request )
1315{
1316 IOPMinformee * informee;
1317 unsigned long childPower = kIOPMUnknown;
1318 IOService * theChild;
1319 IOService * whichObject;
1320 bool all_acked = false;
1321
1322 PM_ASSERT_IN_GATE();
1323 whichObject = (IOService *) request->fArg0;
1324 assert(whichObject);
1c79356b 1325
55e303ae 1326 // one of our interested drivers?
2d21ac55
A
1327 informee = fInterestedDrivers->findItem( whichObject );
1328 if ( informee == NULL )
55e303ae 1329 {
2d21ac55 1330 if ( !isChild(whichObject, gIOPowerPlane) )
55e303ae 1331 {
2d21ac55
A
1332 OUR_PMLog(kPMLogAcknowledgeErr1, 0, 0);
1333 goto no_err;
55e303ae 1334 } else {
2d21ac55 1335 OUR_PMLog(kPMLogChildAcknowledge, fHeadNotePendingAcks, 0);
55e303ae
A
1336 }
1337 } else {
2d21ac55 1338 OUR_PMLog(kPMLogDriverAcknowledge, fHeadNotePendingAcks, 0);
55e303ae 1339 }
2d21ac55
A
1340
1341 if ( fHeadNotePendingAcks != 0 )
55e303ae 1342 {
2d21ac55
A
1343 assert(fPowerStates != NULL);
1344
55e303ae 1345 // yes, make sure we're expecting acks
2d21ac55 1346 if ( informee != NULL )
55e303ae
A
1347 {
1348 // it's an interested driver
1349 // make sure we're expecting this ack
2d21ac55 1350 if ( informee->timer != 0 )
55e303ae 1351 {
2d21ac55
A
1352#if LOG_SETPOWER_TIMES
1353 if (informee->timer > 0)
55e303ae 1354 {
2d21ac55
A
1355 uint64_t nsec = computeTimeDeltaNS(&informee->startTime);
1356 if (nsec > LOG_SETPOWER_TIMES)
1357 PM_DEBUG("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) async took %d ms\n",
1358 informee->whatObject->getName(),
1359 (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
1360 informee->whatObject,
1361 fName, fCurrentPowerState, fHeadNoteState, NS_TO_MS(nsec));
55e303ae 1362 }
2d21ac55
A
1363#endif
1364 // mark it acked
1365 informee->timer = 0;
1366 // that's one fewer to worry about
1367 fHeadNotePendingAcks--;
55e303ae
A
1368 } else {
1369 // this driver has already acked
2d21ac55 1370 OUR_PMLog(kPMLogAcknowledgeErr2, 0, 0);
55e303ae
A
1371 }
1372 } else {
1373 // it's a child
1374 // make sure we're expecting this ack
2d21ac55 1375 if ( ((IOPowerConnection *)whichObject)->getAwaitingAck() )
55e303ae
A
1376 {
1377 // that's one fewer to worry about
2d21ac55 1378 fHeadNotePendingAcks--;
0b4e3aa0
A
1379 ((IOPowerConnection *)whichObject)->setAwaitingAck(false);
1380 theChild = (IOService *)whichObject->copyChildEntry(gIOPowerPlane);
2d21ac55 1381 if ( theChild )
55e303ae 1382 {
0b4e3aa0
A
1383 childPower = theChild->currentPowerConsumption();
1384 theChild->release();
1385 }
2d21ac55 1386 if ( childPower == kIOPMUnknown )
55e303ae 1387 {
2d21ac55 1388 fPowerStates[fHeadNoteState].staticPower = kIOPMUnknown;
55e303ae 1389 } else {
2d21ac55 1390 if ( fPowerStates[fHeadNoteState].staticPower != kIOPMUnknown )
55e303ae 1391 {
2d21ac55 1392 fPowerStates[fHeadNoteState].staticPower += childPower;
0b4e3aa0
A
1393 }
1394 }
0b4e3aa0 1395 }
55e303ae 1396 }
2d21ac55
A
1397
1398 if ( fHeadNotePendingAcks == 0 ) {
1399 // yes, stop the timer
1400 stop_ack_timer();
1401 // and now we can continue
1402 all_acked = true;
1403 }
55e303ae 1404 } else {
2d21ac55 1405 OUR_PMLog(kPMLogAcknowledgeErr3, 0, 0); // not expecting anybody to ack
1c79356b 1406 }
2d21ac55
A
1407
1408no_err:
1409 if (whichObject)
1410 whichObject->release();
1411
1412 return all_acked;
1c79356b
A
1413}
1414
1415//*********************************************************************************
2d21ac55 1416// [public virtual] acknowledgeSetPowerState
1c79356b
A
1417//
1418// After we instructed our controlling driver to change power states,
1419// it has called to say it has finished doing so.
1420// We continue to process the power state change.
1421//*********************************************************************************
1422
1423IOReturn IOService::acknowledgeSetPowerState ( void )
1424{
2d21ac55 1425 IOPMRequest * request;
9bccf70c 1426
2d21ac55
A
1427 if (!initialized)
1428 return IOPMNotYetInitialized;
91447636 1429
2d21ac55
A
1430 request = acquirePMRequest( this, kIOPMRequestTypeAckSetPowerState );
1431 if (!request)
1432 {
1433 PM_ERROR("%s::%s no memory\n", getName(), __FUNCTION__);
1434 return kIOReturnNoMemory;
1435 }
1c79356b 1436
2d21ac55
A
1437 submitPMRequest( request );
1438 return kIOReturnSuccess;
1439}
1c79356b
A
1440
1441//*********************************************************************************
2d21ac55 1442// [private] adjustPowerState
1c79356b 1443//
2d21ac55
A
1444// Child has signaled a change - child changed it's desire, new child added,
1445// existing child removed. Adjust our power state accordingly.
1c79356b
A
1446//*********************************************************************************
1447
2d21ac55 1448void IOService::adjustPowerState( void )
1c79356b 1449{
2d21ac55
A
1450 PM_ASSERT_IN_GATE();
1451 if (inPlane(gIOPowerPlane))
1452 {
1453 rebuildChildClampBits();
1454 computeDesiredState();
1455 if ( fControllingDriver && fParentsKnowState )
1456 changeState();
1457 }
1458 else
1459 {
1460 PM_DEBUG("[%s] %s: not in power tree\n", getName(), __FUNCTION__);
1461 return;
1462 }
1463 fWillAdjustPowerState = false;
1c79356b
A
1464}
1465
1c79356b 1466//*********************************************************************************
2d21ac55 1467// [public deprecated] powerDomainWillChangeTo
1c79356b
A
1468//
1469// Called by the power-hierarchy parent notifying of a new power state
1470// in the power domain.
1471// We enqueue a parent power-change to our queue of power changes.
1472// This may or may not cause us to change power, depending on what
1473// kind of change is occuring in the domain.
1474//*********************************************************************************
1475
2d21ac55
A
1476IOReturn IOService::powerDomainWillChangeTo (
1477 IOPMPowerFlags newPowerFlags,
1478 IOPowerConnection * whichParent )
1c79356b 1479{
2d21ac55
A
1480 assert(false);
1481 return kIOReturnUnsupported;
1482}
1c79356b 1483
2d21ac55
A
1484//*********************************************************************************
1485// [private] handlePowerDomainWillChangeTo
1486//*********************************************************************************
1c79356b 1487
2d21ac55
A
1488void IOService::handlePowerDomainWillChangeTo ( IOPMRequest * request )
1489{
1490 IOPMPowerFlags newPowerFlags = (IOPMPowerFlags) request->fArg0;
1491 IOPowerConnection * whichParent = (IOPowerConnection *) request->fArg1;
1492 bool powerWillDrop = (bool) request->fArg2;
1493 OSIterator * iter;
1494 OSObject * next;
1495 IOPowerConnection * connection;
1496 unsigned long newPowerState;
1497 IOPMPowerFlags combinedPowerFlags;
1498 bool savedParentsKnowState;
1499 IOReturn result = IOPMAckImplied;
1500
1501 PM_ASSERT_IN_GATE();
1502 OUR_PMLog(kPMLogWillChange, newPowerFlags, 0);
1503
cf7d32b8 1504 if (!inPlane(gIOPowerPlane) || !whichParent || !whichParent->getAwaitingAck())
2d21ac55
A
1505 {
1506 PM_DEBUG("[%s] %s: not in power tree\n", getName(), __FUNCTION__);
cf7d32b8 1507 goto exit_no_ack;
2d21ac55 1508 }
1c79356b 1509
2d21ac55 1510 savedParentsKnowState = fParentsKnowState;
0b4e3aa0 1511
2d21ac55
A
1512 // Combine parents' power flags to determine our maximum state
1513 // within the new power domain
1514 combinedPowerFlags = 0;
1c79356b 1515
2d21ac55
A
1516 iter = getParentIterator(gIOPowerPlane);
1517 if ( iter )
55e303ae 1518 {
2d21ac55 1519 while ( (next = iter->getNextObject()) )
55e303ae 1520 {
2d21ac55 1521 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
55e303ae 1522 {
2d21ac55
A
1523 if ( connection == whichParent )
1524 combinedPowerFlags |= newPowerFlags;
1525 else
1c79356b 1526 combinedPowerFlags |= connection->parentCurrentPowerFlags();
1c79356b
A
1527 }
1528 }
1529 iter->release();
1530 }
2d21ac55
A
1531
1532 if ( fControllingDriver )
55e303ae 1533 {
2d21ac55
A
1534 newPowerState = fControllingDriver->maxCapabilityForDomainState(
1535 combinedPowerFlags);
1536
1537 result = enqueuePowerChange(
1538 /* flags */ IOPMParentInitiated | IOPMDomainWillChange,
1539 /* power state */ newPowerState,
1540 /* domain state */ combinedPowerFlags,
1541 /* connection */ whichParent,
1542 /* parent state */ newPowerFlags);
1543 }
1544
1545 // If parent is dropping power, immediately update the parent's
1546 // capability flags. Any future merging of parent(s) combined
1547 // power flags should account for this power drop.
1548
1549 if (powerWillDrop)
1550 {
1551 setParentInfo(newPowerFlags, whichParent, true);
1552 }
1c79356b 1553
2d21ac55
A
1554 // Parent is expecting an ACK from us. If we did not embark on a state
1555 // transition, when enqueuePowerChang() returns IOPMAckImplied. We are
1556 // still required to issue an ACK to our parent.
1557
1558 if (IOPMAckImplied == result)
1559 {
1560 IOService * parent;
1561 parent = (IOService *) whichParent->copyParentEntry(gIOPowerPlane);
1562 assert(parent);
1563 if ( parent )
1564 {
1565 parent->acknowledgePowerChange( whichParent );
1566 parent->release();
1567 }
1568 }
1569
1570 // If the parent registers it's power driver late, then this is the
1571 // first opportunity to tell our parent about our desire.
1572
1573 if (!savedParentsKnowState && fParentsKnowState)
1574 {
1575 PM_TRACE("[%s] powerDomainWillChangeTo: parentsKnowState = true\n",
1576 getName());
1577 ask_parent( fDesiredPowerState );
1578 }
cf7d32b8
A
1579
1580exit_no_ack:
1581 // Drop the retain from notifyChild().
1582 if (whichParent) whichParent->release();
2d21ac55 1583}
1c79356b
A
1584
1585//*********************************************************************************
2d21ac55 1586// [public deprecated] powerDomainDidChangeTo
1c79356b
A
1587//
1588// Called by the power-hierarchy parent after the power state of the power domain
1589// has settled at a new level.
1590// We enqueue a parent power-change to our queue of power changes.
1591// This may or may not cause us to change power, depending on what
1592// kind of change is occuring in the domain.
1593//*********************************************************************************
1594
2d21ac55
A
1595IOReturn IOService::powerDomainDidChangeTo (
1596 IOPMPowerFlags newPowerFlags,
1597 IOPowerConnection * whichParent )
1c79356b 1598{
2d21ac55
A
1599 assert(false);
1600 return kIOReturnUnsupported;
1601}
1c79356b 1602
2d21ac55
A
1603//*********************************************************************************
1604// [private] handlePowerDomainDidChangeTo
1605//*********************************************************************************
1c79356b 1606
2d21ac55
A
1607void IOService::handlePowerDomainDidChangeTo ( IOPMRequest * request )
1608{
1609 IOPMPowerFlags newPowerFlags = (IOPMPowerFlags) request->fArg0;
1610 IOPowerConnection * whichParent = (IOPowerConnection *) request->fArg1;
1611 unsigned long newPowerState;
1612 bool savedParentsKnowState;
1613 IOReturn result = IOPMAckImplied;
1614
1615 PM_ASSERT_IN_GATE();
1616 OUR_PMLog(kPMLogDidChange, newPowerFlags, 0);
1617
cf7d32b8 1618 if (!inPlane(gIOPowerPlane) || !whichParent || !whichParent->getAwaitingAck())
2d21ac55
A
1619 {
1620 PM_DEBUG("[%s] %s: not in power tree\n", getName(), __FUNCTION__);
cf7d32b8 1621 goto exit_no_ack;
2d21ac55 1622 }
0b4e3aa0 1623
2d21ac55 1624 savedParentsKnowState = fParentsKnowState;
0b4e3aa0 1625
2d21ac55
A
1626 setParentInfo(newPowerFlags, whichParent, true);
1627
1628 if ( fControllingDriver )
1629 {
1630 newPowerState = fControllingDriver->maxCapabilityForDomainState(
1631 fParentsCurrentPowerFlags);
1632
1633 result = enqueuePowerChange(
1634 /* flags */ IOPMParentInitiated | IOPMDomainDidChange,
1635 /* power state */ newPowerState,
1636 /* domain state */ fParentsCurrentPowerFlags,
1637 /* connection */ whichParent,
1638 /* parent state */ 0);
1639 }
0b4e3aa0 1640
2d21ac55
A
1641 // Parent is expecting an ACK from us. If we did not embark on a state
1642 // transition, when enqueuePowerChang() returns IOPMAckImplied. We are
1643 // still required to issue an ACK to our parent.
1644
1645 if (IOPMAckImplied == result)
1646 {
1647 IOService * parent;
1648 parent = (IOService *) whichParent->copyParentEntry(gIOPowerPlane);
1649 assert(parent);
1650 if ( parent )
1651 {
1652 parent->acknowledgePowerChange( whichParent );
1653 parent->release();
1654 }
1655 }
1656
1657 // If the parent registers it's power driver late, then this is the
1658 // first opportunity to tell our parent about our desire.
1659
1660 if (!savedParentsKnowState && fParentsKnowState)
1661 {
1662 PM_TRACE("[%s] powerDomainDidChangeTo: parentsKnowState = true\n",
1663 getName());
1664 ask_parent( fDesiredPowerState );
1665 }
cf7d32b8
A
1666
1667exit_no_ack:
1668 // Drop the retain from notifyChild().
1669 if (whichParent) whichParent->release();
2d21ac55 1670}
0b4e3aa0
A
1671
1672//*********************************************************************************
2d21ac55 1673// [private] setParentInfo
0b4e3aa0
A
1674//
1675// Set our connection data for one specific parent, and then combine all the parent
1676// data together.
1677//*********************************************************************************
2d21ac55
A
1678
1679void IOService::setParentInfo (
1680 IOPMPowerFlags newPowerFlags,
1681 IOPowerConnection * whichParent,
1682 bool knowsState )
0b4e3aa0 1683{
2d21ac55
A
1684 OSIterator * iter;
1685 OSObject * next;
1686 IOPowerConnection * conn;
1c79356b 1687
2d21ac55
A
1688 PM_ASSERT_IN_GATE();
1689
1690 // set our connection data
1691 whichParent->setParentCurrentPowerFlags(newPowerFlags);
1692 whichParent->setParentKnowsState(knowsState);
0b4e3aa0 1693
55e303ae 1694 // recompute our parent info
2d21ac55
A
1695 fParentsCurrentPowerFlags = 0;
1696 fParentsKnowState = true;
1c79356b
A
1697
1698 iter = getParentIterator(gIOPowerPlane);
2d21ac55 1699 if ( iter )
55e303ae 1700 {
2d21ac55 1701 while ( (next = iter->getNextObject()) )
55e303ae 1702 {
2d21ac55 1703 if ( (conn = OSDynamicCast(IOPowerConnection, next)) )
55e303ae 1704 {
2d21ac55
A
1705 fParentsKnowState &= conn->parentKnowsState();
1706 fParentsCurrentPowerFlags |= conn->parentCurrentPowerFlags();
1c79356b
A
1707 }
1708 }
1709 iter->release();
1710 }
1c79356b
A
1711}
1712
90556fb8 1713//*********************************************************************************
2d21ac55 1714// [private] rebuildChildClampBits
90556fb8
A
1715//
1716// The ChildClamp bits (kIOPMChildClamp & kIOPMChildClamp2) in our capabilityFlags
2d21ac55
A
1717// indicate that one of our children (or grandchildren or great-grandchildren ...)
1718// doesn't support idle or system sleep in its current state. Since we don't track
1719// the origin of each bit, every time any child changes state we have to clear
1720// these bits and rebuild them.
90556fb8
A
1721//*********************************************************************************
1722
2d21ac55 1723void IOService::rebuildChildClampBits ( void )
90556fb8 1724{
2d21ac55
A
1725 unsigned long i;
1726 OSIterator * iter;
1727 OSObject * next;
1728 IOPowerConnection * connection;
1729 unsigned long powerState;
1730
1731 // A child's desires has changed. We need to rebuild the child-clamp bits in
1732 // our power state array. Start by clearing the bits in each power state.
90556fb8 1733
2d21ac55 1734 for ( i = 0; i < fNumberOfPowerStates; i++ )
55e303ae 1735 {
2d21ac55 1736 fPowerStates[i].capabilityFlags &= ~(kIOPMChildClamp | kIOPMChildClamp2);
90556fb8
A
1737 }
1738
2d21ac55
A
1739 // Loop through the children. When we encounter the calling child, save the
1740 // computed state as this child's desire. And set the ChildClamp bits in any
1741 // of our states that some child has clamp on.
90556fb8
A
1742
1743 iter = getChildIterator(gIOPowerPlane);
2d21ac55 1744 if ( iter )
90556fb8 1745 {
2d21ac55 1746 while ( (next = iter->getNextObject()) )
90556fb8 1747 {
2d21ac55 1748 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
90556fb8 1749 {
2d21ac55
A
1750 if (connection->getReadyFlag() == false)
1751 {
1752 PM_CONNECT("[%s] %s: connection not ready\n",
1753 getName(), __FUNCTION__);
1754 continue;
1755 }
1756
1757 powerState = connection->getDesiredDomainState();
1758 if (powerState < fNumberOfPowerStates)
1759 {
1760 if ( connection->getPreventIdleSleepFlag() )
1761 fPowerStates[powerState].capabilityFlags |= kIOPMChildClamp;
1762 if ( connection->getPreventSystemSleepFlag() )
1763 fPowerStates[powerState].capabilityFlags |= kIOPMChildClamp2;
1764 }
90556fb8
A
1765 }
1766 }
1767 iter->release();
1768 }
90556fb8
A
1769}
1770
1c79356b 1771//*********************************************************************************
2d21ac55 1772// [public virtual] requestPowerDomainState
1c79356b 1773//
2d21ac55
A
1774// The child of a power domain calls it parent here to request power of a certain
1775// character.
1c79356b 1776//*********************************************************************************
2d21ac55
A
1777
1778IOReturn IOService::requestPowerDomainState (
1779 IOPMPowerFlags desiredState,
1780 IOPowerConnection * whichChild,
1781 unsigned long specification )
1c79356b 1782{
2d21ac55
A
1783 unsigned long i;
1784 unsigned long computedState;
1785 unsigned long theDesiredState;
1786 IOService * child;
1787
1788 if (!initialized)
1789 return IOPMNotYetInitialized;
1790
1791 if (gIOPMWorkLoop->onThread() == false)
1792 {
1793 PM_DEBUG("[%s] called requestPowerDomainState\n", getName());
1794 return kIOReturnSuccess;
1795 }
1c79356b 1796
2d21ac55 1797 theDesiredState = desiredState & ~(kIOPMPreventIdleSleep | kIOPMPreventSystemSleep);
1c79356b 1798
2d21ac55
A
1799 OUR_PMLog(kPMLogRequestDomain, desiredState, specification);
1800
1801 if (!isChild(whichChild, gIOPowerPlane))
1802 return kIOReturnNotAttached;
1803
1804 if (fControllingDriver == NULL || !fPowerStates)
1c79356b 1805 return IOPMNotYetInitialized;
2d21ac55
A
1806
1807 child = (IOService *) whichChild->getChildEntry(gIOPowerPlane);
1808 assert(child);
1c79356b
A
1809
1810 switch (specification) {
1811 case IOPMLowestState:
1812 i = 0;
2d21ac55 1813 while ( i < fNumberOfPowerStates )
55e303ae 1814 {
2d21ac55
A
1815 if ( ( fPowerStates[i].outputPowerCharacter & theDesiredState) ==
1816 (theDesiredState & fOutputPowerCharacterFlags) )
55e303ae 1817 {
1c79356b
A
1818 break;
1819 }
1820 i++;
1821 }
2d21ac55 1822 if ( i >= fNumberOfPowerStates )
55e303ae 1823 {
1c79356b 1824 return IOPMNoSuchState;
55e303ae 1825 }
1c79356b
A
1826 break;
1827
1828 case IOPMNextLowerState:
2d21ac55
A
1829 i = fCurrentPowerState - 1;
1830 while ( (int) i >= 0 )
55e303ae 1831 {
2d21ac55
A
1832 if ( ( fPowerStates[i].outputPowerCharacter & theDesiredState) ==
1833 (theDesiredState & fOutputPowerCharacterFlags) )
55e303ae 1834 {
1c79356b
A
1835 break;
1836 }
1837 i--;
1838 }
2d21ac55 1839 if ( (int) i < 0 )
55e303ae 1840 {
1c79356b
A
1841 return IOPMNoSuchState;
1842 }
1843 break;
1844
1845 case IOPMHighestState:
2d21ac55
A
1846 i = fNumberOfPowerStates;
1847 while ( (int) i >= 0 )
55e303ae 1848 {
1c79356b 1849 i--;
2d21ac55
A
1850 if ( ( fPowerStates[i].outputPowerCharacter & theDesiredState) ==
1851 (theDesiredState & fOutputPowerCharacterFlags) )
55e303ae 1852 {
1c79356b
A
1853 break;
1854 }
1855 }
2d21ac55 1856 if ( (int) i < 0 )
55e303ae 1857 {
1c79356b
A
1858 return IOPMNoSuchState;
1859 }
1860 break;
1861
1862 case IOPMNextHigherState:
2d21ac55
A
1863 i = fCurrentPowerState + 1;
1864 while ( i < fNumberOfPowerStates )
55e303ae 1865 {
2d21ac55
A
1866 if ( ( fPowerStates[i].outputPowerCharacter & theDesiredState) ==
1867 (theDesiredState & fOutputPowerCharacterFlags) )
55e303ae 1868 {
1c79356b
A
1869 break;
1870 }
55e303ae 1871 i++;
1c79356b 1872 }
2d21ac55 1873 if ( i == fNumberOfPowerStates )
55e303ae 1874 {
1c79356b
A
1875 return IOPMNoSuchState;
1876 }
1877 break;
1878
1879 default:
1880 return IOPMBadSpecification;
1881 }
1882
0b4e3aa0 1883 computedState = i;
0b4e3aa0 1884
2d21ac55 1885 // Clamp removed on the initial power request from a new child.
1c79356b 1886
2d21ac55
A
1887 if (fClampOn && !whichChild->childHasRequestedPower())
1888 {
1889 PM_TRACE("[%s] %p power clamp removed (child = %p)\n",
1890 getName(), this, whichChild);
1891 fClampOn = false;
1892 fDeviceDesire = 0;
1893 }
90556fb8 1894
2d21ac55 1895 // Record the child's desires on the connection.
1c79356b 1896
2d21ac55
A
1897 whichChild->setDesiredDomainState( computedState );
1898 whichChild->setPreventIdleSleepFlag( desiredState & kIOPMPreventIdleSleep );
1899 whichChild->setPreventSystemSleepFlag( desiredState & kIOPMPreventSystemSleep );
1900 whichChild->setChildHasRequestedPower();
1901
1902 if (whichChild->getReadyFlag() == false)
1903 return IOPMNoErr;
1904
1905 // Issue a ping for us to re-evaluate all children desires and
1906 // possibly change power state.
1907
1908 if (!fWillAdjustPowerState && !fDeviceOverrides)
1909 {
1910 IOPMRequest * childRequest;
1911
1912 childRequest = acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState );
1913 if (childRequest)
1914 {
1915 submitPMRequest( childRequest );
1916 fWillAdjustPowerState = true;
1917 }
1918 }
1c79356b 1919
2d21ac55
A
1920 return IOPMNoErr;
1921}
1c79356b
A
1922
1923//*********************************************************************************
2d21ac55 1924// [public virtual] temporaryPowerClampOn
1c79356b
A
1925//
1926// A power domain wants to clamp its power on till it has children which
1927// will thendetermine the power domain state.
1928//
1929// We enter the highest state until addPowerChild is called.
1930//*********************************************************************************
1931
1932IOReturn IOService::temporaryPowerClampOn ( void )
1933{
2d21ac55
A
1934 IOPMRequest * request;
1935
1936 if (!initialized)
1937 return IOPMNotYetInitialized;
1938
1939 request = acquirePMRequest( this, kIOPMRequestTypeTemporaryPowerClamp );
1940 if (!request)
1941 return kIOReturnNoMemory;
1942
1943 submitPMRequest( request );
1c79356b
A
1944 return IOPMNoErr;
1945}
1946
1c79356b 1947//*********************************************************************************
2d21ac55 1948// [public virtual] makeUsable
1c79356b
A
1949//
1950// Some client of our device is asking that we become usable. Although
1951// this has not come from a subclassed device object, treat it exactly
1952// as if it had. In this way, subsequent requests for lower power from
1953// a subclassed device object will pre-empt this request.
1954//
1955// We treat this as a subclass object request to switch to the
1956// highest power state.
1957//*********************************************************************************
1958
1959IOReturn IOService::makeUsable ( void )
1960{
2d21ac55 1961 IOPMRequest * request;
1c79356b 1962
2d21ac55
A
1963 if (!initialized)
1964 return IOPMNotYetInitialized;
1965
1966 OUR_PMLog(kPMLogMakeUsable, 0, 0);
1967
1968 request = acquirePMRequest( this, kIOPMRequestTypeMakeUsable );
1969 if (!request)
1970 return kIOReturnNoMemory;
1971
1972 submitPMRequest( request );
1c79356b
A
1973 return IOPMNoErr;
1974}
1975
2d21ac55
A
1976//*********************************************************************************
1977// [private] handleMakeUsable
0c530ab8 1978//
2d21ac55
A
1979// Handle a request to become usable.
1980//*********************************************************************************
0c530ab8 1981
2d21ac55 1982void IOService::handleMakeUsable ( IOPMRequest * request )
0c530ab8 1983{
2d21ac55
A
1984 PM_ASSERT_IN_GATE();
1985 if ( fControllingDriver )
1986 {
1987 fDeviceDesire = fNumberOfPowerStates - 1;
1988 computeDesiredState();
1989 if ( inPlane(gIOPowerPlane) && fParentsKnowState )
1990 {
1991 changeState();
1992 }
1993 }
1994 else
1995 {
1996 fNeedToBecomeUsable = true;
0c530ab8 1997 }
0c530ab8
A
1998}
1999
1c79356b 2000//*********************************************************************************
2d21ac55 2001// [public virtual] currentCapability
1c79356b
A
2002//*********************************************************************************
2003
2004IOPMPowerFlags IOService::currentCapability ( void )
2005{
2d21ac55
A
2006 if (!initialized)
2007 return IOPMNotPowerManaged;
1c79356b 2008
2d21ac55
A
2009 return fCurrentCapabilityFlags;
2010}
1c79356b
A
2011
2012//*********************************************************************************
2d21ac55 2013// [public virtual] changePowerStateTo
1c79356b
A
2014//
2015// For some reason, our power-controlling driver has decided it needs to change
2016// power state. We enqueue the power change so that appropriate parties
2017// will be notified, and then we will instruct the driver to make the change.
2018//*********************************************************************************
2019
2020IOReturn IOService::changePowerStateTo ( unsigned long ordinal )
2021{
2d21ac55 2022 IOPMRequest * request;
1c79356b 2023
2d21ac55
A
2024 if (!initialized)
2025 return IOPMNotYetInitialized;
2026
2027 OUR_PMLog(kPMLogChangeStateTo, ordinal, 0);
2028
2029 request = acquirePMRequest( this, kIOPMRequestTypeChangePowerStateTo );
2030 if (!request)
2031 return kIOReturnNoMemory;
2032
2033 request->fArg0 = (void *) ordinal;
2034 request->fArg1 = (void *) false;
1c79356b 2035
2d21ac55
A
2036 // Avoid needless downwards power transitions by clamping power in
2037 // computeDesiredState() until the delayed request is processed.
2038
2039 if (gIOPMWorkLoop->inGate())
2040 {
2041 fTempClampPowerState = max(fTempClampPowerState, ordinal);
2042 fTempClampCount++;
2043 request->fArg1 = (void *) true;
2044 }
2045
2046 submitPMRequest( request );
1c79356b
A
2047 return IOPMNoErr;
2048}
2049
2050//*********************************************************************************
2d21ac55
A
2051// [private] handleChangePowerStateTo
2052//*********************************************************************************
2053
2054void IOService::handleChangePowerStateTo ( IOPMRequest * request )
2055{
2056 unsigned long ordinal = (unsigned long) request->fArg0;
2057
2058 PM_ASSERT_IN_GATE();
2059 if (request->fArg1)
2060 {
2061 assert(fTempClampCount != 0);
2062 if (fTempClampCount)
2063 fTempClampCount--;
2064 if (!fTempClampCount)
2065 fTempClampPowerState = 0;
2066 }
2067
2068 if ( fControllingDriver && (ordinal < fNumberOfPowerStates))
2069 {
2070 fDriverDesire = ordinal;
2071 computeDesiredState();
2072 if ( inPlane(gIOPowerPlane) && fParentsKnowState )
2073 {
2074 changeState();
2075 }
2076 }
2077}
2078
2079//*********************************************************************************
2080// [public virtual] changePowerStateToPriv
1c79356b
A
2081//
2082// For some reason, a subclassed device object has decided it needs to change
2083// power state. We enqueue the power change so that appropriate parties
2084// will be notified, and then we will instruct the driver to make the change.
2085//*********************************************************************************
2086
2087IOReturn IOService::changePowerStateToPriv ( unsigned long ordinal )
2088{
2d21ac55 2089 IOPMRequest * request;
1c79356b 2090
2d21ac55
A
2091 if (!initialized)
2092 return IOPMNotYetInitialized;
2093
2094 request = acquirePMRequest( this, kIOPMRequestTypeChangePowerStateToPriv );
2095 if (!request)
2096 return kIOReturnNoMemory;
2097
2098 request->fArg0 = (void *) ordinal;
2099 request->fArg1 = (void *) false;
2100
2101 // Avoid needless downwards power transitions by clamping power in
2102 // computeDesiredState() until the delayed request is processed.
2103
2104 if (gIOPMWorkLoop->inGate())
2105 {
2106 fTempClampPowerState = max(fTempClampPowerState, ordinal);
2107 fTempClampCount++;
2108 request->fArg1 = (void *) true;
2109 }
1c79356b 2110
2d21ac55 2111 submitPMRequest( request );
1c79356b
A
2112 return IOPMNoErr;
2113}
2114
2d21ac55
A
2115//*********************************************************************************
2116// [private] handleChangePowerStateToPriv
2117//*********************************************************************************
2118
2119void IOService::handleChangePowerStateToPriv ( IOPMRequest * request )
2120{
2121 unsigned long ordinal = (unsigned long) request->fArg0;
2122
2123 PM_ASSERT_IN_GATE();
2124 OUR_PMLog(kPMLogChangeStateToPriv, ordinal, 0);
2125 if (request->fArg1)
2126 {
2127 assert(fTempClampCount != 0);
2128 if (fTempClampCount)
2129 fTempClampCount--;
2130 if (!fTempClampCount)
2131 fTempClampPowerState = 0;
2132 }
2133
2134 if ( fControllingDriver && (ordinal < fNumberOfPowerStates))
2135 {
2136 fDeviceDesire = ordinal;
2137 computeDesiredState();
2138 if ( inPlane(gIOPowerPlane) && fParentsKnowState )
2139 {
2140 changeState();
2141 }
2142 }
2143}
1c79356b
A
2144
2145//*********************************************************************************
2d21ac55 2146// [private] computeDesiredState
1c79356b
A
2147//*********************************************************************************
2148
2d21ac55 2149void IOService::computeDesiredState ( unsigned long tempDesire )
1c79356b 2150{
2d21ac55
A
2151 OSIterator * iter;
2152 OSObject * next;
2153 IOPowerConnection * connection;
2154 unsigned long newDesiredState = 0;
2155 unsigned long childDesire = 0;
2156 unsigned long deviceDesire;
2157
2158 if (tempDesire)
2159 deviceDesire = tempDesire;
2160 else
2161 deviceDesire = fDeviceDesire;
2162
2163 // If clamp is on, always override deviceDesire to max.
2164
2165 if (fClampOn && fNumberOfPowerStates)
2166 deviceDesire = fNumberOfPowerStates - 1;
2167
2168 // Compute the maximum of our children's desires,
2169 // our controlling driver's desire, and the subclass device's desire.
1c79356b 2170
2d21ac55 2171 if ( !fDeviceOverrides )
55e303ae 2172 {
1c79356b 2173 iter = getChildIterator(gIOPowerPlane);
2d21ac55 2174 if ( iter )
55e303ae 2175 {
2d21ac55 2176 while ( (next = iter->getNextObject()) )
55e303ae 2177 {
2d21ac55 2178 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
55e303ae 2179 {
2d21ac55
A
2180 if (connection->getReadyFlag() == false)
2181 {
2182 PM_CONNECT("[%s] %s: connection not ready\n",
2183 getName(), __FUNCTION__);
2184 continue;
2185 }
2186
2187 if (connection->getDesiredDomainState() > childDesire)
2188 childDesire = connection->getDesiredDomainState();
1c79356b
A
2189 }
2190 }
2191 iter->release();
2192 }
2d21ac55
A
2193
2194 fChildrenDesire = childDesire;
2195 newDesiredState = max(childDesire, fDriverDesire);
1c79356b
A
2196 }
2197
2d21ac55
A
2198 newDesiredState = max(deviceDesire, newDesiredState);
2199 if (fTempClampCount && (fTempClampPowerState < fNumberOfPowerStates))
2200 newDesiredState = max(fTempClampPowerState, newDesiredState);
2201
2202 fDesiredPowerState = newDesiredState;
2203
2204 // Limit check against number of power states.
2205
2206 if (fNumberOfPowerStates == 0)
2207 fDesiredPowerState = 0;
2208 else if (fDesiredPowerState >= fNumberOfPowerStates)
2209 fDesiredPowerState = fNumberOfPowerStates - 1;
1c79356b 2210
2d21ac55
A
2211 // Restart idle timer if stopped and deviceDesire has increased.
2212
2213 if (fDeviceDesire && fActivityTimerStopped)
2214 {
2215 fActivityTimerStopped = false;
2216 start_PM_idle_timer();
2217 }
2218
2219 // Invalidate cached tickle power state when desires change, and not
2220 // due to a tickle request. This invalidation must occur before the
2221 // power state change to minimize races. We want to err on the side
2222 // of servicing more activity tickles rather than dropping one when
2223 // the device is in a low power state.
2224
2225 if (fPMRequest && (fPMRequest->getType() != kIOPMRequestTypeActivityTickle) &&
2226 (fActivityTicklePowerState != -1))
2227 {
2228 IOLockLock(fActivityLock);
2229 fActivityTicklePowerState = -1;
2230 IOLockUnlock(fActivityLock);
2231 }
0b4e3aa0 2232
2d21ac55
A
2233 PM_TRACE(" NewState %ld, Child %ld, Driver %ld, Device %ld, Clamp %d (%ld)\n",
2234 fDesiredPowerState, childDesire, fDriverDesire, deviceDesire,
2235 fClampOn, fTempClampCount ? fTempClampPowerState : 0);
2236}
1c79356b 2237
0b4e3aa0 2238//*********************************************************************************
2d21ac55 2239// [private] changeState
0b4e3aa0
A
2240//
2241// A subclass object, our controlling driver, or a power domain child
2242// has asked for a different power state. Here we compute what new
2243// state we should enter and enqueue the change (or start it).
2244//*********************************************************************************
2245
2246IOReturn IOService::changeState ( void )
2247{
2d21ac55
A
2248 IOReturn result;
2249
2250 PM_ASSERT_IN_GATE();
2251 assert(inPlane(gIOPowerPlane));
2252 assert(fParentsKnowState);
2253 assert(fControllingDriver);
2254
2255 result = enqueuePowerChange(
2256 /* flags */ IOPMWeInitiated,
2257 /* power state */ fDesiredPowerState,
2258 /* domain state */ 0,
2259 /* connection */ 0,
2260 /* parent state */ 0);
1c79356b 2261
2d21ac55
A
2262 return result;
2263}
1c79356b
A
2264
2265//*********************************************************************************
2d21ac55 2266// [public virtual] currentPowerConsumption
1c79356b
A
2267//
2268//*********************************************************************************
2269
2270unsigned long IOService::currentPowerConsumption ( void )
2271{
2d21ac55 2272 if (!initialized)
0b4e3aa0 2273 return kIOPMUnknown;
2d21ac55
A
2274
2275 return fCurrentPowerConsumption;
2276}
2277
2278//*********************************************************************************
2279// [public virtual] getPMworkloop
2280//*********************************************************************************
2281
2282IOWorkLoop * IOService::getPMworkloop ( void )
2283{
2284 return gIOPMWorkLoop;
1c79356b
A
2285}
2286
2287//*********************************************************************************
2d21ac55 2288// [public virtual] activityTickle
1c79356b 2289//
1c79356b
A
2290// The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
2291// flag to be set, and the device state checked. If the device has been
2292// powered down, it is powered up again.
2d21ac55
A
2293// The tickle with parameter kIOPMSubclassPolicy is ignored here and
2294// should be intercepted by a subclass.
1c79356b
A
2295//*********************************************************************************
2296
55e303ae 2297bool IOService::activityTickle ( unsigned long type, unsigned long stateNumber )
1c79356b 2298{
2d21ac55
A
2299 IOPMRequest * request;
2300 bool noPowerChange = true;
e7c99d92 2301
2d21ac55
A
2302 if ( initialized && stateNumber && (type == kIOPMSuperclassPolicy1) )
2303 {
2304 IOLockLock(fActivityLock);
e7c99d92 2305
2d21ac55 2306 // Record device activity for the idle timer handler.
e7c99d92 2307
2d21ac55
A
2308 fDeviceActive = true;
2309 clock_get_uptime(&fDeviceActiveTimestamp);
55e303ae 2310
2d21ac55
A
2311 // Record the last tickle power state.
2312 // This helps to filter out redundant tickles as
2313 // this function may be called from the data path.
1c79356b 2314
2d21ac55
A
2315 if (fActivityTicklePowerState < (long)stateNumber)
2316 {
2317 fActivityTicklePowerState = stateNumber;
2318 noPowerChange = false;
1c79356b 2319
2d21ac55
A
2320 request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
2321 if (request)
2322 {
2323 request->fArg0 = (void *) stateNumber; // power state
2324 request->fArg1 = (void *) true; // power rise
2325 submitPMRequest(request);
2326 }
2327 }
1c79356b 2328
2d21ac55
A
2329 IOLockUnlock(fActivityLock);
2330 }
1c79356b 2331
2d21ac55
A
2332 // Returns false if the activityTickle might cause a transition to a
2333 // higher powered state, true otherwise.
2334
2335 return noPowerChange;
2336}
1c79356b
A
2337
2338//*********************************************************************************
2d21ac55 2339// [public virtual] setIdleTimerPeriod
1c79356b
A
2340//
2341// A subclass policy-maker is going to use our standard idleness
2342// detection service. Make a command queue and an idle timer and
2343// connect them to the power management workloop. Finally,
2344// start the timer.
2345//*********************************************************************************
2346
2d21ac55 2347IOReturn IOService::setIdleTimerPeriod ( unsigned long period )
1c79356b 2348{
2d21ac55
A
2349 IOWorkLoop * wl = getPMworkloop();
2350
2351 if (!initialized || !wl)
2352 return IOPMNotYetInitialized;
2353
2354 OUR_PMLog(PMsetIdleTimerPeriod, period, 0);
1c79356b 2355
2d21ac55 2356 fIdleTimerPeriod = period;
1c79356b 2357
2d21ac55 2358 if ( period > 0 )
55e303ae 2359 {
55e303ae 2360 // make the timer event
2d21ac55 2361 if ( fIdleTimerEventSource == NULL )
55e303ae 2362 {
2d21ac55
A
2363 IOTimerEventSource * timerSrc;
2364
2365 timerSrc = IOTimerEventSource::timerEventSource(
2366 this, PM_idle_timer_expired);
2367
2368 if (timerSrc && (wl->addEventSource(timerSrc) != kIOReturnSuccess))
2369 {
2370 timerSrc->release();
2371 timerSrc = 0;
2372 }
2373
2374 fIdleTimerEventSource = timerSrc;
1c79356b
A
2375 }
2376
2377 start_PM_idle_timer();
2378 }
2379 return IOPMNoErr;
2380}
2381
91447636 2382//******************************************************************************
2d21ac55 2383// [public virtual] nextIdleTimeout
91447636
A
2384//
2385// Returns how many "seconds from now" the device should idle into its
2386// next lowest power state.
2387//******************************************************************************
2d21ac55 2388
91447636
A
2389SInt32 IOService::nextIdleTimeout(
2390 AbsoluteTime currentTime,
2391 AbsoluteTime lastActivity,
2392 unsigned int powerState)
2393{
2394 AbsoluteTime delta;
2395 UInt64 delta_ns;
2396 SInt32 delta_secs;
2397 SInt32 delay_secs;
1c79356b 2398
91447636
A
2399 // Calculate time difference using funky macro from clock.h.
2400 delta = currentTime;
2401 SUB_ABSOLUTETIME(&delta, &lastActivity);
2402
2403 // Figure it in seconds.
2404 absolutetime_to_nanoseconds(delta, &delta_ns);
2405 delta_secs = (SInt32)(delta_ns / NSEC_PER_SEC);
2406
2407 // Be paranoid about delta somehow exceeding timer period.
2d21ac55
A
2408 if (delta_secs < (int) fIdleTimerPeriod )
2409 delay_secs = (int) fIdleTimerPeriod - delta_secs;
91447636 2410 else
2d21ac55 2411 delay_secs = (int) fIdleTimerPeriod;
91447636
A
2412
2413 return (SInt32)delay_secs;
2414}
2415
2416//******************************************************************************
2d21ac55 2417// [public virtual] start_PM_idle_timer
1c79356b
A
2418//
2419// The parameter is a pointer to us. Use it to call our timeout method.
91447636 2420//******************************************************************************
2d21ac55 2421
1c79356b
A
2422void IOService::start_PM_idle_timer ( void )
2423{
91447636
A
2424 static const int maxTimeout = 100000;
2425 static const int minTimeout = 1;
55e303ae 2426 AbsoluteTime uptime;
91447636 2427 SInt32 idle_in = 0;
e7c99d92 2428
2d21ac55
A
2429 if (!initialized || !fIdleTimerEventSource)
2430 return;
2431
2432 IOLockLock(fActivityLock);
e7c99d92
A
2433
2434 clock_get_uptime(&uptime);
91447636
A
2435
2436 // Subclasses may modify idle sleep algorithm
2d21ac55 2437 idle_in = nextIdleTimeout(uptime, fDeviceActiveTimestamp, fCurrentPowerState);
e7c99d92 2438
91447636 2439 // Check for out-of range responses
2d21ac55 2440 if (idle_in > maxTimeout)
55e303ae 2441 {
91447636
A
2442 // use standard implementation
2443 idle_in = IOService::nextIdleTimeout(uptime,
2d21ac55
A
2444 fDeviceActiveTimestamp,
2445 fCurrentPowerState);
2446 } else if (idle_in < minTimeout) {
2447 idle_in = fIdleTimerPeriod;
e7c99d92
A
2448 }
2449
2d21ac55 2450 IOLockUnlock(fActivityLock);
e7c99d92 2451
2d21ac55 2452 fIdleTimerEventSource->setTimeout(idle_in, NSEC_PER_SEC);
1c79356b
A
2453}
2454
1c79356b 2455//*********************************************************************************
2d21ac55 2456// [private] PM_idle_timer_expired
1c79356b
A
2457//
2458// The parameter is a pointer to us. Use it to call our timeout method.
2459//*********************************************************************************
2460
2d21ac55 2461void PM_idle_timer_expired ( OSObject * ourSelves, IOTimerEventSource * )
1c79356b
A
2462{
2463 ((IOService *)ourSelves)->PM_idle_timer_expiration();
2464}
2465
1c79356b 2466//*********************************************************************************
2d21ac55 2467// [public virtual] PM_idle_timer_expiration
1c79356b
A
2468//
2469// The idle timer has expired. If there has been activity since the last
2470// expiration, just restart the timer and return. If there has not been
2471// activity, switch to the next lower power state and restart the timer.
2472//*********************************************************************************
2473
2474void IOService::PM_idle_timer_expiration ( void )
2475{
2d21ac55
A
2476 IOPMRequest * request;
2477 bool restartTimer = true;
2478
2479 if ( !initialized || !fIdleTimerPeriod )
55e303ae 2480 return;
1c79356b 2481
2d21ac55 2482 IOLockLock(fActivityLock);
1c79356b 2483
2d21ac55 2484 // Check for device activity (tickles) over last timer period.
1c79356b 2485
2d21ac55
A
2486 if (fDeviceActive)
2487 {
2488 // Device was active - do not drop power, restart timer.
2489 fDeviceActive = false;
2490 }
2491 else
2492 {
2493 // No device activity - drop power state by one level.
2494 // Decrement the cached tickle power state when possible.
2495 // This value may be (-1) before activityTickle() is called,
2496 // but the power drop request must be issued regardless.
1c79356b 2497
2d21ac55
A
2498 if (fActivityTicklePowerState > 0)
2499 {
2500 fActivityTicklePowerState--;
2501 }
1c79356b 2502
2d21ac55
A
2503 request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
2504 if (request)
2505 {
2506 request->fArg0 = (void *) 0; // power state (irrelevant)
2507 request->fArg1 = (void *) false; // power drop
2508 submitPMRequest( request );
1c79356b 2509
2d21ac55
A
2510 // Do not restart timer until after the tickle request has been
2511 // processed.
91447636 2512
2d21ac55
A
2513 restartTimer = false;
2514 }
1c79356b 2515 }
2d21ac55
A
2516
2517 IOLockUnlock(fActivityLock);
2518
2519 if (restartTimer)
2520 start_PM_idle_timer();
1c79356b
A
2521}
2522
2d21ac55
A
2523//*********************************************************************************
2524// [public virtual] command_received
2525//
2526//*********************************************************************************
2527
2528void IOService::command_received ( void *statePtr , void *, void * , void * )
2529{
2530}
1c79356b
A
2531
2532//*********************************************************************************
2d21ac55 2533// [public virtual] setAggressiveness
1c79356b
A
2534//
2535// Pass on the input parameters to all power domain children. All those which are
2536// power domains will pass it on to their children, etc.
2537//*********************************************************************************
2538
2539IOReturn IOService::setAggressiveness ( unsigned long type, unsigned long newLevel )
2540{
2d21ac55
A
2541 OSIterator * iter;
2542 OSObject * next;
2543 IOPowerConnection * connection;
2544 IOService * child;
2545
2546 if (!initialized)
2547 return IOPMNotYetInitialized;
1c79356b 2548
2d21ac55
A
2549 if (getPMRootDomain() == this)
2550 OUR_PMLog(kPMLogSetAggressiveness, type, newLevel);
1c79356b 2551
2d21ac55 2552 if ( type <= kMaxType )
55e303ae 2553 {
2d21ac55
A
2554 fAggressivenessValue[type] = newLevel;
2555 fAggressivenessValid[type] = true;
1c79356b
A
2556 }
2557
2558 iter = getChildIterator(gIOPowerPlane);
2d21ac55 2559 if ( iter )
55e303ae 2560 {
2d21ac55 2561 while ( (next = iter->getNextObject()) )
55e303ae 2562 {
2d21ac55 2563 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
55e303ae 2564 {
2d21ac55
A
2565 if (connection->getReadyFlag() == false)
2566 {
2567 PM_CONNECT("[%s] %s: connection not ready\n",
2568 getName(), __FUNCTION__);
2569 continue;
2570 }
2571
0b4e3aa0 2572 child = ((IOService *)(connection->copyChildEntry(gIOPowerPlane)));
2d21ac55 2573 if ( child )
55e303ae 2574 {
0b4e3aa0
A
2575 child->setAggressiveness(type, newLevel);
2576 child->release();
2577 }
1c79356b
A
2578 }
2579 }
2580 iter->release();
2581 }
2582
2583 return IOPMNoErr;
2584}
2585
2586//*********************************************************************************
2d21ac55 2587// [public virtual] getAggressiveness
1c79356b
A
2588//
2589// Called by the user client.
2590//*********************************************************************************
2591
2592IOReturn IOService::getAggressiveness ( unsigned long type, unsigned long * currentLevel )
2593{
2d21ac55 2594 if ( !initialized || (type > kMaxType) )
91447636 2595 return kIOReturnBadArgument;
55e303ae 2596
2d21ac55 2597 if ( !fAggressivenessValid[type] )
55e303ae
A
2598 return kIOReturnInvalid;
2599
2d21ac55
A
2600 *currentLevel = fAggressivenessValue[type];
2601
1c79356b
A
2602 return kIOReturnSuccess;
2603}
2604
2605//*********************************************************************************
2d21ac55
A
2606// [public] getPowerState
2607//
2608//*********************************************************************************
2609
2610UInt32 IOService::getPowerState ( void )
2611{
2612 if (!initialized)
2613 return 0;
2614
2615 return fCurrentPowerState;
2616}
2617
2618//*********************************************************************************
2619// [public virtual] systemWake
1c79356b
A
2620//
2621// Pass this to all power domain children. All those which are
2622// power domains will pass it on to their children, etc.
2623//*********************************************************************************
2624
2625IOReturn IOService::systemWake ( void )
2626{
2d21ac55
A
2627 OSIterator * iter;
2628 OSObject * next;
2629 IOPowerConnection * connection;
2630 IOService * theChild;
1c79356b 2631
2d21ac55 2632 OUR_PMLog(kPMLogSystemWake, 0, 0);
1c79356b
A
2633
2634 iter = getChildIterator(gIOPowerPlane);
2d21ac55 2635 if ( iter )
55e303ae 2636 {
2d21ac55 2637 while ( (next = iter->getNextObject()) )
55e303ae 2638 {
2d21ac55 2639 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
55e303ae 2640 {
2d21ac55
A
2641 if (connection->getReadyFlag() == false)
2642 {
2643 PM_CONNECT("[%s] %s: connection not ready\n",
2644 getName(), __FUNCTION__);
2645 continue;
2646 }
2647
0b4e3aa0 2648 theChild = (IOService *)connection->copyChildEntry(gIOPowerPlane);
2d21ac55 2649 if ( theChild )
55e303ae 2650 {
0b4e3aa0 2651 theChild->systemWake();
55e303ae 2652 theChild->release();
0b4e3aa0 2653 }
1c79356b
A
2654 }
2655 }
2656 iter->release();
2657 }
2658
2d21ac55 2659 if ( fControllingDriver != NULL )
55e303ae 2660 {
2d21ac55 2661 if ( fControllingDriver->didYouWakeSystem() )
55e303ae 2662 {
1c79356b
A
2663 makeUsable();
2664 }
2665 }
2666
2667 return IOPMNoErr;
2668}
2669
1c79356b 2670//*********************************************************************************
2d21ac55 2671// [public virtual] temperatureCriticalForZone
1c79356b
A
2672//*********************************************************************************
2673
2674IOReturn IOService::temperatureCriticalForZone ( IOService * whichZone )
2675{
2d21ac55
A
2676 IOService * theParent;
2677 IOService * theNub;
0b4e3aa0 2678
2d21ac55 2679 OUR_PMLog(kPMLogCriticalTemp, 0, 0);
1c79356b 2680
2d21ac55 2681 if ( inPlane(gIOPowerPlane) && !fWeAreRoot )
55e303ae 2682 {
0b4e3aa0 2683 theNub = (IOService *)copyParentEntry(gIOPowerPlane);
2d21ac55 2684 if ( theNub )
55e303ae 2685 {
0b4e3aa0
A
2686 theParent = (IOService *)theNub->copyParentEntry(gIOPowerPlane);
2687 theNub->release();
2d21ac55 2688 if ( theParent )
55e303ae 2689 {
0b4e3aa0
A
2690 theParent->temperatureCriticalForZone(whichZone);
2691 theParent->release();
2692 }
2693 }
1c79356b
A
2694 }
2695 return IOPMNoErr;
2696}
2697
1c79356b 2698//*********************************************************************************
2d21ac55 2699// [public] powerOverrideOnPriv
1c79356b
A
2700//*********************************************************************************
2701
1c79356b
A
2702IOReturn IOService::powerOverrideOnPriv ( void )
2703{
2d21ac55 2704 IOPMRequest * request;
1c79356b 2705
2d21ac55
A
2706 if (!initialized)
2707 return IOPMNotYetInitialized;
1c79356b 2708
2d21ac55
A
2709 if (gIOPMWorkLoop->inGate())
2710 {
2711 fDeviceOverrides = true;
2712 return IOPMNoErr;
2713 }
2714
2715 request = acquirePMRequest( this, kIOPMRequestTypePowerOverrideOnPriv );
2716 if (!request)
2717 return kIOReturnNoMemory;
2718
2719 submitPMRequest( request );
2720 return IOPMNoErr;
2721}
1c79356b
A
2722
2723//*********************************************************************************
2d21ac55 2724// [public] powerOverrideOffPriv
1c79356b 2725//*********************************************************************************
2d21ac55 2726
1c79356b
A
2727IOReturn IOService::powerOverrideOffPriv ( void )
2728{
2d21ac55 2729 IOPMRequest * request;
1c79356b 2730
2d21ac55
A
2731 if (!initialized)
2732 return IOPMNotYetInitialized;
2733
2734 if (gIOPMWorkLoop->inGate())
2735 {
2736 fDeviceOverrides = false;
2737 return IOPMNoErr;
2738 }
2739
2740 request = acquirePMRequest( this, kIOPMRequestTypePowerOverrideOffPriv );
2741 if (!request)
2742 return kIOReturnNoMemory;
2743
2744 submitPMRequest( request );
2745 return IOPMNoErr;
1c79356b
A
2746}
2747
2d21ac55
A
2748//*********************************************************************************
2749// [private] handlePowerOverrideChanged
2750//*********************************************************************************
2751
2752void IOService::handlePowerOverrideChanged ( IOPMRequest * request )
2753{
2754 PM_ASSERT_IN_GATE();
2755 if (request->getType() == kIOPMRequestTypePowerOverrideOnPriv)
2756 {
2757 OUR_PMLog(kPMLogOverrideOn, 0, 0);
2758 fDeviceOverrides = true;
2759 }
2760 else
2761 {
2762 OUR_PMLog(kPMLogOverrideOff, 0, 0);
2763 fDeviceOverrides = false;
2764 }
2765
2766 if (fControllingDriver && inPlane(gIOPowerPlane) && fParentsKnowState)
2767 {
2768 computeDesiredState();
2769 changeState();
2770 }
2771}
1c79356b
A
2772
2773//*********************************************************************************
2d21ac55 2774// [private] enqueuePowerChange
1c79356b
A
2775//*********************************************************************************
2776
0c530ab8 2777IOReturn IOService::enqueuePowerChange (
2d21ac55
A
2778 unsigned long flags,
2779 unsigned long whatStateOrdinal,
2780 unsigned long domainState,
2781 IOPowerConnection * whichParent,
2782 unsigned long singleParentState )
2783{
2784 changeNoteItem changeNote;
2785 IOPMPowerState * powerStatePtr;
2786
2787 PM_ASSERT_IN_GATE();
2788 assert( fMachineState == kIOPM_Finished );
2789 assert( whatStateOrdinal < fNumberOfPowerStates );
2790
2791 if (whatStateOrdinal >= fNumberOfPowerStates)
55e303ae 2792 return IOPMAckImplied;
1c79356b 2793
2d21ac55
A
2794 powerStatePtr = &fPowerStates[whatStateOrdinal];
2795
2796 // Initialize the change note
2797 changeNote.flags = flags;
2798 changeNote.newStateNumber = whatStateOrdinal;
2799 changeNote.outputPowerCharacter = powerStatePtr->outputPowerCharacter;
2800 changeNote.inputPowerRequirement = powerStatePtr->inputPowerRequirement;
2801 changeNote.capabilityFlags = powerStatePtr->capabilityFlags;
2802 changeNote.parent = NULL;
2803
2804 if (flags & IOPMParentInitiated )
55e303ae 2805 {
2d21ac55
A
2806 changeNote.domainState = domainState;
2807 changeNote.parent = whichParent;
2808 changeNote.singleParentState = singleParentState;
1c79356b
A
2809 }
2810
2d21ac55
A
2811 if (flags & IOPMWeInitiated )
2812 {
2813 start_our_change(&changeNote);
2814 return 0;
2815 }
2816 else
2817 {
2818 return start_parent_change(&changeNote);
2819 }
2820}
1c79356b 2821
2d21ac55
A
2822//*********************************************************************************
2823// [private] notifyInterestedDrivers
2824//*********************************************************************************
2825
2826bool IOService::notifyInterestedDrivers ( void )
2827{
2828 IOPMinformee * informee;
2829 IOPMinformeeList * list = fInterestedDrivers;
2830 DriverCallParam * param;
2831 IOItemCount count;
2832
2833 PM_ASSERT_IN_GATE();
2834 assert( fDriverCallBusy == false );
2835 assert( fDriverCallParamCount == 0 );
2836 assert( fHeadNotePendingAcks == 0 );
2837
2838 count = list->numberOfItems();
2839 if (!count)
2840 goto done; // no interested drivers
2841
2842 // Allocate an array of interested drivers and their return values
2843 // for the callout thread. Everything else is still "owned" by the
2844 // PM work loop, which can run to process acknowledgePowerChange()
2845 // responses.
2846
2847 param = (DriverCallParam *) fDriverCallParamPtr;
2848 if (count > fDriverCallParamSlots)
2849 {
2850 if (fDriverCallParamSlots)
2851 {
2852 assert(fDriverCallParamPtr);
2853 IODelete(fDriverCallParamPtr, DriverCallParam, fDriverCallParamSlots);
2854 fDriverCallParamPtr = 0;
2855 fDriverCallParamSlots = 0;
2856 }
2857
2858 param = IONew(DriverCallParam, count);
2859 if (!param)
2860 goto done; // no memory
2861
2862 fDriverCallParamPtr = (void *) param;
2863 fDriverCallParamSlots = count;
2864 }
2865
2866 informee = list->firstInList();
2867 assert(informee);
2868 for (IOItemCount i = 0; i < count; i++)
2869 {
2870 informee->timer = -1;
2871 param[i].Target = informee;
2872 informee->retain();
2873 informee = list->nextInList( informee );
2874 }
2875
2876 fDriverCallParamCount = count;
2877 fHeadNotePendingAcks = count;
2878
2879 // Machine state will be blocked pending callout thread completion.
2880
2881 PM_LOCK();
2882 fDriverCallBusy = true;
2883 PM_UNLOCK();
2884 thread_call_enter( fDriverCallEntry );
2885 return true;
2886
2887done:
2888 // no interested drivers or did not schedule callout thread due to error.
2889 return false;
2890}
2891
2892//*********************************************************************************
2893// [private] notifyInterestedDriversDone
2894//*********************************************************************************
2895
2896void IOService::notifyInterestedDriversDone ( void )
2897{
2898 IOPMinformee * informee;
2899 IOItemCount count;
2900 DriverCallParam * param;
2901 IOReturn result;
2902
2903 PM_ASSERT_IN_GATE();
2904 param = (DriverCallParam *) fDriverCallParamPtr;
2905 count = fDriverCallParamCount;
2906
2907 assert( fDriverCallBusy == false );
2908 assert( fMachineState == kIOPM_DriverThreadCallDone );
2909
2910 if (param && count)
2911 {
2912 for (IOItemCount i = 0; i < count; i++, param++)
2913 {
2914 informee = (IOPMinformee *) param->Target;
2915 result = param->Result;
2916
2917 if ((result == IOPMAckImplied) || (result < 0))
2918 {
2919 // child return IOPMAckImplied
2920 informee->timer = 0;
2921 fHeadNotePendingAcks--;
2922 }
2923 else if (informee->timer)
2924 {
2925 assert(informee->timer == -1);
2926
2927 // Driver has not acked, and has returned a positive result.
2928 // Enforce a minimum permissible timeout value.
2929 // Make the min value large enough so timeout is less likely
2930 // to occur if a driver misinterpreted that the return value
2931 // should be in microsecond units. And make it large enough
2932 // to be noticeable if a driver neglects to ack.
2933
2934 if (result < kMinAckTimeoutTicks)
2935 result = kMinAckTimeoutTicks;
2936
2937 informee->timer = (result / (ACK_TIMER_PERIOD / ns_per_us)) + 1;
2938 }
2939 // else, child has already acked or driver has removed interest,
2940 // and head_note_pendingAcks decremented.
2941 // informee may have been removed from the interested drivers list,
2942 // thus the informee must be retained across the callout.
2943
2944 informee->release();
2945 }
2946
2947 fDriverCallParamCount = 0;
2948
2949 if ( fHeadNotePendingAcks )
2950 {
2951 OUR_PMLog(kPMLogStartAckTimer, 0, 0);
2952 start_ack_timer();
2953 }
2954 }
2955
2956 // Hop back to original machine state path (from notifyAll)
2957 fMachineState = fNextMachineState;
2958
2959 notifyChildren();
2960}
2961
2962//*********************************************************************************
2963// [private] notifyChildren
2964//*********************************************************************************
2965
2966void IOService::notifyChildren ( void )
2967{
2968 OSIterator * iter;
2969 OSObject * next;
2970 IOPowerConnection * connection;
2971 OSArray * children = 0;
1c79356b 2972
2d21ac55
A
2973 if (fStrictTreeOrder)
2974 children = OSArray::withCapacity(8);
1c79356b 2975
2d21ac55
A
2976 // Sum child power consumption in notifyChild()
2977 fPowerStates[fHeadNoteState].staticPower = 0;
2978
2979 iter = getChildIterator(gIOPowerPlane);
2980 if ( iter )
2981 {
2982 while ((next = iter->getNextObject()))
55e303ae 2983 {
2d21ac55
A
2984 if ((connection = OSDynamicCast(IOPowerConnection, next)))
2985 {
2986 if (connection->getReadyFlag() == false)
2987 {
2988 PM_CONNECT("[%s] %s: connection not ready\n",
2989 getName(), __FUNCTION__);
2990 continue;
2991 }
2992
2993 if (children)
2994 children->setObject( connection );
2995 else
2996 notifyChild( connection,
2997 fDriverCallReason == kDriverCallInformPreChange );
2998 }
1c79356b 2999 }
2d21ac55 3000 iter->release();
1c79356b
A
3001 }
3002
2d21ac55
A
3003 if (children)
3004 {
3005 if (children->getCount() == 0)
3006 {
3007 children->release();
3008 children = 0;
3009 }
3010 else
3011 {
3012 assert(fNotifyChildArray == 0);
3013 fNotifyChildArray = children;
3014 fNextMachineState = fMachineState;
3015 fMachineState = kIOPM_NotifyChildrenDone;
3016 }
3017 }
3018}
1c79356b 3019
2d21ac55
A
3020//*********************************************************************************
3021// [private] notifyChildrenDone
3022//*********************************************************************************
1c79356b 3023
2d21ac55
A
3024void IOService::notifyChildrenDone ( void )
3025{
3026 PM_ASSERT_IN_GATE();
3027 assert(fNotifyChildArray);
3028 assert(fMachineState == kIOPM_NotifyChildrenDone);
3029
3030 // Interested drivers have all acked (if any), ack timer stopped.
3031 // Notify one child, wait for it's ack, then repeat for next child.
3032 // This is a workaround for some drivers with multiple instances at
3033 // the same branch in the power tree, but the driver is slow to power
3034 // up unless the tree ordering is observed. Problem observed only on
3035 // system wake, not on system sleep.
3036 //
3037 // We have the ability to power off in reverse child index order.
3038 // That works nicely on some machines, but not on all HW configs.
3039
3040 if (fNotifyChildArray->getCount())
3041 {
3042 IOPowerConnection * connection;
3043 connection = (IOPowerConnection *) fNotifyChildArray->getObject(0);
3044 fNotifyChildArray->removeObject(0);
3045 notifyChild( connection, fDriverCallReason == kDriverCallInformPreChange );
3046 }
3047 else
3048 {
3049 fNotifyChildArray->release();
3050 fNotifyChildArray = 0;
3051 fMachineState = fNextMachineState;
3052 }
1c79356b
A
3053}
3054
1c79356b 3055//*********************************************************************************
2d21ac55 3056// [private] notifyAll
1c79356b
A
3057//*********************************************************************************
3058
3059IOReturn IOService::notifyAll ( bool is_prechange )
3060{
2d21ac55 3061 // Save the next machine_state to be restored by notifyInterestedDriversDone()
1c79356b 3062
2d21ac55
A
3063 PM_ASSERT_IN_GATE();
3064 fNextMachineState = fMachineState;
3065 fMachineState = kIOPM_DriverThreadCallDone;
3066 fDriverCallReason = is_prechange ?
3067 kDriverCallInformPreChange : kDriverCallInformPostChange;
6601e61a 3068
2d21ac55
A
3069 if (!notifyInterestedDrivers())
3070 notifyInterestedDriversDone();
55e303ae 3071
2d21ac55
A
3072 return IOPMWillAckLater;
3073}
0c530ab8 3074
2d21ac55
A
3075//*********************************************************************************
3076// [private, static] pmDriverCallout
3077//
3078// Thread call context
3079//*********************************************************************************
0c530ab8 3080
2d21ac55
A
3081IOReturn IOService::actionDriverCalloutDone (
3082 OSObject * target,
3083 void * arg0, void * arg1,
3084 void * arg2, void * arg3 )
3085{
3086 IOServicePM * pwrMgt = (IOServicePM *) arg0;
0c530ab8 3087
2d21ac55
A
3088 PM_LOCK();
3089 fDriverCallBusy = false;
3090 PM_UNLOCK();
1c79356b 3091
2d21ac55
A
3092 if (gIOPMReplyQueue)
3093 gIOPMReplyQueue->signalWorkAvailable();
1c79356b 3094
2d21ac55
A
3095 return kIOReturnSuccess;
3096}
1c79356b 3097
2d21ac55
A
3098void IOService::pmDriverCallout ( IOService * from )
3099{
3100 assert(from);
3101 switch (from->fDriverCallReason)
3102 {
3103 case kDriverCallSetPowerState:
3104 from->driverSetPowerState();
3105 break;
3106
3107 case kDriverCallInformPreChange:
3108 case kDriverCallInformPostChange:
3109 from->driverInformPowerChange();
3110 break;
3111
3112 default:
3113 IOPanic("IOService::pmDriverCallout bad machine state");
3114 }
3115
3116 gIOPMWorkLoop->runAction(actionDriverCalloutDone,
3117 /* target */ from,
3118 /* arg0 */ (void *) from->pwrMgt );
3119}
3120
3121//*********************************************************************************
3122// [private] driverSetPowerState
3123//
3124// Thread call context
3125//*********************************************************************************
3126
3127void IOService::driverSetPowerState ( void )
3128{
3129 IOService * driver;
3130 unsigned long powerState;
3131 DriverCallParam * param;
3132 IOReturn result;
3133 AbsoluteTime end;
3134
3135 assert( fDriverCallBusy );
3136 param = (DriverCallParam *) fDriverCallParamPtr;
3137 assert( param );
3138 assert( fDriverCallParamCount == 1 );
3139
3140 driver = fControllingDriver;
3141 powerState = fHeadNoteState;
3142
3143 if (!fWillPMStop)
3144 {
3145 OUR_PMLog( kPMLogProgramHardware, (UInt32) this, powerState);
3146 clock_get_uptime(&fDriverCallStartTime);
3147 result = driver->setPowerState( powerState, this );
3148 clock_get_uptime(&end);
3149 OUR_PMLog((UInt32) -kPMLogProgramHardware, (UInt32) this, (UInt32) result);
3150
3151#if LOG_SETPOWER_TIMES
3152 if ((result == IOPMAckImplied) || (result < 0))
55e303ae 3153 {
2d21ac55 3154 uint64_t nsec;
0c530ab8 3155
2d21ac55
A
3156 SUB_ABSOLUTETIME(&end, &fDriverCallStartTime);
3157 absolutetime_to_nanoseconds(end, &nsec);
3158 if (nsec > LOG_SETPOWER_TIMES)
3159 PM_DEBUG("%s::setPowerState(%p, %lu -> %lu) took %d ms\n",
3160 fName, this, fCurrentPowerState, powerState, NS_TO_MS(nsec));
1c79356b 3161 }
2d21ac55
A
3162#endif
3163 }
3164 else
3165 result = kIOPMAckImplied;
1c79356b 3166
2d21ac55
A
3167 param->Result = result;
3168}
55e303ae 3169
2d21ac55
A
3170//*********************************************************************************
3171// [private] driverInformPowerChange
3172//
3173// Thread call context
3174//*********************************************************************************
0c530ab8 3175
2d21ac55
A
3176void IOService::driverInformPowerChange ( void )
3177{
3178 IOItemCount count;
3179 IOPMinformee * informee;
3180 IOService * driver;
3181 IOReturn result;
3182 IOPMPowerFlags powerFlags;
3183 unsigned long powerState;
3184 DriverCallParam * param;
3185 AbsoluteTime end;
3186
3187 assert( fDriverCallBusy );
3188 param = (DriverCallParam *) fDriverCallParamPtr;
3189 count = fDriverCallParamCount;
3190 assert( count && param );
3191
3192 powerFlags = fHeadNoteCapabilityFlags;
3193 powerState = fHeadNoteState;
3194
3195 for (IOItemCount i = 0; i < count; i++)
3196 {
3197 informee = (IOPMinformee *) param->Target;
3198 driver = informee->whatObject;
3199
3200 if (!fWillPMStop && informee->active)
3201 {
3202 if (fDriverCallReason == kDriverCallInformPreChange)
3203 {
3204 OUR_PMLog(kPMLogInformDriverPreChange, (UInt32) this, powerState);
3205 clock_get_uptime(&informee->startTime);
3206 result = driver->powerStateWillChangeTo(powerFlags, powerState, this);
3207 clock_get_uptime(&end);
3208 OUR_PMLog((UInt32)-kPMLogInformDriverPreChange, (UInt32) this, result);
3209 }
3210 else
3211 {
3212 OUR_PMLog(kPMLogInformDriverPostChange, (UInt32) this, powerState);
3213 clock_get_uptime(&informee->startTime);
3214 result = driver->powerStateDidChangeTo(powerFlags, powerState, this);
3215 clock_get_uptime(&end);
3216 OUR_PMLog((UInt32)-kPMLogInformDriverPostChange, (UInt32) this, result);
3217 }
3218
3219#if LOG_SETPOWER_TIMES
3220 if ((result == IOPMAckImplied) || (result < 0))
3221 {
3222 uint64_t nsec;
3223
3224 SUB_ABSOLUTETIME(&end, &informee->startTime);
3225 absolutetime_to_nanoseconds(end, &nsec);
3226 if (nsec > LOG_SETPOWER_TIMES)
3227 PM_DEBUG("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) took %d ms\n",
3228 driver->getName(),
3229 (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
3230 driver, fName, fCurrentPowerState, powerState, NS_TO_MS(nsec));
3231 }
3232#endif
3233 }
3234 else
3235 result = kIOPMAckImplied;
0c530ab8 3236
2d21ac55
A
3237 param->Result = result;
3238 param++;
3239 }
1c79356b
A
3240}
3241
1c79356b 3242//*********************************************************************************
2d21ac55 3243// [private] notifyChild
1c79356b
A
3244//
3245// Notify a power domain child of an upcoming power change.
1c79356b
A
3246// If the object acknowledges the current change, we return TRUE.
3247//*********************************************************************************
3248
3249bool IOService::notifyChild ( IOPowerConnection * theNub, bool is_prechange )
3250{
2d21ac55
A
3251 IOReturn k = IOPMAckImplied;
3252 unsigned long childPower;
3253 IOService * theChild;
3254 IOPMRequest * childRequest;
3255 int requestType;
3256
3257 PM_ASSERT_IN_GATE();
3a60a9f5 3258 theChild = (IOService *)(theNub->copyChildEntry(gIOPowerPlane));
2d21ac55 3259 if (!theChild)
55e303ae 3260 {
2d21ac55 3261 assert(false);
0b4e3aa0 3262 return true;
55e303ae 3263 }
2d21ac55 3264
3a60a9f5
A
3265 // Unless the child handles the notification immediately and returns
3266 // kIOPMAckImplied, we'll be awaiting their acknowledgement later.
2d21ac55 3267 fHeadNotePendingAcks++;
3a60a9f5
A
3268 theNub->setAwaitingAck(true);
3269
2d21ac55
A
3270 requestType = is_prechange ?
3271 kIOPMRequestTypePowerDomainWillChange :
3272 kIOPMRequestTypePowerDomainDidChange;
3273
3274 childRequest = acquirePMRequest( theChild, requestType );
3275 if (childRequest)
3276 {
cf7d32b8 3277 theNub->retain();
2d21ac55
A
3278 childRequest->fArg0 = (void *) fHeadNoteOutputFlags;
3279 childRequest->fArg1 = (void *) theNub;
3280 childRequest->fArg2 = (void *) (fHeadNoteState < fCurrentPowerState);
3281 theChild->submitPMRequest( childRequest );
3282 k = IOPMWillAckLater;
3283 }
3284 else
3285 {
3286 k = IOPMAckImplied;
3287 fHeadNotePendingAcks--;
3288 theNub->setAwaitingAck(false);
0b4e3aa0 3289 childPower = theChild->currentPowerConsumption();
2d21ac55 3290 if ( childPower == kIOPMUnknown )
55e303ae 3291 {
2d21ac55 3292 fPowerStates[fHeadNoteState].staticPower = kIOPMUnknown;
55e303ae 3293 } else {
2d21ac55 3294 if ( fPowerStates[fHeadNoteState].staticPower != kIOPMUnknown )
55e303ae 3295 {
2d21ac55 3296 fPowerStates[fHeadNoteState].staticPower += childPower;
0b4e3aa0
A
3297 }
3298 }
55e303ae 3299 }
55e303ae 3300
2d21ac55
A
3301 theChild->release();
3302 return (k == IOPMAckImplied);
1c79356b
A
3303}
3304
1c79356b 3305//*********************************************************************************
2d21ac55 3306// [private] OurChangeTellClientsPowerDown
1c79356b
A
3307//
3308// All registered applications and kernel clients have positively acknowledged our
3309// intention of lowering power. Here we notify them all that we will definitely
3310// lower the power. If we don't have to wait for any of them to acknowledge, we
3311// carry on by notifying interested drivers. Otherwise, we do wait.
3312//*********************************************************************************
3313
55e303ae 3314void IOService::OurChangeTellClientsPowerDown ( void )
0b4e3aa0 3315{
2d21ac55
A
3316 fMachineState = kIOPM_OurChangeTellPriorityClientsPowerDown;
3317 tellChangeDown1(fHeadNoteState);
0b4e3aa0
A
3318}
3319
0b4e3aa0 3320//*********************************************************************************
2d21ac55 3321// [private] OurChangeTellPriorityClientsPowerDown
0b4e3aa0
A
3322//
3323// All registered applications and kernel clients have positively acknowledged our
3324// intention of lowering power. Here we notify "priority" clients that we are
3325// lowering power. If we don't have to wait for any of them to acknowledge, we
3326// carry on by notifying interested drivers. Otherwise, we do wait.
3327//*********************************************************************************
3328
55e303ae 3329void IOService::OurChangeTellPriorityClientsPowerDown ( void )
1c79356b 3330{
2d21ac55
A
3331 fMachineState = kIOPM_OurChangeNotifyInterestedDriversWillChange;
3332 tellChangeDown2(fHeadNoteState);
1c79356b
A
3333}
3334
1c79356b 3335//*********************************************************************************
2d21ac55 3336// [private] OurChangeNotifyInterestedDriversWillChange
1c79356b
A
3337//
3338// All registered applications and kernel clients have acknowledged our notification
3339// that we are lowering power. Here we notify interested drivers. If we don't have
2d21ac55
A
3340// to wait for any of them to acknowledge, we instruct our power driver to make the
3341// change. Otherwise, we do wait.
1c79356b
A
3342//*********************************************************************************
3343
55e303ae 3344void IOService::OurChangeNotifyInterestedDriversWillChange ( void )
1c79356b 3345{
2d21ac55
A
3346 fMachineState = kIOPM_OurChangeSetPowerState;
3347 notifyAll( true );
1c79356b
A
3348}
3349
1c79356b 3350//*********************************************************************************
2d21ac55 3351// [private] OurChangeSetPowerState
1c79356b
A
3352//
3353// All interested drivers have acknowledged our pre-change notification of a power
3354// change we initiated. Here we instruct our controlling driver to make
3355// the change to the hardware. If it does so, we continue processing
3356// (waiting for settle and notifying interested parties post-change.)
3357// If it doesn't, we have to wait for it to acknowledge and then continue.
3358//*********************************************************************************
3359
55e303ae 3360void IOService::OurChangeSetPowerState ( void )
1c79356b 3361{
2d21ac55
A
3362 fNextMachineState = kIOPM_OurChangeWaitForPowerSettle;
3363 fMachineState = kIOPM_DriverThreadCallDone;
3364 fDriverCallReason = kDriverCallSetPowerState;
55e303ae 3365
2d21ac55
A
3366 if (notifyControllingDriver() == false)
3367 notifyControllingDriverDone();
1c79356b
A
3368}
3369
1c79356b 3370//*********************************************************************************
2d21ac55 3371// [private] OurChangeWaitForPowerSettle
1c79356b
A
3372//
3373// Our controlling driver has changed power state on the hardware
3374// during a power change we initiated. Here we see if we need to wait
3375// for power to settle before continuing. If not, we continue processing
3376// (notifying interested parties post-change). If so, we wait and
3377// continue later.
3378//*********************************************************************************
3379
55e303ae 3380void IOService::OurChangeWaitForPowerSettle ( void )
1c79356b 3381{
2d21ac55
A
3382 fMachineState = kIOPM_OurChangeNotifyInterestedDriversDidChange;
3383 fSettleTimeUS = compute_settle_time();
3384 if ( fSettleTimeUS )
55e303ae 3385 {
2d21ac55
A
3386 startSettleTimer(fSettleTimeUS);
3387 }
1c79356b
A
3388}
3389
1c79356b 3390//*********************************************************************************
2d21ac55 3391// [private] OurChangeNotifyInterestedDriversDidChange
1c79356b
A
3392//
3393// Power has settled on a power change we initiated. Here we notify
3394// all our interested parties post-change. If they all acknowledge, we're
3395// done with this change note, and we can start on the next one.
3396// Otherwise we have to wait for acknowledgements and finish up later.
3397//*********************************************************************************
3398
55e303ae 3399void IOService::OurChangeNotifyInterestedDriversDidChange ( void )
1c79356b 3400{
2d21ac55
A
3401 fMachineState = kIOPM_OurChangeFinish;
3402 notifyAll(false);
1c79356b
A
3403}
3404
1c79356b 3405//*********************************************************************************
2d21ac55 3406// [private] OurChangeFinish
1c79356b
A
3407//
3408// Power has settled on a power change we initiated, and
3409// all our interested parties have acknowledged. We're
3410// done with this change note, and we can start on the next one.
3411//*********************************************************************************
3412
55e303ae 3413void IOService::OurChangeFinish ( void )
1c79356b
A
3414{
3415 all_done();
3416}
3417
0b4e3aa0 3418//*********************************************************************************
2d21ac55 3419// [private] ParentDownTellPriorityClientsPowerDown
0b4e3aa0
A
3420//
3421// All applications and kernel clients have been notified of a power lowering
3422// initiated by the parent and we had to wait for responses. Here
3423// we notify any priority clients. If they all ack, we continue with the power change.
3424// If at least one doesn't, we have to wait for it to acknowledge and then continue.
3425//*********************************************************************************
3426
2d21ac55 3427void IOService::ParentDownTellPriorityClientsPowerDown ( void )
0b4e3aa0 3428{
2d21ac55
A
3429 fMachineState = kIOPM_ParentDownNotifyInterestedDriversWillChange;
3430 tellChangeDown2(fHeadNoteState);
0b4e3aa0
A
3431}
3432
1c79356b 3433//*********************************************************************************
2d21ac55 3434// [private] ParentDownNotifyInterestedDriversWillChange
1c79356b
A
3435//
3436// All applications and kernel clients have been notified of a power lowering
3437// initiated by the parent and we had to wait for their responses. Here we notify
3438// any interested drivers and power domain children. If they all ack, we continue
3439// with the power change.
3440// If at least one doesn't, we have to wait for it to acknowledge and then continue.
3441//*********************************************************************************
3442
2d21ac55 3443void IOService::ParentDownNotifyInterestedDriversWillChange ( void )
1c79356b 3444{
2d21ac55
A
3445 fMachineState = kIOPM_ParentDownSetPowerState;
3446 notifyAll( true );
1c79356b
A
3447}
3448
1c79356b 3449//*********************************************************************************
2d21ac55 3450// [private] ParentDownSetPowerState
1c79356b
A
3451//
3452// We had to wait for it, but all parties have acknowledged our pre-change
3453// notification of a power lowering initiated by the parent.
3454// Here we instruct our controlling driver
3455// to put the hardware in the state it needs to be in when the domain is
3456// lowered. If it does so, we continue processing
3457// (waiting for settle and acknowledging the parent.)
3458// If it doesn't, we have to wait for it to acknowledge and then continue.
3459//*********************************************************************************
3460
2d21ac55 3461void IOService::ParentDownSetPowerState ( void )
1c79356b 3462{
2d21ac55
A
3463 fNextMachineState = kIOPM_ParentDownWaitForPowerSettle;
3464 fMachineState = kIOPM_DriverThreadCallDone;
3465 fDriverCallReason = kDriverCallSetPowerState;
1c79356b 3466
2d21ac55
A
3467 if (notifyControllingDriver() == false)
3468 notifyControllingDriverDone();
1c79356b
A
3469}
3470
1c79356b 3471//*********************************************************************************
2d21ac55 3472// [private] ParentDownWaitForPowerSettle
1c79356b
A
3473//
3474// Our controlling driver has changed power state on the hardware
3475// during a power change initiated by our parent. We have had to wait
3476// for acknowledgement from interested parties, or we have had to wait
3477// for the controlling driver to change the state. Here we see if we need
3478// to wait for power to settle before continuing. If not, we continue
3479// processing (acknowledging our preparedness to the parent).
3480// If so, we wait and continue later.
3481//*********************************************************************************
3482
2d21ac55 3483void IOService::ParentDownWaitForPowerSettle ( void )
1c79356b 3484{
2d21ac55
A
3485 fMachineState = kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange;
3486 fSettleTimeUS = compute_settle_time();
3487 if ( fSettleTimeUS )
55e303ae 3488 {
2d21ac55
A
3489 startSettleTimer(fSettleTimeUS);
3490 }
1c79356b
A
3491}
3492
1c79356b 3493//*********************************************************************************
2d21ac55 3494// [private] ParentDownNotifyDidChangeAndAcknowledgeChange
1c79356b
A
3495//
3496// Power has settled on a power change initiated by our parent. Here we
3497// notify interested parties.
3498//*********************************************************************************
3499
2d21ac55 3500void IOService::ParentDownNotifyDidChangeAndAcknowledgeChange ( void )
1c79356b 3501{
2d21ac55
A
3502 fMachineState = kIOPM_ParentDownAcknowledgeChange;
3503 notifyAll(false);
1c79356b
A
3504}
3505
1c79356b 3506//*********************************************************************************
2d21ac55 3507// [private] ParentDownAcknowledgeChange
1c79356b
A
3508//
3509// We had to wait for it, but all parties have acknowledged our post-change
3510// notification of a power lowering initiated by the parent.
3511// Here we acknowledge the parent.
3512// We are done with this change note, and we can start on the next one.
3513//*********************************************************************************
3514
2d21ac55 3515void IOService::ParentDownAcknowledgeChange ( void )
1c79356b 3516{
2d21ac55
A
3517 IORegistryEntry * nub;
3518 IOService * parent;
3519
3520 nub = fHeadNoteParent;
55e303ae 3521 nub->retain();
1c79356b 3522 all_done();
0b4e3aa0 3523 parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
2d21ac55 3524 if ( parent )
55e303ae 3525 {
0b4e3aa0
A
3526 parent->acknowledgePowerChange((IOService *)nub);
3527 parent->release();
3528 }
3529 nub->release();
1c79356b
A
3530}
3531
1c79356b 3532//*********************************************************************************
2d21ac55 3533// [private] ParentUpSetPowerState
1c79356b
A
3534//
3535// Our parent has informed us via powerStateDidChange that it has
3536// raised the power in our power domain, and we have had to wait
3537// for some interested party to acknowledge our notification.
3538// Here we instruct our controlling
3539// driver to program the hardware to take advantage of the higher domain
3540// power. If it does so, we continue processing
3541// (waiting for settle and notifying interested parties post-change.)
3542// If it doesn't, we have to wait for it to acknowledge and then continue.
3543//*********************************************************************************
3544
2d21ac55 3545void IOService::ParentUpSetPowerState ( void )
1c79356b 3546{
2d21ac55
A
3547 fNextMachineState = kIOPM_ParentUpWaitForSettleTime;
3548 fMachineState = kIOPM_DriverThreadCallDone;
3549 fDriverCallReason = kDriverCallSetPowerState;
1c79356b 3550
2d21ac55
A
3551 if (notifyControllingDriver() == false)
3552 notifyControllingDriverDone();
1c79356b
A
3553}
3554
1c79356b 3555//*********************************************************************************
2d21ac55 3556// [private] ParentUpWaitForSettleTime
1c79356b
A
3557//
3558// Our controlling driver has changed power state on the hardware
3559// during a power raise initiated by the parent, but we had to wait for it.
3560// Here we see if we need to wait for power to settle before continuing.
3561// If not, we continue processing (notifying interested parties post-change).
3562// If so, we wait and continue later.
3563//*********************************************************************************
3564
2d21ac55 3565void IOService::ParentUpWaitForSettleTime ( void )
1c79356b 3566{
2d21ac55
A
3567 fMachineState = kIOPM_ParentUpNotifyInterestedDriversDidChange;
3568 fSettleTimeUS = compute_settle_time();
3569 if ( fSettleTimeUS )
55e303ae 3570 {
2d21ac55 3571 startSettleTimer(fSettleTimeUS);
1c79356b 3572 }
1c79356b
A
3573}
3574
1c79356b 3575//*********************************************************************************
2d21ac55 3576// [private] ParentUpNotifyInterestedDriversDidChange
1c79356b
A
3577//
3578// Power has settled on a power raise initiated by the parent.
3579// Here we notify all our interested parties post-change. If they all acknowledge,
3580// we're done with this change note, and we can start on the next one.
3581// Otherwise we have to wait for acknowledgements and finish up later.
3582//*********************************************************************************
3583
2d21ac55 3584void IOService::ParentUpNotifyInterestedDriversDidChange ( void )
1c79356b 3585{
2d21ac55
A
3586 fMachineState = kIOPM_ParentUpAcknowledgePowerChange;
3587 notifyAll(false);
1c79356b
A
3588}
3589
1c79356b 3590//*********************************************************************************
2d21ac55 3591// [private] ParentUpAcknowledgePowerChange
1c79356b
A
3592//
3593// All parties have acknowledged our post-change notification of a power
3594// raising initiated by the parent. Here we acknowledge the parent.
3595// We are done with this change note, and we can start on the next one.
3596//*********************************************************************************
3597
2d21ac55 3598void IOService::ParentUpAcknowledgePowerChange ( void )
1c79356b 3599{
2d21ac55
A
3600 IORegistryEntry * nub;
3601 IOService * parent;
3602
3603 nub = fHeadNoteParent;
55e303ae 3604 nub->retain();
1c79356b 3605 all_done();
0b4e3aa0 3606 parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
2d21ac55 3607 if ( parent )
55e303ae 3608 {
0b4e3aa0
A
3609 parent->acknowledgePowerChange((IOService *)nub);
3610 parent->release();
3611 }
3612 nub->release();
1c79356b
A
3613}
3614
1c79356b 3615//*********************************************************************************
2d21ac55 3616// [private] all_done
1c79356b
A
3617//
3618// A power change is complete, and the used post-change note is at
3619// the head of the queue. Remove it and set myCurrentState to the result
3620// of the change. Start up the next change in queue.
3621//*********************************************************************************
3622
3623void IOService::all_done ( void )
0b4e3aa0 3624{
2d21ac55
A
3625 unsigned long previous_state;
3626
3627 fMachineState = kIOPM_Finished;
1c79356b 3628
55e303ae 3629 // our power change
2d21ac55 3630 if ( fHeadNoteFlags & IOPMWeInitiated )
55e303ae
A
3631 {
3632 // could our driver switch to the new state?
2d21ac55 3633 if ( !( fHeadNoteFlags & IOPMNotDone) )
55e303ae 3634 {
2d21ac55
A
3635 // we changed, tell our parent
3636 if ( !fWeAreRoot )
3637 {
3638 ask_parent(fHeadNoteState);
3639 }
3640
55e303ae 3641 // yes, did power raise?
2d21ac55 3642 if ( fCurrentPowerState < fHeadNoteState )
55e303ae
A
3643 {
3644 // yes, inform clients and apps
2d21ac55 3645 tellChangeUp (fHeadNoteState);
1c79356b 3646 }
2d21ac55 3647 previous_state = fCurrentPowerState;
55e303ae 3648 // either way
2d21ac55
A
3649 fCurrentPowerState = fHeadNoteState;
3650#if PM_VARS_SUPPORT
3651 fPMVars->myCurrentState = fCurrentPowerState;
3652#endif
3653 OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, 0);
3654
55e303ae 3655 // inform subclass policy-maker
2d21ac55
A
3656 if (!fWillPMStop && fParentsKnowState)
3657 powerChangeDone(previous_state);
3658 else
3659 PM_DEBUG("%s::powerChangeDone() skipped\n", getName());
1c79356b 3660 }
1c79356b 3661 }
55e303ae
A
3662
3663 // parent's power change
2d21ac55 3664 if ( fHeadNoteFlags & IOPMParentInitiated)
55e303ae 3665 {
2d21ac55
A
3666 if (((fHeadNoteFlags & IOPMDomainWillChange) && (fCurrentPowerState >= fHeadNoteState)) ||
3667 ((fHeadNoteFlags & IOPMDomainDidChange) && (fCurrentPowerState < fHeadNoteState)))
55e303ae
A
3668 {
3669 // did power raise?
2d21ac55 3670 if ( fCurrentPowerState < fHeadNoteState )
55e303ae
A
3671 {
3672 // yes, inform clients and apps
2d21ac55 3673 tellChangeUp (fHeadNoteState);
1c79356b 3674 }
55e303ae 3675 // either way
2d21ac55
A
3676 previous_state = fCurrentPowerState;
3677 fCurrentPowerState = fHeadNoteState;
3678#if PM_VARS_SUPPORT
3679 fPMVars->myCurrentState = fCurrentPowerState;
3680#endif
3681 fMaxCapability = fControllingDriver->maxCapabilityForDomainState(fHeadNoteDomainState);
1c79356b 3682
2d21ac55 3683 OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, 0);
1c79356b 3684
2d21ac55
A
3685 // inform subclass policy-maker
3686 if (!fWillPMStop && fParentsKnowState)
3687 powerChangeDone(previous_state);
3688 else
3689 PM_DEBUG("%s::powerChangeDone() skipped\n", getName());
1c79356b
A
3690 }
3691 }
0c530ab8 3692
2d21ac55
A
3693 if (fCurrentPowerState < fNumberOfPowerStates)
3694 {
3695 const IOPMPowerState * powerStatePtr = &fPowerStates[fCurrentPowerState];
0c530ab8 3696
2d21ac55
A
3697 fCurrentCapabilityFlags = powerStatePtr->capabilityFlags;
3698 if (fCurrentCapabilityFlags & kIOPMStaticPowerValid)
3699 fCurrentPowerConsumption = powerStatePtr->staticPower;
3700 }
cf7d32b8
A
3701
3702 // When power rises enough to satisfy the tickle's desire for more power,
3703 // the condition preventing idle-timer from dropping power is removed.
3704
3705 if (fCurrentPowerState >= fIdleTimerMinPowerState)
3706 {
3707 fIdleTimerMinPowerState = 0;
3708 }
1c79356b
A
3709}
3710
1c79356b 3711//*********************************************************************************
2d21ac55 3712// [public] settleTimerExpired
1c79356b
A
3713//
3714// Power has settled after our last change. Notify interested parties that
3715// there is a new power state.
3716//*********************************************************************************
3717
3718void IOService::settleTimerExpired ( void )
3719{
2d21ac55 3720 fSettleTimeUS = 0;
1c79356b
A
3721}
3722
1c79356b 3723//*********************************************************************************
2d21ac55 3724// [private] compute_settle_time
1c79356b
A
3725//
3726// Compute the power-settling delay in microseconds for the
3727// change from myCurrentState to head_note_state.
3728//*********************************************************************************
3729
3730unsigned long IOService::compute_settle_time ( void )
3731{
2d21ac55
A
3732 unsigned long totalTime;
3733 unsigned long i;
3734
3735 PM_ASSERT_IN_GATE();
1c79356b 3736
55e303ae
A
3737 // compute total time to attain the new state
3738 totalTime = 0;
2d21ac55 3739 i = fCurrentPowerState;
55e303ae
A
3740
3741 // we're lowering power
2d21ac55 3742 if ( fHeadNoteState < fCurrentPowerState )
55e303ae 3743 {
2d21ac55 3744 while ( i > fHeadNoteState )
55e303ae 3745 {
2d21ac55 3746 totalTime += fPowerStates[i].settleDownTime;
1c79356b
A
3747 i--;
3748 }
3749 }
3750
55e303ae 3751 // we're raising power
2d21ac55 3752 if ( fHeadNoteState > fCurrentPowerState )
55e303ae 3753 {
2d21ac55 3754 while ( i < fHeadNoteState )
55e303ae 3755 {
2d21ac55 3756 totalTime += fPowerStates[i+1].settleUpTime;
1c79356b
A
3757 i++;
3758 }
3759 }
3760
3761 return totalTime;
3762}
3763
1c79356b 3764//*********************************************************************************
2d21ac55 3765// [private] startSettleTimer
1c79356b 3766//
2d21ac55 3767// Enter a power-settling delay in microseconds and start a timer for that delay.
1c79356b
A
3768//*********************************************************************************
3769
3770IOReturn IOService::startSettleTimer ( unsigned long delay )
3771{
3772 AbsoluteTime deadline;
2d21ac55 3773 boolean_t pending;
1c79356b 3774
2d21ac55
A
3775 retain();
3776 clock_interval_to_deadline(delay, kMicrosecondScale, &deadline);
3777 pending = thread_call_enter_delayed(fSettleTimer, deadline);
3778 if (pending) release();
1c79356b
A
3779
3780 return IOPMNoErr;
3781}
3782
3783//*********************************************************************************
2d21ac55 3784// [public] ackTimerTick
1c79356b
A
3785//
3786// The acknowledgement timeout periodic timer has ticked.
3787// If we are awaiting acks for a power change notification,
3788// we decrement the timer word of each interested driver which hasn't acked.
3789// If a timer word becomes zero, we pretend the driver aknowledged.
3790// If we are waiting for the controlling driver to change the power
3791// state of the hardware, we decrement its timer word, and if it becomes
3792// zero, we pretend the driver acknowledged.
2d21ac55
A
3793//
3794// Returns true if the timer tick made it possible to advance to the next
3795// machine state, false otherwise.
1c79356b
A
3796//*********************************************************************************
3797
3798void IOService::ack_timer_ticked ( void )
3799{
2d21ac55
A
3800 assert(false);
3801}
1c79356b 3802
2d21ac55
A
3803bool IOService::ackTimerTick( void )
3804{
3805 IOPMinformee * nextObject;
3806 bool done = false;
1c79356b 3807
2d21ac55
A
3808 PM_ASSERT_IN_GATE();
3809 switch (fMachineState) {
55e303ae 3810 case kIOPM_OurChangeWaitForPowerSettle:
2d21ac55
A
3811 case kIOPM_ParentDownWaitForPowerSettle:
3812 case kIOPM_ParentUpWaitForSettleTime:
3813 // are we waiting for controlling driver to acknowledge?
3814 if ( fDriverTimer > 0 )
3815 {
3816 // yes, decrement timer tick
3817 fDriverTimer--;
3818 if ( fDriverTimer == 0 )
55e303ae 3819 {
2d21ac55
A
3820 // controlling driver is tardy
3821 uint64_t nsec = computeTimeDeltaNS(&fDriverCallStartTime);
3822 OUR_PMLog(kPMLogCtrlDriverTardy, 0, 0);
3823 setProperty(kIOPMTardyAckSPSKey, kOSBooleanTrue);
3824 PM_ERROR("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms\n",
3825 fName, this, fCurrentPowerState, fHeadNoteState, NS_TO_MS(nsec));
3826
3827 if (gIOKitDebug & kIOLogDebugPower)
3828 {
3829 panic("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms",
3830 fName, this, fCurrentPowerState, fHeadNoteState, NS_TO_MS(nsec));
3831 }
3832 else
3833 {
3834 // Unblock state machine and pretend driver has acked.
3835 done = true;
3836 }
55e303ae
A
3837 } else {
3838 // still waiting, set timer again
1c79356b 3839 start_ack_timer();
1c79356b
A
3840 }
3841 }
1c79356b
A
3842 break;
3843
55e303ae
A
3844 case kIOPM_OurChangeSetPowerState:
3845 case kIOPM_OurChangeFinish:
2d21ac55
A
3846 case kIOPM_ParentDownSetPowerState:
3847 case kIOPM_ParentDownAcknowledgeChange:
3848 case kIOPM_ParentUpSetPowerState:
3849 case kIOPM_ParentUpAcknowledgePowerChange:
3850 case kIOPM_NotifyChildrenDone:
55e303ae 3851 // are we waiting for interested parties to acknowledge?
2d21ac55 3852 if ( fHeadNotePendingAcks != 0 )
55e303ae
A
3853 {
3854 // yes, go through the list of interested drivers
2d21ac55 3855 nextObject = fInterestedDrivers->firstInList();
55e303ae 3856 // and check each one
2d21ac55 3857 while ( nextObject != NULL )
55e303ae 3858 {
2d21ac55 3859 if ( nextObject->timer > 0 )
55e303ae 3860 {
2d21ac55 3861 nextObject->timer--;
55e303ae 3862 // this one should have acked by now
2d21ac55 3863 if ( nextObject->timer == 0 )
55e303ae 3864 {
2d21ac55
A
3865 uint64_t nsec = computeTimeDeltaNS(&nextObject->startTime);
3866 OUR_PMLog(kPMLogIntDriverTardy, 0, 0);
3867 nextObject->whatObject->setProperty(kIOPMTardyAckPSCKey, kOSBooleanTrue);
3868 PM_ERROR("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) timed out after %d ms\n",
3869 nextObject->whatObject->getName(),
3870 (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
3871 nextObject->whatObject, fName, fCurrentPowerState, fHeadNoteState,
3872 NS_TO_MS(nsec));
3873
3874 // Pretend driver has acked.
3875 fHeadNotePendingAcks--;
1c79356b
A
3876 }
3877 }
2d21ac55 3878 nextObject = fInterestedDrivers->nextInList(nextObject);
1c79356b 3879 }
55e303ae
A
3880
3881 // is that the last?
2d21ac55 3882 if ( fHeadNotePendingAcks == 0 )
55e303ae 3883 {
55e303ae 3884 // yes, we can continue
2d21ac55 3885 done = true;
55e303ae
A
3886 } else {
3887 // no, set timer again
1c79356b 3888 start_ack_timer();
1c79356b 3889 }
1c79356b
A
3890 }
3891 break;
3892
2d21ac55
A
3893 case kIOPM_ParentDownTellPriorityClientsPowerDown:
3894 case kIOPM_ParentDownNotifyInterestedDriversWillChange:
55e303ae 3895 case kIOPM_OurChangeTellClientsPowerDown:
55e303ae 3896 case kIOPM_OurChangeTellPriorityClientsPowerDown:
55e303ae 3897 case kIOPM_OurChangeNotifyInterestedDriversWillChange:
2d21ac55
A
3898 // apps didn't respond in time
3899 cleanClientResponses(true);
3900 OUR_PMLog(kPMLogClientTardy, 0, 1);
3901 if (fMachineState == kIOPM_OurChangeTellClientsPowerDown)
3902 {
3903 // tardy equates to veto
3904 fDoNotPowerDown = true;
3905 }
3906 done = true;
1c79356b 3907 break;
2d21ac55 3908
1c79356b 3909 default:
2d21ac55
A
3910 PM_TRACE("[%s] unexpected ack timer tick (state = %ld)\n",
3911 getName(), fMachineState);
1c79356b
A
3912 break;
3913 }
2d21ac55 3914 return done;
1c79356b
A
3915}
3916
1c79356b 3917//*********************************************************************************
2d21ac55 3918// [private] start_ack_timer
1c79356b
A
3919//*********************************************************************************
3920
3921void IOService::start_ack_timer ( void )
3922{
2d21ac55 3923 start_ack_timer( ACK_TIMER_PERIOD, kNanosecondScale );
1c79356b
A
3924}
3925
2d21ac55
A
3926void IOService::start_ack_timer ( UInt32 interval, UInt32 scale )
3927{
3928 AbsoluteTime deadline;
3929 boolean_t pending;
3930
3931 clock_interval_to_deadline(interval, scale, &deadline);
3932
3933 retain();
3934 pending = thread_call_enter_delayed(fAckTimer, deadline);
3935 if (pending) release();
3936}
1c79356b
A
3937
3938//*********************************************************************************
2d21ac55 3939// [private] stop_ack_timer
1c79356b
A
3940//*********************************************************************************
3941
3942void IOService::stop_ack_timer ( void )
3943{
2d21ac55 3944 boolean_t pending;
1c79356b 3945
2d21ac55
A
3946 pending = thread_call_cancel(fAckTimer);
3947 if (pending) release();
3948}
1c79356b
A
3949
3950//*********************************************************************************
2d21ac55 3951// [static] settleTimerExpired
1c79356b 3952//
2d21ac55 3953// Inside PM work loop's gate.
1c79356b
A
3954//*********************************************************************************
3955
2d21ac55
A
3956IOReturn
3957IOService::actionAckTimerExpired (
3958 OSObject * target,
3959 void * arg0, void * arg1,
3960 void * arg2, void * arg3 )
1c79356b 3961{
2d21ac55
A
3962 IOService * me = (IOService *) target;
3963 bool done;
1c79356b 3964
2d21ac55
A
3965 // done will be true if the timer tick unblocks the machine state,
3966 // otherwise no need to signal the work loop.
1c79356b 3967
2d21ac55
A
3968 done = me->ackTimerTick();
3969 if (done && gIOPMReplyQueue)
3970 gIOPMReplyQueue->signalWorkAvailable();
1c79356b 3971
2d21ac55
A
3972 return kIOReturnSuccess;
3973}
1c79356b
A
3974
3975//*********************************************************************************
2d21ac55 3976// ack_timer_expired
1c79356b 3977//
2d21ac55 3978// Thread call function. Holds a retain while the callout is in flight.
1c79356b
A
3979//*********************************************************************************
3980
2d21ac55
A
3981void
3982IOService::ack_timer_expired ( thread_call_param_t arg0, thread_call_param_t arg1 )
1c79356b 3983{
2d21ac55 3984 IOService * me = (IOService *) arg0;
55e303ae 3985
2d21ac55
A
3986 if (gIOPMWorkLoop)
3987 {
3988 gIOPMWorkLoop->runAction(&actionAckTimerExpired, me);
3989 }
3990 me->release();
1c79356b
A
3991}
3992
1c79356b 3993//*********************************************************************************
2d21ac55 3994// settleTimerExpired
1c79356b 3995//
2d21ac55 3996// Inside PM work loop's gate.
1c79356b
A
3997//*********************************************************************************
3998
2d21ac55
A
3999static IOReturn
4000settleTimerExpired (
4001 OSObject * target,
4002 void * arg0, void * arg1,
4003 void * arg2, void * arg3 )
1c79356b 4004{
2d21ac55
A
4005 IOService * me = (IOService *) target;
4006 me->settleTimerExpired();
4007 return kIOReturnSuccess;
4008}
1c79356b 4009
2d21ac55
A
4010//*********************************************************************************
4011// settle_timer_expired
4012//
4013// Thread call function. Holds a retain while the callout is in flight.
4014//*********************************************************************************
55e303ae 4015
2d21ac55
A
4016static void
4017settle_timer_expired ( thread_call_param_t arg0, thread_call_param_t arg1 )
4018{
4019 IOService * me = (IOService *) arg0;
1c79356b 4020
2d21ac55
A
4021 if (gIOPMWorkLoop && gIOPMReplyQueue)
4022 {
4023 gIOPMWorkLoop->runAction(settleTimerExpired, me);
4024 gIOPMReplyQueue->signalWorkAvailable();
4025 }
4026 me->release();
4027}
1c79356b
A
4028
4029//*********************************************************************************
2d21ac55 4030// [private] start_parent_change
1c79356b 4031//
2d21ac55
A
4032// Here we begin the processing of a power change initiated by our parent.
4033//*********************************************************************************
4034
4035IOReturn IOService::start_parent_change ( const changeNoteItem * changeNote )
4036{
4037 fHeadNoteFlags = changeNote->flags;
4038 fHeadNoteState = changeNote->newStateNumber;
4039 fHeadNoteOutputFlags = changeNote->outputPowerCharacter;
4040 fHeadNoteDomainState = changeNote->domainState;
4041 fHeadNoteParent = changeNote->parent;
4042 fHeadNoteCapabilityFlags = changeNote->capabilityFlags;
4043
4044 PM_ASSERT_IN_GATE();
4045 OUR_PMLog( kPMLogStartParentChange, fHeadNoteState, fCurrentPowerState );
4046
4047 // Power domain is lowering power
4048 if ( fHeadNoteState < fCurrentPowerState )
55e303ae 4049 {
2d21ac55
A
4050 setParentInfo(
4051 changeNote->singleParentState,
4052 fHeadNoteParent, true );
55e303ae 4053
2d21ac55
A
4054 // tell apps and kernel clients
4055 fInitialChange = false;
4056 fMachineState = kIOPM_ParentDownTellPriorityClientsPowerDown;
4057 tellChangeDown1(fHeadNoteState);
55e303ae 4058 return IOPMWillAckLater;
1c79356b
A
4059 }
4060
2d21ac55
A
4061 // Power domain is raising power
4062 if ( fHeadNoteState > fCurrentPowerState )
55e303ae 4063 {
2d21ac55
A
4064 IOPMPowerState * powerStatePtr;
4065
4066 if ( fDesiredPowerState > fCurrentPowerState )
55e303ae 4067 {
2d21ac55 4068 if ( fDesiredPowerState < fHeadNoteState )
55e303ae 4069 {
2d21ac55
A
4070 // We power up, but not all the way
4071 fHeadNoteState = fDesiredPowerState;
4072 powerStatePtr = &fPowerStates[fHeadNoteState];
4073 fHeadNoteOutputFlags = powerStatePtr->outputPowerCharacter;
4074 fHeadNoteCapabilityFlags = powerStatePtr->capabilityFlags;
4075 OUR_PMLog(kPMLogAmendParentChange, fHeadNoteState, 0);
55e303ae
A
4076 }
4077 } else {
2d21ac55
A
4078 // We don't need to change
4079 fHeadNoteState = fCurrentPowerState;
4080 powerStatePtr = &fPowerStates[fHeadNoteState];
4081 fHeadNoteOutputFlags = powerStatePtr->outputPowerCharacter;
4082 fHeadNoteCapabilityFlags = powerStatePtr->capabilityFlags;
4083 OUR_PMLog(kPMLogAmendParentChange, fHeadNoteState, 0);
1c79356b
A
4084 }
4085 }
4086
2d21ac55
A
4087 if ((fHeadNoteState > fCurrentPowerState) &&
4088 (fHeadNoteFlags & IOPMDomainDidChange))
4089 {
4090 // Parent did change up - start our change up
4091 fInitialChange = false;
4092 fMachineState = kIOPM_ParentUpSetPowerState;
4093 notifyAll( true );
55e303ae 4094 return IOPMWillAckLater;
1c79356b
A
4095 }
4096
4097 all_done();
55e303ae 4098 return IOPMAckImplied;
1c79356b
A
4099}
4100
1c79356b 4101//*********************************************************************************
2d21ac55 4102// [private] start_our_change
1c79356b 4103//
2d21ac55 4104// Here we begin the processing of a power change initiated by us.
1c79356b
A
4105//*********************************************************************************
4106
2d21ac55 4107void IOService::start_our_change ( const changeNoteItem * changeNote )
1c79356b 4108{
2d21ac55
A
4109 fHeadNoteFlags = changeNote->flags;
4110 fHeadNoteState = changeNote->newStateNumber;
4111 fHeadNoteOutputFlags = changeNote->outputPowerCharacter;
4112 fHeadNoteCapabilityFlags = changeNote->capabilityFlags;
1c79356b 4113
2d21ac55
A
4114 PM_ASSERT_IN_GATE();
4115
4116 OUR_PMLog( kPMLogStartDeviceChange, fHeadNoteState, fCurrentPowerState );
1c79356b 4117
55e303ae 4118 // can our driver switch to the new state?
2d21ac55
A
4119 if (( fHeadNoteCapabilityFlags & IOPMNotAttainable ) ||
4120 ((fMaxCapability < fHeadNoteState) && (!fWeAreRoot)))
55e303ae 4121 {
55e303ae 4122 // mark the change note un-actioned
2d21ac55
A
4123 fHeadNoteFlags |= IOPMNotDone;
4124
4125 // no, ask the parent to do it then
4126 if ( !fWeAreRoot )
55e303ae 4127 {
2d21ac55 4128 ask_parent(fHeadNoteState);
1c79356b 4129 }
55e303ae
A
4130 all_done();
4131 return;
1c79356b
A
4132 }
4133
2d21ac55 4134 if ( !fInitialChange )
55e303ae 4135 {
2d21ac55 4136 if ( fHeadNoteState == fCurrentPowerState )
55e303ae
A
4137 {
4138 // we initiated a null change; forget it
4139 all_done();
1c79356b
A
4140 return;
4141 }
4142 }
2d21ac55 4143 fInitialChange = false;
1c79356b 4144
55e303ae 4145 // dropping power?
2d21ac55 4146 if ( fHeadNoteState < fCurrentPowerState )
55e303ae
A
4147 {
4148 // yes, in case we have to wait for acks
2d21ac55
A
4149 fMachineState = kIOPM_OurChangeTellClientsPowerDown;
4150 fDoNotPowerDown = false;
55e303ae
A
4151
4152 // ask apps and kernel clients if we can drop power
2d21ac55
A
4153 fOutOfBandParameter = kNotifyApps;
4154 askChangeDown(fHeadNoteState);
55e303ae 4155 } else {
55e303ae 4156 // in case they don't all ack
2d21ac55 4157 fMachineState = kIOPM_OurChangeSetPowerState;
55e303ae 4158 // notify interested drivers and children
2d21ac55 4159 notifyAll(true);
1c79356b
A
4160 }
4161}
4162
1c79356b 4163//*********************************************************************************
2d21ac55 4164// [private] ask_parent
1c79356b
A
4165//
4166// Call the power domain parent to ask for a higher power state in the domain
4167// or to suggest a lower power state.
4168//*********************************************************************************
4169
4170IOReturn IOService::ask_parent ( unsigned long requestedState )
4171{
2d21ac55
A
4172 OSIterator * iter;
4173 OSObject * next;
4174 IOPowerConnection * connection;
4175 IOService * parent;
4176 const IOPMPowerState * powerStatePtr;
4177 unsigned long ourRequest;
4178
4179 PM_ASSERT_IN_GATE();
4180 if (requestedState >= fNumberOfPowerStates)
4181 return IOPMNoErr;
1c79356b 4182
2d21ac55
A
4183 powerStatePtr = &fPowerStates[requestedState];
4184 ourRequest = powerStatePtr->inputPowerRequirement;
4185
4186 if ( powerStatePtr->capabilityFlags & (kIOPMChildClamp | kIOPMPreventIdleSleep) )
55e303ae 4187 {
0b4e3aa0
A
4188 ourRequest |= kIOPMPreventIdleSleep;
4189 }
2d21ac55 4190 if ( powerStatePtr->capabilityFlags & (kIOPMChildClamp2 | kIOPMPreventSystemSleep) )
55e303ae 4191 {
0b4e3aa0
A
4192 ourRequest |= kIOPMPreventSystemSleep;
4193 }
2d21ac55 4194
90556fb8 4195 // is this a new desire?
2d21ac55 4196 if ( fPreviousRequest == ourRequest )
90556fb8
A
4197 {
4198 // no, the parent knows already, just return
2d21ac55 4199 return IOPMNoErr;
1c79356b
A
4200 }
4201
2d21ac55 4202 if ( fWeAreRoot )
55e303ae 4203 {
1c79356b
A
4204 return IOPMNoErr;
4205 }
2d21ac55 4206 fPreviousRequest = ourRequest;
1c79356b
A
4207
4208 iter = getParentIterator(gIOPowerPlane);
2d21ac55 4209 if ( iter )
55e303ae 4210 {
2d21ac55 4211 while ( (next = iter->getNextObject()) )
55e303ae 4212 {
2d21ac55 4213 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
55e303ae 4214 {
0b4e3aa0
A
4215 parent = (IOService *)connection->copyParentEntry(gIOPowerPlane);
4216 if ( parent ) {
2d21ac55
A
4217 if ( parent->requestPowerDomainState(
4218 ourRequest, connection, IOPMLowestState) != IOPMNoErr )
55e303ae 4219 {
2d21ac55 4220 OUR_PMLog(kPMLogRequestDenied, fPreviousRequest, 0);
0b4e3aa0
A
4221 }
4222 parent->release();
1c79356b
A
4223 }
4224 }
4225 }
4226 iter->release();
4227 }
4228
4229 return IOPMNoErr;
4230}
4231
1c79356b 4232//*********************************************************************************
2d21ac55 4233// [private] notifyControllingDriver
1c79356b 4234//*********************************************************************************
1c79356b 4235
2d21ac55
A
4236bool IOService::notifyControllingDriver ( void )
4237{
4238 DriverCallParam * param;
4239 unsigned long powerState;
4240
4241 PM_ASSERT_IN_GATE();
4242 assert( fDriverCallBusy == false );
4243 assert( fDriverCallParamCount == 0 );
4244 assert( fControllingDriver );
4245
4246 powerState = fHeadNoteState;
4247 if (fPowerStates[powerState].capabilityFlags & IOPMNotAttainable )
4248 return false; // state not attainable
4249
4250 param = (DriverCallParam *) fDriverCallParamPtr;
4251 if (!param)
4252 {
4253 param = IONew(DriverCallParam, 1);
4254 if (!param)
4255 return false; // no memory
4256
4257 fDriverCallParamPtr = (void *) param;
4258 fDriverCallParamSlots = 1;
4259 }
0b4e3aa0 4260
2d21ac55
A
4261 param->Target = fControllingDriver;
4262 fDriverCallParamCount = 1;
9bccf70c 4263
2d21ac55 4264 fDriverTimer = -1;
1c79356b 4265
2d21ac55
A
4266 // Machine state for this object will stall waiting for a reply
4267 // from the callout thread.
1c79356b 4268
2d21ac55
A
4269 PM_LOCK();
4270 fDriverCallBusy = true;
4271 PM_UNLOCK();
4272 thread_call_enter( fDriverCallEntry );
4273 return true;
1c79356b
A
4274}
4275
1c79356b 4276//*********************************************************************************
2d21ac55 4277// [private] notifyControllingDriverDone
1c79356b
A
4278//*********************************************************************************
4279
2d21ac55 4280void IOService::notifyControllingDriverDone( void )
1c79356b 4281{
2d21ac55
A
4282 DriverCallParam * param;
4283 IOReturn result;
4284
4285 PM_ASSERT_IN_GATE();
4286 param = (DriverCallParam *) fDriverCallParamPtr;
4287
4288 assert( fDriverCallBusy == false );
4289 assert( fMachineState == kIOPM_DriverThreadCallDone );
4290
4291 if (param)
4292 {
4293 assert(fDriverCallParamCount == 1);
4294
4295 // the return value from setPowerState()
4296 result = param->Result;
4297
4298 if ((result == IOPMAckImplied) || (result < 0))
4299 {
4300 // child return IOPMAckImplied
4301 fDriverTimer = 0;
4302 }
4303 else if (fDriverTimer)
4304 {
4305 assert(fDriverTimer == -1);
4306
4307 // Driver has not acked, and has returned a positive result.
4308 // Enforce a minimum permissible timeout value.
4309 // Make the min value large enough so timeout is less likely
4310 // to occur if a driver misinterpreted that the return value
4311 // should be in microsecond units. And make it large enough
4312 // to be noticeable if a driver neglects to ack.
4313
4314 if (result < kMinAckTimeoutTicks)
4315 result = kMinAckTimeoutTicks;
4316
4317 fDriverTimer = (result / (ACK_TIMER_PERIOD / ns_per_us)) + 1;
4318 }
4319 // else, child has already acked and driver_timer reset to 0.
4320
4321 fDriverCallParamCount = 0;
4322
4323 if ( fDriverTimer )
4324 {
4325 OUR_PMLog(kPMLogStartAckTimer, 0, 0);
4326 start_ack_timer();
4327 }
4328 }
1c79356b 4329
2d21ac55
A
4330 // Hop back to original machine state path.
4331 fMachineState = fNextMachineState;
1c79356b
A
4332}
4333
1c79356b 4334//*********************************************************************************
2d21ac55 4335// [public virtual] askChangeDown
1c79356b
A
4336//
4337// Ask registered applications and kernel clients if we can change to a lower
4338// power state.
4339//
4340// Subclass can override this to send a different message type. Parameter is
4341// the destination state number.
4342//
4343// Return true if we don't have to wait for acknowledgements
4344//*********************************************************************************
4345
0b4e3aa0 4346bool IOService::askChangeDown ( unsigned long stateNum )
1c79356b 4347{
2d21ac55 4348 return tellClientsWithResponse( kIOMessageCanDevicePowerOff );
1c79356b
A
4349}
4350
0b4e3aa0 4351//*********************************************************************************
2d21ac55 4352// [public] tellChangeDown1
0b4e3aa0
A
4353//
4354// Notify registered applications and kernel clients that we are definitely
4355// dropping power.
4356//
4357// Return true if we don't have to wait for acknowledgements
4358//*********************************************************************************
4359
4360bool IOService::tellChangeDown1 ( unsigned long stateNum )
4361{
2d21ac55 4362 fOutOfBandParameter = kNotifyApps;
0b4e3aa0
A
4363 return tellChangeDown(stateNum);
4364}
4365
0b4e3aa0 4366//*********************************************************************************
2d21ac55 4367// [public] tellChangeDown2
0b4e3aa0
A
4368//
4369// Notify priority clients that we are definitely dropping power.
4370//
4371// Return true if we don't have to wait for acknowledgements
4372//*********************************************************************************
4373
4374bool IOService::tellChangeDown2 ( unsigned long stateNum )
4375{
2d21ac55 4376 fOutOfBandParameter = kNotifyPriority;
0b4e3aa0
A
4377 return tellChangeDown(stateNum);
4378}
4379
1c79356b 4380//*********************************************************************************
2d21ac55 4381// [public virtual] tellChangeDown
1c79356b
A
4382//
4383// Notify registered applications and kernel clients that we are definitely
4384// dropping power.
4385//
4386// Subclass can override this to send a different message type. Parameter is
4387// the destination state number.
4388//
4389// Return true if we don't have to wait for acknowledgements
4390//*********************************************************************************
4391
0b4e3aa0 4392bool IOService::tellChangeDown ( unsigned long stateNum )
1c79356b 4393{
2d21ac55
A
4394 return tellClientsWithResponse( kIOMessageDeviceWillPowerOff );
4395}
4396
4397//*********************************************************************************
4398// cleanClientResponses
4399//
4400//*********************************************************************************
4401
4402static void logAppTimeouts ( OSObject * object, void * context)
4403{
4404 struct context *theContext = (struct context *)context;
4405 OSObject *flag;
4406
4407 if( !OSDynamicCast( IOService, object) ) {
4408 flag = theContext->responseFlags->getObject(theContext->counter);
4409 if (kOSBooleanTrue != flag)
4410 {
4411 OSString * clientID = 0;
4412 theContext->us->messageClient(theContext->msgType, object, &clientID);
4413 PM_ERROR(theContext->errorLog, clientID ? clientID->getCStringNoCopy() : "");
4414 if (clientID)
4415 clientID->release();
4416 }
4417 theContext->counter += 1;
4418 }
1c79356b
A
4419}
4420
2d21ac55
A
4421void IOService::cleanClientResponses ( bool logErrors )
4422{
4423 struct context theContext;
4424
4425 if (logErrors && fResponseArray) {
4426 theContext.responseFlags = fResponseArray;
4427 theContext.serialNumber = fSerialNumber;
4428 theContext.counter = 0;
4429 theContext.msgType = kIOMessageCopyClientID;
4430 theContext.us = this;
4431 theContext.maxTimeRequested = 0;
4432 theContext.stateNumber = fHeadNoteState;
4433 theContext.stateFlags = fHeadNoteCapabilityFlags;
4434 theContext.errorLog = "PM notification timeout (%s)\n";
4435
4436 switch ( fOutOfBandParameter ) {
4437 case kNotifyApps:
4438 applyToInterested(gIOAppPowerStateInterest, logAppTimeouts, (void *) &theContext);
4439 case kNotifyPriority:
4440 default:
4441 break;
4442 }
4443 }
4444
4445 if (fResponseArray)
4446 {
4447 // get rid of this stuff
4448 fResponseArray->release();
4449 fResponseArray = NULL;
4450 }
4451
4452 return;
4453}
1c79356b
A
4454
4455//*********************************************************************************
2d21ac55 4456// [public] tellClientsWithResponse
1c79356b
A
4457//
4458// Notify registered applications and kernel clients that we are definitely
4459// dropping power.
4460//
4461// Return true if we don't have to wait for acknowledgements
4462//*********************************************************************************
4463
4464bool IOService::tellClientsWithResponse ( int messageType )
4465{
2d21ac55
A
4466 struct context theContext;
4467
4468 PM_ASSERT_IN_GATE();
1c79356b 4469
2d21ac55
A
4470 fResponseArray = OSArray::withCapacity( 1 );
4471 fSerialNumber += 1;
1c79356b 4472
2d21ac55
A
4473 theContext.responseFlags = fResponseArray;
4474 theContext.serialNumber = fSerialNumber;
4475 theContext.counter = 0;
1c79356b
A
4476 theContext.msgType = messageType;
4477 theContext.us = this;
4478 theContext.maxTimeRequested = 0;
2d21ac55
A
4479 theContext.stateNumber = fHeadNoteState;
4480 theContext.stateFlags = fHeadNoteCapabilityFlags;
0b4e3aa0 4481
2d21ac55 4482 switch ( fOutOfBandParameter ) {
0b4e3aa0 4483 case kNotifyApps:
2d21ac55
A
4484 applyToInterested(gIOAppPowerStateInterest,
4485 pmTellAppWithResponse, (void *)&theContext);
4486 applyToInterested(gIOGeneralInterest,
4487 pmTellClientWithResponse, (void *)&theContext);
0b4e3aa0
A
4488 break;
4489 case kNotifyPriority:
2d21ac55
A
4490 applyToInterested(gIOPriorityPowerStateInterest,
4491 pmTellClientWithResponse, (void *)&theContext);
0b4e3aa0
A
4492 break;
4493 }
1c79356b 4494
55e303ae 4495 // do we have to wait for somebody?
2d21ac55 4496 if ( !checkForDone() )
55e303ae 4497 {
2d21ac55
A
4498 OUR_PMLog(kPMLogStartAckTimer,theContext.maxTimeRequested, 0);
4499 start_ack_timer( theContext.maxTimeRequested / 1000, kMillisecondScale );
1c79356b
A
4500 return false;
4501 }
2d21ac55 4502
55e303ae 4503 // everybody responded
2d21ac55
A
4504 fResponseArray->release();
4505 fResponseArray = NULL;
4506 // cleanClientResponses(false);
1c79356b
A
4507
4508 return true;
4509}
4510
1c79356b 4511//*********************************************************************************
2d21ac55 4512// [static private] pmTellAppWithResponse
1c79356b
A
4513//
4514// We send a message to an application, and we expect a response, so we compute a
4515// cookie we can identify the response with.
4516//*********************************************************************************
2d21ac55
A
4517
4518void IOService::pmTellAppWithResponse ( OSObject * object, void * context )
1c79356b 4519{
2d21ac55
A
4520 struct context * theContext = (struct context *) context;
4521 IOServicePM * pwrMgt = theContext->us->pwrMgt;
4522 AbsoluteTime now;
91447636 4523
2d21ac55 4524 if( OSDynamicCast( IOService, object) )
55e303ae 4525 {
2d21ac55
A
4526 // Automatically 'ack' in kernel clients
4527 theContext->responseFlags->setObject(theContext->counter, kOSBooleanTrue);
4528
4529 const char *who = ((IOService *) object)->getName();
4530 fPlatform->PMLog(who,
4531 kPMLogClientAcknowledge, theContext->msgType, * (UInt32 *) object);
55e303ae 4532 } else {
91447636 4533 UInt32 refcon = ((theContext->serialNumber & 0xFFFF)<<16)
2d21ac55
A
4534 + (theContext->counter & 0xFFFF);
4535 OUR_PMLog(kPMLogAppNotify, theContext->msgType, refcon);
4536
4537#if LOG_APP_RESPONSE_TIMES
4538 OSNumber * num;
4539 clock_get_uptime(&now);
4540 num = OSNumber::withNumber(AbsoluteTime_to_scalar(&now), sizeof(uint64_t) * 8);
4541 if (num)
4542 {
4543 theContext->responseFlags->setObject(theContext->counter, num);
4544 num->release();
4545 }
4546 else
4547#endif
4548 theContext->responseFlags->setObject(theContext->counter, kOSBooleanFalse);
4549
4550 theContext->us->messageClient(theContext->msgType, object, (void *)refcon);
4551 if ( theContext->maxTimeRequested < k30seconds )
55e303ae 4552 {
0b4e3aa0 4553 theContext->maxTimeRequested = k30seconds;
1c79356b 4554 }
2d21ac55
A
4555
4556 theContext->counter += 1;
1c79356b 4557 }
1c79356b
A
4558}
4559
1c79356b 4560//*********************************************************************************
2d21ac55 4561// [static private] pmTellClientWithResponse
1c79356b
A
4562//
4563// We send a message to an in-kernel client, and we expect a response, so we compute a
4564// cookie we can identify the response with.
4565// If it doesn't understand the notification (it is not power-management savvy)
4566// we won't wait for it to prepare for sleep. If it tells us via a return code
4567// in the passed struct that it is currently ready, we won't wait for it to prepare.
4568// If it tells us via the return code in the struct that it does need time, we will chill.
4569//*********************************************************************************
2d21ac55
A
4570
4571void IOService::pmTellClientWithResponse ( OSObject * object, void * context )
1c79356b 4572{
55e303ae
A
4573 struct context *theContext = (struct context *)context;
4574 IOPowerStateChangeNotification notify;
4575 UInt32 refcon;
4576 IOReturn retCode;
55e303ae 4577 OSObject *theFlag;
2d21ac55 4578
1c79356b 4579 refcon = ((theContext->serialNumber & 0xFFFF)<<16) + (theContext->counter & 0xFFFF);
2d21ac55 4580 theContext->responseFlags->setObject(theContext->counter, kOSBooleanFalse);
0b4e3aa0 4581
2d21ac55 4582 IOServicePM * pwrMgt = theContext->us->pwrMgt;
91447636 4583 if (gIOKitDebug & kIOLogPower) {
2d21ac55
A
4584 OUR_PMLog(kPMLogClientNotify, refcon, (UInt32) theContext->msgType);
4585 if (OSDynamicCast(IOService, object)) {
4586 const char *who = ((IOService *) object)->getName();
4587 fPlatform->PMLog(who,
4588 kPMLogClientNotify, * (UInt32 *) object, (UInt32) object);
4589 } else if (OSDynamicCast(_IOServiceInterestNotifier, object)) {
4590 _IOServiceInterestNotifier *n = (_IOServiceInterestNotifier *) object;
4591 OUR_PMLog(kPMLogClientNotify, (UInt32) n->handler, 0);
4592 }
91447636
A
4593 }
4594
0b4e3aa0
A
4595 notify.powerRef = (void *)refcon;
4596 notify.returnValue = 0;
4597 notify.stateNumber = theContext->stateNumber;
4598 notify.stateFlags = theContext->stateFlags;
4599 retCode = theContext->us->messageClient(theContext->msgType,object,(void *)&notify);
2d21ac55 4600 if ( retCode == kIOReturnSuccess )
55e303ae 4601 {
2d21ac55 4602 if ( notify.returnValue == 0 )
55e303ae
A
4603 {
4604 // client doesn't want time to respond
2d21ac55
A
4605 theContext->responseFlags->replaceObject(theContext->counter, kOSBooleanTrue);
4606 OUR_PMLog(kPMLogClientAcknowledge, refcon, (UInt32) object);
55e303ae 4607 } else {
55e303ae
A
4608 // it does want time, and it hasn't responded yet
4609 theFlag = theContext->responseFlags->getObject(theContext->counter);
2d21ac55 4610 if ( kOSBooleanTrue != theFlag )
55e303ae 4611 {
2d21ac55
A
4612 // so note its time requirement
4613 if ( theContext->maxTimeRequested < notify.returnValue )
55e303ae 4614 {
2d21ac55 4615 theContext->maxTimeRequested = notify.returnValue;
1c79356b
A
4616 }
4617 }
1c79356b 4618 }
55e303ae 4619 } else {
2d21ac55 4620 OUR_PMLog(kPMLogClientAcknowledge, refcon, 0);
55e303ae 4621 // not a client of ours
55e303ae 4622 // so we won't be waiting for response
2d21ac55 4623 theContext->responseFlags->replaceObject(theContext->counter, kOSBooleanTrue);
1c79356b
A
4624 }
4625 theContext->counter += 1;
4626}
4627
1c79356b 4628//*********************************************************************************
2d21ac55 4629// [public virtual] tellNoChangeDown
1c79356b
A
4630//
4631// Notify registered applications and kernel clients that we are not
4632// dropping power.
4633//
4634// Subclass can override this to send a different message type. Parameter is
4635// the aborted destination state number.
4636//*********************************************************************************
4637
4638void IOService::tellNoChangeDown ( unsigned long )
4639{
2d21ac55 4640 return tellClients( kIOMessageDeviceWillNotPowerOff );
1c79356b
A
4641}
4642
1c79356b 4643//*********************************************************************************
2d21ac55 4644// [public virtual] tellChangeUp
1c79356b
A
4645//
4646// Notify registered applications and kernel clients that we are raising power.
4647//
4648// Subclass can override this to send a different message type. Parameter is
4649// the aborted destination state number.
4650//*********************************************************************************
4651
4652void IOService::tellChangeUp ( unsigned long )
4653{
2d21ac55 4654 return tellClients( kIOMessageDeviceHasPoweredOn );
1c79356b
A
4655}
4656
1c79356b 4657//*********************************************************************************
2d21ac55 4658// [public] tellClients
1c79356b
A
4659//
4660// Notify registered applications and kernel clients of something.
4661//*********************************************************************************
4662
4663void IOService::tellClients ( int messageType )
4664{
4665 struct context theContext;
4666
4667 theContext.msgType = messageType;
4668 theContext.us = this;
2d21ac55
A
4669 theContext.stateNumber = fHeadNoteState;
4670 theContext.stateFlags = fHeadNoteCapabilityFlags;
1c79356b 4671
2d21ac55
A
4672 applyToInterested(gIOPriorityPowerStateInterest,tellClient,(void *)&theContext);
4673 applyToInterested(gIOAppPowerStateInterest,tellClient, (void *)&theContext);
4674 applyToInterested(gIOGeneralInterest,tellClient, (void *)&theContext);
1c79356b
A
4675}
4676
1c79356b 4677//*********************************************************************************
2d21ac55 4678// [global] tellClient
1c79356b
A
4679//
4680// Notify a registered application or kernel client of something.
4681//*********************************************************************************
2d21ac55
A
4682
4683void tellClient ( OSObject * object, void * context )
1c79356b 4684{
2d21ac55
A
4685 struct context * theContext = (struct context *) context;
4686 IOPowerStateChangeNotification notify;
1c79356b 4687
0b4e3aa0
A
4688 notify.powerRef = (void *) 0;
4689 notify.returnValue = 0;
4690 notify.stateNumber = theContext->stateNumber;
4691 notify.stateFlags = theContext->stateFlags;
4692
2d21ac55 4693 theContext->us->messageClient(theContext->msgType, object, &notify);
1c79356b
A
4694}
4695
2d21ac55
A
4696//*********************************************************************************
4697// [private] checkForDone
4698//*********************************************************************************
1c79356b 4699
1c79356b
A
4700bool IOService::checkForDone ( void )
4701{
2d21ac55
A
4702 int i = 0;
4703 OSObject * theFlag;
1c79356b 4704
2d21ac55 4705 if ( fResponseArray == NULL )
55e303ae 4706 {
1c79356b
A
4707 return true;
4708 }
55e303ae 4709
2d21ac55 4710 for ( i = 0; ; i++ )
55e303ae 4711 {
2d21ac55
A
4712 theFlag = fResponseArray->getObject(i);
4713 if ( theFlag == NULL )
55e303ae 4714 {
1c79356b
A
4715 break;
4716 }
2d21ac55 4717 if ( kOSBooleanTrue != theFlag )
55e303ae 4718 {
1c79356b
A
4719 return false;
4720 }
4721 }
1c79356b
A
4722 return true;
4723}
4724
2d21ac55
A
4725//*********************************************************************************
4726// [public] responseValid
4727//*********************************************************************************
1c79356b 4728
2d21ac55
A
4729bool IOService::responseValid ( unsigned long x, int pid )
4730{
4731 UInt16 serialComponent;
4732 UInt16 ordinalComponent;
4733 OSObject * theFlag;
4734 unsigned long refcon = (unsigned long) x;
4735
4736 serialComponent = (refcon >> 16) & 0xFFFF;
4737 ordinalComponent = (refcon & 0xFFFF);
4738
4739 if ( serialComponent != fSerialNumber )
55e303ae 4740 {
1c79356b
A
4741 return false;
4742 }
4743
2d21ac55 4744 if ( fResponseArray == NULL )
55e303ae 4745 {
1c79356b
A
4746 return false;
4747 }
4748
2d21ac55 4749 theFlag = fResponseArray->getObject(ordinalComponent);
1c79356b 4750
2d21ac55 4751 if ( theFlag == 0 )
55e303ae 4752 {
1c79356b
A
4753 return false;
4754 }
2d21ac55
A
4755
4756 OSNumber * num;
4757 if ((num = OSDynamicCast(OSNumber, theFlag)))
4758 {
4759#if LOG_APP_RESPONSE_TIMES
4760 AbsoluteTime now;
4761 AbsoluteTime start;
4762 uint64_t nsec;
4763
4764 clock_get_uptime(&now);
4765 AbsoluteTime_to_scalar(&start) = num->unsigned64BitValue();
4766 SUB_ABSOLUTETIME(&now, &start);
4767 absolutetime_to_nanoseconds(now, &nsec);
4768
4769 // > 100 ms
4770 if (nsec > LOG_APP_RESPONSE_TIMES)
4771 {
4772 OSString * name = IOCopyLogNameForPID(pid);
4773 PM_DEBUG("PM response took %d ms (%s)\n", NS_TO_MS(nsec),
4774 name ? name->getCStringNoCopy() : "");
4775 if (name)
4776 name->release();
4777 }
4778#endif
4779 theFlag = kOSBooleanFalse;
4780 }
4781
4782 if ( kOSBooleanFalse == theFlag )
55e303ae 4783 {
2d21ac55 4784 fResponseArray->replaceObject(ordinalComponent, kOSBooleanTrue);
1c79356b
A
4785 }
4786
1c79356b
A
4787 return true;
4788}
4789
2d21ac55
A
4790//*********************************************************************************
4791// [public virtual] allowPowerChange
1c79356b
A
4792//
4793// Our power state is about to lower, and we have notified applications
4794// and kernel clients, and one of them has acknowledged. If this is the last to do
4795// so, and all acknowledgements are positive, we continue with the power change.
4796//
4797// We serialize this processing with timer expiration with a command gate on the
4798// power management workloop, which the timer expiration is command gated to as well.
2d21ac55
A
4799//*********************************************************************************
4800
1c79356b
A
4801IOReturn IOService::allowPowerChange ( unsigned long refcon )
4802{
2d21ac55
A
4803 IOPMRequest * request;
4804
4805 if ( !initialized )
55e303ae
A
4806 {
4807 // we're unloading
4808 return kIOReturnSuccess;
1c79356b
A
4809 }
4810
2d21ac55
A
4811 request = acquirePMRequest( this, kIOPMRequestTypeAllowPowerChange );
4812 if (!request)
4813 {
4814 PM_ERROR("%s::%s no memory\n", getName(), __FUNCTION__);
4815 return kIOReturnNoMemory;
4816 }
4817
4818 request->fArg0 = (void *) refcon;
4819 request->fArg1 = (void *) proc_selfpid();
4820 submitPMRequest( request );
4821
4822 return kIOReturnSuccess;
1c79356b 4823}
2d21ac55 4824
1c79356b
A
4825IOReturn serializedAllowPowerChange ( OSObject *owner, void * refcon, void *, void *, void *)
4826{
2d21ac55
A
4827 // [deprecated] public
4828 return kIOReturnUnsupported;
1c79356b
A
4829}
4830
4831IOReturn IOService::serializedAllowPowerChange2 ( unsigned long refcon )
4832{
2d21ac55
A
4833 // [deprecated] public
4834 return kIOReturnUnsupported;
1c79356b
A
4835}
4836
2d21ac55
A
4837//*********************************************************************************
4838// [public virtual] cancelPowerChange
1c79356b
A
4839//
4840// Our power state is about to lower, and we have notified applications
4841// and kernel clients, and one of them has vetoed the change. If this is the last
4842// client to respond, we abandon the power change.
4843//
4844// We serialize this processing with timer expiration with a command gate on the
4845// power management workloop, which the timer expiration is command gated to as well.
2d21ac55
A
4846//*********************************************************************************
4847
1c79356b
A
4848IOReturn IOService::cancelPowerChange ( unsigned long refcon )
4849{
2d21ac55
A
4850 IOPMRequest * request;
4851
4852 if ( !initialized )
55e303ae
A
4853 {
4854 // we're unloading
4855 return kIOReturnSuccess;
1c79356b
A
4856 }
4857
2d21ac55
A
4858 request = acquirePMRequest( this, kIOPMRequestTypeCancelPowerChange );
4859 if (!request)
4860 {
4861 PM_ERROR("%s::%s no memory\n", getName(), __FUNCTION__);
4862 return kIOReturnNoMemory;
4863 }
4864
4865 request->fArg0 = (void *) refcon;
4866 request->fArg1 = (void *) proc_selfpid();
4867 submitPMRequest( request );
4868
4869 return kIOReturnSuccess;
1c79356b 4870}
2d21ac55 4871
1c79356b
A
4872IOReturn serializedCancelPowerChange ( OSObject *owner, void * refcon, void *, void *, void *)
4873{
2d21ac55
A
4874 // [deprecated] public
4875 return kIOReturnUnsupported;
1c79356b
A
4876}
4877
4878IOReturn IOService::serializedCancelPowerChange2 ( unsigned long refcon )
4879{
2d21ac55
A
4880 // [deprecated] public
4881 return kIOReturnUnsupported;
1c79356b
A
4882}
4883
91447636 4884#if 0
1c79356b 4885//*********************************************************************************
91447636 4886// c_PM_clamp_Timer_Expired (C Func)
1c79356b 4887//
91447636 4888// Called when our clamp timer expires...we will call the object method.
1c79356b
A
4889//*********************************************************************************
4890
2d21ac55 4891static void c_PM_Clamp_Timer_Expired ( OSObject * client, IOTimerEventSource * )
1c79356b 4892{
91447636
A
4893 if (client)
4894 ((IOService *)client)->PM_Clamp_Timer_Expired ();
1c79356b 4895}
91447636
A
4896#endif
4897
1c79356b
A
4898//*********************************************************************************
4899// PM_Clamp_Timer_Expired
4900//
4901// called when clamp timer expires...set power state to 0.
4902//*********************************************************************************
4903
2d21ac55 4904void IOService::PM_Clamp_Timer_Expired ( void )
1c79356b 4905{
91447636 4906#if 0
2d21ac55 4907 if ( ! initialized )
55e303ae
A
4908 {
4909 // we're unloading
4910 return;
1c79356b
A
4911 }
4912
4913 changePowerStateToPriv (0);
91447636 4914#endif
1c79356b
A
4915}
4916
2d21ac55 4917//*********************************************************************************
91447636 4918// clampPowerOn
1c79356b 4919//
91447636 4920// Set to highest available power state for a minimum of duration milliseconds
2d21ac55 4921//*********************************************************************************
91447636
A
4922
4923#define kFiveMinutesInNanoSeconds (300 * NSEC_PER_SEC)
1c79356b 4924
2d21ac55 4925void IOService::clampPowerOn ( unsigned long duration )
1c79356b 4926{
91447636 4927#if 0
2d21ac55 4928 changePowerStateToPriv (fNumberOfPowerStates-1);
91447636 4929
2d21ac55
A
4930 if ( pwrMgt->clampTimerEventSrc == NULL ) {
4931 pwrMgt->clampTimerEventSrc = IOTimerEventSource::timerEventSource(this,
91447636
A
4932 c_PM_Clamp_Timer_Expired);
4933
4934 IOWorkLoop * workLoop = getPMworkloop ();
4935
2d21ac55
A
4936 if ( !pwrMgt->clampTimerEventSrc || !workLoop ||
4937 ( workLoop->addEventSource( pwrMgt->clampTimerEventSrc) != kIOReturnSuccess) ) {
91447636
A
4938
4939 }
4940 }
1c79356b 4941
2d21ac55 4942 pwrMgt->clampTimerEventSrc->setTimeout(300*USEC_PER_SEC, USEC_PER_SEC);
91447636
A
4943#endif
4944}
1c79356b
A
4945
4946//*********************************************************************************
2d21ac55 4947// [public virtual] setPowerState
1c79356b
A
4948//
4949// Does nothing here. This should be implemented in a subclass driver.
4950//*********************************************************************************
4951
2d21ac55
A
4952IOReturn IOService::setPowerState (
4953 unsigned long powerStateOrdinal, IOService * whatDevice )
1c79356b
A
4954{
4955 return IOPMNoErr;
4956}
4957
1c79356b 4958//*********************************************************************************
2d21ac55 4959// [public virtual] maxCapabilityForDomainState
1c79356b
A
4960//
4961// Finds the highest power state in the array whose input power
4962// requirement is equal to the input parameter. Where a more intelligent
4963// decision is possible, override this in the subclassed driver.
4964//*********************************************************************************
4965
4966unsigned long IOService::maxCapabilityForDomainState ( IOPMPowerFlags domainState )
4967{
4968 int i;
4969
2d21ac55 4970 if (fNumberOfPowerStates == 0 )
55e303ae 4971 {
1c79356b
A
4972 return 0;
4973 }
2d21ac55 4974 for ( i = fNumberOfPowerStates - 1; i >= 0; i-- )
55e303ae 4975 {
2d21ac55
A
4976 if ( (domainState & fPowerStates[i].inputPowerRequirement) ==
4977 fPowerStates[i].inputPowerRequirement )
55e303ae 4978 {
1c79356b
A
4979 return i;
4980 }
4981 }
4982 return 0;
4983}
4984
1c79356b 4985//*********************************************************************************
2d21ac55 4986// [public virtual] initialPowerStateForDomainState
1c79356b
A
4987//
4988// Finds the highest power state in the array whose input power
4989// requirement is equal to the input parameter. Where a more intelligent
4990// decision is possible, override this in the subclassed driver.
4991//*********************************************************************************
4992
4993unsigned long IOService::initialPowerStateForDomainState ( IOPMPowerFlags domainState )
4994{
55e303ae 4995 int i;
1c79356b 4996
2d21ac55 4997 if (fNumberOfPowerStates == 0 )
55e303ae
A
4998 {
4999 return 0;
5000 }
2d21ac55 5001 for ( i = fNumberOfPowerStates - 1; i >= 0; i-- )
55e303ae 5002 {
2d21ac55
A
5003 if ( (domainState & fPowerStates[i].inputPowerRequirement) ==
5004 fPowerStates[i].inputPowerRequirement )
55e303ae
A
5005 {
5006 return i;
5007 }
5008 }
5009 return 0;
1c79356b
A
5010}
5011
1c79356b 5012//*********************************************************************************
2d21ac55 5013// [public virtual] powerStateForDomainState
1c79356b
A
5014//
5015// Finds the highest power state in the array whose input power
5016// requirement is equal to the input parameter. Where a more intelligent
5017// decision is possible, override this in the subclassed driver.
5018//*********************************************************************************
5019
5020unsigned long IOService::powerStateForDomainState ( IOPMPowerFlags domainState )
5021{
55e303ae 5022 int i;
1c79356b 5023
2d21ac55 5024 if (fNumberOfPowerStates == 0 )
55e303ae
A
5025 {
5026 return 0;
5027 }
2d21ac55 5028 for ( i = fNumberOfPowerStates - 1; i >= 0; i-- )
55e303ae 5029 {
2d21ac55
A
5030 if ( (domainState & fPowerStates[i].inputPowerRequirement) ==
5031 fPowerStates[i].inputPowerRequirement )
55e303ae
A
5032 {
5033 return i;
5034 }
5035 }
5036 return 0;
1c79356b
A
5037}
5038
1c79356b 5039//*********************************************************************************
2d21ac55 5040// [public virtual] didYouWakeSystem
1c79356b
A
5041//
5042// Does nothing here. This should be implemented in a subclass driver.
5043//*********************************************************************************
5044
5045bool IOService::didYouWakeSystem ( void )
5046{
5047 return false;
5048}
5049
1c79356b 5050//*********************************************************************************
2d21ac55 5051// [public virtual] powerStateWillChangeTo
1c79356b
A
5052//
5053// Does nothing here. This should be implemented in a subclass driver.
5054//*********************************************************************************
5055
2d21ac55 5056IOReturn IOService::powerStateWillChangeTo ( IOPMPowerFlags, unsigned long, IOService * )
1c79356b 5057{
2d21ac55 5058 return kIOPMAckImplied;
1c79356b
A
5059}
5060
1c79356b 5061//*********************************************************************************
2d21ac55 5062// [public virtual] powerStateDidChangeTo
1c79356b
A
5063//
5064// Does nothing here. This should be implemented in a subclass driver.
5065//*********************************************************************************
5066
2d21ac55 5067IOReturn IOService::powerStateDidChangeTo ( IOPMPowerFlags, unsigned long, IOService * )
1c79356b 5068{
2d21ac55 5069 return kIOPMAckImplied;
1c79356b
A
5070}
5071
1c79356b 5072//*********************************************************************************
2d21ac55 5073// [public virtual] powerChangeDone
1c79356b 5074//
2d21ac55 5075// Called from PM work loop thread.
1c79356b
A
5076// Does nothing here. This should be implemented in a subclass policy-maker.
5077//*********************************************************************************
5078
5079void IOService::powerChangeDone ( unsigned long )
5080{
5081}
5082
1c79356b 5083//*********************************************************************************
2d21ac55 5084// [public virtual] newTemperature
1c79356b
A
5085//
5086// Does nothing here. This should be implemented in a subclass driver.
5087//*********************************************************************************
5088
5089IOReturn IOService::newTemperature ( long currentTemp, IOService * whichZone )
1c79356b
A
5090{
5091 return IOPMNoErr;
5092}
5093
2d21ac55
A
5094//*********************************************************************************
5095// [public virtual] systemWillShutdown
5096//
5097// System shutdown and restart notification.
5098//*********************************************************************************
1c79356b 5099
2d21ac55
A
5100void IOService::systemWillShutdown( IOOptionBits specifier )
5101{
5102 IOPMrootDomain * rootDomain = IOService::getPMRootDomain();
5103 if (rootDomain)
5104 rootDomain->acknowledgeSystemWillShutdown( this );
5105}
1c79356b 5106
1c79356b 5107//*********************************************************************************
2d21ac55
A
5108// [private static] acquirePMRequest
5109//*********************************************************************************
5110
5111IOPMRequest *
5112IOService::acquirePMRequest( IOService * target, IOOptionBits requestType )
5113{
5114 IOPMRequest * request;
5115
5116 assert(target);
5117
5118 request = IOPMRequest::create();
5119 if (request)
5120 {
5121 request->init( target, requestType );
5122 }
5123 return request;
5124}
5125
5126//*********************************************************************************
5127// [private static] releasePMRequest
5128//*********************************************************************************
5129
5130void IOService::releasePMRequest( IOPMRequest * request )
5131{
5132 if (request)
5133 {
5134 request->reset();
5135 request->release();
5136 }
5137}
5138
5139//*********************************************************************************
5140// [private] submitPMRequest
5141//*********************************************************************************
5142
5143void IOService::submitPMRequest( IOPMRequest * request )
5144{
5145 assert( request );
5146 assert( gIOPMReplyQueue );
5147 assert( gIOPMRequestQueue );
5148
5149 PM_TRACE("[+ %02lx] %p [%p %s] %p %p %p\n",
5150 request->getType(), request,
5151 request->getTarget(), request->getTarget()->getName(),
5152 request->fArg0, request->fArg1, request->fArg2);
5153
5154 if (request->isReply())
5155 gIOPMReplyQueue->queuePMRequest( request );
5156 else
5157 gIOPMRequestQueue->queuePMRequest( request );
5158}
5159
5160void IOService::submitPMRequest( IOPMRequest ** requests, IOItemCount count )
5161{
5162 assert( requests );
5163 assert( count > 0 );
5164 assert( gIOPMRequestQueue );
5165
5166 for (IOItemCount i = 0; i < count; i++)
5167 {
5168 IOPMRequest * req = requests[i];
5169 PM_TRACE("[+ %02lx] %p [%p %s] %p %p %p\n",
5170 req->getType(), req,
5171 req->getTarget(), req->getTarget()->getName(),
5172 req->fArg0, req->fArg1, req->fArg2);
5173 }
5174
5175 gIOPMRequestQueue->queuePMRequestChain( requests, count );
5176}
5177
5178//*********************************************************************************
5179// [private] servicePMRequestQueue
5180//*********************************************************************************
5181
5182bool IOService::servicePMRequestQueue(
5183 IOPMRequest * request,
5184 IOPMRequestQueue * queue )
5185{
5186 // Calling PM methods without PMinit() is not allowed, fail the requests.
5187
5188 if (!initialized)
5189 {
5190 PM_DEBUG("[%s] %s: PM not initialized\n", getName(), __FUNCTION__);
5191 goto done;
5192 }
5193
5194 // Create an IOPMWorkQueue on demand, when the initial PM request is
5195 // received.
5196
5197 if (!fPMWorkQueue)
5198 {
5199 // Allocate and attach an IOPMWorkQueue on demand to avoid taking
5200 // the work loop lock in PMinit(), which may deadlock with certain
5201 // drivers / families.
5202
5203 fPMWorkQueue = IOPMWorkQueue::create(
5204 /* target */ this,
5205 /* Work */ OSMemberFunctionCast(IOPMWorkQueue::Action, this,
5206 &IOService::servicePMRequest),
5207 /* Done */ OSMemberFunctionCast(IOPMWorkQueue::Action, this,
5208 &IOService::retirePMRequest)
5209 );
5210
5211 if (fPMWorkQueue &&
5212 (gIOPMWorkLoop->addEventSource(fPMWorkQueue) != kIOReturnSuccess))
5213 {
5214 PM_ERROR("[%s] %s: addEventSource failed\n",
5215 getName(), __FUNCTION__);
5216 fPMWorkQueue->release();
5217 fPMWorkQueue = 0;
5218 }
5219
5220 if (!fPMWorkQueue)
5221 {
5222 PM_ERROR("[%s] %s: not ready (type %02lx)\n",
5223 getName(), __FUNCTION__, request->getType());
5224 goto done;
5225 }
5226 }
5227
5228 fPMWorkQueue->queuePMRequest(request);
5229 return false; // do not signal more
5230
5231done:
5232 gIOPMFreeQueue->queuePMRequest( request );
5233 return false; // do not signal more
5234}
5235
5236//*********************************************************************************
5237// [private] servicePMFreeQueue
5238//
5239// Called by IOPMFreeQueue to recycle a completed request.
5240//*********************************************************************************
5241
5242bool IOService::servicePMFreeQueue(
5243 IOPMRequest * request,
5244 IOPMRequestQueue * queue )
5245{
5246 bool more = request->hasParentRequest();
5247 releasePMRequest( request );
5248 return more;
5249}
5250
5251//*********************************************************************************
5252// [private] retirePMRequest
1c79356b 5253//
2d21ac55 5254// Called by IOPMWorkQueue to retire a completed request.
1c79356b 5255//*********************************************************************************
2d21ac55
A
5256
5257bool IOService::retirePMRequest( IOPMRequest * request, IOPMWorkQueue * queue )
1c79356b 5258{
2d21ac55 5259 assert(request && queue);
1c79356b 5260
2d21ac55
A
5261 PM_TRACE("[- %02lx] %p [%p %s] State %ld, Busy %ld\n",
5262 request->getType(), request, this, getName(),
5263 fMachineState, gIOPMBusyCount);
91447636 5264
2d21ac55 5265 // Catch requests created by PM_idle_timer_expiration().
1c79356b 5266
2d21ac55
A
5267 if ((request->getType() == kIOPMRequestTypeActivityTickle) &&
5268 (request->fArg1 == (void *) false))
5269 {
5270 // Idle timer power drop request completed.
5271 // Restart the idle timer if deviceDesire can go lower, otherwise set
5272 // a flag so we know to restart idle timer when deviceDesire goes up.
1c79356b 5273
2d21ac55
A
5274 if (fDeviceDesire > 0)
5275 start_PM_idle_timer();
5276 else
5277 fActivityTimerStopped = true;
5278 }
1c79356b 5279
2d21ac55
A
5280 gIOPMFreeQueue->queuePMRequest( request );
5281 return true;
5282}
1c79356b 5283
2d21ac55
A
5284//*********************************************************************************
5285// [private] isPMBlocked
5286//
5287// Check if machine state transition is blocked.
5288//*********************************************************************************
1c79356b 5289
2d21ac55
A
5290bool IOService::isPMBlocked ( IOPMRequest * request, int count )
5291{
5292 int reason = 0;
5293
5294 do {
5295 if (kIOPM_Finished == fMachineState)
5296 break;
5297
5298 if (kIOPM_DriverThreadCallDone == fMachineState)
5299 {
5300 // 5 = kDriverCallInformPreChange
5301 // 6 = kDriverCallInformPostChange
5302 // 7 = kDriverCallSetPowerState
5303 if (fDriverCallBusy) reason = 5 + fDriverCallReason;
5304 break;
5305 }
5306
5307 // Waiting on driver's setPowerState() timeout.
5308 if (fDriverTimer)
5309 {
5310 reason = 1; break;
5311 }
5312
5313 // Child or interested driver acks pending.
5314 if (fHeadNotePendingAcks)
5315 {
5316 reason = 2; break;
5317 }
5318
5319 // Waiting on apps or priority power interest clients.
5320 if (fResponseArray)
5321 {
5322 reason = 3; break;
5323 }
5324
5325 // Waiting on settle timer expiration.
5326 if (fSettleTimeUS)
5327 {
5328 reason = 4; break;
5329 }
5330 } while (false);
5331
5332 fWaitReason = reason;
5333
5334 if (reason)
5335 {
5336 if (count)
5337 {
5338 PM_TRACE("[B %02lx] %p [%p %s] State %ld, Reason %d\n",
5339 request->getType(), request, this, getName(),
5340 fMachineState, reason);
5341 }
5342
5343 return true;
5344 }
1c79356b 5345
2d21ac55 5346 return false;
1c79356b
A
5347}
5348
2d21ac55
A
5349//*********************************************************************************
5350// [private] servicePMRequest
5351//
5352// Service a request from our work queue.
5353//*********************************************************************************
5354
5355bool IOService::servicePMRequest( IOPMRequest * request, IOPMWorkQueue * queue )
5356{
5357 bool done = false;
5358 int loop = 0;
5359
5360 assert(request && queue);
5361
5362 while (isPMBlocked(request, loop++) == false)
5363 {
5364 PM_TRACE("[W %02lx] %p [%p %s] State %ld\n",
5365 request->getType(), request, this, getName(), fMachineState);
5366
5367 fPMRequest = request;
5368
5369 // Every PM machine states must be handled in one of the cases below.
5370
5371 switch ( fMachineState )
5372 {
5373 case kIOPM_Finished:
5374 executePMRequest( request );
5375 break;
5376
5377 case kIOPM_OurChangeTellClientsPowerDown:
5378 // our change, was it vetoed?
5379 if (fDesiredPowerState > fHeadNoteState)
5380 {
5381 PM_DEBUG("%s: idle cancel\n", fName);
5382 fDoNotPowerDown = true;
5383 }
5384 if (!fDoNotPowerDown)
5385 {
5386 // no, we can continue
5387 OurChangeTellClientsPowerDown();
5388 }
5389 else
5390 {
5391 // yes, rescind the warning
5392 tellNoChangeDown(fHeadNoteState);
5393 // mark the change note un-actioned
5394 fHeadNoteFlags |= IOPMNotDone;
5395 // and we're done
5396 all_done();
5397 }
5398 break;
5399
5400 case kIOPM_OurChangeTellPriorityClientsPowerDown:
5401 OurChangeTellPriorityClientsPowerDown();
5402 break;
5403
5404 case kIOPM_OurChangeNotifyInterestedDriversWillChange:
5405 OurChangeNotifyInterestedDriversWillChange();
5406 break;
5407
5408 case kIOPM_OurChangeSetPowerState:
5409 OurChangeSetPowerState();
5410 break;
5411
5412 case kIOPM_OurChangeWaitForPowerSettle:
5413 OurChangeWaitForPowerSettle();
5414 break;
5415
5416 case kIOPM_OurChangeNotifyInterestedDriversDidChange:
5417 OurChangeNotifyInterestedDriversDidChange();
5418 break;
5419
5420 case kIOPM_OurChangeFinish:
5421 OurChangeFinish();
5422 break;
5423
5424 case kIOPM_ParentDownTellPriorityClientsPowerDown:
5425 ParentDownTellPriorityClientsPowerDown();
5426 break;
5427
5428 case kIOPM_ParentDownNotifyInterestedDriversWillChange:
5429 ParentDownNotifyInterestedDriversWillChange();
5430 break;
5431
5432 case kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange:
5433 ParentDownNotifyDidChangeAndAcknowledgeChange();
5434 break;
5435
5436 case kIOPM_ParentDownSetPowerState:
5437 ParentDownSetPowerState();
5438 break;
5439
5440 case kIOPM_ParentDownWaitForPowerSettle:
5441 ParentDownWaitForPowerSettle();
5442 break;
5443
5444 case kIOPM_ParentDownAcknowledgeChange:
5445 ParentDownAcknowledgeChange();
5446 break;
5447
5448 case kIOPM_ParentUpSetPowerState:
5449 ParentUpSetPowerState();
5450 break;
5451
5452 case kIOPM_ParentUpWaitForSettleTime:
5453 ParentUpWaitForSettleTime();
5454 break;
5455
5456 case kIOPM_ParentUpNotifyInterestedDriversDidChange:
5457 ParentUpNotifyInterestedDriversDidChange();
5458 break;
5459
5460 case kIOPM_ParentUpAcknowledgePowerChange:
5461 ParentUpAcknowledgePowerChange();
5462 break;
5463
5464 case kIOPM_DriverThreadCallDone:
5465 if (fDriverCallReason == kDriverCallSetPowerState)
5466 notifyControllingDriverDone();
5467 else
5468 notifyInterestedDriversDone();
5469 break;
5470
5471 case kIOPM_NotifyChildrenDone:
5472 notifyChildrenDone();
5473 break;
5474
5475 default:
5476 IOPanic("servicePMWorkQueue: unknown machine state");
5477 }
5478
5479 fPMRequest = 0;
5480
5481 if (fMachineState == kIOPM_Finished)
5482 {
5483 //PM_TRACE("[%s] PM End: Request %p (type %02lx)\n",
5484 // getName(), request, request->getType());
5485 done = true;
5486 break;
5487 }
5488 }
1c79356b 5489
2d21ac55
A
5490 return done;
5491}
1c79356b 5492
1c79356b 5493//*********************************************************************************
2d21ac55
A
5494// [private] executePMRequest
5495//*********************************************************************************
5496
5497void IOService::executePMRequest( IOPMRequest * request )
5498{
5499 assert( kIOPM_Finished == fMachineState );
5500
5501 switch (request->getType())
5502 {
5503 case kIOPMRequestTypePMStop:
5504 handlePMstop( request );
5505 break;
5506
5507 case kIOPMRequestTypeAddPowerChild1:
5508 addPowerChild1( request );
5509 break;
5510
5511 case kIOPMRequestTypeAddPowerChild2:
5512 addPowerChild2( request );
5513 break;
5514
5515 case kIOPMRequestTypeAddPowerChild3:
5516 addPowerChild3( request );
5517 break;
5518
5519 case kIOPMRequestTypeRegisterPowerDriver:
5520 handleRegisterPowerDriver( request );
5521 break;
5522
5523 case kIOPMRequestTypeAdjustPowerState:
5524 adjustPowerState();
5525 break;
5526
5527 case kIOPMRequestTypeMakeUsable:
5528 handleMakeUsable( request );
5529 break;
5530
5531 case kIOPMRequestTypeTemporaryPowerClamp:
5532 fClampOn = true;
5533 handleMakeUsable( request );
5534 break;
5535
5536 case kIOPMRequestTypePowerDomainWillChange:
5537 handlePowerDomainWillChangeTo( request );
5538 break;
5539
5540 case kIOPMRequestTypePowerDomainDidChange:
5541 handlePowerDomainDidChangeTo( request );
5542 break;
5543
5544 case kIOPMRequestTypeChangePowerStateTo:
5545 handleChangePowerStateTo( request );
5546 break;
5547
5548 case kIOPMRequestTypeChangePowerStateToPriv:
5549 handleChangePowerStateToPriv( request );
5550 break;
5551
5552 case kIOPMRequestTypePowerOverrideOnPriv:
5553 case kIOPMRequestTypePowerOverrideOffPriv:
5554 handlePowerOverrideChanged( request );
5555 break;
5556
5557 case kIOPMRequestTypeActivityTickle:
5558 if (request)
5559 {
5560 bool setDeviceDesire = false;
5561
5562 if (request->fArg1)
5563 {
cf7d32b8
A
5564 // Power rise from activity tickle.
5565 unsigned long ticklePowerState = (unsigned long) request->fArg0;
5566 if ((fDeviceDesire < ticklePowerState) &&
5567 (ticklePowerState < fNumberOfPowerStates))
5568 {
2d21ac55 5569 setDeviceDesire = true;
cf7d32b8
A
5570 fIdleTimerMinPowerState = ticklePowerState;
5571 }
5572 }
5573 else if (fDeviceDesire > fIdleTimerMinPowerState)
2d21ac55 5574 {
cf7d32b8 5575 // Power drop from idle timer expiration.
2d21ac55
A
5576 request->fArg0 = (void *) (fDeviceDesire - 1);
5577 setDeviceDesire = true;
5578 }
5579
5580 if (setDeviceDesire)
5581 {
5582 // handleChangePowerStateToPriv() does not check the
5583 // request type, as long as the args are appropriate
5584 // for kIOPMRequestTypeChangePowerStateToPriv.
5585
5586 request->fArg1 = (void *) false;
5587 handleChangePowerStateToPriv( request );
5588 }
5589 }
5590 break;
5591
5592 default:
5593 IOPanic("executePMRequest: unknown request type");
5594 }
5595}
5596
5597//*********************************************************************************
5598// [private] servicePMReplyQueue
5599//*********************************************************************************
5600
5601bool IOService::servicePMReplyQueue( IOPMRequest * request, IOPMRequestQueue * queue )
5602{
5603 bool more = false;
5604
5605 assert( request && queue );
5606 assert( request->isReply() );
5607
5608 PM_TRACE("[A %02lx] %p [%p %s] State %ld\n",
5609 request->getType(), request, this, getName(), fMachineState);
5610
5611 switch ( request->getType() )
5612 {
5613 case kIOPMRequestTypeAllowPowerChange:
5614 case kIOPMRequestTypeCancelPowerChange:
5615 // Check if we are expecting this response.
5616 if (responseValid((unsigned long) request->fArg0, (int) request->fArg1))
5617 {
5618 if (kIOPMRequestTypeCancelPowerChange == request->getType())
5619 fDoNotPowerDown = true;
5620
5621 if (checkForDone())
5622 {
5623 stop_ack_timer();
5624 if ( fResponseArray )
5625 {
5626 fResponseArray->release();
5627 fResponseArray = NULL;
5628 }
5629 more = true;
5630 }
5631 }
5632 break;
5633
5634 case kIOPMRequestTypeAckPowerChange:
5635 more = handleAcknowledgePowerChange( request );
5636 break;
5637
5638 case kIOPMRequestTypeAckSetPowerState:
5639 if (fDriverTimer == -1)
5640 {
5641 // driver acked while setPowerState() call is in-flight.
5642 // take this ack, return value from setPowerState() is irrelevant.
5643 OUR_PMLog(kPMLogDriverAcknowledgeSet,
5644 (UInt32) this, fDriverTimer);
5645 fDriverTimer = 0;
5646 }
5647 else if (fDriverTimer > 0)
5648 {
5649 // expected ack, stop the timer
5650 stop_ack_timer();
5651
5652#if LOG_SETPOWER_TIMES
5653 uint64_t nsec = computeTimeDeltaNS(&fDriverCallStartTime);
5654 if (nsec > LOG_SETPOWER_TIMES)
5655 PM_DEBUG("%s::setPowerState(%p, %lu -> %lu) async took %d ms\n",
5656 fName, this, fCurrentPowerState, fHeadNoteState, NS_TO_MS(nsec));
5657#endif
5658 OUR_PMLog(kPMLogDriverAcknowledgeSet, (UInt32) this, fDriverTimer);
5659 fDriverTimer = 0;
5660 more = true;
5661 }
5662 else
5663 {
5664 // unexpected ack
5665 OUR_PMLog(kPMLogAcknowledgeErr4, (UInt32) this, 0);
5666 }
5667 break;
5668
5669 case kIOPMRequestTypeInterestChanged:
5670 handleInterestChanged( request );
5671 more = true;
5672 break;
5673
5674 default:
5675 IOPanic("servicePMReplyQueue: unknown reply type");
5676 }
5677
5678 releasePMRequest( request );
5679 return more;
5680}
5681
5682//*********************************************************************************
5683// IOPMRequest Class
5684//
5685// Requests from PM clients, and also used for inter-object messaging within PM.
5686//*********************************************************************************
5687
5688OSDefineMetaClassAndStructors( IOPMRequest, IOCommand );
5689
5690IOPMRequest * IOPMRequest::create( void )
5691{
5692 IOPMRequest * me = OSTypeAlloc(IOPMRequest);
5693 if (me && !me->init(0, kIOPMRequestTypeInvalid))
5694 {
5695 me->release();
5696 me = 0;
5697 }
5698 return me;
5699}
5700
5701bool IOPMRequest::init( IOService * target, IOOptionBits type )
5702{
5703 if (!IOCommand::init())
5704 return false;
5705
5706 fType = type;
5707 fTarget = target;
5708 fParent = 0;
5709 fChildCount = 0;
5710 fArg0 = fArg1 = fArg2 = 0;
5711
5712 if (fTarget)
5713 fTarget->retain();
5714
5715 return true;
5716}
5717
5718void IOPMRequest::reset( void )
5719{
5720 assert( fChildCount == 0 );
5721
5722 fType = kIOPMRequestTypeInvalid;
5723
5724 if (fParent)
5725 {
5726 fParent->fChildCount--;
5727 fParent = 0;
5728 }
5729
5730 if (fTarget)
5731 {
5732 fTarget->release();
5733 fTarget = 0;
5734 }
5735}
5736
5737//*********************************************************************************
5738// IOPMRequestQueue Class
1c79356b 5739//
2d21ac55
A
5740// Global queues. As PM-aware drivers load and unload, their IOPMWorkQueue's are
5741// created and deallocated. IOPMRequestQueue are created once and never released.
1c79356b 5742//*********************************************************************************
2d21ac55
A
5743
5744OSDefineMetaClassAndStructors( IOPMRequestQueue, IOEventSource );
5745
5746IOPMRequestQueue * IOPMRequestQueue::create( IOService * inOwner, Action inAction )
1c79356b 5747{
2d21ac55
A
5748 IOPMRequestQueue * me = OSTypeAlloc(IOPMRequestQueue);
5749 if (me && !me->init(inOwner, inAction))
5750 {
5751 me->release();
5752 me = 0;
5753 }
5754 return me;
5755}
1c79356b 5756
2d21ac55
A
5757bool IOPMRequestQueue::init( IOService * inOwner, Action inAction )
5758{
5759 if (!inAction || !IOEventSource::init(inOwner, (IOEventSourceAction)inAction))
1c79356b
A
5760 return false;
5761
2d21ac55
A
5762 queue_init(&fQueue);
5763 fLock = IOLockAlloc();
5764 return (fLock != 0);
5765}
1c79356b 5766
2d21ac55
A
5767void IOPMRequestQueue::free( void )
5768{
5769 if (fLock)
5770 {
5771 IOLockFree(fLock);
5772 fLock = 0;
5773 }
5774 return IOEventSource::free();
5775}
1c79356b 5776
2d21ac55
A
5777void IOPMRequestQueue::queuePMRequest( IOPMRequest * request )
5778{
5779 assert(request);
5780 IOLockLock(fLock);
5781 queue_enter(&fQueue, request, IOPMRequest *, fCommandChain);
5782 IOLockUnlock(fLock);
5783 if (workLoop) signalWorkAvailable();
5784}
1c79356b 5785
2d21ac55
A
5786void
5787IOPMRequestQueue::queuePMRequestChain( IOPMRequest ** requests, IOItemCount count )
5788{
5789 IOPMRequest * next;
5790
5791 assert(requests && count);
5792 IOLockLock(fLock);
5793 while (count--)
5794 {
5795 next = *requests;
5796 requests++;
5797 queue_enter(&fQueue, next, IOPMRequest *, fCommandChain);
5798 }
5799 IOLockUnlock(fLock);
5800 if (workLoop) signalWorkAvailable();
5801}
5802
5803bool IOPMRequestQueue::checkForWork( void )
5804{
5805 Action dqAction = (Action) action;
5806 IOPMRequest * request;
5807 IOService * target;
5808 bool more = false;
5809
5810 IOLockLock( fLock );
5811
5812 while (!queue_empty(&fQueue))
5813 {
5814 queue_remove_first( &fQueue, request, IOPMRequest *, fCommandChain );
5815 IOLockUnlock( fLock );
5816 target = request->getTarget();
5817 assert(target);
5818 more |= (*dqAction)( target, request, this );
5819 IOLockLock( fLock );
5820 }
5821
5822 IOLockUnlock( fLock );
5823 return more;
5824}
5825
5826void IOPMRequestQueue::signalWorkAvailable( void )
5827{
5828 IOEventSource::signalWorkAvailable();
5829}
5830
5831//*********************************************************************************
5832// IOPMWorkQueue Class
5833//
5834// Every object in the power plane that has handled a PM request, will have an
5835// instance of IOPMWorkQueue allocated for it.
5836//*********************************************************************************
1c79356b 5837
2d21ac55 5838OSDefineMetaClassAndStructors( IOPMWorkQueue, IOEventSource );
1c79356b 5839
2d21ac55
A
5840IOPMWorkQueue *
5841IOPMWorkQueue::create( IOService * inOwner, Action work, Action retire )
5842{
5843 IOPMWorkQueue * me = OSTypeAlloc(IOPMWorkQueue);
5844 if (me && !me->init(inOwner, work, retire))
5845 {
5846 me->release();
5847 me = 0;
5848 }
5849 return me;
5850}
5851
5852bool IOPMWorkQueue::init( IOService * inOwner, Action work, Action retire )
5853{
5854 if (!work || !retire ||
5855 !IOEventSource::init(inOwner, (IOEventSourceAction)0))
5856 return false;
5857
5858 queue_init(&fWorkQueue);
5859
5860 fWorkAction = work;
5861 fRetireAction = retire;
5862
5863 return true;
5864}
5865
5866void IOPMWorkQueue::queuePMRequest( IOPMRequest * request )
5867{
5868 assert( request );
5869 assert( onThread() );
5870
5871 gIOPMBusyCount++;
5872 queue_enter(&fWorkQueue, request, IOPMRequest *, fCommandChain);
5873 checkForWork();
5874}
5875
5876bool IOPMWorkQueue::checkForWork( void )
5877{
5878 IOPMRequest * request;
5879 IOService * target = (IOService *) owner;
5880 bool done;
5881
5882 while (!queue_empty(&fWorkQueue))
5883 {
5884 request = (IOPMRequest *) queue_first(&fWorkQueue);
5885 assert(request->getTarget() == target);
5886 if (request->hasChildRequest()) break;
5887 done = (*fWorkAction)( target, request, this );
5888 if (!done) break;
5889
5890 assert(gIOPMBusyCount > 0);
5891 if (gIOPMBusyCount) gIOPMBusyCount--;
5892 queue_remove_first(&fWorkQueue, request, IOPMRequest *, fCommandChain);
5893 (*fRetireAction)( target, request, this );
5894 }
5895
5896 return false;
5897}
5898
5899OSDefineMetaClassAndStructors(IOServicePM, OSObject)
5900
5901//*********************************************************************************
5902// serialize
5903//
5904// Serialize IOServicePM for debugging.
5905//*********************************************************************************
5906
5907static void
5908setPMProperty( OSDictionary * dict, const char * key, unsigned long value )
5909{
5910 OSNumber * num = OSNumber::withNumber(value, sizeof(value) * 8);
5911 if (num)
5912 {
5913 dict->setObject(key, num);
5914 num->release();
5915 }
1c79356b
A
5916}
5917
2d21ac55
A
5918bool IOServicePM::serialize( OSSerialize * s ) const
5919{
5920 OSDictionary * dict;
5921 bool ok = false;
5922
5923 dict = OSDictionary::withCapacity(8);
5924 if (dict)
5925 {
5926 setPMProperty( dict, "CurrentPowerState", CurrentPowerState );
5927 if (DesiredPowerState != CurrentPowerState)
5928 setPMProperty( dict, "DesiredPowerState", DesiredPowerState );
5929 if (kIOPM_Finished != MachineState)
5930 setPMProperty( dict, "MachineState", MachineState );
5931 if (ChildrenDesire)
5932 setPMProperty( dict, "ChildrenPowerState", ChildrenDesire );
5933 if (DeviceDesire)
5934 setPMProperty( dict, "DeviceChangePowerState", DeviceDesire );
5935 if (DriverDesire)
5936 setPMProperty( dict, "DriverChangePowerState", DriverDesire );
5937 if (DeviceOverrides)
5938 dict->setObject( "PowerOverrideOn", kOSBooleanTrue );
5939
5940 ok = dict->serialize(s);
5941 dict->release();
5942 }
5943
5944 return ok;
5945}