2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 #include <IOKit/IOService.h>
24 #include <IOKit/IOLib.h>
25 #include <IOKit/IOCommandQueue.h>
26 #include <IOKit/IOCommandGate.h>
27 #include <IOKit/IOTimerEventSource.h>
28 #include <IOKit/IOWorkLoop.h>
29 #include <IOKit/IOPlatformExpert.h>
30 #include <IOKit/assert.h>
31 #include <IOKit/IOMessage.h>
32 #include <IOKit/pwr_mgt/IOPMinformee.h>
33 #include "IOKit/pwr_mgt/IOPMinformeeList.h"
34 #include "IOKit/pwr_mgt/IOPMchangeNoteList.h"
35 #include "IOKit/pwr_mgt/IOPMlog.h"
36 #include "IOKit/pwr_mgt/IOPowerConnection.h"
38 static void ack_timer_expired(thread_call_param_t
);
39 static void settle_timer_expired(thread_call_param_t
);
40 void PMreceiveCmd ( OSObject
*, void *, void *, void *, void * );
41 static void PM_idle_timer_expired(OSObject
*, IOTimerEventSource
*);
42 static void c_PM_Clamp_Timer_Expired (OSObject
* client
,IOTimerEventSource
*);
43 void tellAppWithResponse ( OSObject
* object
, void * context
);
44 void tellClientWithResponse ( OSObject
* object
, void * context
);
45 void tellClient ( OSObject
* object
, void * context
);
46 IOReturn
serializedAllowPowerChange ( OSObject
*, void *, void *, void *, void *);
47 IOReturn
serializedCancelPowerChange ( OSObject
*, void *, void *, void *, void *);
49 extern const IORegistryPlane
* gIOPowerPlane
;
52 // and there's 1000 nanoseconds in a microsecond:
53 #define ns_per_us 1000
56 // The current change note is processed by a state machine.
57 // Inputs are acks from interested parties, ack from the controlling driver,
58 // ack timeouts, settle timeout, and powerStateDidChange from the parent.
59 // These are the states:
62 IOPMour_prechange_03
= 1,
82 struct context
{ // used for applyToInterested
83 OSArray
* responseFlags
;
86 UInt32 maxTimeRequested
;
92 // five minutes in microseconds
93 #define FIVE_MINUTES 5*60*1000000
94 #define k15seconds 15*1000000
97 There are two different kinds of power state changes. One is initiated by a subclassed device object which has either
98 decided to change power state, or its controlling driver has suggested it, or some other driver wants to use the
99 idle device and has asked it to become usable. The second kind of power state change is initiated by the power
100 domain parent. The two are handled slightly differently.
102 There is a queue of so-called change notifications, or change notes for short. Usually the queue is empty, and when
103 it isn't, usually there is one change note in it, but since it's possible to have more than one power state change pending
104 at one time, a queue is implemented. Example: the subclass device decides it's idle and initiates a change to a lower
105 power state. This causes interested parties to be notified, but they don't all acknowledge right away. This causes the
106 change note to sit in the queue until all the acks are received. During this time, the device decides it isn't idle anymore and
107 wants to raise power back up again. This change can't be started, however, because the previous one isn't complete yet,
108 so the second one waits in the queue. During this time, the parent decides to lower or raise the power state of the entire
109 power domain and notifies the device, and that notification goes into the queue, too, and can't be actioned until the
112 This is how a power change initiated by the subclass device is handled:
113 First, all interested parties are notified of the change via their powerStateWillChangeTo method. If they all don't
114 acknowledge via return code, then we have to wait. If they do, or when they finally all acknowledge via our
115 acknowledgePowerChange method, then we can continue. We call the controlling driver, instructing it to change to
116 the new state. Then we wait for power to settle. If there is no settling-time, or after it has passed, we notify
117 interested parties again, this time via their powerStateDidChangeTo methods. When they have all acked, we're done.
118 If we lowered power and don't need the power domain to be in its current power state, we suggest to the parent that
119 it lower the power domain state.
121 This is how a change to a lower power domain state initiated by the parent is handled:
122 First, we figure out what power state we will be in when the new domain state is reached. Then all interested parties are
123 notified that we are moving to that new state. When they have acknowledged, we call the controlling driver to assume
124 that state and we wait for power to settle. Then we acknowledge our preparedness to our parent. When all its interested
125 parties have acknowledged, it lowers power and then notifies its interested parties again. When we get this call, we notify
126 our interested parties that the power state has changed, and when they have all acknowledged, we're done.
128 This is how a change to a higher power domain state initiated by the parent is handled:
129 We figure out what power state we will be in when the new domain state is reached. If it is different from our current
130 state we acknowledge the parent. When all the parent's interested parties have acknowledged, it raises power in the
131 domain and waits for power to settle. Then it notifies everyone that the new state has been reached. When we get this call,
132 we call the controlling driver, instructing it to assume the new state, and wait for power to settle. Then we notify our interested
133 parties. When they all acknowledge we are done.
135 In either of the two cases above, it is possible that we will not be changing state even though the domain is. Examples:
136 A change to a lower domain state may not affect us because we are already in a low enough state, and
137 We will not take advantage of a change to a higher domain state, because we have no need of the higher power.
138 In such a case, there is nothing to do but acknowledge the parent. So when the parent calls our powerDomainWillChange
139 method, and we decide that we will not be changing state, we merely acknowledge the parent, via return code, and wait.
140 When the parent subsequently calls powerStateDidChange, we acknowledge again via return code, and the change is complete.
142 Power state changes are processed in a state machine, and since there are four varieties of power state changes, there are
143 four major paths through the state machine:
145 The fourth is nearly trivial. In this path, the parent is changing the domain state, but we are not changing the device state.
146 The change starts when the parent calls powerDomainWillChange. All we do is acknowledge the parent.
147 When the parent calls powerStateDidChange, we acknowledge the parent again, and we're done.
149 The first is fairly simple. It starts when a power domain child calls requestPowerDomainState and we decide to change power states
150 to accomodate the child, or if our power-controlling driver calls changePowerStateTo, or if some other driver which is using our
151 device calls makeUsable, or if a subclassed object calls changePowerStateToPriv. These are all power changes initiated by us, not
152 forced upon us by the parent. We start by notifying interested parties. If they all acknowledge via return code, we can go
153 on to state "our_prechange_1". Otherwise, we start the ack timer and wait for the stragglers to acknowlege by calling
154 acknowledgePowerChange. We move on to state "our_prechange_1" when all the stragglers have acknowledged,
155 or when the ack timer expires on all those which didn't acknowledge. In "our_prechange_1" we call the power-controlling
156 driver to change the power state of the hardware. If it returns saying it has done so, we go on to state "our_prechange_2".
157 Otherwise, we have to wait for it, so we set the ack timer and wait. When it calls acknowledgeSetPowerState, or when the
158 ack timer expires, we go on. In "our_prechange_2", we look in the power state array to see if there is any settle time required
159 when changing from our current state to the new state. If not, we go right away to "our_prechange_3". Otherwise, we
160 set the settle timer and wait. When it expires, we move on. In "our_prechange_3" state, we notify all our interested parties
161 via their powerStateDidChange methods that we have finished changing power state. If they all acknowledge via return
162 code, we move on to "our_prechange_4". Otherwise we set the ack timer and wait. When they have all acknowledged, or
163 when the ack timer has expired for those that didn't, we move on to "our_prechange_4", where we remove the used
164 change note from the head of the queue and start the next one if one exists.
166 Parent-initiated changes are more complex in the state machine. First, power going up and power going down are handled
167 differently, so they have different paths throught the state machine. Second, we can acknowledge the parent's notification
168 in two different ways, so each of the parent paths is really two.
170 When the parent calls our powerDomainWillChange method, notifying us that it will lower power in the domain, we decide
171 what state that will put our device in. Then we embark on the state machine path "IOPMparent_down_1"
172 and "IOPMparent_down_2", in which we notify interested parties of the upcoming change, instruct our driver to make
173 the change, check for settle time, and notify interested parties of the completed change. If we get to the end of this path without
174 stalling due to an interested party which didn't acknowledge via return code, due to the controlling driver not able to change
175 state right away, or due to a non-zero settling time, then we return IOPMAckImplied to the parent, and we're done with the change.
176 If we do stall in any of those states, we return IOPMWillAckLater to the parent and enter the parallel path "IOPMparent_down_4"
177 "IOPMparent_down_5", and "IOPMparent_down_3", where we continue with the same processing, except that at the end we
178 acknowledge the parent explicitly via acknowledgePowerChange, and we're done with the change.
179 Then when the parent calls us at powerStateDidChange we acknowledging via return code, because we have already made
180 the power change. In any case, when we are done we remove the used change note from the head of the queue and start on the next one.
182 The case of the parent raising power in the domain is handled similarly in that there are parallel paths, one for no-stall
183 that ends in implicit acknowleging the parent, and one that has stalled at least once that ends in explicit acknowledging
184 the parent. This case is different, though in that our device changes state in the second half, after the parent calls
185 powerStateDidChange rather than before, as in the power-lowering case.
187 When the parent calls our powerDomainWillChange method, notifying us that it will raise power in the domain, we acknowledge
188 via return code, because there's really nothing we can do until the power is actually raised in the domain.
189 When the parent calls us at powerStateDidChange, we start by notifying our interested parties. If they all acknowledge via return code,
190 we go on to" IOPMparent_up_1" to instruct the driver to raise its power level. After that, we check for any
191 necessary settling time in "IOPMparent_up_2", and we notify all interested parties that power has changed
192 in "IOPMparent_up_3". If none of these operations stall, we acknowledge the parent via return code, release
193 the change note, and start the next, if there is one. If one of them does stall, we enter the parallel path "IOPMparent_up_0",
194 "IOPMparent_up_4", "IOPMparent_up_5", and "IOPMparent_up_6", which ends with
195 our explicit acknowledgement to the parent.
200 const char priv_key
[ ] = "Power Management private data";
201 const char prot_key
[ ] = "Power Management protected data";
204 void IOService::PMinit ( void )
206 if ( ! initialized
) {
208 pm_vars
= new IOPMprot
; // make space for our variables
213 setProperty(prot_key
, (OSObject
*) pm_vars
); // add these to the properties
214 setProperty(priv_key
, (OSObject
*) priv
);
217 pm_vars
->theNumberOfPowerStates
= 0; // then initialize them
218 priv
->we_are_root
= false;
219 pm_vars
->theControllingDriver
= NULL
;
220 priv
->our_lock
= IOLockAlloc();
221 priv
->flags_lock
= IOLockAlloc();
222 priv
->interestedDrivers
= new IOPMinformeeList
;
223 priv
->interestedDrivers
->initialize();
224 priv
->changeList
= new IOPMchangeNoteList
;
225 priv
->changeList
->initialize();
226 pm_vars
->aggressiveness
= 0;
227 for (unsigned int i
= 0; i
<= kMaxType
; i
++) {
228 pm_vars
->current_aggressiveness_values
[i
] = 0;
229 pm_vars
->current_aggressiveness_valid
[i
] = false;
231 pm_vars
->myCurrentState
= 0;
232 priv
->imminentState
= 0;
234 priv
->ourDesiredPowerState
= 0;
235 pm_vars
->parentsCurrentPowerFlags
= 0;
236 pm_vars
->maxCapability
= 0;
237 priv
->driverDesire
= 0;
238 priv
->deviceDesire
= 0;
239 priv
->initial_change
= true;
240 priv
->need_to_become_usable
= false;
241 priv
->previousRequest
= 0;
242 priv
->device_overrides
= false;
243 priv
->machine_state
= IOPMfinished
;
244 pm_vars
->commandQueue
= NULL
;
245 priv
->timerEventSrc
= NULL
;
246 priv
->clampTimerEventSrc
= NULL
;
247 pm_vars
->PMworkloop
= NULL
;
248 priv
->activityLock
= NULL
;
249 pm_vars
->ourName
= getName();
250 pm_vars
->thePlatform
= getPlatform();
251 pm_vars
->parentsKnowState
= false;
252 assert( pm_vars
->thePlatform
!= 0 );
253 priv
->clampOn
= false;
254 pm_vars
->serialNumber
= 0;
255 pm_vars
->responseFlags
= NULL
;
256 pm_vars
->doNotPowerDown
= true;
257 pm_vars
->PMcommandGate
= NULL
;
258 priv
->ackTimer
= thread_call_allocate((thread_call_func_t
)ack_timer_expired
, (thread_call_param_t
)this);
259 priv
->settleTimer
= thread_call_allocate((thread_call_func_t
)settle_timer_expired
, (thread_call_param_t
)this);
265 //*********************************************************************************
268 // Free up the data created in PMinit.
269 //*********************************************************************************
270 void IOService::PMstop ( void )
274 IOPowerConnection
* connection
;
278 removeProperty(prot_key
); // remove the properties
279 removeProperty(priv_key
);
281 iter
= getParentIterator(gIOPowerPlane
); // detach parents
284 while ( (next
= iter
->getNextObject()) ) {
285 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
286 ((IOService
*)(connection
->getParentEntry(gIOPowerPlane
)))->removePowerChild(connection
);
291 detachAbove( gIOPowerPlane
); // detach IOConnections
293 pm_vars
->parentsKnowState
= false; // no more power state changes
296 // This loop is insufficient. Currently only leaf nodes are removed, and it's not clear today what
297 // it means to remove a subtree from the tree. Should the IOPowerConnection at the top of it stay
298 // or go? Should its child be notified of a change in the domain state?
300 iter
= getChildIterator(gIOPowerPlane
); // detach children
303 while ( (next
= iter
->getNextObject()) ) {
304 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
305 removePowerChild(connection
);
312 if ( priv
->clampTimerEventSrc
!= NULL
) {
313 getPMworkloop()->removeEventSource(priv
->clampTimerEventSrc
);
314 priv
->clampTimerEventSrc
->release();
315 priv
->clampTimerEventSrc
= NULL
;
317 if ( priv
->timerEventSrc
!= NULL
) {
318 pm_vars
->PMworkloop
->removeEventSource(priv
->timerEventSrc
);
319 priv
->timerEventSrc
->release();
320 priv
->timerEventSrc
= NULL
;
322 thread_call_free(priv
->settleTimer
);
323 thread_call_free(priv
->ackTimer
);
325 priv
->interestedDrivers
->release(); // remove lists
326 priv
->changeList
->release();
327 pm_vars
->release(); // remove the instance variables
334 //*********************************************************************************
337 // A policy-maker calls its nub here when initializing, to be attached into
338 // the power management hierarchy. The default function is to call the
339 // platform expert, which knows how to do it. This method is overridden
340 // by a nub subclass which may either know how to do it, or may need
341 // to take other action.
343 // This may be the only "power management" method used in a nub,
344 // meaning it may not be initialized for power management.
345 //*********************************************************************************
346 void IOService::joinPMtree ( IOService
* driver
)
348 IOPlatformExpert
* thePlatform
;
350 thePlatform
= getPlatform();
351 assert(thePlatform
!= 0 );
352 thePlatform
->PMRegisterDevice(this,driver
);
356 //*********************************************************************************
359 // Power Managment is informing us that we are the root power domain.
360 // The only difference between us and any other power domain is that
361 // we have no parent and therefore never call it.
362 //*********************************************************************************
363 IOReturn
IOService::youAreRoot ( void )
365 priv
-> we_are_root
= true;
366 pm_vars
->parentsKnowState
= true;
367 attachToParent( getRegistryRoot(),gIOPowerPlane
);
373 //*********************************************************************************
376 // Power Management is informing us who our parent is.
377 // If we have a controlling driver, find out, given our newly-informed
378 // power domain state, what state it would be in, and then tell it
379 // to assume that state.
380 //*********************************************************************************
381 IOReturn
IOService::setPowerParent ( IOPowerConnection
* theParent
, bool stateKnown
, IOPMPowerFlags currentState
)
385 IOPowerConnection
* connection
;
386 unsigned long tempDesire
;
388 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogSetParent
,stateKnown
,currentState
);
390 if ( stateKnown
&& ((pm_vars
->PMworkloop
== NULL
) || (pm_vars
->PMcommandGate
== NULL
)) ) {
391 getPMworkloop(); // we have a path to the root
392 if ( pm_vars
->PMworkloop
!= NULL
) { // find out the workloop
393 if ( pm_vars
->PMcommandGate
== NULL
) { // and make our command gate
394 pm_vars
->PMcommandGate
= IOCommandGate::commandGate((OSObject
*)this);
395 if ( pm_vars
->PMcommandGate
!= NULL
) {
396 pm_vars
->PMworkloop
->addEventSource(pm_vars
->PMcommandGate
);
402 theParent
->setParentCurrentPowerFlags(currentState
); // set our connection data
403 theParent
->setParentKnowsState(stateKnown
);
405 pm_vars
->parentsKnowState
= true; // combine parent knowledge
406 pm_vars
->parentsCurrentPowerFlags
= 0;
408 iter
= getParentIterator(gIOPowerPlane
);
411 while ( (next
= iter
->getNextObject()) ) {
412 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
413 pm_vars
->parentsKnowState
&= connection
->parentKnowsState();
414 pm_vars
->parentsCurrentPowerFlags
|= connection
->parentCurrentPowerFlags();
420 if ( (pm_vars
->theControllingDriver
!= NULL
) &&
421 (pm_vars
->parentsKnowState
) ) {
422 pm_vars
->maxCapability
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(pm_vars
->parentsCurrentPowerFlags
);
423 tempDesire
= priv
->deviceDesire
; // initially change into the state we are already in
424 priv
->deviceDesire
= pm_vars
->theControllingDriver
->initialPowerStateForDomainState(pm_vars
->parentsCurrentPowerFlags
);
426 priv
->deviceDesire
= tempDesire
; // put this back like before
432 //*********************************************************************************
435 // Power Management is informing us who our children are.
436 //*********************************************************************************
437 IOReturn
IOService::addPowerChild ( IOService
* theChild
)
439 IOPowerConnection
* connection
;
442 if ( ! initialized
) {
443 return IOPMNotYetInitialized
; // we're not a power-managed IOService
446 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAddChild
,0,0);
448 connection
= new IOPowerConnection
; // make a nub
451 connection
->start(this);
453 attachToChild( connection
,gIOPowerPlane
); // connect it up
454 connection
->attachToChild( theChild
,gIOPowerPlane
);
455 connection
->release();
457 if ( (pm_vars
->theControllingDriver
== NULL
) || // tell it the current state of the power domain
458 ! (inPlane(gIOPowerPlane
)) ||
459 ! (pm_vars
->parentsKnowState
) ) {
460 theChild
->setPowerParent(connection
,false,0);
461 if ( inPlane(gIOPowerPlane
) ) {
462 for (i
= 0; i
<= kMaxType
; i
++) {
463 if ( pm_vars
->current_aggressiveness_valid
[i
] ) {
464 theChild
->setAggressiveness (i
, pm_vars
->current_aggressiveness_values
[i
]);
470 theChild
->setPowerParent(connection
,true,pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].outputPowerCharacter
);
471 for (i
= 0; i
<= kMaxType
; i
++) {
472 if ( pm_vars
->current_aggressiveness_valid
[i
] ) {
473 theChild
->setAggressiveness (i
, pm_vars
->current_aggressiveness_values
[i
]);
476 add_child_to_active_change(connection
); // catch it up if change is in progress
483 //*********************************************************************************
486 //*********************************************************************************
487 IOReturn
IOService::removePowerChild ( IOPowerConnection
* theChild
)
489 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRemoveChild
,0,0);
491 detachFromChild(theChild
,gIOPowerPlane
); // remove the departing child
493 if ( (pm_vars
->theControllingDriver
== NULL
) || // if not fully initialized
494 ! (inPlane(gIOPowerPlane
)) ||
495 ! (pm_vars
->parentsKnowState
) ) {
496 return IOPMNoErr
; // we can do no more
499 changeState(); // change state if we can now tolerate lower power
505 //*********************************************************************************
506 // registerPowerDriver
508 // A driver has called us volunteering to control power to our device.
509 // If the power state array it provides is richer than the one we already
510 // know about (supplied by an earlier volunteer), then accept the offer.
511 // Notify all interested parties of our power state, which we now know.
512 //*********************************************************************************
514 IOReturn
IOService::registerPowerDriver ( IOService
* controllingDriver
, IOPMPowerState
* powerStates
, unsigned long numberOfStates
)
517 unsigned long tempDesire
;
519 if ( (numberOfStates
> pm_vars
->theNumberOfPowerStates
) && (numberOfStates
> 1) ) {
520 if ( priv
->changeList
->currentChange() == -1 ) {
521 if ( controllingDriver
!= NULL
) {
522 if ( numberOfStates
<= IOPMMaxPowerStates
) {
523 switch ( powerStates
[0].version
) {
525 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriver
,
526 (unsigned long)numberOfStates
, (unsigned long)powerStates
[0].version
);
527 for ( i
= 0; i
< numberOfStates
; i
++ ) {
528 pm_vars
->thePowerStates
[i
] = powerStates
[i
];
532 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriver
,
533 (unsigned long) numberOfStates
,(unsigned long) powerStates
[0].version
);
534 for ( i
= 0; i
< numberOfStates
; i
++ ) {
535 pm_vars
->thePowerStates
[i
].version
= powerStates
[i
].version
;
536 pm_vars
->thePowerStates
[i
].capabilityFlags
= powerStates
[i
].capabilityFlags
;
537 pm_vars
->thePowerStates
[i
].outputPowerCharacter
= powerStates
[i
].outputPowerCharacter
;
538 pm_vars
->thePowerStates
[i
].inputPowerRequirement
= powerStates
[i
].inputPowerRequirement
;
539 pm_vars
->thePowerStates
[i
].staticPower
= powerStates
[i
].staticPower
;
540 pm_vars
->thePowerStates
[i
].unbudgetedPower
= powerStates
[i
].unbudgetedPower
;
541 pm_vars
->thePowerStates
[i
].powerToAttain
= powerStates
[i
].powerToAttain
;
542 pm_vars
->thePowerStates
[i
].timeToAttain
= powerStates
[i
].timeToAttain
;
543 pm_vars
->thePowerStates
[i
].settleUpTime
= powerStates
[i
].settleUpTime
;
544 pm_vars
->thePowerStates
[i
].timeToLower
= powerStates
[i
].timeToLower
;
545 pm_vars
->thePowerStates
[i
].settleDownTime
= powerStates
[i
].settleDownTime
;
546 pm_vars
->thePowerStates
[i
].powerDomainBudget
= powerStates
[i
].powerDomainBudget
;
550 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr1
,
551 (unsigned long)powerStates
[0].version
,0);
555 pm_vars
->myCharacterFlags
= 0; // make a mask of all the character bits we know about
556 for ( i
= 0; i
< numberOfStates
; i
++ ) {
557 pm_vars
->myCharacterFlags
|= pm_vars
->thePowerStates
[i
].outputPowerCharacter
;
560 pm_vars
->theNumberOfPowerStates
= numberOfStates
;
561 pm_vars
->theControllingDriver
= controllingDriver
;
562 if ( priv
->interestedDrivers
->findItem(controllingDriver
) == NULL
) { // register it as interested
563 registerInterestedDriver (controllingDriver
); // unless already done
565 if ( priv
->need_to_become_usable
) {
566 priv
->need_to_become_usable
= false;
567 priv
->deviceDesire
= pm_vars
->theNumberOfPowerStates
- 1;
570 if ( inPlane(gIOPowerPlane
) &&
571 (pm_vars
->parentsKnowState
) ) {
572 pm_vars
->maxCapability
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(pm_vars
->parentsCurrentPowerFlags
);
573 tempDesire
= priv
->deviceDesire
; // initially change into the state we are already in
574 priv
->deviceDesire
= pm_vars
->theControllingDriver
->initialPowerStateForDomainState(pm_vars
->parentsCurrentPowerFlags
);
576 priv
->deviceDesire
= tempDesire
; // put this back like before
580 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr2
,(unsigned long)numberOfStates
,0);
584 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr4
,0,0);
589 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr5
,(unsigned long)numberOfStates
,0);
594 //*********************************************************************************
595 // registerInterestedDriver
597 // Add the caller to our list of interested drivers and return our current
598 // power state. If we don't have a power-controlling driver yet, we will
599 // call this interested driver again later when we do get a driver and find
600 // out what the current power state of the device is.
601 //*********************************************************************************
603 IOPMPowerFlags
IOService::registerInterestedDriver ( IOService
* theDriver
)
605 IOPMinformee
* newInformee
;
606 IOPMPowerFlags futureCapability
;
608 if (theDriver
== NULL
) {
612 newInformee
= new IOPMinformee
; // make new driver node
613 newInformee
->initialize(theDriver
);
614 priv
->interestedDrivers
->addToList(newInformee
); // add it to list of drivers
616 if ( (pm_vars
->theControllingDriver
== NULL
) ||
617 ! (inPlane(gIOPowerPlane
)) ||
618 ! (pm_vars
->parentsKnowState
) ) {
619 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInterestedDriver
,IOPMNotPowerManaged
,0);
620 return IOPMNotPowerManaged
; // can't tell it a state yet
623 switch (priv
->machine_state
) { // can we notify new driver of a change in progress?
624 case IOPMour_prechange_1
:
625 case IOPMour_prechange_4
:
626 case IOPMparent_down_4
:
627 case IOPMparent_down_6
:
628 case IOPMparent_up_0
:
629 case IOPMparent_up_6
:
630 futureCapability
= priv
->head_note_capabilityFlags
; // yes, remember what we tell it
631 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInterestedDriver
,(unsigned long)futureCapability
,1);
632 add_driver_to_active_change(newInformee
); // notify it
633 return futureCapability
; // and return the same thing
636 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInterestedDriver
,
637 (unsigned long) pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
,2);
638 return pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
; // no, return current capability
642 //*********************************************************************************
643 // deRegisterInterestedDriver
645 //*********************************************************************************
646 IOReturn
IOService::deRegisterInterestedDriver ( IOService
* theDriver
)
648 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRemoveDriver
,0,0);
650 priv
->interestedDrivers
->removeFromList(theDriver
); // remove the departing driver
656 //*********************************************************************************
657 // acknowledgePowerChange
659 // After we notified one of the interested drivers or a power-domain child
660 // of an impending change in power, it has called to say it is now
661 // prepared for the change. If this object is the last to
662 // acknowledge this change, we take whatever action we have been waiting
664 // That may include acknowledging to our parent. In this case, we do it
665 // last of all to insure that this doesn't cause the parent to call us some-
666 // where else and alter data we are relying on here (like the very existance
667 // of a "current change note".)
668 //*********************************************************************************
670 IOReturn
IOService::acknowledgePowerChange ( IOService
* whichObject
)
672 IOPMinformee
* ackingObject
;
674 ackingObject
= priv
->interestedDrivers
->findItem(whichObject
); // one of our interested drivers?
675 if ( ackingObject
== NULL
) {
676 if ( ! isChild(whichObject
,gIOPowerPlane
) ) {
677 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr1
,0,0);
678 kprintf("errant driver: %s\n",whichObject
->getName());
679 return IOPMNoErr
; // no, just return
682 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChildAcknowledge
,0,0);
686 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogDriverAcknowledge
,0,0);
689 if (! acquire_lock() ) {
693 if (priv
->head_note_pendingAcks
!= 0 ) { // yes, make sure we're expecting acks
694 if ( ackingObject
!= NULL
) { // it's an interested driver
695 if ( ackingObject
->timer
!= 0 ) { // make sure we're expecting this ack
696 ackingObject
->timer
= 0; // mark it acked
697 priv
->head_note_pendingAcks
-= 1; // that's one fewer to worry about
698 if ( priv
->head_note_pendingAcks
== 0 ) { // is that the last?
699 stop_ack_timer(); // yes, stop the timer
700 IOUnlock(priv
->our_lock
);
701 all_acked(); // and now we can continue
706 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr2
,0,0); // this driver has already acked
707 kprintf("errant driver: %s\n",whichObject
->getName());
710 else { // it's a child
711 priv
->head_note_pendingAcks
-= 1; // that's one fewer to worry about
712 if ( priv
->head_note_pendingAcks
== 0 ) { // is that the last?
713 stop_ack_timer(); // yes, stop the timer
714 IOUnlock(priv
->our_lock
);
715 all_acked(); // and now we can continue
721 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr3
,0,0); // not expecting anybody to ack
722 kprintf("errant driver: %s\n",whichObject
->getName());
724 IOUnlock(priv
->our_lock
);
728 //*********************************************************************************
729 // acknowledgeSetPowerState
731 // After we instructed our controlling driver to change power states,
732 // it has called to say it has finished doing so.
733 // We continue to process the power state change.
734 //*********************************************************************************
736 IOReturn
IOService::acknowledgeSetPowerState ( void )
738 if (! acquire_lock() ) {
741 if ( priv
->driver_timer
== -1 ) {
742 priv
->driver_timer
= 0; // driver is acking instead of using return code
745 if ( priv
->driver_timer
> 0 ) { // are we expecting this?
746 stop_ack_timer(); // yes, stop the timer
747 priv
->driver_timer
= 0;
748 IOUnlock(priv
->our_lock
);
749 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogDriverAcknowledgeSet
,0,0);
754 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr4
,0,0); // no
757 IOUnlock(priv
->our_lock
);
762 //*********************************************************************************
765 // Either the controlling driver has called acknowledgeSetPowerState
766 // or the acknowledgement timer has expired while waiting for that.
767 // We carry on processing the current change note.
768 //*********************************************************************************
770 void IOService::driver_acked ( void )
772 switch (priv
->machine_state
) {
773 case IOPMour_prechange_2
:
776 case IOPMparent_down_5
:
779 case IOPMparent_up_4
:
786 //*********************************************************************************
787 // powerDomainWillChangeTo
789 // Called by the power-hierarchy parent notifying of a new power state
790 // in the power domain.
791 // We enqueue a parent power-change to our queue of power changes.
792 // This may or may not cause us to change power, depending on what
793 // kind of change is occuring in the domain.
794 //*********************************************************************************
796 IOReturn
IOService::powerDomainWillChangeTo ( IOPMPowerFlags newPowerStateFlags
, IOPowerConnection
* whichParent
)
800 IOPowerConnection
* connection
;
801 unsigned long newStateNumber
;
802 IOPMPowerFlags combinedPowerFlags
;
804 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogWillChange
,(unsigned long)newPowerStateFlags
,0);
806 if ( ! inPlane(gIOPowerPlane
) ) {
807 return IOPMAckImplied
; // somebody goofed
810 if ( (pm_vars
->PMworkloop
== NULL
) || (pm_vars
->PMcommandGate
== NULL
) ) {
811 getPMworkloop(); // we have a path to the root,
812 if ( pm_vars
->PMworkloop
!= NULL
) { // so find out the workloop
813 if ( pm_vars
->PMcommandGate
== NULL
) { // and make our command gate
814 pm_vars
->PMcommandGate
= IOCommandGate::commandGate((OSObject
*)this);
815 if ( pm_vars
->PMcommandGate
!= NULL
) {
816 pm_vars
->PMworkloop
->addEventSource(pm_vars
->PMcommandGate
);
822 combinedPowerFlags
= 0; // combine parents' power states
824 iter
= getParentIterator(gIOPowerPlane
);
827 while ( (next
= iter
->getNextObject()) ) {
828 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
829 if ( connection
== whichParent
){
830 combinedPowerFlags
|= newPowerStateFlags
;
833 combinedPowerFlags
|= connection
->parentCurrentPowerFlags();
840 if ( pm_vars
->theControllingDriver
== NULL
) { // we can't take any more action
841 return IOPMAckImplied
;
843 newStateNumber
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(combinedPowerFlags
);
844 return enqueuePowerChange(IOPMParentInitiated
| IOPMDomainWillChange
, newStateNumber
,combinedPowerFlags
,whichParent
); //make the change
848 //*********************************************************************************
849 // powerDomainDidChangeTo
851 // Called by the power-hierarchy parent after the power state of the power domain
852 // has settled at a new level.
853 // We enqueue a parent power-change to our queue of power changes.
854 // This may or may not cause us to change power, depending on what
855 // kind of change is occuring in the domain.
856 //*********************************************************************************
858 IOReturn
IOService::powerDomainDidChangeTo ( IOPMPowerFlags newPowerStateFlags
, IOPowerConnection
* whichParent
)
862 IOPowerConnection
* connection
;
863 unsigned long newStateNumber
;
865 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogDidChange
,newPowerStateFlags
,0);
867 whichParent
->setParentCurrentPowerFlags(newPowerStateFlags
); // set our connection data
868 whichParent
->setParentKnowsState(true);
870 pm_vars
->parentsCurrentPowerFlags
= 0; // recompute our parent info
871 pm_vars
->parentsKnowState
= true;
873 iter
= getParentIterator(gIOPowerPlane
);
876 while ( (next
= iter
->getNextObject()) ) {
877 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
878 pm_vars
->parentsKnowState
&= connection
->parentKnowsState();
879 pm_vars
->parentsCurrentPowerFlags
|= connection
->parentCurrentPowerFlags();
885 if ( pm_vars
->theControllingDriver
== NULL
) {
886 return IOPMAckImplied
;
889 newStateNumber
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(pm_vars
->parentsCurrentPowerFlags
);
890 return enqueuePowerChange(IOPMParentInitiated
| IOPMDomainDidChange
, newStateNumber
,pm_vars
->parentsCurrentPowerFlags
,whichParent
); // tell interested parties about it
894 //*********************************************************************************
895 // requestPowerDomainState
898 //*********************************************************************************
899 IOReturn
IOService::requestPowerDomainState ( IOPMPowerFlags desiredState
, IOPowerConnection
* whichChild
, unsigned long specification
)
904 IOPowerConnection
* connection
;
906 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRequestDomain
,
907 (unsigned long)desiredState
,(unsigned long)specification
);
909 if ( pm_vars
->theControllingDriver
== NULL
) {
910 return IOPMNotYetInitialized
;
913 switch (specification
) {
914 case IOPMLowestState
:
916 while ( i
< pm_vars
->theNumberOfPowerStates
) {
917 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& desiredState
) == (desiredState
& pm_vars
->myCharacterFlags
) ) {
922 if ( i
>= pm_vars
->theNumberOfPowerStates
) {
923 return IOPMNoSuchState
;
927 case IOPMNextLowerState
:
928 i
= pm_vars
->myCurrentState
- 1;
930 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& desiredState
) == (desiredState
& pm_vars
->myCharacterFlags
) ) {
936 return IOPMNoSuchState
;
940 case IOPMHighestState
:
941 i
= pm_vars
->theNumberOfPowerStates
;
944 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& desiredState
) == (desiredState
& pm_vars
->myCharacterFlags
) ) {
949 return IOPMNoSuchState
;
953 case IOPMNextHigherState
:
954 i
= pm_vars
->myCurrentState
+ 1;
955 while ( i
< pm_vars
->theNumberOfPowerStates
) {
956 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& desiredState
) == (desiredState
& pm_vars
->myCharacterFlags
) ) {
961 if ( i
== pm_vars
->theNumberOfPowerStates
) {
962 return IOPMNoSuchState
;
967 return IOPMBadSpecification
;
970 // Now loop through the children. When we encounter the calling child, save
971 // the new state as this child's desire. Then, compute a new maximum
972 // of everybody's desires.
974 iter
= getChildIterator(gIOPowerPlane
);
977 while ( (next
= iter
->getNextObject()) ) {
978 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
979 if ( connection
== whichChild
) {
980 connection
->setDesiredDomainState(i
);
987 if ( inPlane(gIOPowerPlane
) &&
988 (pm_vars
->parentsKnowState
) ) {
989 changeState(); // change state if all children can now tolerate lower power
992 if ( priv
->clampOn
) { // are we clamped on, waiting for this child?
993 priv
->clampOn
= false; // yes, remove the clamp
994 changePowerStateToPriv(0);
1001 //*********************************************************************************
1002 // temporaryPowerClampOn
1004 // A power domain wants to clamp its power on till it has children which
1005 // will thendetermine the power domain state.
1007 // We enter the highest state until addPowerChild is called.
1008 //*********************************************************************************
1010 IOReturn
IOService::temporaryPowerClampOn ( void )
1012 priv
->clampOn
= true;
1018 //*********************************************************************************
1021 // Some client of our device is asking that we become usable. Although
1022 // this has not come from a subclassed device object, treat it exactly
1023 // as if it had. In this way, subsequent requests for lower power from
1024 // a subclassed device object will pre-empt this request.
1026 // We treat this as a subclass object request to switch to the
1027 // highest power state.
1028 //*********************************************************************************
1030 IOReturn
IOService::makeUsable ( void )
1032 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogMakeUsable
,0,0);
1034 if ( pm_vars
->theControllingDriver
== NULL
) {
1035 priv
->need_to_become_usable
= true;
1038 priv
->deviceDesire
= pm_vars
->theNumberOfPowerStates
- 1;
1039 if ( inPlane(gIOPowerPlane
) && (pm_vars
->parentsKnowState
) ) {
1040 return changeState();
1046 //*********************************************************************************
1047 // currentCapability
1049 //*********************************************************************************
1051 IOPMPowerFlags
IOService::currentCapability ( void )
1053 if ( pm_vars
->theControllingDriver
== NULL
) {
1057 return pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
;
1062 //*********************************************************************************
1063 // changePowerStateTo
1065 // For some reason, our power-controlling driver has decided it needs to change
1066 // power state. We enqueue the power change so that appropriate parties
1067 // will be notified, and then we will instruct the driver to make the change.
1068 //*********************************************************************************
1070 IOReturn
IOService::changePowerStateTo ( unsigned long ordinal
)
1072 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeStateTo
,ordinal
,0);
1074 if ( ordinal
>= pm_vars
->theNumberOfPowerStates
) {
1075 return IOPMParameterError
;
1077 priv
->driverDesire
= ordinal
;
1078 if ( inPlane(gIOPowerPlane
) && (pm_vars
->parentsKnowState
) ) {
1079 return changeState();
1085 //*********************************************************************************
1086 // changePowerStateToPriv
1088 // For some reason, a subclassed device object has decided it needs to change
1089 // power state. We enqueue the power change so that appropriate parties
1090 // will be notified, and then we will instruct the driver to make the change.
1091 //*********************************************************************************
1093 IOReturn
IOService::changePowerStateToPriv ( unsigned long ordinal
)
1095 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeStateToPriv
,ordinal
,0);
1097 if ( pm_vars
->theControllingDriver
== NULL
) {
1098 return IOPMNotYetInitialized
;
1100 if ( ordinal
>= pm_vars
->theNumberOfPowerStates
) {
1101 return IOPMParameterError
;
1103 priv
->deviceDesire
= ordinal
;
1104 if ( inPlane(gIOPowerPlane
) && (pm_vars
->parentsKnowState
) ) {
1105 return changeState();
1112 //*********************************************************************************
1115 // A subclass object, our controlling driver, or a power domain child
1116 // has asked for a different power state. Here we compute what new
1117 // state we should enter and enqueue the change (or start it).
1118 //*********************************************************************************
1120 IOReturn
IOService::changeState ( void )
1124 IOPowerConnection
* connection
;
1125 unsigned long newDesiredState
= 0;
1127 // Compute the maximum of our children's desires, our controlling driver's desire, and the subclass device's desire.
1129 if ( ! priv
->device_overrides
) {
1130 iter
= getChildIterator(gIOPowerPlane
);
1133 while ( (next
= iter
->getNextObject()) ) {
1134 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1135 if ( connection
->getDesiredDomainState() > newDesiredState
) {
1136 newDesiredState
= connection
->getDesiredDomainState();
1143 if ( priv
->driverDesire
> newDesiredState
) {
1144 newDesiredState
= priv
->driverDesire
;
1148 if ( priv
->deviceDesire
> newDesiredState
) {
1149 newDesiredState
= priv
->deviceDesire
;
1152 priv
->ourDesiredPowerState
= newDesiredState
;
1154 if ( (pm_vars
->theControllingDriver
== NULL
) || // if not fully initialized
1155 ! (inPlane(gIOPowerPlane
)) ||
1156 ! (pm_vars
->parentsKnowState
) ) {
1157 return IOPMNoErr
; // we can do no more
1160 return enqueuePowerChange(IOPMWeInitiated
,newDesiredState
,0,0);
1164 //*********************************************************************************
1165 // currentPowerConsumption
1167 //*********************************************************************************
1169 unsigned long IOService::currentPowerConsumption ( void )
1171 if ( pm_vars
->theControllingDriver
== NULL
) {
1175 return pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].staticPower
;
1179 //*********************************************************************************
1182 // The activity tickle with parameter kIOPMSubclassPolicyis not handled
1183 // here and should have been intercepted by the subclass.
1184 // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
1185 // flag to be set, and the device state checked. If the device has been
1186 // powered down, it is powered up again.
1187 //*********************************************************************************
1189 bool IOService::activityTickle ( unsigned long type
, unsigned long stateNumber
=0 )
1191 if ( type
== kIOPMSuperclassPolicy1
) {
1192 if ( (priv
->activityLock
== NULL
) ||
1193 (pm_vars
->theControllingDriver
== NULL
) ||
1194 ( pm_vars
->commandQueue
== NULL
) ) {
1197 IOTakeLock(priv
->activityLock
);
1198 priv
->device_active
= true;
1199 if ( pm_vars
->myCurrentState
>= stateNumber
) {
1200 IOUnlock(priv
->activityLock
);
1203 IOUnlock(priv
->activityLock
); // send a message on the command queue
1204 pm_vars
->commandQueue
->enqueueCommand(true, (void *)kPMunIdleDevice
, (void *)stateNumber
);
1210 //*********************************************************************************
1213 // A child is calling to get a pointer to the Power Management workloop.
1214 // We got it or get it from one of our parents.
1215 //*********************************************************************************
1217 IOWorkLoop
* IOService::getPMworkloop ( void )
1219 IOService
* aParent
;
1221 if ( ! inPlane(gIOPowerPlane
) ) {
1224 if ( pm_vars
->PMworkloop
== NULL
) { // we have no workloop yet
1225 aParent
= (IOService
*)getParentEntry(gIOPowerPlane
)->getParentEntry(gIOPowerPlane
);
1226 if ( aParent
!= NULL
) { // ask one of our parents for the workloop
1227 pm_vars
->PMworkloop
= aParent
->getPMworkloop();
1230 return pm_vars
->PMworkloop
;
1234 //*********************************************************************************
1235 // setIdleTimerPeriod
1237 // A subclass policy-maker is going to use our standard idleness
1238 // detection service. Make a command queue and an idle timer and
1239 // connect them to the power management workloop. Finally,
1241 //*********************************************************************************
1243 IOReturn
IOService::setIdleTimerPeriod ( unsigned long period
)
1245 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMsetIdleTimerPeriod
,period
, 0);
1247 priv
->idle_timer_period
= period
;
1250 if ( getPMworkloop() == NULL
) {
1251 return kIOReturnError
;
1254 if (pm_vars
->commandQueue
== NULL
) { // make the command queue
1255 pm_vars
->commandQueue
= IOCommandQueue::commandQueue(this, PMreceiveCmd
);
1256 if (! pm_vars
->commandQueue
||
1257 ( pm_vars
->PMworkloop
->addEventSource( pm_vars
->commandQueue
) != kIOReturnSuccess
) ) {
1258 return kIOReturnError
;
1261 // make the timer event
1262 if ( priv
->timerEventSrc
== NULL
) {
1263 priv
->timerEventSrc
= IOTimerEventSource::timerEventSource(this,
1264 PM_idle_timer_expired
);
1265 if ( ! priv
->timerEventSrc
||
1266 ( pm_vars
->PMworkloop
->addEventSource( priv
->timerEventSrc
) != kIOReturnSuccess
) ) {
1267 return kIOReturnError
;
1271 if ( priv
->activityLock
== NULL
) {
1272 priv
->activityLock
= IOLockAlloc();
1275 start_PM_idle_timer();
1281 //*********************************************************************************
1282 // start_PM_idle_timer
1284 // The parameter is a pointer to us. Use it to call our timeout method.
1285 //*********************************************************************************
1286 void IOService::start_PM_idle_timer ( void )
1288 priv
->timerEventSrc
->setTimeout(priv
->idle_timer_period
, NSEC_PER_SEC
);
1292 //*********************************************************************************
1293 // PM_idle_timer_expired
1295 // The parameter is a pointer to us. Use it to call our timeout method.
1296 //*********************************************************************************
1298 void PM_idle_timer_expired(OSObject
* ourSelves
, IOTimerEventSource
*)
1300 ((IOService
*)ourSelves
)->PM_idle_timer_expiration();
1304 //*********************************************************************************
1305 // PM_idle_timer_expiration
1307 // The idle timer has expired. If there has been activity since the last
1308 // expiration, just restart the timer and return. If there has not been
1309 // activity, switch to the next lower power state and restart the timer.
1310 //*********************************************************************************
1312 void IOService::PM_idle_timer_expiration ( void )
1314 if ( ! initialized
) {
1315 return; // we're unloading
1318 if ( priv
->idle_timer_period
> 0 ) {
1319 IOTakeLock(priv
->activityLock
);
1320 if ( priv
->device_active
) {
1321 priv
->device_active
= false;
1322 IOUnlock(priv
->activityLock
);
1323 start_PM_idle_timer();
1326 if ( pm_vars
->myCurrentState
> 0 ) {
1327 IOUnlock(priv
->activityLock
);
1328 priv
->askingFor
= pm_vars
->myCurrentState
- 1;
1329 changePowerStateToPriv(pm_vars
->myCurrentState
- 1);
1330 start_PM_idle_timer();
1333 IOUnlock(priv
->activityLock
);
1334 start_PM_idle_timer();
1340 // **********************************************************************************
1345 // **********************************************************************************
1346 void PMreceiveCmd ( OSObject
* theDriver
, void * command
, void * param1
, void * param2
, void *param3
)
1348 ((IOService
*)theDriver
)->command_received(command
,param1
,param2
,param3
);
1352 // **********************************************************************************
1355 // We have received a command from ourselves on the command queue.
1356 // This is to prevent races with timer-expiration code.
1357 // **********************************************************************************
1358 void IOService::command_received ( void * command
, void *stateNumber
, void * , void *)
1360 if ( ! initialized
) {
1361 return; // we're unloading
1364 if ( command
== (void *)kPMunIdleDevice
) {
1365 if ( (pm_vars
->myCurrentState
< (unsigned long)stateNumber
) &&
1366 (priv
->imminentState
< (unsigned long)stateNumber
) &&
1367 ((unsigned long)stateNumber
> priv
->askingFor
) ) {
1368 priv
->askingFor
= (unsigned long)stateNumber
;
1369 changePowerStateToPriv((unsigned long)stateNumber
);
1375 //*********************************************************************************
1376 // setAggressiveness
1378 // Pass on the input parameters to all power domain children. All those which are
1379 // power domains will pass it on to their children, etc.
1380 //*********************************************************************************
1382 IOReturn
IOService::setAggressiveness ( unsigned long type
, unsigned long newLevel
)
1386 IOPowerConnection
* connection
;
1388 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogSetAggressiveness
,type
, newLevel
);
1390 if ( type
<= kMaxType
) {
1391 pm_vars
->current_aggressiveness_values
[type
] = newLevel
;
1392 pm_vars
->current_aggressiveness_valid
[type
] = true;
1395 iter
= getChildIterator(gIOPowerPlane
);
1398 while ( (next
= iter
->getNextObject()) ) {
1399 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1400 ((IOService
*)(connection
->getChildEntry(gIOPowerPlane
)))->setAggressiveness(type
, newLevel
);
1409 //*********************************************************************************
1410 // getAggressiveness
1412 // Called by the user client.
1413 //*********************************************************************************
1415 IOReturn
IOService::getAggressiveness ( unsigned long type
, unsigned long * currentLevel
)
1417 if ( type
<= kMaxType
) {
1418 *currentLevel
= pm_vars
->current_aggressiveness_values
[type
];
1420 return kIOReturnSuccess
;
1423 //*********************************************************************************
1426 // Pass this to all power domain children. All those which are
1427 // power domains will pass it on to their children, etc.
1428 //*********************************************************************************
1430 IOReturn
IOService::systemWake ( void )
1434 IOPowerConnection
* connection
;
1436 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogSystemWake
,0, 0);
1438 iter
= getChildIterator(gIOPowerPlane
);
1441 while ( (next
= iter
->getNextObject()) ) {
1442 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1443 ((IOService
*)(connection
->getChildEntry(gIOPowerPlane
)))->systemWake();
1449 if ( pm_vars
->theControllingDriver
!= NULL
) {
1450 if ( pm_vars
->theControllingDriver
->didYouWakeSystem() ) {
1459 //*********************************************************************************
1460 // temperatureCriticalForZone
1462 //*********************************************************************************
1464 IOReturn
IOService::temperatureCriticalForZone ( IOService
* whichZone
)
1466 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogCriticalTemp
,0,0);
1468 if ( inPlane(gIOPowerPlane
) && ! (priv
->we_are_root
) ) {
1469 ((IOService
*)(getParentEntry(gIOPowerPlane
)->getParentEntry(gIOPowerPlane
)))->temperatureCriticalForZone(whichZone
);
1475 //*********************************************************************************
1476 // powerOverrideOnPriv
1478 //*********************************************************************************
1481 IOReturn
IOService::powerOverrideOnPriv ( void )
1483 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogOverrideOn
,0,0);
1485 priv
->device_overrides
= true; // turn on the override
1486 return changeState(); // change state if that changed something
1490 //*********************************************************************************
1491 // powerOverrideOffPriv
1493 //*********************************************************************************
1494 IOReturn
IOService::powerOverrideOffPriv ( void )
1496 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogOverrideOff
,0,0);
1498 priv
->device_overrides
= false; // turn off the override
1499 return changeState(); // change state if that changed something
1503 //*********************************************************************************
1504 // enqueuePowerChange
1506 // Allocate a new state change notification, initialize it with fields from the
1507 // caller, and add it to the tail of the list of pending power changes.
1509 // If it is early enough in the list, and almost all the time it is the only one in
1510 // the list, start the power change.
1512 // In rare instances, this change will preempt the previous change in the list.
1513 // If the previous change is un-actioned in any way (because we are still
1514 // processing an even earlier power change), and if both the previous change
1515 // in the list and this change are initiated by us (not the parent), then we
1516 // needn't perform the previous change, so we collapse the list a little.
1517 //*********************************************************************************
1519 IOReturn
IOService::enqueuePowerChange ( unsigned long flags
, unsigned long whatStateOrdinal
, unsigned long domainState
, IOPowerConnection
* whichParent
)
1524 // Create and initialize the new change note
1526 newNote
= priv
->changeList
->createChangeNote();
1527 if ( newNote
== -1 ) {
1528 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogEnqueueErr
,0,0);
1529 return IOPMAckImplied
; // uh-oh, our list is full
1532 priv
->changeList
->changeNote
[newNote
].newStateNumber
= whatStateOrdinal
;
1533 priv
->changeList
->changeNote
[newNote
].outputPowerCharacter
= pm_vars
->thePowerStates
[whatStateOrdinal
].outputPowerCharacter
;
1534 priv
->changeList
->changeNote
[newNote
].inputPowerRequirement
= pm_vars
->thePowerStates
[whatStateOrdinal
].inputPowerRequirement
;
1535 priv
->changeList
->changeNote
[newNote
].capabilityFlags
= pm_vars
->thePowerStates
[whatStateOrdinal
].capabilityFlags
;
1536 priv
->changeList
->changeNote
[newNote
].flags
= flags
;
1537 if (flags
& IOPMParentInitiated
) {
1538 priv
->changeList
->changeNote
[newNote
].domainState
= domainState
;
1539 priv
->changeList
->changeNote
[newNote
].parent
= whichParent
;
1542 previousNote
= priv
->changeList
->previousChangeNote(newNote
);
1544 if ( previousNote
== -1 ) {
1546 // Queue is empty, we can start this change.
1548 if (flags
& IOPMWeInitiated
) {
1549 start_our_change(newNote
);
1553 return start_parent_change(newNote
);
1557 // The queue is not empty. Try to collapse this new change and the previous one in queue into one change.
1558 // This is possible only if both changes are initiated by us, and neither has been started yet.
1559 // Do this more than once if possible.
1561 // (A change is started iff it is at the head of the queue)
1563 while ( (previousNote
!= priv
->head_note
) && (previousNote
!= -1) &&
1564 (priv
->changeList
->changeNote
[newNote
].flags
& priv
->changeList
->changeNote
[previousNote
].flags
& IOPMWeInitiated
) ) {
1565 priv
->changeList
->changeNote
[previousNote
].outputPowerCharacter
= priv
->changeList
->changeNote
[newNote
].outputPowerCharacter
;
1566 priv
->changeList
->changeNote
[previousNote
].inputPowerRequirement
= priv
->changeList
->changeNote
[newNote
].inputPowerRequirement
;
1567 priv
->changeList
->changeNote
[previousNote
].capabilityFlags
=priv
-> changeList
->changeNote
[newNote
].capabilityFlags
;
1568 priv
->changeList
->changeNote
[previousNote
].newStateNumber
= priv
->changeList
->changeNote
[newNote
].newStateNumber
;
1569 priv
->changeList
->releaseTailChangeNote();
1570 newNote
= previousNote
;
1571 previousNote
= priv
->changeList
->previousChangeNote(newNote
);
1572 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogCollapseQueue
,0,0);
1574 return IOPMWillAckLater
; // in any case, we can't start yet
1578 //*********************************************************************************
1581 // Notify all interested parties either that a change is impending or that the
1582 // previously-notified change is done and power has settled.
1583 // The parameter identifies whether this is the
1584 // pre-change notification or the post-change notification.
1586 //*********************************************************************************
1588 IOReturn
IOService::notifyAll ( bool is_prechange
)
1590 IOPMinformee
* nextObject
;
1593 IOPowerConnection
* connection
;
1595 // To prevent acknowledgePowerChange from finishing the change note and removing it from the queue if
1596 // some driver calls it, we inflate the number of pending acks so it cannot become zero. We'll fix it later.
1598 priv
->head_note_pendingAcks
=1;
1600 // OK, we will go through the lists of interested drivers and power domain children
1601 // and notify each one of this change.
1603 nextObject
= priv
->interestedDrivers
->firstInList(); // notify interested drivers
1604 while ( nextObject
!= NULL
) {
1605 priv
->head_note_pendingAcks
+=1;
1606 if (! inform(nextObject
, is_prechange
) ) {
1608 nextObject
= priv
->interestedDrivers
->nextInList(nextObject
);
1611 if (! acquire_lock() ) {
1614 if ( priv
->head_note_pendingAcks
> 1 ) { // did they all ack?
1615 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0); // no
1618 IOUnlock(priv
->our_lock
); // either way
1620 iter
= getChildIterator(gIOPowerPlane
);
1623 while ( (next
= iter
->getNextObject()) ) {
1624 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1625 priv
->head_note_pendingAcks
+=1;
1626 notifyChild(connection
, is_prechange
);
1632 if (! acquire_lock() ) {
1635 priv
->head_note_pendingAcks
-= 1; // now make this real
1636 if (priv
->head_note_pendingAcks
== 0 ) { // is it all acked?
1637 IOUnlock(priv
->our_lock
); // yes
1638 return IOPMAckImplied
; // return ack to parent
1640 IOUnlock(priv
->our_lock
); // no
1641 return IOPMWillAckLater
;
1645 //*********************************************************************************
1648 // Notify a power domain child of an upcoming power change.
1650 // If the object acknowledges the current change, we return TRUE.
1651 //*********************************************************************************
1653 bool IOService::notifyChild ( IOPowerConnection
* theNub
, bool is_prechange
)
1655 IOReturn k
= IOPMAckImplied
;
1657 if ( is_prechange
) {
1658 k
=((IOService
*)(theNub
->getChildEntry(gIOPowerPlane
)))->powerDomainWillChangeTo( priv
->head_note_outputFlags
,theNub
);
1661 k
=((IOService
*)(theNub
->getChildEntry(gIOPowerPlane
)))->powerDomainDidChangeTo( priv
->head_note_outputFlags
,theNub
);
1664 if ( k
== IOPMAckImplied
) { // did the return code ack?
1665 priv
->head_note_pendingAcks
-=1; // yes
1672 //*********************************************************************************
1675 // Notify an interested driver of an upcoming power change.
1677 // If the object acknowledges the current change, we return TRUE.
1678 //*********************************************************************************
1680 bool IOService::inform ( IOPMinformee
* nextObject
, bool is_prechange
)
1682 IOReturn k
= IOPMAckImplied
;
1684 nextObject
->timer
= -1; // initialize this
1686 if ( is_prechange
) {
1687 pm_vars
->thePlatform
->PMLog (pm_vars
->ourName
,PMlogInformDriverPreChange
,
1688 (unsigned long)priv
->head_note_capabilityFlags
,(unsigned long)priv
->head_note_state
);
1689 k
= nextObject
->whatObject
->powerStateWillChangeTo( priv
->head_note_capabilityFlags
,priv
->head_note_state
,this);
1692 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInformDriverPostChange
,
1693 (unsigned long)priv
->head_note_capabilityFlags
,(unsigned long)priv
->head_note_state
);
1694 k
= nextObject
->whatObject
->powerStateDidChangeTo(priv
->head_note_capabilityFlags
,priv
->head_note_state
,this);
1697 if ( nextObject
->timer
== 0 ) { // did it ack behind our back?
1700 if ( k
==IOPMAckImplied
) { // no, did the return code ack?
1701 nextObject
->timer
= 0; // yes
1702 priv
->head_note_pendingAcks
-= 1;
1706 nextObject
->timer
= 0; // somebody goofed
1707 priv
-> head_note_pendingAcks
-= 1;
1710 nextObject
->timer
= (k
* ns_per_us
/ ACK_TIMER_PERIOD
) + 1; // no, it's a timer
1715 //*********************************************************************************
1718 // All registered applications and kernel clients have positively acknowledged our
1719 // intention of lowering power. Here we notify them all that we will definitely
1720 // lower the power. If we don't have to wait for any of them to acknowledge, we
1721 // carry on by notifying interested drivers. Otherwise, we do wait.
1722 //*********************************************************************************
1724 void IOService::our_prechange_03 ( void )
1726 priv
->machine_state
= IOPMour_prechange_05
; // next state
1727 if ( tellChangeDown(priv
->head_note_state
) ) { // are we waiting for responses?
1728 return our_prechange_05(); // no, notify interested drivers
1733 //*********************************************************************************
1736 // All registered applications and kernel clients have acknowledged our notification
1737 // that we are lowering power. Here we notify interested drivers. If we don't have
1738 // to wait for any of them to acknowledge, we instruct our power driver to make the change.
1739 // Otherwise, we do wait.
1740 //*********************************************************************************
1742 void IOService::our_prechange_05 ( void )
1744 priv
->machine_state
= IOPMour_prechange_1
; // no, in case they don't all ack
1745 if ( notifyAll(true) == IOPMAckImplied
) {
1751 //*********************************************************************************
1754 // All interested drivers have acknowledged our pre-change notification of a power
1755 // change we initiated. Here we instruct our controlling driver to make
1756 // the change to the hardware. If it does so, we continue processing
1757 // (waiting for settle and notifying interested parties post-change.)
1758 // If it doesn't, we have to wait for it to acknowledge and then continue.
1759 //*********************************************************************************
1761 void IOService::our_prechange_1 ( void )
1763 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
) {
1764 our_prechange_2(); // it's done, carry on
1767 priv
->machine_state
= IOPMour_prechange_2
; // it's not, wait for it
1768 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
1774 //*********************************************************************************
1777 // Our controlling driver has changed power state on the hardware
1778 // during a power change we initiated. Here we see if we need to wait
1779 // for power to settle before continuing. If not, we continue processing
1780 // (notifying interested parties post-change). If so, we wait and
1782 //*********************************************************************************
1784 void IOService::our_prechange_2 ( void )
1786 priv
->settle_time
= compute_settle_time();
1787 if ( priv
->settle_time
== 0 ) {
1791 priv
->machine_state
= IOPMour_prechange_3
;
1792 startSettleTimer(priv
->settle_time
);
1797 //*********************************************************************************
1800 // Power has settled on a power change we initiated. Here we notify
1801 // all our interested parties post-change. If they all acknowledge, we're
1802 // done with this change note, and we can start on the next one.
1803 // Otherwise we have to wait for acknowledgements and finish up later.
1804 //*********************************************************************************
1806 void IOService::our_prechange_3 ( void )
1808 priv
->machine_state
= IOPMour_prechange_4
; // in case they don't all ack
1809 if ( notifyAll(false) == IOPMAckImplied
) {
1815 //*********************************************************************************
1818 // Power has settled on a power change we initiated, and
1819 // all our interested parties have acknowledged. We're
1820 // done with this change note, and we can start on the next one.
1821 //*********************************************************************************
1823 void IOService::our_prechange_4 ( void )
1829 //*********************************************************************************
1832 // All applications and kernel clients have been notified of a power lowering
1833 // initiated by the parent and we didn't have to wait for any responses. Here
1834 // we notify any interested drivers and power domain children. If they all ack,
1835 // we continue with the power change.
1836 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
1837 //*********************************************************************************
1839 IOReturn
IOService::parent_down_0 ( void )
1841 priv
->machine_state
= IOPMparent_down_4
; // in case they don't all ack
1842 if ( notifyAll(true) == IOPMAckImplied
) {
1843 return parent_down_1(); // they did
1845 return IOPMWillAckLater
; // they didn't
1849 //*********************************************************************************
1852 // All applications and kernel clients have been notified of a power lowering
1853 // initiated by the parent and we had to wait for their responses. Here we notify
1854 // any interested drivers and power domain children. If they all ack, we continue
1855 // with the power change.
1856 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
1857 //*********************************************************************************
1859 void IOService::parent_down_05 ( void )
1861 priv
->machine_state
= IOPMparent_down_4
; // in case they don't all ack
1862 if ( notifyAll(true) == IOPMAckImplied
) {
1863 parent_down_4(); // they did
1868 //*********************************************************************************
1871 // All parties have acknowledged our pre-change notification of a power
1872 // lowering initiated by the parent. Here we instruct our controlling driver
1873 // to put the hardware in the state it needs to be in when the domain is
1874 // lowered. If it does so, we continue processing
1875 // (waiting for settle and acknowledging the parent.)
1876 // If it doesn't, we have to wait for it to acknowledge and then continue.
1877 //*********************************************************************************
1879 IOReturn
IOService::parent_down_1 ( void )
1881 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
) {
1882 return parent_down_2(); // it's done, carry on
1884 priv
->machine_state
= IOPMparent_down_5
; // it's not, wait for it
1885 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
1887 return IOPMWillAckLater
;
1891 //*********************************************************************************
1894 // We had to wait for it, but all parties have acknowledged our pre-change
1895 // notification of a power lowering initiated by the parent.
1896 // Here we instruct our controlling driver
1897 // to put the hardware in the state it needs to be in when the domain is
1898 // lowered. If it does so, we continue processing
1899 // (waiting for settle and acknowledging the parent.)
1900 // If it doesn't, we have to wait for it to acknowledge and then continue.
1901 //*********************************************************************************
1903 void IOService::parent_down_4 ( void )
1905 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
) {
1906 parent_down_5(); // it's done, carry on
1909 priv
-> machine_state
= IOPMparent_down_5
; // it's not, wait for it
1910 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
1916 //*********************************************************************************
1919 // Our controlling driver has changed power state on the hardware
1920 // during a power change initiated by our parent. Here we see if we need
1921 // to wait for power to settle before continuing. If not, we continue
1922 // processing (acknowledging our preparedness to the parent).
1923 // If so, we wait and continue later.
1924 //*********************************************************************************
1926 IOReturn
IOService::parent_down_2 ( void )
1928 priv
->settle_time
= compute_settle_time();
1929 if ( priv
->settle_time
== 0 ) {
1930 priv
->machine_state
= IOPMparent_down_6
; // in case they don't all ack
1931 if ( notifyAll(false) == IOPMAckImplied
) {
1933 return IOPMAckImplied
;
1935 return IOPMWillAckLater
; // they didn't
1938 priv
->machine_state
= IOPMparent_down_3
;
1939 startSettleTimer(priv
->settle_time
);
1940 return IOPMWillAckLater
;
1945 //*********************************************************************************
1948 // Our controlling driver has changed power state on the hardware
1949 // during a power change initiated by our parent. We have had to wait
1950 // for acknowledgement from interested parties, or we have had to wait
1951 // for the controlling driver to change the state. Here we see if we need
1952 // to wait for power to settle before continuing. If not, we continue
1953 // processing (acknowledging our preparedness to the parent).
1954 // If so, we wait and continue later.
1955 //*********************************************************************************
1957 void IOService::parent_down_5 ( void )
1959 priv
->settle_time
= compute_settle_time();
1960 if ( priv
->settle_time
== 0 ) {
1964 priv
->machine_state
= IOPMparent_down_3
;
1965 startSettleTimer(priv
->settle_time
);
1970 //*********************************************************************************
1973 // Power has settled on a power change initiated by our parent. Here we
1974 // notify interested parties.
1975 //*********************************************************************************
1977 void IOService::parent_down_3 ( void )
1981 priv
->machine_state
= IOPMparent_down_6
; // in case they don't all ack
1982 if ( notifyAll(false) == IOPMAckImplied
) {
1983 parent
= priv
->head_note_parent
;
1985 ((IOService
*)(parent
->getParentEntry(gIOPowerPlane
)))->acknowledgePowerChange(parent
);
1990 //*********************************************************************************
1993 // We had to wait for it, but all parties have acknowledged our post-change
1994 // notification of a power lowering initiated by the parent.
1995 // Here we acknowledge the parent.
1996 // We are done with this change note, and we can start on the next one.
1997 //*********************************************************************************
1999 void IOService::parent_down_6 ( void )
2003 parent
= priv
->head_note_parent
;
2005 ((IOService
*)(parent
->getParentEntry(gIOPowerPlane
)))->acknowledgePowerChange(parent
);
2009 //*********************************************************************************
2012 // Our parent has informed us via powerStateDidChange that it has
2013 // raised the power in our power domain, and we have had to wait
2014 // for some interested party to acknowledge our notification.
2015 // Here we instruct our controlling
2016 // driver to program the hardware to take advantage of the higher domain
2017 // power. If it does so, we continue processing
2018 // (waiting for settle and notifying interested parties post-change.)
2019 // If it doesn't, we have to wait for it to acknowledge and then continue.
2020 //*********************************************************************************
2022 void IOService::parent_up_0 ( void )
2024 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
) {
2025 parent_up_4(); // it did it, carry on
2028 priv
->machine_state
= IOPMparent_up_4
; // it didn't, wait for it
2029 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2035 //*********************************************************************************
2038 // Our parent has informed us via powerStateDidChange that it has
2039 // raised the power in our power domain. Here we instruct our controlling
2040 // driver to program the hardware to take advantage of the higher domain
2041 // power. If it does so, we continue processing
2042 // (waiting for settle and notifying interested parties post-change.)
2043 // If it doesn't, we have to wait for it to acknowledge and then continue.
2044 //*********************************************************************************
2046 IOReturn
IOService::parent_up_1 ( void )
2048 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
) {
2049 return parent_up_2(); // it did it, carry on
2052 priv
->machine_state
= IOPMparent_up_4
; // it didn't, wait for it
2053 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2055 return IOPMWillAckLater
;
2060 //*********************************************************************************
2063 // Our controlling driver has changed power state on the hardware
2064 // during a power raise initiated by the parent. Here we see if we need to wait
2065 // for power to settle before continuing. If not, we continue processing
2066 // (notifying interested parties post-change). If so, we wait and
2068 //*********************************************************************************
2070 IOReturn
IOService::parent_up_2 ( void )
2072 priv
->settle_time
= compute_settle_time();
2073 if ( priv
->settle_time
== 0 ) {
2074 return parent_up_3();
2077 priv
->machine_state
= IOPMparent_up_5
;
2078 startSettleTimer(priv
->settle_time
);
2079 return IOPMWillAckLater
;
2084 //*********************************************************************************
2087 // Our controlling driver has changed power state on the hardware
2088 // during a power raise initiated by the parent, but we had to wait for it.
2089 // Here we see if we need to wait for power to settle before continuing.
2090 // If not, we continue processing (notifying interested parties post-change).
2091 // If so, we wait and continue later.
2092 //*********************************************************************************
2094 void IOService::parent_up_4 ( void )
2096 priv
->settle_time
= compute_settle_time();
2097 if ( priv
->settle_time
== 0 ) {
2101 priv
->machine_state
= IOPMparent_up_5
;
2102 startSettleTimer(priv
->settle_time
);
2107 //*********************************************************************************
2110 // No power settling was required on a power raise initiated by the parent.
2111 // Here we notify all our interested parties post-change. If they all acknowledge,
2112 // we're done with this change note, and we can start on the next one.
2113 // Otherwise we have to wait for acknowledgements and finish up later.
2114 //*********************************************************************************
2116 IOReturn
IOService::parent_up_3 ( void )
2118 priv
->machine_state
= IOPMparent_up_6
; // in case they don't all ack
2119 if ( notifyAll(false) == IOPMAckImplied
) {
2121 return IOPMAckImplied
;
2123 return IOPMWillAckLater
; // they didn't
2127 //*********************************************************************************
2130 // Power has settled on a power raise initiated by the parent.
2131 // Here we notify all our interested parties post-change. If they all acknowledge,
2132 // we're done with this change note, and we can start on the next one.
2133 // Otherwise we have to wait for acknowledgements and finish up later.
2134 //*********************************************************************************
2136 void IOService::parent_up_5 ( void )
2138 priv
->machine_state
= IOPMparent_up_6
; // in case they don't all ack
2139 if ( notifyAll(false) == IOPMAckImplied
) {
2145 //*********************************************************************************
2148 // All parties have acknowledged our post-change notification of a power
2149 // raising initiated by the parent. Here we acknowledge the parent.
2150 // We are done with this change note, and we can start on the next one.
2151 //*********************************************************************************
2153 void IOService::parent_up_6 ( void )
2157 parent
= priv
->head_note_parent
;
2159 ((IOService
*)(parent
->getParentEntry(gIOPowerPlane
)))->acknowledgePowerChange(parent
);
2163 //*********************************************************************************
2166 // A power change is complete, and the used post-change note is at
2167 // the head of the queue. Remove it and set myCurrentState to the result
2168 // of the change. Start up the next change in queue.
2169 //*********************************************************************************
2171 void IOService::all_done ( void )
2173 priv
->machine_state
= IOPMfinished
;
2175 if ( priv
->head_note_flags
& IOPMWeInitiated
) { // our power change
2176 if ( !( priv
->head_note_flags
& IOPMNotDone
) ) { // could our driver switch to the new state?
2177 if ( pm_vars
->myCurrentState
< priv
->head_note_state
) { // yes, did power raise?
2178 tellChangeUp (priv
->head_note_state
); // yes, inform clients and apps
2181 if ( ! priv
->we_are_root
) { // no, if this lowers our
2182 ask_parent(priv
->head_note_state
); // power requirements, tell the parent
2185 pm_vars
->myCurrentState
= priv
->head_note_state
; // either way
2186 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeDone
,(unsigned long)pm_vars
->myCurrentState
,0);
2187 powerChangeDone(pm_vars
->myCurrentState
); // inform subclass policy-maker
2190 // pm_vars->myCurrentState = pm_vars->theControllingDriver->powerStateForDomainState(pm_vars->parentsCurrentPowerFlags);
2193 if ( priv
->head_note_flags
& IOPMParentInitiated
) { // parent's power change
2194 if ( ((priv
->head_note_flags
& IOPMDomainWillChange
) && (pm_vars
->myCurrentState
>= priv
->head_note_state
)) ||
2195 ((priv
->head_note_flags
& IOPMDomainDidChange
) && (pm_vars
->myCurrentState
< priv
->head_note_state
)) ) {
2196 if ( pm_vars
->myCurrentState
< priv
->head_note_state
) { // did power raise?
2197 tellChangeUp (priv
->head_note_state
); // yes, inform clients and apps
2199 pm_vars
->myCurrentState
= priv
->head_note_state
; // either way
2200 pm_vars
->maxCapability
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(priv
->head_note_domainState
);
2202 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeDone
,(unsigned long)pm_vars
->myCurrentState
,0);
2203 powerChangeDone(pm_vars
->myCurrentState
); // inform subclass policy-maker
2207 priv
->changeList
->releaseHeadChangeNote(); // we're done with this
2209 priv
->head_note
= priv
->changeList
->currentChange(); // start next one in queue
2210 if ( priv
->head_note
!= -1 ) {
2212 if (priv
->changeList
->changeNote
[priv
->head_note
].flags
& IOPMWeInitiated
) {
2213 start_our_change(priv
->head_note
);
2216 if ( start_parent_change(priv
->head_note
) == IOPMAckImplied
) {
2217 ((IOService
*)(priv
->head_note_parent
->getParentEntry(gIOPowerPlane
)))->acknowledgePowerChange(priv
->head_note_parent
);
2225 //*********************************************************************************
2228 // A driver or child has acknowledged our notification of an upcoming power
2229 // change, and this acknowledgement is the last one pending
2230 // before we change power or after changing power.
2232 //*********************************************************************************
2234 void IOService::all_acked ( void )
2236 switch (priv
->machine_state
) {
2237 case IOPMour_prechange_1
:
2240 case IOPMour_prechange_4
:
2243 case IOPMparent_down_4
:
2246 case IOPMparent_down_6
:
2249 case IOPMparent_up_0
:
2252 case IOPMparent_up_6
:
2259 //*********************************************************************************
2260 // settleTimerExpired
2262 // Power has settled after our last change. Notify interested parties that
2263 // there is a new power state.
2264 //*********************************************************************************
2266 void IOService::settleTimerExpired ( void )
2268 if ( ! initialized
) {
2269 return; // we're unloading
2272 switch (priv
->machine_state
) {
2273 case IOPMour_prechange_3
:
2276 case IOPMparent_down_3
:
2279 case IOPMparent_up_5
:
2286 //*********************************************************************************
2287 // compute_settle_time
2289 // Compute the power-settling delay in microseconds for the
2290 // change from myCurrentState to head_note_state.
2291 //*********************************************************************************
2293 unsigned long IOService::compute_settle_time ( void )
2295 unsigned long totalTime
;
2298 totalTime
= 0; // compute total time to attain the new state
2299 i
= pm_vars
->myCurrentState
;
2300 if ( priv
->head_note_state
< pm_vars
->myCurrentState
) { // we're lowering power
2301 while ( i
> priv
->head_note_state
) {
2302 totalTime
+= pm_vars
->thePowerStates
[i
].settleDownTime
;
2307 if ( priv
->head_note_state
> pm_vars
->myCurrentState
) { // we're raising power
2308 while ( i
< priv
->head_note_state
) {
2309 totalTime
+= pm_vars
->thePowerStates
[i
+1].settleUpTime
;
2318 //*********************************************************************************
2321 // Enter with a power-settling delay in microseconds and start a nano-second
2322 // timer for that delay.
2323 //*********************************************************************************
2325 IOReturn
IOService::startSettleTimer ( unsigned long delay
)
2327 AbsoluteTime deadline
;
2329 clock_interval_to_deadline(delay
, kMicrosecondScale
, &deadline
);
2331 thread_call_enter_delayed(priv
->settleTimer
, deadline
);
2336 //*********************************************************************************
2339 // The acknowledgement timeout periodic timer has ticked.
2340 // If we are awaiting acks for a power change notification,
2341 // we decrement the timer word of each interested driver which hasn't acked.
2342 // If a timer word becomes zero, we pretend the driver aknowledged.
2343 // If we are waiting for the controlling driver to change the power
2344 // state of the hardware, we decrement its timer word, and if it becomes
2345 // zero, we pretend the driver acknowledged.
2346 //*********************************************************************************
2348 void IOService::ack_timer_ticked ( void )
2350 IOPMinformee
* nextObject
;
2352 if ( ! initialized
) {
2353 return; // we're unloading
2356 if (! acquire_lock() ) {
2360 switch (priv
->machine_state
) {
2361 case IOPMour_prechange_2
:
2362 case IOPMparent_down_5
:
2363 case IOPMparent_up_4
:
2364 if ( priv
->driver_timer
!= 0 ) { // are we waiting for our driver to make its change?
2365 priv
->driver_timer
-= 1; // yes, tick once
2366 if ( priv
->driver_timer
== 0 ) { // it's tardy, we'll go on without it
2367 IOUnlock(priv
->our_lock
);
2368 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogCtrlDriverTardy
,0,0);
2371 else { // still waiting, set timer again
2373 IOUnlock(priv
->our_lock
);
2377 IOUnlock(priv
->our_lock
);
2381 case IOPMour_prechange_1
:
2382 case IOPMour_prechange_4
:
2383 case IOPMparent_down_4
:
2384 case IOPMparent_down_6
:
2385 case IOPMparent_up_0
:
2386 case IOPMparent_up_6
:
2387 if (priv
->head_note_pendingAcks
!= 0 ) { // are we waiting for interested parties to acknowledge?
2388 nextObject
= priv
->interestedDrivers
->firstInList(); // yes, go through the list of interested drivers
2389 while ( nextObject
!= NULL
) { // and check each one
2390 if ( nextObject
->timer
> 0 ) {
2391 nextObject
->timer
-= 1;
2392 if ( nextObject
->timer
== 0 ) { // this one should have acked by now
2393 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogIntDriverTardy
,0,0);
2394 kprintf("interested driver tardy: %s\n",nextObject
->whatObject
->getName());
2395 priv
->head_note_pendingAcks
-= 1;
2398 nextObject
= priv
->interestedDrivers
->nextInList(nextObject
);
2400 if ( priv
->head_note_pendingAcks
== 0 ) { // is that the last?
2401 IOUnlock(priv
->our_lock
);
2402 all_acked(); // yes, we can continue
2404 else { // no, set timer again
2406 IOUnlock(priv
->our_lock
);
2410 IOUnlock(priv
->our_lock
);
2414 case IOPMparent_down_0
: // apps didn't respond to parent-down notification
2415 IOUnlock(priv
->our_lock
);
2416 IOLockLock(priv
->flags_lock
);
2417 if (pm_vars
->responseFlags
) {
2418 pm_vars
->responseFlags
->release(); // get rid of this stuff
2419 pm_vars
->responseFlags
= NULL
;
2421 IOLockUnlock(priv
->flags_lock
);
2422 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,1);
2423 parent_down_05(); // carry on with the change
2426 case IOPMour_prechange_03
: // apps didn't respond to our power-down request
2427 IOUnlock(priv
->our_lock
);
2428 IOLockLock(priv
->flags_lock
);
2429 if (pm_vars
->responseFlags
) {
2430 pm_vars
->responseFlags
->release(); // get rid of this stuff
2431 pm_vars
->responseFlags
= NULL
;
2433 IOLockUnlock(priv
->flags_lock
);
2434 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,2);
2435 tellNoChangeDown(priv
->head_note_state
); // rescind the request
2436 priv
->head_note_flags
|= IOPMNotDone
; // mark the change note un-actioned
2437 all_done(); // and we're done
2440 case IOPMour_prechange_05
: // apps didn't respond to our power-down notification
2441 IOUnlock(priv
->our_lock
);
2442 IOLockLock(priv
->flags_lock
);
2443 if (pm_vars
->responseFlags
) {
2444 pm_vars
->responseFlags
->release(); // get rid of this stuff
2445 pm_vars
->responseFlags
= NULL
;
2447 IOLockUnlock(priv
->flags_lock
);
2448 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,3);
2449 our_prechange_05(); // carry on with the change
2453 IOUnlock(priv
->our_lock
); // not waiting for acks
2459 //*********************************************************************************
2462 //*********************************************************************************
2464 void IOService::start_ack_timer ( void )
2466 AbsoluteTime deadline
;
2468 clock_interval_to_deadline(ACK_TIMER_PERIOD
, kNanosecondScale
, &deadline
);
2470 thread_call_enter_delayed(priv
->ackTimer
, deadline
);
2474 //*********************************************************************************
2477 //*********************************************************************************
2479 void IOService::stop_ack_timer ( void )
2481 thread_call_cancel(priv
->ackTimer
);
2485 //*********************************************************************************
2486 // c-language timer expiration functions
2488 //*********************************************************************************
2490 static void ack_timer_expired ( thread_call_param_t us
)
2492 ((IOService
*)us
)->ack_timer_ticked();
2496 static void settle_timer_expired ( thread_call_param_t us
)
2498 ((IOService
*)us
)->settleTimerExpired();
2502 //*********************************************************************************
2503 // add_child_to_active_change
2505 // A child has just registered with us. If there is
2506 // currently a change in progress, get the new party involved: if we
2507 // have notified all parties and are waiting for acks, notify the new
2509 //*********************************************************************************
2511 IOReturn
IOService::add_child_to_active_change ( IOPowerConnection
* newObject
)
2513 if (! acquire_lock() ) {
2517 switch (priv
->machine_state
) {
2518 case IOPMour_prechange_1
:
2519 case IOPMparent_down_4
:
2520 case IOPMparent_up_0
:
2521 priv
->head_note_pendingAcks
+= 2; // one for this child and one to prevent
2522 IOUnlock(priv
->our_lock
); // incoming acks from changing our state
2523 notifyChild(newObject
, true);
2524 if (! acquire_lock() ) {
2525 --priv
->head_note_pendingAcks
; // put it back
2528 if ( --priv
->head_note_pendingAcks
== 0 ) { // are we still waiting for acks?
2529 stop_ack_timer(); // no, stop the timer
2530 IOUnlock(priv
->our_lock
);
2531 all_acked(); // and now we can continue
2535 case IOPMour_prechange_4
:
2536 case IOPMparent_down_6
:
2537 case IOPMparent_up_6
:
2538 priv
->head_note_pendingAcks
+= 2; // one for this child and one to prevent
2539 IOUnlock(priv
->our_lock
); // incoming acks from changing our state
2540 notifyChild(newObject
, false);
2541 if (! acquire_lock() ) {
2542 --priv
->head_note_pendingAcks
; // put it back
2545 if ( --priv
->head_note_pendingAcks
== 0 ) { // are we still waiting for acks?
2546 stop_ack_timer(); // no, stop the timer
2547 IOUnlock(priv
->our_lock
);
2548 all_acked(); // and now we can continue
2553 IOUnlock(priv
->our_lock
);
2558 //*********************************************************************************
2559 // add_driver_to_active_change
2561 // An interested driver has just registered with us. If there is
2562 // currently a change in progress, get the new party involved: if we
2563 // have notified all parties and are waiting for acks, notify the new
2565 //*********************************************************************************
2567 IOReturn
IOService::add_driver_to_active_change ( IOPMinformee
* newObject
)
2569 if (! acquire_lock() ) {
2573 switch (priv
->machine_state
) {
2574 case IOPMour_prechange_1
:
2575 case IOPMparent_down_4
:
2576 case IOPMparent_up_0
:
2577 priv
->head_note_pendingAcks
+= 2; // one for this driver and one to prevent
2578 IOUnlock(priv
->our_lock
); // incoming acks from changing our state
2579 inform(newObject
, true); // inform the driver
2580 if (! acquire_lock() ) {
2581 --priv
->head_note_pendingAcks
; // put it back
2584 if ( --priv
->head_note_pendingAcks
== 0 ) { // are we still waiting for acks?
2585 stop_ack_timer(); // no, stop the timer
2586 IOUnlock(priv
->our_lock
);
2587 all_acked(); // and now we can continue
2591 case IOPMour_prechange_4
:
2592 case IOPMparent_down_6
:
2593 case IOPMparent_up_6
:
2594 priv
->head_note_pendingAcks
+= 2; // one for this driver and one to prevent
2595 IOUnlock(priv
->our_lock
); // incoming acks from changing our state
2596 inform(newObject
, false); // inform the driver
2597 if (! acquire_lock() ) {
2598 --priv
->head_note_pendingAcks
; // put it back
2601 if ( --priv
->head_note_pendingAcks
== 0 ) { // are we still waiting for acks?
2602 stop_ack_timer(); // no, stop the timer
2603 IOUnlock(priv
->our_lock
);
2604 all_acked(); // and now we can continue
2609 IOUnlock(priv
->our_lock
);
2614 //*********************************************************************************
2615 // start_parent_change
2617 // Here we begin the processing of a change note initiated by our parent
2618 // which is at the head of the queue.
2620 // It is possible for the change to be processed to completion and removed from the queue.
2621 // There are several possible interruptions to the processing, though, and they are:
2622 // we may have to wait for interested parties to acknowledge our pre-change notification,
2623 // we may have to wait for our controlling driver to change the hardware power state,
2624 // there may be a settling time after changing the hardware power state,
2625 // we may have to wait for interested parties to acknowledge our post-change notification,
2626 // we may have to wait for the acknowledgement timer expiration to substitute for the
2627 // acknowledgement from a failing driver.
2628 //*********************************************************************************
2630 IOReturn
IOService::start_parent_change ( unsigned long queue_head
)
2632 priv
->head_note
= queue_head
;
2633 priv
->head_note_flags
= priv
-> changeList
->changeNote
[priv
->head_note
].flags
;
2634 priv
->head_note_state
= priv
->changeList
->changeNote
[priv
->head_note
].newStateNumber
;
2635 priv
->head_note_outputFlags
= priv
->changeList
->changeNote
[priv
->head_note
].outputPowerCharacter
;
2636 priv
->head_note_domainState
= priv
->changeList
->changeNote
[priv
->head_note
].domainState
;
2637 priv
->head_note_parent
= priv
->changeList
->changeNote
[priv
->head_note
].parent
;
2638 priv
->head_note_capabilityFlags
= priv
->changeList
->changeNote
[priv
->head_note
].capabilityFlags
;
2640 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartParentChange
,
2641 (unsigned long)priv
->head_note_state
,(unsigned long)pm_vars
->myCurrentState
);
2643 ask_parent( priv
->ourDesiredPowerState
); // if we need something and haven't told the parent, do so
2645 if ( priv
->head_note_state
< pm_vars
->myCurrentState
) { // power domain is lowering
2646 priv
->initial_change
= false;
2647 priv
->machine_state
= IOPMparent_down_0
; // tell apps and kernel clients
2648 if ( tellChangeDown(priv
->head_note_state
) ) { // are we waiting for responses?
2649 return parent_down_0(); // no, notify interested drivers
2651 return IOPMWillAckLater
; // yes
2654 if ( priv
->head_note_state
> pm_vars
->myCurrentState
) { // parent is raising power, we may or may not
2655 if ( priv
->ourDesiredPowerState
> pm_vars
->myCurrentState
) {
2656 if ( priv
->ourDesiredPowerState
< priv
->head_note_state
) {
2657 priv
->head_note_state
= priv
->ourDesiredPowerState
; // we do, but not all the way
2658 priv
->head_note_outputFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].outputPowerCharacter
;
2659 priv
->head_note_capabilityFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].capabilityFlags
;
2660 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAmendParentChange
,(unsigned long)priv
->head_note_state
,0);
2664 priv
-> head_note_state
= pm_vars
->myCurrentState
; // we don't
2665 priv
->head_note_outputFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].outputPowerCharacter
;
2666 priv
->head_note_capabilityFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].capabilityFlags
;
2667 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAmendParentChange
,(unsigned long)priv
->head_note_state
,0);
2671 if ( (priv
->head_note_state
> pm_vars
->myCurrentState
) &&
2672 (priv
->head_note_flags
& IOPMDomainDidChange
) ) { // changing up
2673 priv
->initial_change
= false;
2674 priv
->machine_state
= IOPMparent_up_0
;
2675 if ( notifyAll(true) == IOPMAckImplied
) {
2676 return parent_up_1();
2678 return IOPMWillAckLater
; // they didn't all ack
2682 return IOPMAckImplied
; // a null change or power will go up
2686 //*********************************************************************************
2689 // Here we begin the processing of a change note initiated by us
2690 // which is at the head of the queue.
2692 // It is possible for the change to be processed to completion and removed from the queue.
2693 // There are several possible interruptions to the processing, though, and they are:
2694 // we may have to wait for interested parties to acknowledge our pre-change notification,
2695 // changes initiated by the parent will wait in the middle for powerStateDidChange,
2696 // we may have to wait for our controlling driver to change the hardware power state,
2697 // there may be a settling time after changing the hardware power state,
2698 // we may have to wait for interested parties to acknowledge our post-change notification,
2699 // we may have to wait for the acknowledgement timer expiration to substitute for the
2700 // acknowledgement from a failing driver.
2701 //*********************************************************************************
2703 void IOService::start_our_change ( unsigned long queue_head
)
2705 priv
->head_note
= queue_head
;
2706 priv
->head_note_flags
= priv
->changeList
->changeNote
[priv
->head_note
].flags
;
2707 priv
->head_note_state
= priv
->changeList
->changeNote
[priv
->head_note
].newStateNumber
;
2708 priv
->head_note_outputFlags
= priv
->changeList
->changeNote
[priv
->head_note
].outputPowerCharacter
;
2709 priv
->head_note_capabilityFlags
= priv
->changeList
->changeNote
[priv
->head_note
].capabilityFlags
;
2711 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartDeviceChange
,
2712 (unsigned long)priv
->head_note_state
,(unsigned long)pm_vars
->myCurrentState
);
2714 if ( priv
->head_note_capabilityFlags
& IOPMNotAttainable
) { // can our driver switch to the new state?
2715 if ( ! priv
->we_are_root
) { // no, ask the parent to do it then
2716 ask_parent(priv
->head_note_state
);
2718 priv
-> head_note_flags
|= IOPMNotDone
; // mark the change note un-actioned
2719 all_done(); // and we're done
2722 // is there enough power in the domain?
2723 if ( (pm_vars
->maxCapability
< priv
->head_note_state
) && (! priv
->we_are_root
) ) {
2724 if ( ! priv
->we_are_root
) { // no, ask the parent to raise it
2725 ask_parent(priv
->head_note_state
);
2727 priv
->head_note_flags
|= IOPMNotDone
; // no, mark the change note un-actioned
2728 all_done(); // and we're done
2729 return; // till the parent raises power
2732 if ( ! priv
->initial_change
) {
2733 if ( priv
->head_note_state
== pm_vars
->myCurrentState
) {
2734 all_done(); // we initiated a null change; forget it
2738 priv
->initial_change
= false;
2740 if ( priv
->head_note_state
< pm_vars
->myCurrentState
) { // dropping power?
2741 priv
->machine_state
= IOPMour_prechange_03
; // yes, in case we have to wait for acks
2742 pm_vars
->doNotPowerDown
= false;
2743 if ( askChangeDown(priv
->head_note_state
) ) { // ask apps and kernel clients if we can drop power
2744 if ( pm_vars
->doNotPowerDown
) { // don't have to wait, did any clients veto?
2745 tellNoChangeDown(priv
->head_note_state
); // yes, rescind the warning
2746 priv
-> head_note_flags
|= IOPMNotDone
; // mark the change note un-actioned
2747 all_done(); // and we're done
2750 our_prechange_03(); // no, tell'em we're dropping power
2755 if ( ! priv
->we_are_root
) { // we are raising power
2756 ask_parent(priv
->head_note_state
); // if this changes our power requirement, tell the parent
2758 priv
->machine_state
= IOPMour_prechange_1
; // in case they don't all ack
2759 if ( notifyAll(true) == IOPMAckImplied
) { // notify interested drivers and children
2766 //*********************************************************************************
2769 // Call the power domain parent to ask for a higher power state in the domain
2770 // or to suggest a lower power state.
2771 //*********************************************************************************
2773 IOReturn
IOService::ask_parent ( unsigned long requestedState
)
2777 IOPowerConnection
* connection
;
2779 if ( priv
->previousRequest
== pm_vars
->thePowerStates
[requestedState
].inputPowerRequirement
) { // is this a new desire?
2780 return IOPMNoErr
; // no, the parent knows already, just return
2783 if ( priv
->we_are_root
) {
2786 priv
->previousRequest
= pm_vars
->thePowerStates
[requestedState
].inputPowerRequirement
;
2788 iter
= getParentIterator(gIOPowerPlane
);
2791 while ( (next
= iter
->getNextObject()) ) {
2792 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
2793 if ( ((IOService
*)(connection
->getParentEntry(gIOPowerPlane
)))->requestPowerDomainState( priv
->previousRequest
,connection
,IOPMLowestState
)!= IOPMNoErr
) {
2794 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRequestDenied
,(unsigned long)priv
->previousRequest
,0);
2805 //*********************************************************************************
2808 // Call the controlling driver and have it change the power state of the
2809 // hardware. If it returns IOPMAckImplied, the change is complete, and
2810 // we return IOPMAckImplied. Otherwise, it will ack when the change
2811 // is done; we return IOPMWillAckLater.
2812 //*********************************************************************************
2814 IOReturn
IOService::instruct_driver ( unsigned long newState
)
2816 IOReturn return_code
;
2818 if ( pm_vars
->thePowerStates
[newState
].capabilityFlags
& IOPMNotAttainable
) { // can our driver switch to the desired state?
2819 return IOPMAckImplied
; // no, so don't try
2821 priv
->driver_timer
= -1;
2823 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogProgramHardware
,newState
,0);
2824 return_code
= pm_vars
->theControllingDriver
->setPowerState( newState
,this ); // yes, instruct it
2825 if ( return_code
== IOPMAckImplied
) { // it finished
2826 priv
->driver_timer
= 0;
2827 return IOPMAckImplied
;
2830 if ( priv
->driver_timer
== 0 ) { // it acked behind our back
2831 return IOPMAckImplied
;
2834 if ( return_code
< 0 ) { // somebody goofed
2835 return IOPMAckImplied
;
2838 priv
->driver_timer
= (return_code
* ns_per_us
/ ACK_TIMER_PERIOD
) + 1; // it didn't finish
2839 return IOPMWillAckLater
;
2843 //*********************************************************************************
2846 // We are acquiring the lock we use to protect our queue head from
2847 // simutaneous access by a thread which calls acknowledgePowerStateChange
2848 // or acknowledgeSetPowerState and the ack timer expiration thread.
2849 // Return TRUE if we acquire the lock, and the queue head didn't change
2850 // while we were acquiring the lock (and maybe blocked).
2851 // If there is no queue head, or it changes while we are blocked,
2852 // return FALSE with the lock unlocked.
2853 //*********************************************************************************
2855 bool IOService::acquire_lock ( void )
2857 long current_change_note
;
2859 current_change_note
= priv
->head_note
;
2860 if ( current_change_note
== -1 ) {
2864 IOTakeLock(priv
->our_lock
);
2865 if ( current_change_note
== priv
->head_note
) {
2868 else { // we blocked and something changed radically
2869 IOUnlock(priv
->our_lock
); // so there's nothing to do any more
2875 //*********************************************************************************
2878 // Ask registered applications and kernel clients if we can change to a lower
2881 // Subclass can override this to send a different message type. Parameter is
2882 // the destination state number.
2884 // Return true if we don't have to wait for acknowledgements
2885 //*********************************************************************************
2887 bool IOService::askChangeDown ( unsigned long )
2889 return tellClientsWithResponse(kIOMessageCanDevicePowerOff
);
2893 //*********************************************************************************
2896 // Notify registered applications and kernel clients that we are definitely
2899 // Subclass can override this to send a different message type. Parameter is
2900 // the destination state number.
2902 // Return true if we don't have to wait for acknowledgements
2903 //*********************************************************************************
2905 bool IOService::tellChangeDown ( unsigned long )
2907 return tellClientsWithResponse(kIOMessageDeviceWillPowerOff
);
2911 //*********************************************************************************
2912 // tellClientsWithResponse
2914 // Notify registered applications and kernel clients that we are definitely
2917 // Return true if we don't have to wait for acknowledgements
2918 //*********************************************************************************
2920 bool IOService::tellClientsWithResponse ( int messageType
)
2922 struct context theContext
;
2923 AbsoluteTime deadline
;
2926 pm_vars
->responseFlags
= OSArray::withCapacity( 1 );
2927 pm_vars
->serialNumber
+= 1;
2929 theContext
.responseFlags
= pm_vars
->responseFlags
;
2930 theContext
.serialNumber
= pm_vars
->serialNumber
;
2931 theContext
.flags_lock
= priv
->flags_lock
;
2932 theContext
.counter
= 1;
2933 theContext
.msgType
= messageType
;
2934 theContext
.us
= this;
2935 theContext
.maxTimeRequested
= 0;
2937 IOLockLock(priv
->flags_lock
);
2938 aBool
= OSBoolean::withBoolean(false); // position zero is false to
2939 theContext
.responseFlags
->setObject(0,aBool
); // prevent allowCancelCommon from succeeding
2941 IOLockUnlock(priv
->flags_lock
);
2943 applyToInterested(gIOAppPowerStateInterest
,tellAppWithResponse
,(void *)&theContext
);
2944 applyToInterested(gIOGeneralInterest
,tellClientWithResponse
,(void *)&theContext
);
2946 if (! acquire_lock() ) {
2949 IOLockLock(priv
->flags_lock
);
2950 aBool
= OSBoolean::withBoolean(true); // now fix position zero
2951 theContext
.responseFlags
->replaceObject(0,aBool
);
2953 IOLockUnlock(priv
->flags_lock
);
2955 if ( ! checkForDone() ) { // we have to wait for somebody
2956 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,theContext
.maxTimeRequested
,0);
2957 clock_interval_to_deadline(theContext
.maxTimeRequested
/ 1000, kMillisecondScale
, &deadline
);
2959 thread_call_enter_delayed(priv
->ackTimer
, deadline
);
2961 IOUnlock(priv
->our_lock
); // yes
2965 IOUnlock(priv
->our_lock
);
2966 IOLockLock(priv
->flags_lock
);
2967 pm_vars
->responseFlags
->release(); // everybody responded
2968 pm_vars
->responseFlags
= NULL
;
2969 IOLockUnlock(priv
->flags_lock
);
2975 //*********************************************************************************
2976 // tellAppWithResponse
2978 // We send a message to an application, and we expect a response, so we compute a
2979 // cookie we can identify the response with.
2980 //*********************************************************************************
2981 void tellAppWithResponse ( OSObject
* object
, void * context
)
2983 struct context
* theContext
= (struct context
*)context
;
2987 if( OSDynamicCast( IOService
, object
) ) {
2988 IOLockLock(theContext
->flags_lock
);
2989 aBool
= OSBoolean::withBoolean(true);
2990 theContext
->responseFlags
->setObject(theContext
->counter
,aBool
);
2992 IOLockUnlock(theContext
->flags_lock
);
2995 refcon
= ((theContext
->serialNumber
& 0xFFFF)<<16) + (theContext
->counter
& 0xFFFF);
2996 IOLockLock(theContext
->flags_lock
);
2997 aBool
= OSBoolean::withBoolean(false);
2998 theContext
->responseFlags
->setObject(theContext
->counter
,aBool
);
3000 IOLockUnlock(theContext
->flags_lock
);
3001 theContext
->us
->messageClient(theContext
->msgType
,object
,(void *)refcon
);
3002 if ( theContext
->maxTimeRequested
< k15seconds
) {
3003 theContext
->maxTimeRequested
= k15seconds
;
3006 theContext
->counter
+= 1;
3010 //*********************************************************************************
3011 // tellClientWithResponse
3013 // We send a message to an in-kernel client, and we expect a response, so we compute a
3014 // cookie we can identify the response with.
3015 // If it doesn't understand the notification (it is not power-management savvy)
3016 // we won't wait for it to prepare for sleep. If it tells us via a return code
3017 // in the passed struct that it is currently ready, we won't wait for it to prepare.
3018 // If it tells us via the return code in the struct that it does need time, we will chill.
3019 //*********************************************************************************
3020 void tellClientWithResponse ( OSObject
* object
, void * context
)
3022 struct context
* theContext
= (struct context
*)context
;
3023 sleepWakeNote paramBlock
;
3029 refcon
= ((theContext
->serialNumber
& 0xFFFF)<<16) + (theContext
->counter
& 0xFFFF);
3030 IOLockLock(theContext
->flags_lock
);
3031 aBool
= OSBoolean::withBoolean(false);
3032 theContext
->responseFlags
->setObject(theContext
->counter
,aBool
);
3034 IOLockUnlock(theContext
->flags_lock
);
3035 paramBlock
.powerRef
= (void *)refcon
;
3036 paramBlock
.returnValue
= 0;
3037 retCode
= theContext
->us
->messageClient(theContext
->msgType
,object
,(void *)¶mBlock
);
3038 if ( retCode
== kIOReturnSuccess
) {
3039 if ( paramBlock
.returnValue
== 0 ) { // client doesn't want time to respond
3040 IOLockLock(theContext
->flags_lock
);
3041 aBool
= OSBoolean::withBoolean(true);
3042 theContext
->responseFlags
->replaceObject(theContext
->counter
,aBool
); // so set its flag true
3044 IOLockUnlock(theContext
->flags_lock
);
3047 IOLockLock(theContext
->flags_lock
);
3048 theFlag
= theContext
->responseFlags
->getObject(theContext
->counter
); // it does want time, and it hasn't
3049 if ( theFlag
!= 0 ) { // responded yet
3050 if ( ((OSBoolean
*)theFlag
)->isFalse() ) { // so note its time requirement
3051 if ( theContext
->maxTimeRequested
< paramBlock
.returnValue
) {
3052 theContext
->maxTimeRequested
= paramBlock
.returnValue
;
3056 IOLockUnlock(theContext
->flags_lock
);
3059 else { // not a client of ours
3060 IOLockLock(theContext
->flags_lock
);
3061 aBool
= OSBoolean::withBoolean(true); // so we won't be waiting for response
3062 theContext
->responseFlags
->replaceObject(theContext
->counter
,aBool
);
3064 IOLockUnlock(theContext
->flags_lock
);
3066 theContext
->counter
+= 1;
3070 //*********************************************************************************
3073 // Notify registered applications and kernel clients that we are not
3076 // Subclass can override this to send a different message type. Parameter is
3077 // the aborted destination state number.
3078 //*********************************************************************************
3080 void IOService::tellNoChangeDown ( unsigned long )
3082 return tellClients(kIOMessageDeviceWillNotPowerOff
);
3086 //*********************************************************************************
3089 // Notify registered applications and kernel clients that we are raising power.
3091 // Subclass can override this to send a different message type. Parameter is
3092 // the aborted destination state number.
3093 //*********************************************************************************
3095 void IOService::tellChangeUp ( unsigned long )
3097 return tellClients(kIOMessageDeviceHasPoweredOn
);
3101 //*********************************************************************************
3104 // Notify registered applications and kernel clients of something.
3105 //*********************************************************************************
3107 void IOService::tellClients ( int messageType
)
3109 struct context theContext
;
3111 theContext
.msgType
= messageType
;
3112 theContext
.us
= this;
3114 applyToInterested(gIOAppPowerStateInterest
,tellClient
,(void *)&theContext
);
3115 applyToInterested(gIOGeneralInterest
,tellClient
,(void *)&theContext
);
3119 //*********************************************************************************
3122 // Notify a registered application or kernel client of something.
3123 //*********************************************************************************
3124 void tellClient ( OSObject
* object
, void * context
)
3126 struct context
* theContext
= (struct context
*)context
;
3128 theContext
->us
->messageClient(theContext
->msgType
,object
,0);
3132 // **********************************************************************************
3135 // **********************************************************************************
3136 bool IOService::checkForDone ( void )
3141 IOLockLock(priv
->flags_lock
);
3142 if ( pm_vars
->responseFlags
== NULL
) {
3143 IOLockUnlock(priv
->flags_lock
);
3146 for ( i
= 0; ; i
++ ) {
3147 theFlag
= pm_vars
->responseFlags
->getObject(i
);
3148 if ( theFlag
== NULL
) {
3151 if ( ((OSBoolean
*)theFlag
)->isFalse() ) {
3152 IOLockUnlock(priv
->flags_lock
);
3156 IOLockUnlock(priv
->flags_lock
);
3161 // **********************************************************************************
3164 // **********************************************************************************
3165 bool IOService::responseValid ( unsigned long x
)
3167 UInt16 serialComponent
;
3168 UInt16 ordinalComponent
;
3170 unsigned long refcon
= (unsigned long)x
;
3173 serialComponent
= (refcon
>>16) & 0xFFFF;
3174 ordinalComponent
= refcon
& 0xFFFF;
3176 if ( serialComponent
!= pm_vars
->serialNumber
) {
3180 IOLockLock(priv
->flags_lock
);
3181 if ( pm_vars
->responseFlags
== NULL
) {
3182 IOLockUnlock(priv
->flags_lock
);
3186 theFlag
= pm_vars
->responseFlags
->getObject(ordinalComponent
);
3188 if ( theFlag
== 0 ) {
3189 IOLockUnlock(priv
->flags_lock
);
3193 if ( ((OSBoolean
*)theFlag
)->isFalse() ) {
3194 aBool
= OSBoolean::withBoolean(true);
3195 pm_vars
->responseFlags
->replaceObject(ordinalComponent
,aBool
);
3199 IOLockUnlock(priv
->flags_lock
);
3204 // **********************************************************************************
3207 // Our power state is about to lower, and we have notified applications
3208 // and kernel clients, and one of them has acknowledged. If this is the last to do
3209 // so, and all acknowledgements are positive, we continue with the power change.
3211 // We serialize this processing with timer expiration with a command gate on the
3212 // power management workloop, which the timer expiration is command gated to as well.
3213 // **********************************************************************************
3214 IOReturn
IOService::allowPowerChange ( unsigned long refcon
)
3216 if ( ! initialized
) {
3217 return kIOReturnSuccess
; // we're unloading
3220 return pm_vars
->PMcommandGate
->runAction(serializedAllowPowerChange
,(void *)refcon
);
3224 IOReturn
serializedAllowPowerChange ( OSObject
*owner
, void * refcon
, void *, void *, void *)
3226 return ((IOService
*)owner
)->serializedAllowPowerChange2((unsigned long)refcon
);
3229 IOReturn
IOService::serializedAllowPowerChange2 ( unsigned long refcon
)
3231 if ( ! responseValid(refcon
) ) { // response valid?
3232 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr5
,refcon
,0);
3233 return kIOReturnSuccess
; // no, just return
3235 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientAcknowledge
,refcon
,0);
3237 return allowCancelCommon();
3241 // **********************************************************************************
3242 // cancelPowerChange
3244 // Our power state is about to lower, and we have notified applications
3245 // and kernel clients, and one of them has vetoed the change. If this is the last
3246 // client to respond, we abandon the power change.
3248 // We serialize this processing with timer expiration with a command gate on the
3249 // power management workloop, which the timer expiration is command gated to as well.
3250 // **********************************************************************************
3251 IOReturn
IOService::cancelPowerChange ( unsigned long refcon
)
3253 if ( ! initialized
) {
3254 return kIOReturnSuccess
; // we're unloading
3257 return pm_vars
->PMcommandGate
->runAction(serializedCancelPowerChange
,(void *)refcon
);
3261 IOReturn
serializedCancelPowerChange ( OSObject
*owner
, void * refcon
, void *, void *, void *)
3263 return ((IOService
*)owner
)->serializedCancelPowerChange2((unsigned long)refcon
);
3266 IOReturn
IOService::serializedCancelPowerChange2 ( unsigned long refcon
)
3268 if ( ! responseValid(refcon
) ) { // response valid?
3269 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr5
,refcon
,0);
3270 return kIOReturnSuccess
; // no, just return
3272 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientCancel
,refcon
,0);
3274 pm_vars
->doNotPowerDown
= true;
3276 return allowCancelCommon();
3280 // **********************************************************************************
3281 // allowCancelCommon
3283 // **********************************************************************************
3284 IOReturn
IOService::allowCancelCommon ( void )
3286 if (! acquire_lock() ) {
3287 return kIOReturnSuccess
;
3290 if ( checkForDone() ) { // is this the last response?
3291 stop_ack_timer(); // yes, stop the timer
3292 IOUnlock(priv
->our_lock
);
3293 IOLockLock(priv
->flags_lock
);
3294 if ( pm_vars
->responseFlags
) {
3295 pm_vars
->responseFlags
->release();
3296 pm_vars
->responseFlags
= NULL
;
3298 IOLockUnlock(priv
->flags_lock
);
3299 switch (priv
->machine_state
) {
3300 case IOPMour_prechange_03
: // our change, was it vetoed?
3301 if ( ! pm_vars
->doNotPowerDown
) {
3302 our_prechange_03(); // no, we can continue
3305 tellNoChangeDown(priv
->head_note_state
); // yes, rescind the warning
3306 priv
->head_note_flags
|= IOPMNotDone
; // mark the change note un-actioned
3307 all_done(); // and we're done
3310 case IOPMour_prechange_05
:
3311 our_prechange_05(); // our change, continue
3313 case IOPMparent_down_0
:
3314 parent_down_05(); // parent change, continueq8q
3317 return kIOReturnSuccess
;
3320 IOUnlock(priv
->our_lock
); // not done yet
3321 return kIOReturnSuccess
;
3325 //*********************************************************************************
3328 // Set to highest available power state for a minimum of duration milliseconds
3329 //*********************************************************************************
3331 #define kFiveMinutesInNanoSeconds (300 * NSEC_PER_SEC)
3333 void IOService::clampPowerOn (unsigned long duration
)
3335 changePowerStateToPriv (pm_vars
->theNumberOfPowerStates
-1);
3337 if ( priv
->clampTimerEventSrc
== NULL
) {
3338 priv
->clampTimerEventSrc
= IOTimerEventSource::timerEventSource(this,
3339 c_PM_Clamp_Timer_Expired
);
3341 IOWorkLoop
* workLoop
= getPMworkloop ();
3343 if ( !priv
->clampTimerEventSrc
|| !workLoop
||
3344 ( workLoop
->addEventSource( priv
->clampTimerEventSrc
) != kIOReturnSuccess
) ) {
3349 priv
->clampTimerEventSrc
->setTimeout(kFiveMinutesInNanoSeconds
, NSEC_PER_SEC
);
3352 //*********************************************************************************
3353 // PM_Clamp_Timer_Expired
3355 // called when clamp timer expires...set power state to 0.
3356 //*********************************************************************************
3358 void IOService::PM_Clamp_Timer_Expired (void)
3360 if ( ! initialized
) {
3361 return; // we're unloading
3364 changePowerStateToPriv (0);
3367 //*********************************************************************************
3368 // c_PM_clamp_Timer_Expired (C Func)
3370 // Called when our clamp timer expires...we will call the object method.
3371 //*********************************************************************************
3373 void c_PM_Clamp_Timer_Expired (OSObject
* client
, IOTimerEventSource
*)
3376 ((IOService
*)client
)->PM_Clamp_Timer_Expired ();
3380 //*********************************************************************************
3383 // Does nothing here. This should be implemented in a subclass driver.
3384 //*********************************************************************************
3386 IOReturn
IOService::setPowerState ( unsigned long powerStateOrdinal
, IOService
* whatDevice
)
3392 //*********************************************************************************
3393 // maxCapabilityForDomainState
3395 // Finds the highest power state in the array whose input power
3396 // requirement is equal to the input parameter. Where a more intelligent
3397 // decision is possible, override this in the subclassed driver.
3398 //*********************************************************************************
3400 unsigned long IOService::maxCapabilityForDomainState ( IOPMPowerFlags domainState
)
3404 if (pm_vars
->theNumberOfPowerStates
== 0 ) {
3407 for ( i
= (pm_vars
->theNumberOfPowerStates
)-1; i
>= 0; i
-- ) {
3408 if ( pm_vars
->thePowerStates
[i
].inputPowerRequirement
== domainState
) {
3416 //*********************************************************************************
3417 // initialPowerStateForDomainState
3419 // Finds the highest power state in the array whose input power
3420 // requirement is equal to the input parameter. Where a more intelligent
3421 // decision is possible, override this in the subclassed driver.
3422 //*********************************************************************************
3424 unsigned long IOService::initialPowerStateForDomainState ( IOPMPowerFlags domainState
)
3428 if (pm_vars
->theNumberOfPowerStates
== 0 ) {
3431 for ( i
= (pm_vars
->theNumberOfPowerStates
)-1; i
>= 0; i
-- ) {
3432 if ( pm_vars
->thePowerStates
[i
].inputPowerRequirement
== domainState
) {
3440 //*********************************************************************************
3441 // powerStateForDomainState
3443 // Finds the highest power state in the array whose input power
3444 // requirement is equal to the input parameter. Where a more intelligent
3445 // decision is possible, override this in the subclassed driver.
3446 //*********************************************************************************
3448 unsigned long IOService::powerStateForDomainState ( IOPMPowerFlags domainState
)
3452 if (pm_vars
->theNumberOfPowerStates
== 0 ) {
3455 for ( i
= (pm_vars
->theNumberOfPowerStates
)-1; i
>= 0; i
-- ) {
3456 if ( pm_vars
->thePowerStates
[i
].inputPowerRequirement
== domainState
) {
3464 //*********************************************************************************
3467 // Does nothing here. This should be implemented in a subclass driver.
3468 //*********************************************************************************
3470 bool IOService::didYouWakeSystem ( void )
3476 //*********************************************************************************
3477 // powerStateWillChangeTo
3479 // Does nothing here. This should be implemented in a subclass driver.
3480 //*********************************************************************************
3482 IOReturn
IOService::powerStateWillChangeTo ( IOPMPowerFlags
, unsigned long, IOService
*)
3488 //*********************************************************************************
3489 // powerStateDidChangeTo
3491 // Does nothing here. This should be implemented in a subclass driver.
3492 //*********************************************************************************
3494 IOReturn
IOService::powerStateDidChangeTo ( IOPMPowerFlags
, unsigned long, IOService
*)
3500 //*********************************************************************************
3503 // Does nothing here. This should be implemented in a subclass policy-maker.
3504 //*********************************************************************************
3506 void IOService::powerChangeDone ( unsigned long )
3511 //*********************************************************************************
3514 // Does nothing here. This should be implemented in a subclass driver.
3515 //*********************************************************************************
3517 IOReturn
IOService::newTemperature ( long currentTemp
, IOService
* whichZone
)
3525 #define super OSObject
3527 OSDefineMetaClassAndStructors(IOPMprot
, OSObject
)
3528 //*********************************************************************************
3531 // Serialize protected instance variables for debug output.
3532 //*********************************************************************************
3533 bool IOPMprot::serialize(OSSerialize
*s
) const
3535 OSString
* theOSString
;
3541 buffer
= ptr
= IONew(char, 2000);
3545 ptr
+= sprintf(ptr
,"{ theNumberOfPowerStates = %d, ",(unsigned int)theNumberOfPowerStates
);
3547 if ( theNumberOfPowerStates
!= 0 ) {
3548 ptr
+= sprintf(ptr
,"version %d, ",(unsigned int)thePowerStates
[0].version
);
3551 if ( theNumberOfPowerStates
!= 0 ) {
3552 for ( i
= 0; i
< (int)theNumberOfPowerStates
; i
++ ) {
3553 ptr
+= sprintf(ptr
,"power state %d = { ",i
);
3554 ptr
+= sprintf(ptr
,"capabilityFlags %08x, ",(unsigned int)thePowerStates
[i
].capabilityFlags
);
3555 ptr
+= sprintf(ptr
,"outputPowerCharacter %08x, ",(unsigned int)thePowerStates
[i
].outputPowerCharacter
);
3556 ptr
+= sprintf(ptr
,"inputPowerRequirement %08x, ",(unsigned int)thePowerStates
[i
].inputPowerRequirement
);
3557 ptr
+= sprintf(ptr
,"staticPower %d, ",(unsigned int)thePowerStates
[i
].staticPower
);
3558 ptr
+= sprintf(ptr
,"unbudgetedPower %d, ",(unsigned int)thePowerStates
[i
].unbudgetedPower
);
3559 ptr
+= sprintf(ptr
,"powerToAttain %d, ",(unsigned int)thePowerStates
[i
].powerToAttain
);
3560 ptr
+= sprintf(ptr
,"timeToAttain %d, ",(unsigned int)thePowerStates
[i
].timeToAttain
);
3561 ptr
+= sprintf(ptr
,"settleUpTime %d, ",(unsigned int)thePowerStates
[i
].settleUpTime
);
3562 ptr
+= sprintf(ptr
,"timeToLower %d, ",(unsigned int)thePowerStates
[i
].timeToLower
);
3563 ptr
+= sprintf(ptr
,"settleDownTime %d, ",(unsigned int)thePowerStates
[i
].settleDownTime
);
3564 ptr
+= sprintf(ptr
,"powerDomainBudget %d }, ",(unsigned int)thePowerStates
[i
].powerDomainBudget
);
3568 ptr
+= sprintf(ptr
,"aggressiveness = %d, ",(unsigned int)aggressiveness
);
3569 ptr
+= sprintf(ptr
,"myCurrentState = %d, ",(unsigned int)myCurrentState
);
3570 ptr
+= sprintf(ptr
,"parentsCurrentPowerFlags = %08x, ",(unsigned int)parentsCurrentPowerFlags
);
3571 ptr
+= sprintf(ptr
,"maxCapability = %d }",(unsigned int)maxCapability
);
3573 theOSString
= OSString::withCString(buffer
);
3574 rtn_code
= theOSString
->serialize(s
);
3575 theOSString
->release();
3576 IODelete(buffer
, char, 2000);
3583 #define super OSObject
3585 OSDefineMetaClassAndStructors(IOPMpriv
, OSObject
)
3586 //*********************************************************************************
3589 // Serialize private instance variables for debug output.
3590 //*********************************************************************************
3591 bool IOPMpriv::serialize(OSSerialize
*s
) const
3593 OSString
* theOSString
;
3597 IOPMinformee
* nextObject
;
3599 buffer
= ptr
= IONew(char, 2000);
3603 ptr
+= sprintf(ptr
,"{ this object = %08x",(unsigned int)owner
);
3604 if ( we_are_root
) {
3605 ptr
+= sprintf(ptr
," (root)");
3607 ptr
+= sprintf(ptr
,", ");
3609 nextObject
= interestedDrivers
->firstInList(); // display interested drivers
3610 while ( nextObject
!= NULL
) {
3611 ptr
+= sprintf(ptr
,"interested driver = %08x, ",(unsigned int)nextObject
->whatObject
);
3612 nextObject
= interestedDrivers
->nextInList(nextObject
);
3615 if ( machine_state
!= IOPMfinished
) {
3616 ptr
+= sprintf(ptr
,"machine_state = %d, ",(unsigned int)machine_state
);
3617 ptr
+= sprintf(ptr
,"driver_timer = %d, ",(unsigned int)driver_timer
);
3618 ptr
+= sprintf(ptr
,"settle_time = %d, ",(unsigned int)settle_time
);
3619 ptr
+= sprintf(ptr
,"head_note_flags = %08x, ",(unsigned int)head_note_flags
);
3620 ptr
+= sprintf(ptr
,"head_note_state = %d, ",(unsigned int)head_note_state
);
3621 ptr
+= sprintf(ptr
,"head_note_outputFlags = %08x, ",(unsigned int)head_note_outputFlags
);
3622 ptr
+= sprintf(ptr
,"head_note_domainState = %08x, ",(unsigned int)head_note_domainState
);
3623 ptr
+= sprintf(ptr
,"head_note_capabilityFlags = %08x, ",(unsigned int)head_note_capabilityFlags
);
3624 ptr
+= sprintf(ptr
,"head_note_pendingAcks = %d, ",(unsigned int)head_note_pendingAcks
);
3627 if ( device_overrides
) {
3628 ptr
+= sprintf(ptr
,"device overrides, ");
3630 ptr
+= sprintf(ptr
,"driverDesire = %d, ",(unsigned int)driverDesire
);
3631 ptr
+= sprintf(ptr
,"deviceDesire = %d, ",(unsigned int)deviceDesire
);
3632 ptr
+= sprintf(ptr
,"ourDesiredPowerState = %d, ",(unsigned int)ourDesiredPowerState
);
3633 ptr
+= sprintf(ptr
,"previousRequest = %d }",(unsigned int)previousRequest
);
3635 theOSString
= OSString::withCString(buffer
);
3636 rtn_code
= theOSString
->serialize(s
);
3637 theOSString
->release();
3638 IODelete(buffer
, char, 2000);