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"
37 #include <kern/clock.h>
39 static void ack_timer_expired(thread_call_param_t
);
40 static void settle_timer_expired(thread_call_param_t
);
41 void PMreceiveCmd ( OSObject
*, void *, void *, void *, void * );
42 static void PM_idle_timer_expired(OSObject
*, IOTimerEventSource
*);
43 static void c_PM_Clamp_Timer_Expired (OSObject
* client
,IOTimerEventSource
*);
44 void tellAppWithResponse ( OSObject
* object
, void * context
);
45 void tellClientWithResponse ( OSObject
* object
, void * context
);
46 void tellClient ( OSObject
* object
, void * context
);
47 IOReturn
serializedAllowPowerChange ( OSObject
*, void *, void *, void *, void *);
48 IOReturn
serializedCancelPowerChange ( OSObject
*, void *, void *, void *, void *);
50 extern const IORegistryPlane
* gIOPowerPlane
;
53 // and there's 1000 nanoseconds in a microsecond:
54 #define ns_per_us 1000
57 // The current change note is processed by a state machine.
58 // Inputs are acks from interested parties, ack from the controlling driver,
59 // ack timeouts, settle timeout, and powerStateDidChange from the parent.
60 // These are the states:
63 IOPMour_prechange_03
= 1,
83 struct context
{ // used for applyToInterested
84 OSArray
* responseFlags
;
87 UInt32 maxTimeRequested
;
93 // five minutes in microseconds
94 #define FIVE_MINUTES 5*60*1000000
95 #define k15seconds 15*1000000
98 There are two different kinds of power state changes. One is initiated by a subclassed device object which has either
99 decided to change power state, or its controlling driver has suggested it, or some other driver wants to use the
100 idle device and has asked it to become usable. The second kind of power state change is initiated by the power
101 domain parent. The two are handled slightly differently.
103 There is a queue of so-called change notifications, or change notes for short. Usually the queue is empty, and when
104 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
105 at one time, a queue is implemented. Example: the subclass device decides it's idle and initiates a change to a lower
106 power state. This causes interested parties to be notified, but they don't all acknowledge right away. This causes the
107 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
108 wants to raise power back up again. This change can't be started, however, because the previous one isn't complete yet,
109 so the second one waits in the queue. During this time, the parent decides to lower or raise the power state of the entire
110 power domain and notifies the device, and that notification goes into the queue, too, and can't be actioned until the
113 This is how a power change initiated by the subclass device is handled:
114 First, all interested parties are notified of the change via their powerStateWillChangeTo method. If they all don't
115 acknowledge via return code, then we have to wait. If they do, or when they finally all acknowledge via our
116 acknowledgePowerChange method, then we can continue. We call the controlling driver, instructing it to change to
117 the new state. Then we wait for power to settle. If there is no settling-time, or after it has passed, we notify
118 interested parties again, this time via their powerStateDidChangeTo methods. When they have all acked, we're done.
119 If we lowered power and don't need the power domain to be in its current power state, we suggest to the parent that
120 it lower the power domain state.
122 This is how a change to a lower power domain state initiated by the parent is handled:
123 First, we figure out what power state we will be in when the new domain state is reached. Then all interested parties are
124 notified that we are moving to that new state. When they have acknowledged, we call the controlling driver to assume
125 that state and we wait for power to settle. Then we acknowledge our preparedness to our parent. When all its interested
126 parties have acknowledged, it lowers power and then notifies its interested parties again. When we get this call, we notify
127 our interested parties that the power state has changed, and when they have all acknowledged, we're done.
129 This is how a change to a higher power domain state initiated by the parent is handled:
130 We figure out what power state we will be in when the new domain state is reached. If it is different from our current
131 state we acknowledge the parent. When all the parent's interested parties have acknowledged, it raises power in the
132 domain and waits for power to settle. Then it notifies everyone that the new state has been reached. When we get this call,
133 we call the controlling driver, instructing it to assume the new state, and wait for power to settle. Then we notify our interested
134 parties. When they all acknowledge we are done.
136 In either of the two cases above, it is possible that we will not be changing state even though the domain is. Examples:
137 A change to a lower domain state may not affect us because we are already in a low enough state, and
138 We will not take advantage of a change to a higher domain state, because we have no need of the higher power.
139 In such a case, there is nothing to do but acknowledge the parent. So when the parent calls our powerDomainWillChange
140 method, and we decide that we will not be changing state, we merely acknowledge the parent, via return code, and wait.
141 When the parent subsequently calls powerStateDidChange, we acknowledge again via return code, and the change is complete.
143 Power state changes are processed in a state machine, and since there are four varieties of power state changes, there are
144 four major paths through the state machine:
146 The fourth is nearly trivial. In this path, the parent is changing the domain state, but we are not changing the device state.
147 The change starts when the parent calls powerDomainWillChange. All we do is acknowledge the parent.
148 When the parent calls powerStateDidChange, we acknowledge the parent again, and we're done.
150 The first is fairly simple. It starts when a power domain child calls requestPowerDomainState and we decide to change power states
151 to accomodate the child, or if our power-controlling driver calls changePowerStateTo, or if some other driver which is using our
152 device calls makeUsable, or if a subclassed object calls changePowerStateToPriv. These are all power changes initiated by us, not
153 forced upon us by the parent. We start by notifying interested parties. If they all acknowledge via return code, we can go
154 on to state "our_prechange_1". Otherwise, we start the ack timer and wait for the stragglers to acknowlege by calling
155 acknowledgePowerChange. We move on to state "our_prechange_1" when all the stragglers have acknowledged,
156 or when the ack timer expires on all those which didn't acknowledge. In "our_prechange_1" we call the power-controlling
157 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".
158 Otherwise, we have to wait for it, so we set the ack timer and wait. When it calls acknowledgeSetPowerState, or when the
159 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
160 when changing from our current state to the new state. If not, we go right away to "our_prechange_3". Otherwise, we
161 set the settle timer and wait. When it expires, we move on. In "our_prechange_3" state, we notify all our interested parties
162 via their powerStateDidChange methods that we have finished changing power state. If they all acknowledge via return
163 code, we move on to "our_prechange_4". Otherwise we set the ack timer and wait. When they have all acknowledged, or
164 when the ack timer has expired for those that didn't, we move on to "our_prechange_4", where we remove the used
165 change note from the head of the queue and start the next one if one exists.
167 Parent-initiated changes are more complex in the state machine. First, power going up and power going down are handled
168 differently, so they have different paths throught the state machine. Second, we can acknowledge the parent's notification
169 in two different ways, so each of the parent paths is really two.
171 When the parent calls our powerDomainWillChange method, notifying us that it will lower power in the domain, we decide
172 what state that will put our device in. Then we embark on the state machine path "IOPMparent_down_1"
173 and "IOPMparent_down_2", in which we notify interested parties of the upcoming change, instruct our driver to make
174 the change, check for settle time, and notify interested parties of the completed change. If we get to the end of this path without
175 stalling due to an interested party which didn't acknowledge via return code, due to the controlling driver not able to change
176 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.
177 If we do stall in any of those states, we return IOPMWillAckLater to the parent and enter the parallel path "IOPMparent_down_4"
178 "IOPMparent_down_5", and "IOPMparent_down_3", where we continue with the same processing, except that at the end we
179 acknowledge the parent explicitly via acknowledgePowerChange, and we're done with the change.
180 Then when the parent calls us at powerStateDidChange we acknowledging via return code, because we have already made
181 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.
183 The case of the parent raising power in the domain is handled similarly in that there are parallel paths, one for no-stall
184 that ends in implicit acknowleging the parent, and one that has stalled at least once that ends in explicit acknowledging
185 the parent. This case is different, though in that our device changes state in the second half, after the parent calls
186 powerStateDidChange rather than before, as in the power-lowering case.
188 When the parent calls our powerDomainWillChange method, notifying us that it will raise power in the domain, we acknowledge
189 via return code, because there's really nothing we can do until the power is actually raised in the domain.
190 When the parent calls us at powerStateDidChange, we start by notifying our interested parties. If they all acknowledge via return code,
191 we go on to" IOPMparent_up_1" to instruct the driver to raise its power level. After that, we check for any
192 necessary settling time in "IOPMparent_up_2", and we notify all interested parties that power has changed
193 in "IOPMparent_up_3". If none of these operations stall, we acknowledge the parent via return code, release
194 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",
195 "IOPMparent_up_4", "IOPMparent_up_5", and "IOPMparent_up_6", which ends with
196 our explicit acknowledgement to the parent.
201 const char priv_key
[ ] = "Power Management private data";
202 const char prot_key
[ ] = "Power Management protected data";
205 void IOService::PMinit ( void )
207 if ( ! initialized
) {
209 pm_vars
= new IOPMprot
; // make space for our variables
214 setProperty(prot_key
, (OSObject
*) pm_vars
); // add these to the properties
215 setProperty(priv_key
, (OSObject
*) priv
);
218 pm_vars
->theNumberOfPowerStates
= 0; // then initialize them
219 priv
->we_are_root
= false;
220 pm_vars
->theControllingDriver
= NULL
;
221 priv
->our_lock
= IOLockAlloc();
222 priv
->flags_lock
= IOLockAlloc();
223 priv
->interestedDrivers
= new IOPMinformeeList
;
224 priv
->interestedDrivers
->initialize();
225 priv
->changeList
= new IOPMchangeNoteList
;
226 priv
->changeList
->initialize();
227 pm_vars
->aggressiveness
= 0;
228 for (unsigned int i
= 0; i
<= kMaxType
; i
++) {
229 pm_vars
->current_aggressiveness_values
[i
] = 0;
230 pm_vars
->current_aggressiveness_valid
[i
] = false;
232 pm_vars
->myCurrentState
= 0;
233 priv
->imminentState
= 0;
235 priv
->ourDesiredPowerState
= 0;
236 pm_vars
->parentsCurrentPowerFlags
= 0;
237 pm_vars
->maxCapability
= 0;
238 priv
->driverDesire
= 0;
239 priv
->deviceDesire
= 0;
240 priv
->initial_change
= true;
241 priv
->need_to_become_usable
= false;
242 priv
->previousRequest
= 0;
243 priv
->device_overrides
= false;
244 priv
->machine_state
= IOPMfinished
;
245 pm_vars
->commandQueue
= NULL
;
246 priv
->timerEventSrc
= NULL
;
247 priv
->clampTimerEventSrc
= NULL
;
248 pm_vars
->PMworkloop
= NULL
;
249 priv
->activityLock
= NULL
;
250 pm_vars
->ourName
= getName();
251 pm_vars
->thePlatform
= getPlatform();
252 pm_vars
->parentsKnowState
= false;
253 assert( pm_vars
->thePlatform
!= 0 );
254 priv
->clampOn
= false;
255 pm_vars
->serialNumber
= 0;
256 pm_vars
->responseFlags
= NULL
;
257 pm_vars
->doNotPowerDown
= true;
258 pm_vars
->PMcommandGate
= NULL
;
259 priv
->ackTimer
= thread_call_allocate((thread_call_func_t
)ack_timer_expired
, (thread_call_param_t
)this);
260 priv
->settleTimer
= thread_call_allocate((thread_call_func_t
)settle_timer_expired
, (thread_call_param_t
)this);
266 //*********************************************************************************
269 // Free up the data created in PMinit.
270 //*********************************************************************************
271 void IOService::PMstop ( void )
275 IOPowerConnection
* connection
;
279 removeProperty(prot_key
); // remove the properties
280 removeProperty(priv_key
);
282 iter
= getParentIterator(gIOPowerPlane
); // detach parents
285 while ( (next
= iter
->getNextObject()) ) {
286 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
287 ((IOService
*)(connection
->getParentEntry(gIOPowerPlane
)))->removePowerChild(connection
);
292 detachAbove( gIOPowerPlane
); // detach IOConnections
294 pm_vars
->parentsKnowState
= false; // no more power state changes
297 // This loop is insufficient. Currently only leaf nodes are removed, and it's not clear today what
298 // it means to remove a subtree from the tree. Should the IOPowerConnection at the top of it stay
299 // or go? Should its child be notified of a change in the domain state?
301 iter
= getChildIterator(gIOPowerPlane
); // detach children
304 while ( (next
= iter
->getNextObject()) ) {
305 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
306 removePowerChild(connection
);
313 if ( priv
->clampTimerEventSrc
!= NULL
) {
314 getPMworkloop()->removeEventSource(priv
->clampTimerEventSrc
);
315 priv
->clampTimerEventSrc
->release();
316 priv
->clampTimerEventSrc
= NULL
;
318 if ( priv
->timerEventSrc
!= NULL
) {
319 pm_vars
->PMworkloop
->removeEventSource(priv
->timerEventSrc
);
320 priv
->timerEventSrc
->release();
321 priv
->timerEventSrc
= NULL
;
323 thread_call_free(priv
->settleTimer
);
324 thread_call_free(priv
->ackTimer
);
326 priv
->interestedDrivers
->release(); // remove lists
327 priv
->changeList
->release();
328 pm_vars
->release(); // remove the instance variables
335 //*********************************************************************************
338 // A policy-maker calls its nub here when initializing, to be attached into
339 // the power management hierarchy. The default function is to call the
340 // platform expert, which knows how to do it. This method is overridden
341 // by a nub subclass which may either know how to do it, or may need
342 // to take other action.
344 // This may be the only "power management" method used in a nub,
345 // meaning it may not be initialized for power management.
346 //*********************************************************************************
347 void IOService::joinPMtree ( IOService
* driver
)
349 IOPlatformExpert
* thePlatform
;
351 thePlatform
= getPlatform();
352 assert(thePlatform
!= 0 );
353 thePlatform
->PMRegisterDevice(this,driver
);
357 //*********************************************************************************
360 // Power Managment is informing us that we are the root power domain.
361 // The only difference between us and any other power domain is that
362 // we have no parent and therefore never call it.
363 //*********************************************************************************
364 IOReturn
IOService::youAreRoot ( void )
366 priv
-> we_are_root
= true;
367 pm_vars
->parentsKnowState
= true;
368 attachToParent( getRegistryRoot(),gIOPowerPlane
);
374 //*********************************************************************************
377 // Power Management is informing us who our parent is.
378 // If we have a controlling driver, find out, given our newly-informed
379 // power domain state, what state it would be in, and then tell it
380 // to assume that state.
381 //*********************************************************************************
382 IOReturn
IOService::setPowerParent ( IOPowerConnection
* theParent
, bool stateKnown
, IOPMPowerFlags currentState
)
386 IOPowerConnection
* connection
;
387 unsigned long tempDesire
;
389 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogSetParent
,stateKnown
,currentState
);
391 if ( stateKnown
&& ((pm_vars
->PMworkloop
== NULL
) || (pm_vars
->PMcommandGate
== NULL
)) ) {
392 getPMworkloop(); // we have a path to the root
393 if ( pm_vars
->PMworkloop
!= NULL
) { // find out the workloop
394 if ( pm_vars
->PMcommandGate
== NULL
) { // and make our command gate
395 pm_vars
->PMcommandGate
= IOCommandGate::commandGate((OSObject
*)this);
396 if ( pm_vars
->PMcommandGate
!= NULL
) {
397 pm_vars
->PMworkloop
->addEventSource(pm_vars
->PMcommandGate
);
403 theParent
->setParentCurrentPowerFlags(currentState
); // set our connection data
404 theParent
->setParentKnowsState(stateKnown
);
406 pm_vars
->parentsKnowState
= true; // combine parent knowledge
407 pm_vars
->parentsCurrentPowerFlags
= 0;
409 iter
= getParentIterator(gIOPowerPlane
);
412 while ( (next
= iter
->getNextObject()) ) {
413 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
414 pm_vars
->parentsKnowState
&= connection
->parentKnowsState();
415 pm_vars
->parentsCurrentPowerFlags
|= connection
->parentCurrentPowerFlags();
421 if ( (pm_vars
->theControllingDriver
!= NULL
) &&
422 (pm_vars
->parentsKnowState
) ) {
423 pm_vars
->maxCapability
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(pm_vars
->parentsCurrentPowerFlags
);
424 tempDesire
= priv
->deviceDesire
; // initially change into the state we are already in
425 priv
->deviceDesire
= pm_vars
->theControllingDriver
->initialPowerStateForDomainState(pm_vars
->parentsCurrentPowerFlags
);
427 priv
->deviceDesire
= tempDesire
; // put this back like before
433 //*********************************************************************************
436 // Power Management is informing us who our children are.
437 //*********************************************************************************
438 IOReturn
IOService::addPowerChild ( IOService
* theChild
)
440 IOPowerConnection
* connection
;
443 if ( ! initialized
) {
444 return IOPMNotYetInitialized
; // we're not a power-managed IOService
447 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAddChild
,0,0);
449 connection
= new IOPowerConnection
; // make a nub
452 connection
->start(this);
454 attachToChild( connection
,gIOPowerPlane
); // connect it up
455 connection
->attachToChild( theChild
,gIOPowerPlane
);
456 connection
->release();
458 if ( (pm_vars
->theControllingDriver
== NULL
) || // tell it the current state of the power domain
459 ! (inPlane(gIOPowerPlane
)) ||
460 ! (pm_vars
->parentsKnowState
) ) {
461 theChild
->setPowerParent(connection
,false,0);
462 if ( inPlane(gIOPowerPlane
) ) {
463 for (i
= 0; i
<= kMaxType
; i
++) {
464 if ( pm_vars
->current_aggressiveness_valid
[i
] ) {
465 theChild
->setAggressiveness (i
, pm_vars
->current_aggressiveness_values
[i
]);
471 theChild
->setPowerParent(connection
,true,pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].outputPowerCharacter
);
472 for (i
= 0; i
<= kMaxType
; i
++) {
473 if ( pm_vars
->current_aggressiveness_valid
[i
] ) {
474 theChild
->setAggressiveness (i
, pm_vars
->current_aggressiveness_values
[i
]);
477 add_child_to_active_change(connection
); // catch it up if change is in progress
484 //*********************************************************************************
487 //*********************************************************************************
488 IOReturn
IOService::removePowerChild ( IOPowerConnection
* theChild
)
490 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRemoveChild
,0,0);
492 detachFromChild(theChild
,gIOPowerPlane
); // remove the departing child
494 if ( (pm_vars
->theControllingDriver
== NULL
) || // if not fully initialized
495 ! (inPlane(gIOPowerPlane
)) ||
496 ! (pm_vars
->parentsKnowState
) ) {
497 return IOPMNoErr
; // we can do no more
500 changeState(); // change state if we can now tolerate lower power
506 //*********************************************************************************
507 // registerPowerDriver
509 // A driver has called us volunteering to control power to our device.
510 // If the power state array it provides is richer than the one we already
511 // know about (supplied by an earlier volunteer), then accept the offer.
512 // Notify all interested parties of our power state, which we now know.
513 //*********************************************************************************
515 IOReturn
IOService::registerPowerDriver ( IOService
* controllingDriver
, IOPMPowerState
* powerStates
, unsigned long numberOfStates
)
518 unsigned long tempDesire
;
520 if ( (numberOfStates
> pm_vars
->theNumberOfPowerStates
) && (numberOfStates
> 1) ) {
521 if ( priv
->changeList
->currentChange() == -1 ) {
522 if ( controllingDriver
!= NULL
) {
523 if ( numberOfStates
<= IOPMMaxPowerStates
) {
524 switch ( powerStates
[0].version
) {
526 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriver
,
527 (unsigned long)numberOfStates
, (unsigned long)powerStates
[0].version
);
528 for ( i
= 0; i
< numberOfStates
; i
++ ) {
529 pm_vars
->thePowerStates
[i
] = powerStates
[i
];
533 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriver
,
534 (unsigned long) numberOfStates
,(unsigned long) powerStates
[0].version
);
535 for ( i
= 0; i
< numberOfStates
; i
++ ) {
536 pm_vars
->thePowerStates
[i
].version
= powerStates
[i
].version
;
537 pm_vars
->thePowerStates
[i
].capabilityFlags
= powerStates
[i
].capabilityFlags
;
538 pm_vars
->thePowerStates
[i
].outputPowerCharacter
= powerStates
[i
].outputPowerCharacter
;
539 pm_vars
->thePowerStates
[i
].inputPowerRequirement
= powerStates
[i
].inputPowerRequirement
;
540 pm_vars
->thePowerStates
[i
].staticPower
= powerStates
[i
].staticPower
;
541 pm_vars
->thePowerStates
[i
].unbudgetedPower
= powerStates
[i
].unbudgetedPower
;
542 pm_vars
->thePowerStates
[i
].powerToAttain
= powerStates
[i
].powerToAttain
;
543 pm_vars
->thePowerStates
[i
].timeToAttain
= powerStates
[i
].timeToAttain
;
544 pm_vars
->thePowerStates
[i
].settleUpTime
= powerStates
[i
].settleUpTime
;
545 pm_vars
->thePowerStates
[i
].timeToLower
= powerStates
[i
].timeToLower
;
546 pm_vars
->thePowerStates
[i
].settleDownTime
= powerStates
[i
].settleDownTime
;
547 pm_vars
->thePowerStates
[i
].powerDomainBudget
= powerStates
[i
].powerDomainBudget
;
551 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr1
,
552 (unsigned long)powerStates
[0].version
,0);
556 pm_vars
->myCharacterFlags
= 0; // make a mask of all the character bits we know about
557 for ( i
= 0; i
< numberOfStates
; i
++ ) {
558 pm_vars
->myCharacterFlags
|= pm_vars
->thePowerStates
[i
].outputPowerCharacter
;
561 pm_vars
->theNumberOfPowerStates
= numberOfStates
;
562 pm_vars
->theControllingDriver
= controllingDriver
;
563 if ( priv
->interestedDrivers
->findItem(controllingDriver
) == NULL
) { // register it as interested
564 registerInterestedDriver (controllingDriver
); // unless already done
566 if ( priv
->need_to_become_usable
) {
567 priv
->need_to_become_usable
= false;
568 priv
->deviceDesire
= pm_vars
->theNumberOfPowerStates
- 1;
571 if ( inPlane(gIOPowerPlane
) &&
572 (pm_vars
->parentsKnowState
) ) {
573 pm_vars
->maxCapability
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(pm_vars
->parentsCurrentPowerFlags
);
574 tempDesire
= priv
->deviceDesire
; // initially change into the state we are already in
575 priv
->deviceDesire
= pm_vars
->theControllingDriver
->initialPowerStateForDomainState(pm_vars
->parentsCurrentPowerFlags
);
577 priv
->deviceDesire
= tempDesire
; // put this back like before
581 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr2
,(unsigned long)numberOfStates
,0);
585 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr4
,0,0);
590 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr5
,(unsigned long)numberOfStates
,0);
595 //*********************************************************************************
596 // registerInterestedDriver
598 // Add the caller to our list of interested drivers and return our current
599 // power state. If we don't have a power-controlling driver yet, we will
600 // call this interested driver again later when we do get a driver and find
601 // out what the current power state of the device is.
602 //*********************************************************************************
604 IOPMPowerFlags
IOService::registerInterestedDriver ( IOService
* theDriver
)
606 IOPMinformee
* newInformee
;
607 IOPMPowerFlags futureCapability
;
609 if (theDriver
== NULL
) {
613 newInformee
= new IOPMinformee
; // make new driver node
614 newInformee
->initialize(theDriver
);
615 priv
->interestedDrivers
->addToList(newInformee
); // add it to list of drivers
617 if ( (pm_vars
->theControllingDriver
== NULL
) ||
618 ! (inPlane(gIOPowerPlane
)) ||
619 ! (pm_vars
->parentsKnowState
) ) {
620 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInterestedDriver
,IOPMNotPowerManaged
,0);
621 return IOPMNotPowerManaged
; // can't tell it a state yet
624 switch (priv
->machine_state
) { // can we notify new driver of a change in progress?
625 case IOPMour_prechange_1
:
626 case IOPMour_prechange_4
:
627 case IOPMparent_down_4
:
628 case IOPMparent_down_6
:
629 case IOPMparent_up_0
:
630 case IOPMparent_up_6
:
631 futureCapability
= priv
->head_note_capabilityFlags
; // yes, remember what we tell it
632 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInterestedDriver
,(unsigned long)futureCapability
,1);
633 add_driver_to_active_change(newInformee
); // notify it
634 return futureCapability
; // and return the same thing
637 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInterestedDriver
,
638 (unsigned long) pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
,2);
639 return pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
; // no, return current capability
643 //*********************************************************************************
644 // deRegisterInterestedDriver
646 //*********************************************************************************
647 IOReturn
IOService::deRegisterInterestedDriver ( IOService
* theDriver
)
649 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRemoveDriver
,0,0);
651 priv
->interestedDrivers
->removeFromList(theDriver
); // remove the departing driver
657 //*********************************************************************************
658 // acknowledgePowerChange
660 // After we notified one of the interested drivers or a power-domain child
661 // of an impending change in power, it has called to say it is now
662 // prepared for the change. If this object is the last to
663 // acknowledge this change, we take whatever action we have been waiting
665 // That may include acknowledging to our parent. In this case, we do it
666 // last of all to insure that this doesn't cause the parent to call us some-
667 // where else and alter data we are relying on here (like the very existance
668 // of a "current change note".)
669 //*********************************************************************************
671 IOReturn
IOService::acknowledgePowerChange ( IOService
* whichObject
)
673 IOPMinformee
* ackingObject
;
675 ackingObject
= priv
->interestedDrivers
->findItem(whichObject
); // one of our interested drivers?
676 if ( ackingObject
== NULL
) {
677 if ( ! isChild(whichObject
,gIOPowerPlane
) ) {
678 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr1
,0,0);
679 kprintf("errant driver: %s\n",whichObject
->getName());
680 return IOPMNoErr
; // no, just return
683 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChildAcknowledge
,0,0);
687 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogDriverAcknowledge
,0,0);
690 if (! acquire_lock() ) {
694 if (priv
->head_note_pendingAcks
!= 0 ) { // yes, make sure we're expecting acks
695 if ( ackingObject
!= NULL
) { // it's an interested driver
696 if ( ackingObject
->timer
!= 0 ) { // make sure we're expecting this ack
697 ackingObject
->timer
= 0; // mark it acked
698 priv
->head_note_pendingAcks
-= 1; // that's one fewer to worry about
699 if ( priv
->head_note_pendingAcks
== 0 ) { // is that the last?
700 stop_ack_timer(); // yes, stop the timer
701 IOUnlock(priv
->our_lock
);
702 all_acked(); // and now we can continue
707 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr2
,0,0); // this driver has already acked
708 kprintf("errant driver: %s\n",whichObject
->getName());
711 else { // it's a child
712 priv
->head_note_pendingAcks
-= 1; // that's one fewer to worry about
713 if ( priv
->head_note_pendingAcks
== 0 ) { // is that the last?
714 stop_ack_timer(); // yes, stop the timer
715 IOUnlock(priv
->our_lock
);
716 all_acked(); // and now we can continue
722 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr3
,0,0); // not expecting anybody to ack
723 kprintf("errant driver: %s\n",whichObject
->getName());
725 IOUnlock(priv
->our_lock
);
729 //*********************************************************************************
730 // acknowledgeSetPowerState
732 // After we instructed our controlling driver to change power states,
733 // it has called to say it has finished doing so.
734 // We continue to process the power state change.
735 //*********************************************************************************
737 IOReturn
IOService::acknowledgeSetPowerState ( void )
739 if (! acquire_lock() ) {
742 if ( priv
->driver_timer
== -1 ) {
743 priv
->driver_timer
= 0; // driver is acking instead of using return code
746 if ( priv
->driver_timer
> 0 ) { // are we expecting this?
747 stop_ack_timer(); // yes, stop the timer
748 priv
->driver_timer
= 0;
749 IOUnlock(priv
->our_lock
);
750 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogDriverAcknowledgeSet
,0,0);
755 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr4
,0,0); // no
758 IOUnlock(priv
->our_lock
);
763 //*********************************************************************************
766 // Either the controlling driver has called acknowledgeSetPowerState
767 // or the acknowledgement timer has expired while waiting for that.
768 // We carry on processing the current change note.
769 //*********************************************************************************
771 void IOService::driver_acked ( void )
773 switch (priv
->machine_state
) {
774 case IOPMour_prechange_2
:
777 case IOPMparent_down_5
:
780 case IOPMparent_up_4
:
787 //*********************************************************************************
788 // powerDomainWillChangeTo
790 // Called by the power-hierarchy parent notifying of a new power state
791 // in the power domain.
792 // We enqueue a parent power-change to our queue of power changes.
793 // This may or may not cause us to change power, depending on what
794 // kind of change is occuring in the domain.
795 //*********************************************************************************
797 IOReturn
IOService::powerDomainWillChangeTo ( IOPMPowerFlags newPowerStateFlags
, IOPowerConnection
* whichParent
)
801 IOPowerConnection
* connection
;
802 unsigned long newStateNumber
;
803 IOPMPowerFlags combinedPowerFlags
;
805 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogWillChange
,(unsigned long)newPowerStateFlags
,0);
807 if ( ! inPlane(gIOPowerPlane
) ) {
808 return IOPMAckImplied
; // somebody goofed
811 if ( (pm_vars
->PMworkloop
== NULL
) || (pm_vars
->PMcommandGate
== NULL
) ) {
812 getPMworkloop(); // we have a path to the root,
813 if ( pm_vars
->PMworkloop
!= NULL
) { // so find out the workloop
814 if ( pm_vars
->PMcommandGate
== NULL
) { // and make our command gate
815 pm_vars
->PMcommandGate
= IOCommandGate::commandGate((OSObject
*)this);
816 if ( pm_vars
->PMcommandGate
!= NULL
) {
817 pm_vars
->PMworkloop
->addEventSource(pm_vars
->PMcommandGate
);
823 combinedPowerFlags
= 0; // combine parents' power states
825 iter
= getParentIterator(gIOPowerPlane
);
828 while ( (next
= iter
->getNextObject()) ) {
829 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
830 if ( connection
== whichParent
){
831 combinedPowerFlags
|= newPowerStateFlags
;
834 combinedPowerFlags
|= connection
->parentCurrentPowerFlags();
841 if ( pm_vars
->theControllingDriver
== NULL
) { // we can't take any more action
842 return IOPMAckImplied
;
844 newStateNumber
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(combinedPowerFlags
);
845 return enqueuePowerChange(IOPMParentInitiated
| IOPMDomainWillChange
, newStateNumber
,combinedPowerFlags
,whichParent
); //make the change
849 //*********************************************************************************
850 // powerDomainDidChangeTo
852 // Called by the power-hierarchy parent after the power state of the power domain
853 // has settled at a new level.
854 // We enqueue a parent power-change to our queue of power changes.
855 // This may or may not cause us to change power, depending on what
856 // kind of change is occuring in the domain.
857 //*********************************************************************************
859 IOReturn
IOService::powerDomainDidChangeTo ( IOPMPowerFlags newPowerStateFlags
, IOPowerConnection
* whichParent
)
863 IOPowerConnection
* connection
;
864 unsigned long newStateNumber
;
866 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogDidChange
,newPowerStateFlags
,0);
868 whichParent
->setParentCurrentPowerFlags(newPowerStateFlags
); // set our connection data
869 whichParent
->setParentKnowsState(true);
871 pm_vars
->parentsCurrentPowerFlags
= 0; // recompute our parent info
872 pm_vars
->parentsKnowState
= true;
874 iter
= getParentIterator(gIOPowerPlane
);
877 while ( (next
= iter
->getNextObject()) ) {
878 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
879 pm_vars
->parentsKnowState
&= connection
->parentKnowsState();
880 pm_vars
->parentsCurrentPowerFlags
|= connection
->parentCurrentPowerFlags();
886 if ( pm_vars
->theControllingDriver
== NULL
) {
887 return IOPMAckImplied
;
890 newStateNumber
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(pm_vars
->parentsCurrentPowerFlags
);
891 return enqueuePowerChange(IOPMParentInitiated
| IOPMDomainDidChange
, newStateNumber
,pm_vars
->parentsCurrentPowerFlags
,whichParent
); // tell interested parties about it
895 //*********************************************************************************
896 // requestPowerDomainState
899 //*********************************************************************************
900 IOReturn
IOService::requestPowerDomainState ( IOPMPowerFlags desiredState
, IOPowerConnection
* whichChild
, unsigned long specification
)
905 IOPowerConnection
* connection
;
907 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRequestDomain
,
908 (unsigned long)desiredState
,(unsigned long)specification
);
910 if ( pm_vars
->theControllingDriver
== NULL
) {
911 return IOPMNotYetInitialized
;
914 switch (specification
) {
915 case IOPMLowestState
:
917 while ( i
< pm_vars
->theNumberOfPowerStates
) {
918 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& desiredState
) == (desiredState
& pm_vars
->myCharacterFlags
) ) {
923 if ( i
>= pm_vars
->theNumberOfPowerStates
) {
924 return IOPMNoSuchState
;
928 case IOPMNextLowerState
:
929 i
= pm_vars
->myCurrentState
- 1;
931 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& desiredState
) == (desiredState
& pm_vars
->myCharacterFlags
) ) {
937 return IOPMNoSuchState
;
941 case IOPMHighestState
:
942 i
= pm_vars
->theNumberOfPowerStates
;
945 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& desiredState
) == (desiredState
& pm_vars
->myCharacterFlags
) ) {
950 return IOPMNoSuchState
;
954 case IOPMNextHigherState
:
955 i
= pm_vars
->myCurrentState
+ 1;
956 while ( i
< pm_vars
->theNumberOfPowerStates
) {
957 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& desiredState
) == (desiredState
& pm_vars
->myCharacterFlags
) ) {
962 if ( i
== pm_vars
->theNumberOfPowerStates
) {
963 return IOPMNoSuchState
;
968 return IOPMBadSpecification
;
971 // Now loop through the children. When we encounter the calling child, save
972 // the new state as this child's desire. Then, compute a new maximum
973 // of everybody's desires.
975 iter
= getChildIterator(gIOPowerPlane
);
978 while ( (next
= iter
->getNextObject()) ) {
979 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
980 if ( connection
== whichChild
) {
981 connection
->setDesiredDomainState(i
);
988 if ( inPlane(gIOPowerPlane
) &&
989 (pm_vars
->parentsKnowState
) ) {
990 changeState(); // change state if all children can now tolerate lower power
993 if ( priv
->clampOn
) { // are we clamped on, waiting for this child?
994 priv
->clampOn
= false; // yes, remove the clamp
995 changePowerStateToPriv(0);
1002 //*********************************************************************************
1003 // temporaryPowerClampOn
1005 // A power domain wants to clamp its power on till it has children which
1006 // will thendetermine the power domain state.
1008 // We enter the highest state until addPowerChild is called.
1009 //*********************************************************************************
1011 IOReturn
IOService::temporaryPowerClampOn ( void )
1013 priv
->clampOn
= true;
1019 //*********************************************************************************
1022 // Some client of our device is asking that we become usable. Although
1023 // this has not come from a subclassed device object, treat it exactly
1024 // as if it had. In this way, subsequent requests for lower power from
1025 // a subclassed device object will pre-empt this request.
1027 // We treat this as a subclass object request to switch to the
1028 // highest power state.
1029 //*********************************************************************************
1031 IOReturn
IOService::makeUsable ( void )
1033 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogMakeUsable
,0,0);
1035 if ( pm_vars
->theControllingDriver
== NULL
) {
1036 priv
->need_to_become_usable
= true;
1039 priv
->deviceDesire
= pm_vars
->theNumberOfPowerStates
- 1;
1040 if ( inPlane(gIOPowerPlane
) && (pm_vars
->parentsKnowState
) ) {
1041 return changeState();
1047 //*********************************************************************************
1048 // currentCapability
1050 //*********************************************************************************
1052 IOPMPowerFlags
IOService::currentCapability ( void )
1054 if ( pm_vars
->theControllingDriver
== NULL
) {
1058 return pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
;
1063 //*********************************************************************************
1064 // changePowerStateTo
1066 // For some reason, our power-controlling driver has decided it needs to change
1067 // power state. We enqueue the power change so that appropriate parties
1068 // will be notified, and then we will instruct the driver to make the change.
1069 //*********************************************************************************
1071 IOReturn
IOService::changePowerStateTo ( unsigned long ordinal
)
1073 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeStateTo
,ordinal
,0);
1075 if ( ordinal
>= pm_vars
->theNumberOfPowerStates
) {
1076 return IOPMParameterError
;
1078 priv
->driverDesire
= ordinal
;
1079 if ( inPlane(gIOPowerPlane
) && (pm_vars
->parentsKnowState
) ) {
1080 return changeState();
1086 //*********************************************************************************
1087 // changePowerStateToPriv
1089 // For some reason, a subclassed device object has decided it needs to change
1090 // power state. We enqueue the power change so that appropriate parties
1091 // will be notified, and then we will instruct the driver to make the change.
1092 //*********************************************************************************
1094 IOReturn
IOService::changePowerStateToPriv ( unsigned long ordinal
)
1096 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeStateToPriv
,ordinal
,0);
1098 if ( pm_vars
->theControllingDriver
== NULL
) {
1099 return IOPMNotYetInitialized
;
1101 if ( ordinal
>= pm_vars
->theNumberOfPowerStates
) {
1102 return IOPMParameterError
;
1104 priv
->deviceDesire
= ordinal
;
1105 if ( inPlane(gIOPowerPlane
) && (pm_vars
->parentsKnowState
) ) {
1106 return changeState();
1113 //*********************************************************************************
1116 // A subclass object, our controlling driver, or a power domain child
1117 // has asked for a different power state. Here we compute what new
1118 // state we should enter and enqueue the change (or start it).
1119 //*********************************************************************************
1121 IOReturn
IOService::changeState ( void )
1125 IOPowerConnection
* connection
;
1126 unsigned long newDesiredState
= 0;
1128 // Compute the maximum of our children's desires, our controlling driver's desire, and the subclass device's desire.
1130 if ( ! priv
->device_overrides
) {
1131 iter
= getChildIterator(gIOPowerPlane
);
1134 while ( (next
= iter
->getNextObject()) ) {
1135 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1136 if ( connection
->getDesiredDomainState() > newDesiredState
) {
1137 newDesiredState
= connection
->getDesiredDomainState();
1144 if ( priv
->driverDesire
> newDesiredState
) {
1145 newDesiredState
= priv
->driverDesire
;
1149 if ( priv
->deviceDesire
> newDesiredState
) {
1150 newDesiredState
= priv
->deviceDesire
;
1153 priv
->ourDesiredPowerState
= newDesiredState
;
1155 if ( (pm_vars
->theControllingDriver
== NULL
) || // if not fully initialized
1156 ! (inPlane(gIOPowerPlane
)) ||
1157 ! (pm_vars
->parentsKnowState
) ) {
1158 return IOPMNoErr
; // we can do no more
1161 return enqueuePowerChange(IOPMWeInitiated
,newDesiredState
,0,0);
1165 //*********************************************************************************
1166 // currentPowerConsumption
1168 //*********************************************************************************
1170 unsigned long IOService::currentPowerConsumption ( void )
1172 if ( pm_vars
->theControllingDriver
== NULL
) {
1176 return pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].staticPower
;
1180 //*********************************************************************************
1183 // The activity tickle with parameter kIOPMSubclassPolicyis not handled
1184 // here and should have been intercepted by the subclass.
1185 // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
1186 // flag to be set, and the device state checked. If the device has been
1187 // powered down, it is powered up again.
1188 //*********************************************************************************
1190 bool IOService::activityTickle ( unsigned long type
, unsigned long stateNumber
=0 )
1192 AbsoluteTime uptime
;
1194 if ( type
== kIOPMSuperclassPolicy1
) {
1195 if ( (priv
->activityLock
== NULL
) ||
1196 (pm_vars
->theControllingDriver
== NULL
) ||
1197 ( pm_vars
->commandQueue
== NULL
) ) {
1200 IOTakeLock(priv
->activityLock
);
1201 priv
->device_active
= true;
1203 clock_get_uptime(&uptime
);
1204 priv
->device_active_timestamp
= uptime
;
1206 if ( pm_vars
->myCurrentState
>= stateNumber
) {
1207 IOUnlock(priv
->activityLock
);
1210 IOUnlock(priv
->activityLock
); // send a message on the command queue
1211 pm_vars
->commandQueue
->enqueueCommand(true, (void *)kPMunIdleDevice
, (void *)stateNumber
);
1217 //*********************************************************************************
1220 // A child is calling to get a pointer to the Power Management workloop.
1221 // We got it or get it from one of our parents.
1222 //*********************************************************************************
1224 IOWorkLoop
* IOService::getPMworkloop ( void )
1226 IOService
* aParent
;
1228 if ( ! inPlane(gIOPowerPlane
) ) {
1231 if ( pm_vars
->PMworkloop
== NULL
) { // we have no workloop yet
1232 aParent
= (IOService
*)getParentEntry(gIOPowerPlane
)->getParentEntry(gIOPowerPlane
);
1233 if ( aParent
!= NULL
) { // ask one of our parents for the workloop
1234 pm_vars
->PMworkloop
= aParent
->getPMworkloop();
1237 return pm_vars
->PMworkloop
;
1241 //*********************************************************************************
1242 // setIdleTimerPeriod
1244 // A subclass policy-maker is going to use our standard idleness
1245 // detection service. Make a command queue and an idle timer and
1246 // connect them to the power management workloop. Finally,
1248 //*********************************************************************************
1250 IOReturn
IOService::setIdleTimerPeriod ( unsigned long period
)
1252 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMsetIdleTimerPeriod
,period
, 0);
1254 priv
->idle_timer_period
= period
;
1257 if ( getPMworkloop() == NULL
) {
1258 return kIOReturnError
;
1261 if (pm_vars
->commandQueue
== NULL
) { // make the command queue
1262 pm_vars
->commandQueue
= IOCommandQueue::commandQueue(this, PMreceiveCmd
);
1263 if (! pm_vars
->commandQueue
||
1264 ( pm_vars
->PMworkloop
->addEventSource( pm_vars
->commandQueue
) != kIOReturnSuccess
) ) {
1265 return kIOReturnError
;
1268 // make the timer event
1269 if ( priv
->timerEventSrc
== NULL
) {
1270 priv
->timerEventSrc
= IOTimerEventSource::timerEventSource(this,
1271 PM_idle_timer_expired
);
1272 if ( ! priv
->timerEventSrc
||
1273 ( pm_vars
->PMworkloop
->addEventSource( priv
->timerEventSrc
) != kIOReturnSuccess
) ) {
1274 return kIOReturnError
;
1278 if ( priv
->activityLock
== NULL
) {
1279 priv
->activityLock
= IOLockAlloc();
1282 start_PM_idle_timer();
1288 //*********************************************************************************
1289 // start_PM_idle_timer
1291 // The parameter is a pointer to us. Use it to call our timeout method.
1292 //*********************************************************************************
1293 void IOService::start_PM_idle_timer ( void )
1295 AbsoluteTime uptime
;
1301 IOLockLock(priv
->activityLock
);
1303 clock_get_uptime(&uptime
);
1305 /* Calculate time difference using funky macro from clock.h.
1308 SUB_ABSOLUTETIME(&delta
, &(priv
->device_active_timestamp
));
1310 /* Figure it in seconds.
1312 absolutetime_to_nanoseconds(delta
, &delta_ns
);
1313 delta_secs
= delta_ns
/ NSEC_PER_SEC
;
1315 /* Be paranoid about delta somehow exceeding timer period.
1317 if (delta_secs
< priv
->idle_timer_period
) {
1318 delay_secs
= priv
->idle_timer_period
- delta_secs
;
1320 delay_secs
= priv
->idle_timer_period
;
1323 priv
->timerEventSrc
->setTimeout(delay_secs
, NSEC_PER_SEC
);
1325 IOLockUnlock(priv
->activityLock
);
1330 //*********************************************************************************
1331 // PM_idle_timer_expired
1333 // The parameter is a pointer to us. Use it to call our timeout method.
1334 //*********************************************************************************
1336 void PM_idle_timer_expired(OSObject
* ourSelves
, IOTimerEventSource
*)
1338 ((IOService
*)ourSelves
)->PM_idle_timer_expiration();
1342 //*********************************************************************************
1343 // PM_idle_timer_expiration
1345 // The idle timer has expired. If there has been activity since the last
1346 // expiration, just restart the timer and return. If there has not been
1347 // activity, switch to the next lower power state and restart the timer.
1348 //*********************************************************************************
1350 void IOService::PM_idle_timer_expiration ( void )
1352 if ( ! initialized
) {
1353 return; // we're unloading
1356 if ( priv
->idle_timer_period
> 0 ) {
1357 IOTakeLock(priv
->activityLock
);
1358 if ( priv
->device_active
) {
1359 priv
->device_active
= false;
1360 IOUnlock(priv
->activityLock
);
1361 start_PM_idle_timer();
1364 if ( pm_vars
->myCurrentState
> 0 ) {
1365 IOUnlock(priv
->activityLock
);
1366 priv
->askingFor
= pm_vars
->myCurrentState
- 1;
1367 changePowerStateToPriv(pm_vars
->myCurrentState
- 1);
1368 start_PM_idle_timer();
1371 IOUnlock(priv
->activityLock
);
1372 start_PM_idle_timer();
1378 // **********************************************************************************
1383 // **********************************************************************************
1384 void PMreceiveCmd ( OSObject
* theDriver
, void * command
, void * param1
, void * param2
, void *param3
)
1386 ((IOService
*)theDriver
)->command_received(command
,param1
,param2
,param3
);
1390 // **********************************************************************************
1393 // We have received a command from ourselves on the command queue.
1394 // This is to prevent races with timer-expiration code.
1395 // **********************************************************************************
1396 void IOService::command_received ( void * command
, void *stateNumber
, void * , void *)
1398 if ( ! initialized
) {
1399 return; // we're unloading
1402 if ( command
== (void *)kPMunIdleDevice
) {
1403 if ( (pm_vars
->myCurrentState
< (unsigned long)stateNumber
) &&
1404 (priv
->imminentState
< (unsigned long)stateNumber
) &&
1405 ((unsigned long)stateNumber
> priv
->askingFor
) ) {
1406 priv
->askingFor
= (unsigned long)stateNumber
;
1407 changePowerStateToPriv((unsigned long)stateNumber
);
1413 //*********************************************************************************
1414 // setAggressiveness
1416 // Pass on the input parameters to all power domain children. All those which are
1417 // power domains will pass it on to their children, etc.
1418 //*********************************************************************************
1420 IOReturn
IOService::setAggressiveness ( unsigned long type
, unsigned long newLevel
)
1424 IOPowerConnection
* connection
;
1426 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogSetAggressiveness
,type
, newLevel
);
1428 if ( type
<= kMaxType
) {
1429 pm_vars
->current_aggressiveness_values
[type
] = newLevel
;
1430 pm_vars
->current_aggressiveness_valid
[type
] = true;
1433 iter
= getChildIterator(gIOPowerPlane
);
1436 while ( (next
= iter
->getNextObject()) ) {
1437 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1438 ((IOService
*)(connection
->getChildEntry(gIOPowerPlane
)))->setAggressiveness(type
, newLevel
);
1447 //*********************************************************************************
1448 // getAggressiveness
1450 // Called by the user client.
1451 //*********************************************************************************
1453 IOReturn
IOService::getAggressiveness ( unsigned long type
, unsigned long * currentLevel
)
1455 if ( type
<= kMaxType
) {
1456 *currentLevel
= pm_vars
->current_aggressiveness_values
[type
];
1458 return kIOReturnSuccess
;
1461 //*********************************************************************************
1464 // Pass this to all power domain children. All those which are
1465 // power domains will pass it on to their children, etc.
1466 //*********************************************************************************
1468 IOReturn
IOService::systemWake ( void )
1472 IOPowerConnection
* connection
;
1474 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogSystemWake
,0, 0);
1476 iter
= getChildIterator(gIOPowerPlane
);
1479 while ( (next
= iter
->getNextObject()) ) {
1480 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1481 ((IOService
*)(connection
->getChildEntry(gIOPowerPlane
)))->systemWake();
1487 if ( pm_vars
->theControllingDriver
!= NULL
) {
1488 if ( pm_vars
->theControllingDriver
->didYouWakeSystem() ) {
1497 //*********************************************************************************
1498 // temperatureCriticalForZone
1500 //*********************************************************************************
1502 IOReturn
IOService::temperatureCriticalForZone ( IOService
* whichZone
)
1504 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogCriticalTemp
,0,0);
1506 if ( inPlane(gIOPowerPlane
) && ! (priv
->we_are_root
) ) {
1507 ((IOService
*)(getParentEntry(gIOPowerPlane
)->getParentEntry(gIOPowerPlane
)))->temperatureCriticalForZone(whichZone
);
1513 //*********************************************************************************
1514 // powerOverrideOnPriv
1516 //*********************************************************************************
1519 IOReturn
IOService::powerOverrideOnPriv ( void )
1521 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogOverrideOn
,0,0);
1523 priv
->device_overrides
= true; // turn on the override
1524 return changeState(); // change state if that changed something
1528 //*********************************************************************************
1529 // powerOverrideOffPriv
1531 //*********************************************************************************
1532 IOReturn
IOService::powerOverrideOffPriv ( void )
1534 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogOverrideOff
,0,0);
1536 priv
->device_overrides
= false; // turn off the override
1537 return changeState(); // change state if that changed something
1541 //*********************************************************************************
1542 // enqueuePowerChange
1544 // Allocate a new state change notification, initialize it with fields from the
1545 // caller, and add it to the tail of the list of pending power changes.
1547 // If it is early enough in the list, and almost all the time it is the only one in
1548 // the list, start the power change.
1550 // In rare instances, this change will preempt the previous change in the list.
1551 // If the previous change is un-actioned in any way (because we are still
1552 // processing an even earlier power change), and if both the previous change
1553 // in the list and this change are initiated by us (not the parent), then we
1554 // needn't perform the previous change, so we collapse the list a little.
1555 //*********************************************************************************
1557 IOReturn
IOService::enqueuePowerChange ( unsigned long flags
, unsigned long whatStateOrdinal
, unsigned long domainState
, IOPowerConnection
* whichParent
)
1562 // Create and initialize the new change note
1564 newNote
= priv
->changeList
->createChangeNote();
1565 if ( newNote
== -1 ) {
1566 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogEnqueueErr
,0,0);
1567 return IOPMAckImplied
; // uh-oh, our list is full
1570 priv
->changeList
->changeNote
[newNote
].newStateNumber
= whatStateOrdinal
;
1571 priv
->changeList
->changeNote
[newNote
].outputPowerCharacter
= pm_vars
->thePowerStates
[whatStateOrdinal
].outputPowerCharacter
;
1572 priv
->changeList
->changeNote
[newNote
].inputPowerRequirement
= pm_vars
->thePowerStates
[whatStateOrdinal
].inputPowerRequirement
;
1573 priv
->changeList
->changeNote
[newNote
].capabilityFlags
= pm_vars
->thePowerStates
[whatStateOrdinal
].capabilityFlags
;
1574 priv
->changeList
->changeNote
[newNote
].flags
= flags
;
1575 if (flags
& IOPMParentInitiated
) {
1576 priv
->changeList
->changeNote
[newNote
].domainState
= domainState
;
1577 priv
->changeList
->changeNote
[newNote
].parent
= whichParent
;
1580 previousNote
= priv
->changeList
->previousChangeNote(newNote
);
1582 if ( previousNote
== -1 ) {
1584 // Queue is empty, we can start this change.
1586 if (flags
& IOPMWeInitiated
) {
1587 start_our_change(newNote
);
1591 return start_parent_change(newNote
);
1595 // The queue is not empty. Try to collapse this new change and the previous one in queue into one change.
1596 // This is possible only if both changes are initiated by us, and neither has been started yet.
1597 // Do this more than once if possible.
1599 // (A change is started iff it is at the head of the queue)
1601 while ( (previousNote
!= priv
->head_note
) && (previousNote
!= -1) &&
1602 (priv
->changeList
->changeNote
[newNote
].flags
& priv
->changeList
->changeNote
[previousNote
].flags
& IOPMWeInitiated
) ) {
1603 priv
->changeList
->changeNote
[previousNote
].outputPowerCharacter
= priv
->changeList
->changeNote
[newNote
].outputPowerCharacter
;
1604 priv
->changeList
->changeNote
[previousNote
].inputPowerRequirement
= priv
->changeList
->changeNote
[newNote
].inputPowerRequirement
;
1605 priv
->changeList
->changeNote
[previousNote
].capabilityFlags
=priv
-> changeList
->changeNote
[newNote
].capabilityFlags
;
1606 priv
->changeList
->changeNote
[previousNote
].newStateNumber
= priv
->changeList
->changeNote
[newNote
].newStateNumber
;
1607 priv
->changeList
->releaseTailChangeNote();
1608 newNote
= previousNote
;
1609 previousNote
= priv
->changeList
->previousChangeNote(newNote
);
1610 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogCollapseQueue
,0,0);
1612 return IOPMWillAckLater
; // in any case, we can't start yet
1616 //*********************************************************************************
1619 // Notify all interested parties either that a change is impending or that the
1620 // previously-notified change is done and power has settled.
1621 // The parameter identifies whether this is the
1622 // pre-change notification or the post-change notification.
1624 //*********************************************************************************
1626 IOReturn
IOService::notifyAll ( bool is_prechange
)
1628 IOPMinformee
* nextObject
;
1631 IOPowerConnection
* connection
;
1633 // To prevent acknowledgePowerChange from finishing the change note and removing it from the queue if
1634 // some driver calls it, we inflate the number of pending acks so it cannot become zero. We'll fix it later.
1636 priv
->head_note_pendingAcks
=1;
1638 // OK, we will go through the lists of interested drivers and power domain children
1639 // and notify each one of this change.
1641 nextObject
= priv
->interestedDrivers
->firstInList(); // notify interested drivers
1642 while ( nextObject
!= NULL
) {
1643 priv
->head_note_pendingAcks
+=1;
1644 if (! inform(nextObject
, is_prechange
) ) {
1646 nextObject
= priv
->interestedDrivers
->nextInList(nextObject
);
1649 if (! acquire_lock() ) {
1652 if ( priv
->head_note_pendingAcks
> 1 ) { // did they all ack?
1653 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0); // no
1656 IOUnlock(priv
->our_lock
); // either way
1658 iter
= getChildIterator(gIOPowerPlane
);
1661 while ( (next
= iter
->getNextObject()) ) {
1662 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1663 priv
->head_note_pendingAcks
+=1;
1664 notifyChild(connection
, is_prechange
);
1670 if (! acquire_lock() ) {
1673 priv
->head_note_pendingAcks
-= 1; // now make this real
1674 if (priv
->head_note_pendingAcks
== 0 ) { // is it all acked?
1675 IOUnlock(priv
->our_lock
); // yes
1676 return IOPMAckImplied
; // return ack to parent
1678 IOUnlock(priv
->our_lock
); // no
1679 return IOPMWillAckLater
;
1683 //*********************************************************************************
1686 // Notify a power domain child of an upcoming power change.
1688 // If the object acknowledges the current change, we return TRUE.
1689 //*********************************************************************************
1691 bool IOService::notifyChild ( IOPowerConnection
* theNub
, bool is_prechange
)
1693 IOReturn k
= IOPMAckImplied
;
1695 if ( is_prechange
) {
1696 k
=((IOService
*)(theNub
->getChildEntry(gIOPowerPlane
)))->powerDomainWillChangeTo( priv
->head_note_outputFlags
,theNub
);
1699 k
=((IOService
*)(theNub
->getChildEntry(gIOPowerPlane
)))->powerDomainDidChangeTo( priv
->head_note_outputFlags
,theNub
);
1702 if ( k
== IOPMAckImplied
) { // did the return code ack?
1703 priv
->head_note_pendingAcks
-=1; // yes
1710 //*********************************************************************************
1713 // Notify an interested driver of an upcoming power change.
1715 // If the object acknowledges the current change, we return TRUE.
1716 //*********************************************************************************
1718 bool IOService::inform ( IOPMinformee
* nextObject
, bool is_prechange
)
1720 IOReturn k
= IOPMAckImplied
;
1722 nextObject
->timer
= -1; // initialize this
1724 if ( is_prechange
) {
1725 pm_vars
->thePlatform
->PMLog (pm_vars
->ourName
,PMlogInformDriverPreChange
,
1726 (unsigned long)priv
->head_note_capabilityFlags
,(unsigned long)priv
->head_note_state
);
1727 k
= nextObject
->whatObject
->powerStateWillChangeTo( priv
->head_note_capabilityFlags
,priv
->head_note_state
,this);
1730 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInformDriverPostChange
,
1731 (unsigned long)priv
->head_note_capabilityFlags
,(unsigned long)priv
->head_note_state
);
1732 k
= nextObject
->whatObject
->powerStateDidChangeTo(priv
->head_note_capabilityFlags
,priv
->head_note_state
,this);
1735 if ( nextObject
->timer
== 0 ) { // did it ack behind our back?
1738 if ( k
==IOPMAckImplied
) { // no, did the return code ack?
1739 nextObject
->timer
= 0; // yes
1740 priv
->head_note_pendingAcks
-= 1;
1744 nextObject
->timer
= 0; // somebody goofed
1745 priv
-> head_note_pendingAcks
-= 1;
1748 nextObject
->timer
= (k
* ns_per_us
/ ACK_TIMER_PERIOD
) + 1; // no, it's a timer
1753 //*********************************************************************************
1756 // All registered applications and kernel clients have positively acknowledged our
1757 // intention of lowering power. Here we notify them all that we will definitely
1758 // lower the power. If we don't have to wait for any of them to acknowledge, we
1759 // carry on by notifying interested drivers. Otherwise, we do wait.
1760 //*********************************************************************************
1762 void IOService::our_prechange_03 ( void )
1764 priv
->machine_state
= IOPMour_prechange_05
; // next state
1765 if ( tellChangeDown(priv
->head_note_state
) ) { // are we waiting for responses?
1766 return our_prechange_05(); // no, notify interested drivers
1771 //*********************************************************************************
1774 // All registered applications and kernel clients have acknowledged our notification
1775 // that we are lowering power. Here we notify interested drivers. If we don't have
1776 // to wait for any of them to acknowledge, we instruct our power driver to make the change.
1777 // Otherwise, we do wait.
1778 //*********************************************************************************
1780 void IOService::our_prechange_05 ( void )
1782 priv
->machine_state
= IOPMour_prechange_1
; // no, in case they don't all ack
1783 if ( notifyAll(true) == IOPMAckImplied
) {
1789 //*********************************************************************************
1792 // All interested drivers have acknowledged our pre-change notification of a power
1793 // change we initiated. Here we instruct our controlling driver to make
1794 // the change to the hardware. If it does so, we continue processing
1795 // (waiting for settle and notifying interested parties post-change.)
1796 // If it doesn't, we have to wait for it to acknowledge and then continue.
1797 //*********************************************************************************
1799 void IOService::our_prechange_1 ( void )
1801 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
) {
1802 our_prechange_2(); // it's done, carry on
1805 priv
->machine_state
= IOPMour_prechange_2
; // it's not, wait for it
1806 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
1812 //*********************************************************************************
1815 // Our controlling driver has changed power state on the hardware
1816 // during a power change we initiated. Here we see if we need to wait
1817 // for power to settle before continuing. If not, we continue processing
1818 // (notifying interested parties post-change). If so, we wait and
1820 //*********************************************************************************
1822 void IOService::our_prechange_2 ( void )
1824 priv
->settle_time
= compute_settle_time();
1825 if ( priv
->settle_time
== 0 ) {
1829 priv
->machine_state
= IOPMour_prechange_3
;
1830 startSettleTimer(priv
->settle_time
);
1835 //*********************************************************************************
1838 // Power has settled on a power change we initiated. Here we notify
1839 // all our interested parties post-change. If they all acknowledge, we're
1840 // done with this change note, and we can start on the next one.
1841 // Otherwise we have to wait for acknowledgements and finish up later.
1842 //*********************************************************************************
1844 void IOService::our_prechange_3 ( void )
1846 priv
->machine_state
= IOPMour_prechange_4
; // in case they don't all ack
1847 if ( notifyAll(false) == IOPMAckImplied
) {
1853 //*********************************************************************************
1856 // Power has settled on a power change we initiated, and
1857 // all our interested parties have acknowledged. We're
1858 // done with this change note, and we can start on the next one.
1859 //*********************************************************************************
1861 void IOService::our_prechange_4 ( void )
1867 //*********************************************************************************
1870 // All applications and kernel clients have been notified of a power lowering
1871 // initiated by the parent and we didn't have to wait for any responses. Here
1872 // we notify any interested drivers and power domain children. If they all ack,
1873 // we continue with the power change.
1874 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
1875 //*********************************************************************************
1877 IOReturn
IOService::parent_down_0 ( void )
1879 priv
->machine_state
= IOPMparent_down_4
; // in case they don't all ack
1880 if ( notifyAll(true) == IOPMAckImplied
) {
1881 return parent_down_1(); // they did
1883 return IOPMWillAckLater
; // they didn't
1887 //*********************************************************************************
1890 // All applications and kernel clients have been notified of a power lowering
1891 // initiated by the parent and we had to wait for their responses. Here we notify
1892 // any interested drivers and power domain children. If they all ack, we continue
1893 // with the power change.
1894 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
1895 //*********************************************************************************
1897 void IOService::parent_down_05 ( void )
1899 priv
->machine_state
= IOPMparent_down_4
; // in case they don't all ack
1900 if ( notifyAll(true) == IOPMAckImplied
) {
1901 parent_down_4(); // they did
1906 //*********************************************************************************
1909 // All parties have acknowledged our pre-change notification of a power
1910 // lowering initiated by the parent. Here we instruct our controlling driver
1911 // to put the hardware in the state it needs to be in when the domain is
1912 // lowered. If it does so, we continue processing
1913 // (waiting for settle and acknowledging the parent.)
1914 // If it doesn't, we have to wait for it to acknowledge and then continue.
1915 //*********************************************************************************
1917 IOReturn
IOService::parent_down_1 ( void )
1919 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
) {
1920 return parent_down_2(); // it's done, carry on
1922 priv
->machine_state
= IOPMparent_down_5
; // it's not, wait for it
1923 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
1925 return IOPMWillAckLater
;
1929 //*********************************************************************************
1932 // We had to wait for it, but all parties have acknowledged our pre-change
1933 // notification of a power lowering initiated by the parent.
1934 // Here we instruct our controlling driver
1935 // to put the hardware in the state it needs to be in when the domain is
1936 // lowered. If it does so, we continue processing
1937 // (waiting for settle and acknowledging the parent.)
1938 // If it doesn't, we have to wait for it to acknowledge and then continue.
1939 //*********************************************************************************
1941 void IOService::parent_down_4 ( void )
1943 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
) {
1944 parent_down_5(); // it's done, carry on
1947 priv
-> machine_state
= IOPMparent_down_5
; // it's not, wait for it
1948 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
1954 //*********************************************************************************
1957 // Our controlling driver has changed power state on the hardware
1958 // during a power change initiated by our parent. Here we see if we need
1959 // to wait for power to settle before continuing. If not, we continue
1960 // processing (acknowledging our preparedness to the parent).
1961 // If so, we wait and continue later.
1962 //*********************************************************************************
1964 IOReturn
IOService::parent_down_2 ( void )
1966 priv
->settle_time
= compute_settle_time();
1967 if ( priv
->settle_time
== 0 ) {
1968 priv
->machine_state
= IOPMparent_down_6
; // in case they don't all ack
1969 if ( notifyAll(false) == IOPMAckImplied
) {
1971 return IOPMAckImplied
;
1973 return IOPMWillAckLater
; // they didn't
1976 priv
->machine_state
= IOPMparent_down_3
;
1977 startSettleTimer(priv
->settle_time
);
1978 return IOPMWillAckLater
;
1983 //*********************************************************************************
1986 // Our controlling driver has changed power state on the hardware
1987 // during a power change initiated by our parent. We have had to wait
1988 // for acknowledgement from interested parties, or we have had to wait
1989 // for the controlling driver to change the state. Here we see if we need
1990 // to wait for power to settle before continuing. If not, we continue
1991 // processing (acknowledging our preparedness to the parent).
1992 // If so, we wait and continue later.
1993 //*********************************************************************************
1995 void IOService::parent_down_5 ( void )
1997 priv
->settle_time
= compute_settle_time();
1998 if ( priv
->settle_time
== 0 ) {
2002 priv
->machine_state
= IOPMparent_down_3
;
2003 startSettleTimer(priv
->settle_time
);
2008 //*********************************************************************************
2011 // Power has settled on a power change initiated by our parent. Here we
2012 // notify interested parties.
2013 //*********************************************************************************
2015 void IOService::parent_down_3 ( void )
2019 priv
->machine_state
= IOPMparent_down_6
; // in case they don't all ack
2020 if ( notifyAll(false) == IOPMAckImplied
) {
2021 parent
= priv
->head_note_parent
;
2023 ((IOService
*)(parent
->getParentEntry(gIOPowerPlane
)))->acknowledgePowerChange(parent
);
2028 //*********************************************************************************
2031 // We had to wait for it, but all parties have acknowledged our post-change
2032 // notification of a power lowering initiated by the parent.
2033 // Here we acknowledge the parent.
2034 // We are done with this change note, and we can start on the next one.
2035 //*********************************************************************************
2037 void IOService::parent_down_6 ( void )
2041 parent
= priv
->head_note_parent
;
2043 ((IOService
*)(parent
->getParentEntry(gIOPowerPlane
)))->acknowledgePowerChange(parent
);
2047 //*********************************************************************************
2050 // Our parent has informed us via powerStateDidChange that it has
2051 // raised the power in our power domain, and we have had to wait
2052 // for some interested party to acknowledge our notification.
2053 // Here we instruct our controlling
2054 // driver to program the hardware to take advantage of the higher domain
2055 // power. If it does so, we continue processing
2056 // (waiting for settle and notifying interested parties post-change.)
2057 // If it doesn't, we have to wait for it to acknowledge and then continue.
2058 //*********************************************************************************
2060 void IOService::parent_up_0 ( void )
2062 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
) {
2063 parent_up_4(); // it did it, carry on
2066 priv
->machine_state
= IOPMparent_up_4
; // it didn't, wait for it
2067 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2073 //*********************************************************************************
2076 // Our parent has informed us via powerStateDidChange that it has
2077 // raised the power in our power domain. Here we instruct our controlling
2078 // driver to program the hardware to take advantage of the higher domain
2079 // power. If it does so, we continue processing
2080 // (waiting for settle and notifying interested parties post-change.)
2081 // If it doesn't, we have to wait for it to acknowledge and then continue.
2082 //*********************************************************************************
2084 IOReturn
IOService::parent_up_1 ( void )
2086 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
) {
2087 return parent_up_2(); // it did it, carry on
2090 priv
->machine_state
= IOPMparent_up_4
; // it didn't, wait for it
2091 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2093 return IOPMWillAckLater
;
2098 //*********************************************************************************
2101 // Our controlling driver has changed power state on the hardware
2102 // during a power raise initiated by the parent. Here we see if we need to wait
2103 // for power to settle before continuing. If not, we continue processing
2104 // (notifying interested parties post-change). If so, we wait and
2106 //*********************************************************************************
2108 IOReturn
IOService::parent_up_2 ( void )
2110 priv
->settle_time
= compute_settle_time();
2111 if ( priv
->settle_time
== 0 ) {
2112 return parent_up_3();
2115 priv
->machine_state
= IOPMparent_up_5
;
2116 startSettleTimer(priv
->settle_time
);
2117 return IOPMWillAckLater
;
2122 //*********************************************************************************
2125 // Our controlling driver has changed power state on the hardware
2126 // during a power raise initiated by the parent, but we had to wait for it.
2127 // Here we see if we need to wait for power to settle before continuing.
2128 // If not, we continue processing (notifying interested parties post-change).
2129 // If so, we wait and continue later.
2130 //*********************************************************************************
2132 void IOService::parent_up_4 ( void )
2134 priv
->settle_time
= compute_settle_time();
2135 if ( priv
->settle_time
== 0 ) {
2139 priv
->machine_state
= IOPMparent_up_5
;
2140 startSettleTimer(priv
->settle_time
);
2145 //*********************************************************************************
2148 // No power settling was required on a power raise initiated by the parent.
2149 // Here we notify all our interested parties post-change. If they all acknowledge,
2150 // we're done with this change note, and we can start on the next one.
2151 // Otherwise we have to wait for acknowledgements and finish up later.
2152 //*********************************************************************************
2154 IOReturn
IOService::parent_up_3 ( void )
2156 priv
->machine_state
= IOPMparent_up_6
; // in case they don't all ack
2157 if ( notifyAll(false) == IOPMAckImplied
) {
2159 return IOPMAckImplied
;
2161 return IOPMWillAckLater
; // they didn't
2165 //*********************************************************************************
2168 // Power has settled on a power raise initiated by the parent.
2169 // Here we notify all our interested parties post-change. If they all acknowledge,
2170 // we're done with this change note, and we can start on the next one.
2171 // Otherwise we have to wait for acknowledgements and finish up later.
2172 //*********************************************************************************
2174 void IOService::parent_up_5 ( void )
2176 priv
->machine_state
= IOPMparent_up_6
; // in case they don't all ack
2177 if ( notifyAll(false) == IOPMAckImplied
) {
2183 //*********************************************************************************
2186 // All parties have acknowledged our post-change notification of a power
2187 // raising initiated by the parent. Here we acknowledge the parent.
2188 // We are done with this change note, and we can start on the next one.
2189 //*********************************************************************************
2191 void IOService::parent_up_6 ( void )
2195 parent
= priv
->head_note_parent
;
2197 ((IOService
*)(parent
->getParentEntry(gIOPowerPlane
)))->acknowledgePowerChange(parent
);
2201 //*********************************************************************************
2204 // A power change is complete, and the used post-change note is at
2205 // the head of the queue. Remove it and set myCurrentState to the result
2206 // of the change. Start up the next change in queue.
2207 //*********************************************************************************
2209 void IOService::all_done ( void )
2211 priv
->machine_state
= IOPMfinished
;
2213 if ( priv
->head_note_flags
& IOPMWeInitiated
) { // our power change
2214 if ( !( priv
->head_note_flags
& IOPMNotDone
) ) { // could our driver switch to the new state?
2215 if ( pm_vars
->myCurrentState
< priv
->head_note_state
) { // yes, did power raise?
2216 tellChangeUp (priv
->head_note_state
); // yes, inform clients and apps
2219 if ( ! priv
->we_are_root
) { // no, if this lowers our
2220 ask_parent(priv
->head_note_state
); // power requirements, tell the parent
2223 pm_vars
->myCurrentState
= priv
->head_note_state
; // either way
2224 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeDone
,(unsigned long)pm_vars
->myCurrentState
,0);
2225 powerChangeDone(pm_vars
->myCurrentState
); // inform subclass policy-maker
2228 // pm_vars->myCurrentState = pm_vars->theControllingDriver->powerStateForDomainState(pm_vars->parentsCurrentPowerFlags);
2231 if ( priv
->head_note_flags
& IOPMParentInitiated
) { // parent's power change
2232 if ( ((priv
->head_note_flags
& IOPMDomainWillChange
) && (pm_vars
->myCurrentState
>= priv
->head_note_state
)) ||
2233 ((priv
->head_note_flags
& IOPMDomainDidChange
) && (pm_vars
->myCurrentState
< priv
->head_note_state
)) ) {
2234 if ( pm_vars
->myCurrentState
< priv
->head_note_state
) { // did power raise?
2235 tellChangeUp (priv
->head_note_state
); // yes, inform clients and apps
2237 pm_vars
->myCurrentState
= priv
->head_note_state
; // either way
2238 pm_vars
->maxCapability
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(priv
->head_note_domainState
);
2240 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeDone
,(unsigned long)pm_vars
->myCurrentState
,0);
2241 powerChangeDone(pm_vars
->myCurrentState
); // inform subclass policy-maker
2245 priv
->changeList
->releaseHeadChangeNote(); // we're done with this
2247 priv
->head_note
= priv
->changeList
->currentChange(); // start next one in queue
2248 if ( priv
->head_note
!= -1 ) {
2250 if (priv
->changeList
->changeNote
[priv
->head_note
].flags
& IOPMWeInitiated
) {
2251 start_our_change(priv
->head_note
);
2254 if ( start_parent_change(priv
->head_note
) == IOPMAckImplied
) {
2255 ((IOService
*)(priv
->head_note_parent
->getParentEntry(gIOPowerPlane
)))->acknowledgePowerChange(priv
->head_note_parent
);
2263 //*********************************************************************************
2266 // A driver or child has acknowledged our notification of an upcoming power
2267 // change, and this acknowledgement is the last one pending
2268 // before we change power or after changing power.
2270 //*********************************************************************************
2272 void IOService::all_acked ( void )
2274 switch (priv
->machine_state
) {
2275 case IOPMour_prechange_1
:
2278 case IOPMour_prechange_4
:
2281 case IOPMparent_down_4
:
2284 case IOPMparent_down_6
:
2287 case IOPMparent_up_0
:
2290 case IOPMparent_up_6
:
2297 //*********************************************************************************
2298 // settleTimerExpired
2300 // Power has settled after our last change. Notify interested parties that
2301 // there is a new power state.
2302 //*********************************************************************************
2304 void IOService::settleTimerExpired ( void )
2306 if ( ! initialized
) {
2307 return; // we're unloading
2310 switch (priv
->machine_state
) {
2311 case IOPMour_prechange_3
:
2314 case IOPMparent_down_3
:
2317 case IOPMparent_up_5
:
2324 //*********************************************************************************
2325 // compute_settle_time
2327 // Compute the power-settling delay in microseconds for the
2328 // change from myCurrentState to head_note_state.
2329 //*********************************************************************************
2331 unsigned long IOService::compute_settle_time ( void )
2333 unsigned long totalTime
;
2336 totalTime
= 0; // compute total time to attain the new state
2337 i
= pm_vars
->myCurrentState
;
2338 if ( priv
->head_note_state
< pm_vars
->myCurrentState
) { // we're lowering power
2339 while ( i
> priv
->head_note_state
) {
2340 totalTime
+= pm_vars
->thePowerStates
[i
].settleDownTime
;
2345 if ( priv
->head_note_state
> pm_vars
->myCurrentState
) { // we're raising power
2346 while ( i
< priv
->head_note_state
) {
2347 totalTime
+= pm_vars
->thePowerStates
[i
+1].settleUpTime
;
2356 //*********************************************************************************
2359 // Enter with a power-settling delay in microseconds and start a nano-second
2360 // timer for that delay.
2361 //*********************************************************************************
2363 IOReturn
IOService::startSettleTimer ( unsigned long delay
)
2365 AbsoluteTime deadline
;
2367 clock_interval_to_deadline(delay
, kMicrosecondScale
, &deadline
);
2369 thread_call_enter_delayed(priv
->settleTimer
, deadline
);
2374 //*********************************************************************************
2377 // The acknowledgement timeout periodic timer has ticked.
2378 // If we are awaiting acks for a power change notification,
2379 // we decrement the timer word of each interested driver which hasn't acked.
2380 // If a timer word becomes zero, we pretend the driver aknowledged.
2381 // If we are waiting for the controlling driver to change the power
2382 // state of the hardware, we decrement its timer word, and if it becomes
2383 // zero, we pretend the driver acknowledged.
2384 //*********************************************************************************
2386 void IOService::ack_timer_ticked ( void )
2388 IOPMinformee
* nextObject
;
2390 if ( ! initialized
) {
2391 return; // we're unloading
2394 if (! acquire_lock() ) {
2398 switch (priv
->machine_state
) {
2399 case IOPMour_prechange_2
:
2400 case IOPMparent_down_5
:
2401 case IOPMparent_up_4
:
2402 if ( priv
->driver_timer
!= 0 ) { // are we waiting for our driver to make its change?
2403 priv
->driver_timer
-= 1; // yes, tick once
2404 if ( priv
->driver_timer
== 0 ) { // it's tardy, we'll go on without it
2405 IOUnlock(priv
->our_lock
);
2406 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogCtrlDriverTardy
,0,0);
2409 else { // still waiting, set timer again
2411 IOUnlock(priv
->our_lock
);
2415 IOUnlock(priv
->our_lock
);
2419 case IOPMour_prechange_1
:
2420 case IOPMour_prechange_4
:
2421 case IOPMparent_down_4
:
2422 case IOPMparent_down_6
:
2423 case IOPMparent_up_0
:
2424 case IOPMparent_up_6
:
2425 if (priv
->head_note_pendingAcks
!= 0 ) { // are we waiting for interested parties to acknowledge?
2426 nextObject
= priv
->interestedDrivers
->firstInList(); // yes, go through the list of interested drivers
2427 while ( nextObject
!= NULL
) { // and check each one
2428 if ( nextObject
->timer
> 0 ) {
2429 nextObject
->timer
-= 1;
2430 if ( nextObject
->timer
== 0 ) { // this one should have acked by now
2431 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogIntDriverTardy
,0,0);
2432 kprintf("interested driver tardy: %s\n",nextObject
->whatObject
->getName());
2433 priv
->head_note_pendingAcks
-= 1;
2436 nextObject
= priv
->interestedDrivers
->nextInList(nextObject
);
2438 if ( priv
->head_note_pendingAcks
== 0 ) { // is that the last?
2439 IOUnlock(priv
->our_lock
);
2440 all_acked(); // yes, we can continue
2442 else { // no, set timer again
2444 IOUnlock(priv
->our_lock
);
2448 IOUnlock(priv
->our_lock
);
2452 case IOPMparent_down_0
: // apps didn't respond to parent-down notification
2453 IOUnlock(priv
->our_lock
);
2454 IOLockLock(priv
->flags_lock
);
2455 if (pm_vars
->responseFlags
) {
2456 pm_vars
->responseFlags
->release(); // get rid of this stuff
2457 pm_vars
->responseFlags
= NULL
;
2459 IOLockUnlock(priv
->flags_lock
);
2460 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,1);
2461 parent_down_05(); // carry on with the change
2464 case IOPMour_prechange_03
: // apps didn't respond to our power-down request
2465 IOUnlock(priv
->our_lock
);
2466 IOLockLock(priv
->flags_lock
);
2467 if (pm_vars
->responseFlags
) {
2468 pm_vars
->responseFlags
->release(); // get rid of this stuff
2469 pm_vars
->responseFlags
= NULL
;
2471 IOLockUnlock(priv
->flags_lock
);
2472 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,2);
2473 tellNoChangeDown(priv
->head_note_state
); // rescind the request
2474 priv
->head_note_flags
|= IOPMNotDone
; // mark the change note un-actioned
2475 all_done(); // and we're done
2478 case IOPMour_prechange_05
: // apps didn't respond to our power-down notification
2479 IOUnlock(priv
->our_lock
);
2480 IOLockLock(priv
->flags_lock
);
2481 if (pm_vars
->responseFlags
) {
2482 pm_vars
->responseFlags
->release(); // get rid of this stuff
2483 pm_vars
->responseFlags
= NULL
;
2485 IOLockUnlock(priv
->flags_lock
);
2486 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,3);
2487 our_prechange_05(); // carry on with the change
2491 IOUnlock(priv
->our_lock
); // not waiting for acks
2497 //*********************************************************************************
2500 //*********************************************************************************
2502 void IOService::start_ack_timer ( void )
2504 AbsoluteTime deadline
;
2506 clock_interval_to_deadline(ACK_TIMER_PERIOD
, kNanosecondScale
, &deadline
);
2508 thread_call_enter_delayed(priv
->ackTimer
, deadline
);
2512 //*********************************************************************************
2515 //*********************************************************************************
2517 void IOService::stop_ack_timer ( void )
2519 thread_call_cancel(priv
->ackTimer
);
2523 //*********************************************************************************
2524 // c-language timer expiration functions
2526 //*********************************************************************************
2528 static void ack_timer_expired ( thread_call_param_t us
)
2530 ((IOService
*)us
)->ack_timer_ticked();
2534 static void settle_timer_expired ( thread_call_param_t us
)
2536 ((IOService
*)us
)->settleTimerExpired();
2540 //*********************************************************************************
2541 // add_child_to_active_change
2543 // A child has just registered with us. If there is
2544 // currently a change in progress, get the new party involved: if we
2545 // have notified all parties and are waiting for acks, notify the new
2547 //*********************************************************************************
2549 IOReturn
IOService::add_child_to_active_change ( IOPowerConnection
* newObject
)
2551 if (! acquire_lock() ) {
2555 switch (priv
->machine_state
) {
2556 case IOPMour_prechange_1
:
2557 case IOPMparent_down_4
:
2558 case IOPMparent_up_0
:
2559 priv
->head_note_pendingAcks
+= 2; // one for this child and one to prevent
2560 IOUnlock(priv
->our_lock
); // incoming acks from changing our state
2561 notifyChild(newObject
, true);
2562 if (! acquire_lock() ) {
2563 --priv
->head_note_pendingAcks
; // put it back
2566 if ( --priv
->head_note_pendingAcks
== 0 ) { // are we still waiting for acks?
2567 stop_ack_timer(); // no, stop the timer
2568 IOUnlock(priv
->our_lock
);
2569 all_acked(); // and now we can continue
2573 case IOPMour_prechange_4
:
2574 case IOPMparent_down_6
:
2575 case IOPMparent_up_6
:
2576 priv
->head_note_pendingAcks
+= 2; // one for this child and one to prevent
2577 IOUnlock(priv
->our_lock
); // incoming acks from changing our state
2578 notifyChild(newObject
, false);
2579 if (! acquire_lock() ) {
2580 --priv
->head_note_pendingAcks
; // put it back
2583 if ( --priv
->head_note_pendingAcks
== 0 ) { // are we still waiting for acks?
2584 stop_ack_timer(); // no, stop the timer
2585 IOUnlock(priv
->our_lock
);
2586 all_acked(); // and now we can continue
2591 IOUnlock(priv
->our_lock
);
2596 //*********************************************************************************
2597 // add_driver_to_active_change
2599 // An interested driver has just registered with us. If there is
2600 // currently a change in progress, get the new party involved: if we
2601 // have notified all parties and are waiting for acks, notify the new
2603 //*********************************************************************************
2605 IOReturn
IOService::add_driver_to_active_change ( IOPMinformee
* newObject
)
2607 if (! acquire_lock() ) {
2611 switch (priv
->machine_state
) {
2612 case IOPMour_prechange_1
:
2613 case IOPMparent_down_4
:
2614 case IOPMparent_up_0
:
2615 priv
->head_note_pendingAcks
+= 2; // one for this driver and one to prevent
2616 IOUnlock(priv
->our_lock
); // incoming acks from changing our state
2617 inform(newObject
, true); // inform the driver
2618 if (! acquire_lock() ) {
2619 --priv
->head_note_pendingAcks
; // put it back
2622 if ( --priv
->head_note_pendingAcks
== 0 ) { // are we still waiting for acks?
2623 stop_ack_timer(); // no, stop the timer
2624 IOUnlock(priv
->our_lock
);
2625 all_acked(); // and now we can continue
2629 case IOPMour_prechange_4
:
2630 case IOPMparent_down_6
:
2631 case IOPMparent_up_6
:
2632 priv
->head_note_pendingAcks
+= 2; // one for this driver and one to prevent
2633 IOUnlock(priv
->our_lock
); // incoming acks from changing our state
2634 inform(newObject
, false); // inform the driver
2635 if (! acquire_lock() ) {
2636 --priv
->head_note_pendingAcks
; // put it back
2639 if ( --priv
->head_note_pendingAcks
== 0 ) { // are we still waiting for acks?
2640 stop_ack_timer(); // no, stop the timer
2641 IOUnlock(priv
->our_lock
);
2642 all_acked(); // and now we can continue
2647 IOUnlock(priv
->our_lock
);
2652 //*********************************************************************************
2653 // start_parent_change
2655 // Here we begin the processing of a change note initiated by our parent
2656 // which is at the head of the queue.
2658 // It is possible for the change to be processed to completion and removed from the queue.
2659 // There are several possible interruptions to the processing, though, and they are:
2660 // we may have to wait for interested parties to acknowledge our pre-change notification,
2661 // we may have to wait for our controlling driver to change the hardware power state,
2662 // there may be a settling time after changing the hardware power state,
2663 // we may have to wait for interested parties to acknowledge our post-change notification,
2664 // we may have to wait for the acknowledgement timer expiration to substitute for the
2665 // acknowledgement from a failing driver.
2666 //*********************************************************************************
2668 IOReturn
IOService::start_parent_change ( unsigned long queue_head
)
2670 priv
->head_note
= queue_head
;
2671 priv
->head_note_flags
= priv
-> changeList
->changeNote
[priv
->head_note
].flags
;
2672 priv
->head_note_state
= priv
->changeList
->changeNote
[priv
->head_note
].newStateNumber
;
2673 priv
->head_note_outputFlags
= priv
->changeList
->changeNote
[priv
->head_note
].outputPowerCharacter
;
2674 priv
->head_note_domainState
= priv
->changeList
->changeNote
[priv
->head_note
].domainState
;
2675 priv
->head_note_parent
= priv
->changeList
->changeNote
[priv
->head_note
].parent
;
2676 priv
->head_note_capabilityFlags
= priv
->changeList
->changeNote
[priv
->head_note
].capabilityFlags
;
2678 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartParentChange
,
2679 (unsigned long)priv
->head_note_state
,(unsigned long)pm_vars
->myCurrentState
);
2681 ask_parent( priv
->ourDesiredPowerState
); // if we need something and haven't told the parent, do so
2683 if ( priv
->head_note_state
< pm_vars
->myCurrentState
) { // power domain is lowering
2684 priv
->initial_change
= false;
2685 priv
->machine_state
= IOPMparent_down_0
; // tell apps and kernel clients
2686 if ( tellChangeDown(priv
->head_note_state
) ) { // are we waiting for responses?
2687 return parent_down_0(); // no, notify interested drivers
2689 return IOPMWillAckLater
; // yes
2692 if ( priv
->head_note_state
> pm_vars
->myCurrentState
) { // parent is raising power, we may or may not
2693 if ( priv
->ourDesiredPowerState
> pm_vars
->myCurrentState
) {
2694 if ( priv
->ourDesiredPowerState
< priv
->head_note_state
) {
2695 priv
->head_note_state
= priv
->ourDesiredPowerState
; // we do, but not all the way
2696 priv
->head_note_outputFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].outputPowerCharacter
;
2697 priv
->head_note_capabilityFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].capabilityFlags
;
2698 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAmendParentChange
,(unsigned long)priv
->head_note_state
,0);
2702 priv
-> head_note_state
= pm_vars
->myCurrentState
; // we don't
2703 priv
->head_note_outputFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].outputPowerCharacter
;
2704 priv
->head_note_capabilityFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].capabilityFlags
;
2705 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAmendParentChange
,(unsigned long)priv
->head_note_state
,0);
2709 if ( (priv
->head_note_state
> pm_vars
->myCurrentState
) &&
2710 (priv
->head_note_flags
& IOPMDomainDidChange
) ) { // changing up
2711 priv
->initial_change
= false;
2712 priv
->machine_state
= IOPMparent_up_0
;
2713 if ( notifyAll(true) == IOPMAckImplied
) {
2714 return parent_up_1();
2716 return IOPMWillAckLater
; // they didn't all ack
2720 return IOPMAckImplied
; // a null change or power will go up
2724 //*********************************************************************************
2727 // Here we begin the processing of a change note initiated by us
2728 // which is at the head of the queue.
2730 // It is possible for the change to be processed to completion and removed from the queue.
2731 // There are several possible interruptions to the processing, though, and they are:
2732 // we may have to wait for interested parties to acknowledge our pre-change notification,
2733 // changes initiated by the parent will wait in the middle for powerStateDidChange,
2734 // we may have to wait for our controlling driver to change the hardware power state,
2735 // there may be a settling time after changing the hardware power state,
2736 // we may have to wait for interested parties to acknowledge our post-change notification,
2737 // we may have to wait for the acknowledgement timer expiration to substitute for the
2738 // acknowledgement from a failing driver.
2739 //*********************************************************************************
2741 void IOService::start_our_change ( unsigned long queue_head
)
2743 priv
->head_note
= queue_head
;
2744 priv
->head_note_flags
= priv
->changeList
->changeNote
[priv
->head_note
].flags
;
2745 priv
->head_note_state
= priv
->changeList
->changeNote
[priv
->head_note
].newStateNumber
;
2746 priv
->head_note_outputFlags
= priv
->changeList
->changeNote
[priv
->head_note
].outputPowerCharacter
;
2747 priv
->head_note_capabilityFlags
= priv
->changeList
->changeNote
[priv
->head_note
].capabilityFlags
;
2749 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartDeviceChange
,
2750 (unsigned long)priv
->head_note_state
,(unsigned long)pm_vars
->myCurrentState
);
2752 if ( priv
->head_note_capabilityFlags
& IOPMNotAttainable
) { // can our driver switch to the new state?
2753 if ( ! priv
->we_are_root
) { // no, ask the parent to do it then
2754 ask_parent(priv
->head_note_state
);
2756 priv
-> head_note_flags
|= IOPMNotDone
; // mark the change note un-actioned
2757 all_done(); // and we're done
2760 // is there enough power in the domain?
2761 if ( (pm_vars
->maxCapability
< priv
->head_note_state
) && (! priv
->we_are_root
) ) {
2762 if ( ! priv
->we_are_root
) { // no, ask the parent to raise it
2763 ask_parent(priv
->head_note_state
);
2765 priv
->head_note_flags
|= IOPMNotDone
; // no, mark the change note un-actioned
2766 all_done(); // and we're done
2767 return; // till the parent raises power
2770 if ( ! priv
->initial_change
) {
2771 if ( priv
->head_note_state
== pm_vars
->myCurrentState
) {
2772 all_done(); // we initiated a null change; forget it
2776 priv
->initial_change
= false;
2778 if ( priv
->head_note_state
< pm_vars
->myCurrentState
) { // dropping power?
2779 priv
->machine_state
= IOPMour_prechange_03
; // yes, in case we have to wait for acks
2780 pm_vars
->doNotPowerDown
= false;
2781 if ( askChangeDown(priv
->head_note_state
) ) { // ask apps and kernel clients if we can drop power
2782 if ( pm_vars
->doNotPowerDown
) { // don't have to wait, did any clients veto?
2783 tellNoChangeDown(priv
->head_note_state
); // yes, rescind the warning
2784 priv
-> head_note_flags
|= IOPMNotDone
; // mark the change note un-actioned
2785 all_done(); // and we're done
2788 our_prechange_03(); // no, tell'em we're dropping power
2793 if ( ! priv
->we_are_root
) { // we are raising power
2794 ask_parent(priv
->head_note_state
); // if this changes our power requirement, tell the parent
2796 priv
->machine_state
= IOPMour_prechange_1
; // in case they don't all ack
2797 if ( notifyAll(true) == IOPMAckImplied
) { // notify interested drivers and children
2804 //*********************************************************************************
2807 // Call the power domain parent to ask for a higher power state in the domain
2808 // or to suggest a lower power state.
2809 //*********************************************************************************
2811 IOReturn
IOService::ask_parent ( unsigned long requestedState
)
2815 IOPowerConnection
* connection
;
2817 if ( priv
->previousRequest
== pm_vars
->thePowerStates
[requestedState
].inputPowerRequirement
) { // is this a new desire?
2818 return IOPMNoErr
; // no, the parent knows already, just return
2821 if ( priv
->we_are_root
) {
2824 priv
->previousRequest
= pm_vars
->thePowerStates
[requestedState
].inputPowerRequirement
;
2826 iter
= getParentIterator(gIOPowerPlane
);
2829 while ( (next
= iter
->getNextObject()) ) {
2830 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
2831 if ( ((IOService
*)(connection
->getParentEntry(gIOPowerPlane
)))->requestPowerDomainState( priv
->previousRequest
,connection
,IOPMLowestState
)!= IOPMNoErr
) {
2832 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRequestDenied
,(unsigned long)priv
->previousRequest
,0);
2843 //*********************************************************************************
2846 // Call the controlling driver and have it change the power state of the
2847 // hardware. If it returns IOPMAckImplied, the change is complete, and
2848 // we return IOPMAckImplied. Otherwise, it will ack when the change
2849 // is done; we return IOPMWillAckLater.
2850 //*********************************************************************************
2852 IOReturn
IOService::instruct_driver ( unsigned long newState
)
2854 IOReturn return_code
;
2856 if ( pm_vars
->thePowerStates
[newState
].capabilityFlags
& IOPMNotAttainable
) { // can our driver switch to the desired state?
2857 return IOPMAckImplied
; // no, so don't try
2859 priv
->driver_timer
= -1;
2861 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogProgramHardware
,newState
,0);
2862 return_code
= pm_vars
->theControllingDriver
->setPowerState( newState
,this ); // yes, instruct it
2863 if ( return_code
== IOPMAckImplied
) { // it finished
2864 priv
->driver_timer
= 0;
2865 return IOPMAckImplied
;
2868 if ( priv
->driver_timer
== 0 ) { // it acked behind our back
2869 return IOPMAckImplied
;
2872 if ( return_code
< 0 ) { // somebody goofed
2873 return IOPMAckImplied
;
2876 priv
->driver_timer
= (return_code
* ns_per_us
/ ACK_TIMER_PERIOD
) + 1; // it didn't finish
2877 return IOPMWillAckLater
;
2881 //*********************************************************************************
2884 // We are acquiring the lock we use to protect our queue head from
2885 // simutaneous access by a thread which calls acknowledgePowerStateChange
2886 // or acknowledgeSetPowerState and the ack timer expiration thread.
2887 // Return TRUE if we acquire the lock, and the queue head didn't change
2888 // while we were acquiring the lock (and maybe blocked).
2889 // If there is no queue head, or it changes while we are blocked,
2890 // return FALSE with the lock unlocked.
2891 //*********************************************************************************
2893 bool IOService::acquire_lock ( void )
2895 long current_change_note
;
2897 current_change_note
= priv
->head_note
;
2898 if ( current_change_note
== -1 ) {
2902 IOTakeLock(priv
->our_lock
);
2903 if ( current_change_note
== priv
->head_note
) {
2906 else { // we blocked and something changed radically
2907 IOUnlock(priv
->our_lock
); // so there's nothing to do any more
2913 //*********************************************************************************
2916 // Ask registered applications and kernel clients if we can change to a lower
2919 // Subclass can override this to send a different message type. Parameter is
2920 // the destination state number.
2922 // Return true if we don't have to wait for acknowledgements
2923 //*********************************************************************************
2925 bool IOService::askChangeDown ( unsigned long )
2927 return tellClientsWithResponse(kIOMessageCanDevicePowerOff
);
2931 //*********************************************************************************
2934 // Notify registered applications and kernel clients that we are definitely
2937 // Subclass can override this to send a different message type. Parameter is
2938 // the destination state number.
2940 // Return true if we don't have to wait for acknowledgements
2941 //*********************************************************************************
2943 bool IOService::tellChangeDown ( unsigned long )
2945 return tellClientsWithResponse(kIOMessageDeviceWillPowerOff
);
2949 //*********************************************************************************
2950 // tellClientsWithResponse
2952 // Notify registered applications and kernel clients that we are definitely
2955 // Return true if we don't have to wait for acknowledgements
2956 //*********************************************************************************
2958 bool IOService::tellClientsWithResponse ( int messageType
)
2960 struct context theContext
;
2961 AbsoluteTime deadline
;
2964 pm_vars
->responseFlags
= OSArray::withCapacity( 1 );
2965 pm_vars
->serialNumber
+= 1;
2967 theContext
.responseFlags
= pm_vars
->responseFlags
;
2968 theContext
.serialNumber
= pm_vars
->serialNumber
;
2969 theContext
.flags_lock
= priv
->flags_lock
;
2970 theContext
.counter
= 1;
2971 theContext
.msgType
= messageType
;
2972 theContext
.us
= this;
2973 theContext
.maxTimeRequested
= 0;
2975 IOLockLock(priv
->flags_lock
);
2976 aBool
= OSBoolean::withBoolean(false); // position zero is false to
2977 theContext
.responseFlags
->setObject(0,aBool
); // prevent allowCancelCommon from succeeding
2979 IOLockUnlock(priv
->flags_lock
);
2981 applyToInterested(gIOAppPowerStateInterest
,tellAppWithResponse
,(void *)&theContext
);
2982 applyToInterested(gIOGeneralInterest
,tellClientWithResponse
,(void *)&theContext
);
2984 if (! acquire_lock() ) {
2987 IOLockLock(priv
->flags_lock
);
2988 aBool
= OSBoolean::withBoolean(true); // now fix position zero
2989 theContext
.responseFlags
->replaceObject(0,aBool
);
2991 IOLockUnlock(priv
->flags_lock
);
2993 if ( ! checkForDone() ) { // we have to wait for somebody
2994 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,theContext
.maxTimeRequested
,0);
2995 clock_interval_to_deadline(theContext
.maxTimeRequested
/ 1000, kMillisecondScale
, &deadline
);
2997 thread_call_enter_delayed(priv
->ackTimer
, deadline
);
2999 IOUnlock(priv
->our_lock
); // yes
3003 IOUnlock(priv
->our_lock
);
3004 IOLockLock(priv
->flags_lock
);
3005 pm_vars
->responseFlags
->release(); // everybody responded
3006 pm_vars
->responseFlags
= NULL
;
3007 IOLockUnlock(priv
->flags_lock
);
3013 //*********************************************************************************
3014 // tellAppWithResponse
3016 // We send a message to an application, and we expect a response, so we compute a
3017 // cookie we can identify the response with.
3018 //*********************************************************************************
3019 void tellAppWithResponse ( OSObject
* object
, void * context
)
3021 struct context
* theContext
= (struct context
*)context
;
3025 if( OSDynamicCast( IOService
, object
) ) {
3026 IOLockLock(theContext
->flags_lock
);
3027 aBool
= OSBoolean::withBoolean(true);
3028 theContext
->responseFlags
->setObject(theContext
->counter
,aBool
);
3030 IOLockUnlock(theContext
->flags_lock
);
3033 refcon
= ((theContext
->serialNumber
& 0xFFFF)<<16) + (theContext
->counter
& 0xFFFF);
3034 IOLockLock(theContext
->flags_lock
);
3035 aBool
= OSBoolean::withBoolean(false);
3036 theContext
->responseFlags
->setObject(theContext
->counter
,aBool
);
3038 IOLockUnlock(theContext
->flags_lock
);
3039 theContext
->us
->messageClient(theContext
->msgType
,object
,(void *)refcon
);
3040 if ( theContext
->maxTimeRequested
< k15seconds
) {
3041 theContext
->maxTimeRequested
= k15seconds
;
3044 theContext
->counter
+= 1;
3048 //*********************************************************************************
3049 // tellClientWithResponse
3051 // We send a message to an in-kernel client, and we expect a response, so we compute a
3052 // cookie we can identify the response with.
3053 // If it doesn't understand the notification (it is not power-management savvy)
3054 // we won't wait for it to prepare for sleep. If it tells us via a return code
3055 // in the passed struct that it is currently ready, we won't wait for it to prepare.
3056 // If it tells us via the return code in the struct that it does need time, we will chill.
3057 //*********************************************************************************
3058 void tellClientWithResponse ( OSObject
* object
, void * context
)
3060 struct context
* theContext
= (struct context
*)context
;
3061 sleepWakeNote paramBlock
;
3067 refcon
= ((theContext
->serialNumber
& 0xFFFF)<<16) + (theContext
->counter
& 0xFFFF);
3068 IOLockLock(theContext
->flags_lock
);
3069 aBool
= OSBoolean::withBoolean(false);
3070 theContext
->responseFlags
->setObject(theContext
->counter
,aBool
);
3072 IOLockUnlock(theContext
->flags_lock
);
3073 paramBlock
.powerRef
= (void *)refcon
;
3074 paramBlock
.returnValue
= 0;
3075 retCode
= theContext
->us
->messageClient(theContext
->msgType
,object
,(void *)¶mBlock
);
3076 if ( retCode
== kIOReturnSuccess
) {
3077 if ( paramBlock
.returnValue
== 0 ) { // client doesn't want time to respond
3078 IOLockLock(theContext
->flags_lock
);
3079 aBool
= OSBoolean::withBoolean(true);
3080 theContext
->responseFlags
->replaceObject(theContext
->counter
,aBool
); // so set its flag true
3082 IOLockUnlock(theContext
->flags_lock
);
3085 IOLockLock(theContext
->flags_lock
);
3086 theFlag
= theContext
->responseFlags
->getObject(theContext
->counter
); // it does want time, and it hasn't
3087 if ( theFlag
!= 0 ) { // responded yet
3088 if ( ((OSBoolean
*)theFlag
)->isFalse() ) { // so note its time requirement
3089 if ( theContext
->maxTimeRequested
< paramBlock
.returnValue
) {
3090 theContext
->maxTimeRequested
= paramBlock
.returnValue
;
3094 IOLockUnlock(theContext
->flags_lock
);
3097 else { // not a client of ours
3098 IOLockLock(theContext
->flags_lock
);
3099 aBool
= OSBoolean::withBoolean(true); // so we won't be waiting for response
3100 theContext
->responseFlags
->replaceObject(theContext
->counter
,aBool
);
3102 IOLockUnlock(theContext
->flags_lock
);
3104 theContext
->counter
+= 1;
3108 //*********************************************************************************
3111 // Notify registered applications and kernel clients that we are not
3114 // Subclass can override this to send a different message type. Parameter is
3115 // the aborted destination state number.
3116 //*********************************************************************************
3118 void IOService::tellNoChangeDown ( unsigned long )
3120 return tellClients(kIOMessageDeviceWillNotPowerOff
);
3124 //*********************************************************************************
3127 // Notify registered applications and kernel clients that we are raising power.
3129 // Subclass can override this to send a different message type. Parameter is
3130 // the aborted destination state number.
3131 //*********************************************************************************
3133 void IOService::tellChangeUp ( unsigned long )
3135 return tellClients(kIOMessageDeviceHasPoweredOn
);
3139 //*********************************************************************************
3142 // Notify registered applications and kernel clients of something.
3143 //*********************************************************************************
3145 void IOService::tellClients ( int messageType
)
3147 struct context theContext
;
3149 theContext
.msgType
= messageType
;
3150 theContext
.us
= this;
3152 applyToInterested(gIOAppPowerStateInterest
,tellClient
,(void *)&theContext
);
3153 applyToInterested(gIOGeneralInterest
,tellClient
,(void *)&theContext
);
3157 //*********************************************************************************
3160 // Notify a registered application or kernel client of something.
3161 //*********************************************************************************
3162 void tellClient ( OSObject
* object
, void * context
)
3164 struct context
* theContext
= (struct context
*)context
;
3166 theContext
->us
->messageClient(theContext
->msgType
,object
,0);
3170 // **********************************************************************************
3173 // **********************************************************************************
3174 bool IOService::checkForDone ( void )
3179 IOLockLock(priv
->flags_lock
);
3180 if ( pm_vars
->responseFlags
== NULL
) {
3181 IOLockUnlock(priv
->flags_lock
);
3184 for ( i
= 0; ; i
++ ) {
3185 theFlag
= pm_vars
->responseFlags
->getObject(i
);
3186 if ( theFlag
== NULL
) {
3189 if ( ((OSBoolean
*)theFlag
)->isFalse() ) {
3190 IOLockUnlock(priv
->flags_lock
);
3194 IOLockUnlock(priv
->flags_lock
);
3199 // **********************************************************************************
3202 // **********************************************************************************
3203 bool IOService::responseValid ( unsigned long x
)
3205 UInt16 serialComponent
;
3206 UInt16 ordinalComponent
;
3208 unsigned long refcon
= (unsigned long)x
;
3211 serialComponent
= (refcon
>>16) & 0xFFFF;
3212 ordinalComponent
= refcon
& 0xFFFF;
3214 if ( serialComponent
!= pm_vars
->serialNumber
) {
3218 IOLockLock(priv
->flags_lock
);
3219 if ( pm_vars
->responseFlags
== NULL
) {
3220 IOLockUnlock(priv
->flags_lock
);
3224 theFlag
= pm_vars
->responseFlags
->getObject(ordinalComponent
);
3226 if ( theFlag
== 0 ) {
3227 IOLockUnlock(priv
->flags_lock
);
3231 if ( ((OSBoolean
*)theFlag
)->isFalse() ) {
3232 aBool
= OSBoolean::withBoolean(true);
3233 pm_vars
->responseFlags
->replaceObject(ordinalComponent
,aBool
);
3237 IOLockUnlock(priv
->flags_lock
);
3242 // **********************************************************************************
3245 // Our power state is about to lower, and we have notified applications
3246 // and kernel clients, and one of them has acknowledged. If this is the last to do
3247 // so, and all acknowledgements are positive, we continue with the power change.
3249 // We serialize this processing with timer expiration with a command gate on the
3250 // power management workloop, which the timer expiration is command gated to as well.
3251 // **********************************************************************************
3252 IOReturn
IOService::allowPowerChange ( unsigned long refcon
)
3254 if ( ! initialized
) {
3255 return kIOReturnSuccess
; // we're unloading
3258 return pm_vars
->PMcommandGate
->runAction(serializedAllowPowerChange
,(void *)refcon
);
3262 IOReturn
serializedAllowPowerChange ( OSObject
*owner
, void * refcon
, void *, void *, void *)
3264 return ((IOService
*)owner
)->serializedAllowPowerChange2((unsigned long)refcon
);
3267 IOReturn
IOService::serializedAllowPowerChange2 ( unsigned long refcon
)
3269 if ( ! responseValid(refcon
) ) { // response valid?
3270 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr5
,refcon
,0);
3271 return kIOReturnSuccess
; // no, just return
3273 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientAcknowledge
,refcon
,0);
3275 return allowCancelCommon();
3279 // **********************************************************************************
3280 // cancelPowerChange
3282 // Our power state is about to lower, and we have notified applications
3283 // and kernel clients, and one of them has vetoed the change. If this is the last
3284 // client to respond, we abandon the power change.
3286 // We serialize this processing with timer expiration with a command gate on the
3287 // power management workloop, which the timer expiration is command gated to as well.
3288 // **********************************************************************************
3289 IOReturn
IOService::cancelPowerChange ( unsigned long refcon
)
3291 if ( ! initialized
) {
3292 return kIOReturnSuccess
; // we're unloading
3295 return pm_vars
->PMcommandGate
->runAction(serializedCancelPowerChange
,(void *)refcon
);
3299 IOReturn
serializedCancelPowerChange ( OSObject
*owner
, void * refcon
, void *, void *, void *)
3301 return ((IOService
*)owner
)->serializedCancelPowerChange2((unsigned long)refcon
);
3304 IOReturn
IOService::serializedCancelPowerChange2 ( unsigned long refcon
)
3306 if ( ! responseValid(refcon
) ) { // response valid?
3307 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr5
,refcon
,0);
3308 return kIOReturnSuccess
; // no, just return
3310 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientCancel
,refcon
,0);
3312 pm_vars
->doNotPowerDown
= true;
3314 return allowCancelCommon();
3318 // **********************************************************************************
3319 // allowCancelCommon
3321 // **********************************************************************************
3322 IOReturn
IOService::allowCancelCommon ( void )
3324 if (! acquire_lock() ) {
3325 return kIOReturnSuccess
;
3328 if ( checkForDone() ) { // is this the last response?
3329 stop_ack_timer(); // yes, stop the timer
3330 IOUnlock(priv
->our_lock
);
3331 IOLockLock(priv
->flags_lock
);
3332 if ( pm_vars
->responseFlags
) {
3333 pm_vars
->responseFlags
->release();
3334 pm_vars
->responseFlags
= NULL
;
3336 IOLockUnlock(priv
->flags_lock
);
3337 switch (priv
->machine_state
) {
3338 case IOPMour_prechange_03
: // our change, was it vetoed?
3339 if ( ! pm_vars
->doNotPowerDown
) {
3340 our_prechange_03(); // no, we can continue
3343 tellNoChangeDown(priv
->head_note_state
); // yes, rescind the warning
3344 priv
->head_note_flags
|= IOPMNotDone
; // mark the change note un-actioned
3345 all_done(); // and we're done
3348 case IOPMour_prechange_05
:
3349 our_prechange_05(); // our change, continue
3351 case IOPMparent_down_0
:
3352 parent_down_05(); // parent change, continueq8q
3355 return kIOReturnSuccess
;
3358 IOUnlock(priv
->our_lock
); // not done yet
3359 return kIOReturnSuccess
;
3363 //*********************************************************************************
3366 // Set to highest available power state for a minimum of duration milliseconds
3367 //*********************************************************************************
3369 #define kFiveMinutesInNanoSeconds (300 * NSEC_PER_SEC)
3371 void IOService::clampPowerOn (unsigned long duration
)
3373 changePowerStateToPriv (pm_vars
->theNumberOfPowerStates
-1);
3375 if ( priv
->clampTimerEventSrc
== NULL
) {
3376 priv
->clampTimerEventSrc
= IOTimerEventSource::timerEventSource(this,
3377 c_PM_Clamp_Timer_Expired
);
3379 IOWorkLoop
* workLoop
= getPMworkloop ();
3381 if ( !priv
->clampTimerEventSrc
|| !workLoop
||
3382 ( workLoop
->addEventSource( priv
->clampTimerEventSrc
) != kIOReturnSuccess
) ) {
3387 priv
->clampTimerEventSrc
->setTimeout(kFiveMinutesInNanoSeconds
, NSEC_PER_SEC
);
3390 //*********************************************************************************
3391 // PM_Clamp_Timer_Expired
3393 // called when clamp timer expires...set power state to 0.
3394 //*********************************************************************************
3396 void IOService::PM_Clamp_Timer_Expired (void)
3398 if ( ! initialized
) {
3399 return; // we're unloading
3402 changePowerStateToPriv (0);
3405 //*********************************************************************************
3406 // c_PM_clamp_Timer_Expired (C Func)
3408 // Called when our clamp timer expires...we will call the object method.
3409 //*********************************************************************************
3411 void c_PM_Clamp_Timer_Expired (OSObject
* client
, IOTimerEventSource
*)
3414 ((IOService
*)client
)->PM_Clamp_Timer_Expired ();
3418 //*********************************************************************************
3421 // Does nothing here. This should be implemented in a subclass driver.
3422 //*********************************************************************************
3424 IOReturn
IOService::setPowerState ( unsigned long powerStateOrdinal
, IOService
* whatDevice
)
3430 //*********************************************************************************
3431 // maxCapabilityForDomainState
3433 // Finds the highest power state in the array whose input power
3434 // requirement is equal to the input parameter. Where a more intelligent
3435 // decision is possible, override this in the subclassed driver.
3436 //*********************************************************************************
3438 unsigned long IOService::maxCapabilityForDomainState ( IOPMPowerFlags domainState
)
3442 if (pm_vars
->theNumberOfPowerStates
== 0 ) {
3445 for ( i
= (pm_vars
->theNumberOfPowerStates
)-1; i
>= 0; i
-- ) {
3446 if ( pm_vars
->thePowerStates
[i
].inputPowerRequirement
== domainState
) {
3454 //*********************************************************************************
3455 // initialPowerStateForDomainState
3457 // Finds the highest power state in the array whose input power
3458 // requirement is equal to the input parameter. Where a more intelligent
3459 // decision is possible, override this in the subclassed driver.
3460 //*********************************************************************************
3462 unsigned long IOService::initialPowerStateForDomainState ( IOPMPowerFlags domainState
)
3466 if (pm_vars
->theNumberOfPowerStates
== 0 ) {
3469 for ( i
= (pm_vars
->theNumberOfPowerStates
)-1; i
>= 0; i
-- ) {
3470 if ( pm_vars
->thePowerStates
[i
].inputPowerRequirement
== domainState
) {
3478 //*********************************************************************************
3479 // powerStateForDomainState
3481 // Finds the highest power state in the array whose input power
3482 // requirement is equal to the input parameter. Where a more intelligent
3483 // decision is possible, override this in the subclassed driver.
3484 //*********************************************************************************
3486 unsigned long IOService::powerStateForDomainState ( IOPMPowerFlags domainState
)
3490 if (pm_vars
->theNumberOfPowerStates
== 0 ) {
3493 for ( i
= (pm_vars
->theNumberOfPowerStates
)-1; i
>= 0; i
-- ) {
3494 if ( pm_vars
->thePowerStates
[i
].inputPowerRequirement
== domainState
) {
3502 //*********************************************************************************
3505 // Does nothing here. This should be implemented in a subclass driver.
3506 //*********************************************************************************
3508 bool IOService::didYouWakeSystem ( void )
3514 //*********************************************************************************
3515 // powerStateWillChangeTo
3517 // Does nothing here. This should be implemented in a subclass driver.
3518 //*********************************************************************************
3520 IOReturn
IOService::powerStateWillChangeTo ( IOPMPowerFlags
, unsigned long, IOService
*)
3526 //*********************************************************************************
3527 // powerStateDidChangeTo
3529 // Does nothing here. This should be implemented in a subclass driver.
3530 //*********************************************************************************
3532 IOReturn
IOService::powerStateDidChangeTo ( IOPMPowerFlags
, unsigned long, IOService
*)
3538 //*********************************************************************************
3541 // Does nothing here. This should be implemented in a subclass policy-maker.
3542 //*********************************************************************************
3544 void IOService::powerChangeDone ( unsigned long )
3549 //*********************************************************************************
3552 // Does nothing here. This should be implemented in a subclass driver.
3553 //*********************************************************************************
3555 IOReturn
IOService::newTemperature ( long currentTemp
, IOService
* whichZone
)
3563 #define super OSObject
3565 OSDefineMetaClassAndStructors(IOPMprot
, OSObject
)
3566 //*********************************************************************************
3569 // Serialize protected instance variables for debug output.
3570 //*********************************************************************************
3571 bool IOPMprot::serialize(OSSerialize
*s
) const
3573 OSString
* theOSString
;
3579 buffer
= ptr
= IONew(char, 2000);
3583 ptr
+= sprintf(ptr
,"{ theNumberOfPowerStates = %d, ",(unsigned int)theNumberOfPowerStates
);
3585 if ( theNumberOfPowerStates
!= 0 ) {
3586 ptr
+= sprintf(ptr
,"version %d, ",(unsigned int)thePowerStates
[0].version
);
3589 if ( theNumberOfPowerStates
!= 0 ) {
3590 for ( i
= 0; i
< (int)theNumberOfPowerStates
; i
++ ) {
3591 ptr
+= sprintf(ptr
,"power state %d = { ",i
);
3592 ptr
+= sprintf(ptr
,"capabilityFlags %08x, ",(unsigned int)thePowerStates
[i
].capabilityFlags
);
3593 ptr
+= sprintf(ptr
,"outputPowerCharacter %08x, ",(unsigned int)thePowerStates
[i
].outputPowerCharacter
);
3594 ptr
+= sprintf(ptr
,"inputPowerRequirement %08x, ",(unsigned int)thePowerStates
[i
].inputPowerRequirement
);
3595 ptr
+= sprintf(ptr
,"staticPower %d, ",(unsigned int)thePowerStates
[i
].staticPower
);
3596 ptr
+= sprintf(ptr
,"unbudgetedPower %d, ",(unsigned int)thePowerStates
[i
].unbudgetedPower
);
3597 ptr
+= sprintf(ptr
,"powerToAttain %d, ",(unsigned int)thePowerStates
[i
].powerToAttain
);
3598 ptr
+= sprintf(ptr
,"timeToAttain %d, ",(unsigned int)thePowerStates
[i
].timeToAttain
);
3599 ptr
+= sprintf(ptr
,"settleUpTime %d, ",(unsigned int)thePowerStates
[i
].settleUpTime
);
3600 ptr
+= sprintf(ptr
,"timeToLower %d, ",(unsigned int)thePowerStates
[i
].timeToLower
);
3601 ptr
+= sprintf(ptr
,"settleDownTime %d, ",(unsigned int)thePowerStates
[i
].settleDownTime
);
3602 ptr
+= sprintf(ptr
,"powerDomainBudget %d }, ",(unsigned int)thePowerStates
[i
].powerDomainBudget
);
3606 ptr
+= sprintf(ptr
,"aggressiveness = %d, ",(unsigned int)aggressiveness
);
3607 ptr
+= sprintf(ptr
,"myCurrentState = %d, ",(unsigned int)myCurrentState
);
3608 ptr
+= sprintf(ptr
,"parentsCurrentPowerFlags = %08x, ",(unsigned int)parentsCurrentPowerFlags
);
3609 ptr
+= sprintf(ptr
,"maxCapability = %d }",(unsigned int)maxCapability
);
3611 theOSString
= OSString::withCString(buffer
);
3612 rtn_code
= theOSString
->serialize(s
);
3613 theOSString
->release();
3614 IODelete(buffer
, char, 2000);
3621 #define super OSObject
3623 OSDefineMetaClassAndStructors(IOPMpriv
, OSObject
)
3624 //*********************************************************************************
3627 // Serialize private instance variables for debug output.
3628 //*********************************************************************************
3629 bool IOPMpriv::serialize(OSSerialize
*s
) const
3631 OSString
* theOSString
;
3635 IOPMinformee
* nextObject
;
3637 buffer
= ptr
= IONew(char, 2000);
3641 ptr
+= sprintf(ptr
,"{ this object = %08x",(unsigned int)owner
);
3642 if ( we_are_root
) {
3643 ptr
+= sprintf(ptr
," (root)");
3645 ptr
+= sprintf(ptr
,", ");
3647 nextObject
= interestedDrivers
->firstInList(); // display interested drivers
3648 while ( nextObject
!= NULL
) {
3649 ptr
+= sprintf(ptr
,"interested driver = %08x, ",(unsigned int)nextObject
->whatObject
);
3650 nextObject
= interestedDrivers
->nextInList(nextObject
);
3653 if ( machine_state
!= IOPMfinished
) {
3654 ptr
+= sprintf(ptr
,"machine_state = %d, ",(unsigned int)machine_state
);
3655 ptr
+= sprintf(ptr
,"driver_timer = %d, ",(unsigned int)driver_timer
);
3656 ptr
+= sprintf(ptr
,"settle_time = %d, ",(unsigned int)settle_time
);
3657 ptr
+= sprintf(ptr
,"head_note_flags = %08x, ",(unsigned int)head_note_flags
);
3658 ptr
+= sprintf(ptr
,"head_note_state = %d, ",(unsigned int)head_note_state
);
3659 ptr
+= sprintf(ptr
,"head_note_outputFlags = %08x, ",(unsigned int)head_note_outputFlags
);
3660 ptr
+= sprintf(ptr
,"head_note_domainState = %08x, ",(unsigned int)head_note_domainState
);
3661 ptr
+= sprintf(ptr
,"head_note_capabilityFlags = %08x, ",(unsigned int)head_note_capabilityFlags
);
3662 ptr
+= sprintf(ptr
,"head_note_pendingAcks = %d, ",(unsigned int)head_note_pendingAcks
);
3665 if ( device_overrides
) {
3666 ptr
+= sprintf(ptr
,"device overrides, ");
3668 ptr
+= sprintf(ptr
,"driverDesire = %d, ",(unsigned int)driverDesire
);
3669 ptr
+= sprintf(ptr
,"deviceDesire = %d, ",(unsigned int)deviceDesire
);
3670 ptr
+= sprintf(ptr
,"ourDesiredPowerState = %d, ",(unsigned int)ourDesiredPowerState
);
3671 ptr
+= sprintf(ptr
,"previousRequest = %d }",(unsigned int)previousRequest
);
3673 theOSString
= OSString::withCString(buffer
);
3674 rtn_code
= theOSString
->serialize(s
);
3675 theOSString
->release();
3676 IODelete(buffer
, char, 2000);