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 #define super IORegistryEntry
41 static void ack_timer_expired(thread_call_param_t
);
42 static void settle_timer_expired(thread_call_param_t
);
43 void PMreceiveCmd ( OSObject
*, void *, void *, void *, void * );
44 static void PM_idle_timer_expired(OSObject
*, IOTimerEventSource
*);
45 static void c_PM_Clamp_Timer_Expired (OSObject
* client
,IOTimerEventSource
*);
46 void tellAppWithResponse ( OSObject
* object
, void * context
);
47 void tellClientWithResponse ( OSObject
* object
, void * context
);
48 void tellClient ( OSObject
* object
, void * context
);
49 IOReturn
serializedAllowPowerChange ( OSObject
*, void *, void *, void *, void *);
50 IOReturn
serializedCancelPowerChange ( OSObject
*, void *, void *, void *, void *);
52 extern const IORegistryPlane
* gIOPowerPlane
;
55 // and there's 1000 nanoseconds in a microsecond:
56 #define ns_per_us 1000
59 // The current change note is processed by a state machine.
60 // Inputs are acks from interested parties, ack from the controlling driver,
61 // ack timeouts, settle timeout, and powerStateDidChange from the parent.
62 // These are the states:
65 IOPMour_prechange_03
= 1,
87 enum { // values of outofbandparameter
92 struct context
{ // used for applyToInterested
93 OSArray
* responseFlags
;
96 UInt32 maxTimeRequested
;
100 unsigned long stateNumber
;
101 IOPMPowerFlags stateFlags
;
104 // five minutes in microseconds
105 #define FIVE_MINUTES 5*60*1000000
106 #define k30seconds 30*1000000
109 There are two different kinds of power state changes. One is initiated by a subclassed device object which has either
110 decided to change power state, or its controlling driver has suggested it, or some other driver wants to use the
111 idle device and has asked it to become usable. The second kind of power state change is initiated by the power
112 domain parent. The two are handled slightly differently.
114 There is a queue of so-called change notifications, or change notes for short. Usually the queue is empty, and when
115 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
116 at one time, a queue is implemented. Example: the subclass device decides it's idle and initiates a change to a lower
117 power state. This causes interested parties to be notified, but they don't all acknowledge right away. This causes the
118 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
119 wants to raise power back up again. This change can't be started, however, because the previous one isn't complete yet,
120 so the second one waits in the queue. During this time, the parent decides to lower or raise the power state of the entire
121 power domain and notifies the device, and that notification goes into the queue, too, and can't be actioned until the
124 This is how a power change initiated by the subclass device is handled:
125 First, all interested parties are notified of the change via their powerStateWillChangeTo method. If they all don't
126 acknowledge via return code, then we have to wait. If they do, or when they finally all acknowledge via our
127 acknowledgePowerChange method, then we can continue. We call the controlling driver, instructing it to change to
128 the new state. Then we wait for power to settle. If there is no settling-time, or after it has passed, we notify
129 interested parties again, this time via their powerStateDidChangeTo methods. When they have all acked, we're done.
130 If we lowered power and don't need the power domain to be in its current power state, we suggest to the parent that
131 it lower the power domain state.
133 This is how a change to a lower power domain state initiated by the parent is handled:
134 First, we figure out what power state we will be in when the new domain state is reached. Then all interested parties are
135 notified that we are moving to that new state. When they have acknowledged, we call the controlling driver to assume
136 that state and we wait for power to settle. Then we acknowledge our preparedness to our parent. When all its interested
137 parties have acknowledged, it lowers power and then notifies its interested parties again. When we get this call, we notify
138 our interested parties that the power state has changed, and when they have all acknowledged, we're done.
140 This is how a change to a higher power domain state initiated by the parent is handled:
141 We figure out what power state we will be in when the new domain state is reached. If it is different from our current
142 state we acknowledge the parent. When all the parent's interested parties have acknowledged, it raises power in the
143 domain and waits for power to settle. Then it notifies everyone that the new state has been reached. When we get this call,
144 we call the controlling driver, instructing it to assume the new state, and wait for power to settle. Then we notify our interested
145 parties. When they all acknowledge we are done.
147 In either of the two cases above, it is possible that we will not be changing state even though the domain is. Examples:
148 A change to a lower domain state may not affect us because we are already in a low enough state, and
149 We will not take advantage of a change to a higher domain state, because we have no need of the higher power.
150 In such a case, there is nothing to do but acknowledge the parent. So when the parent calls our powerDomainWillChange
151 method, and we decide that we will not be changing state, we merely acknowledge the parent, via return code, and wait.
152 When the parent subsequently calls powerStateDidChange, we acknowledge again via return code, and the change is complete.
154 Power state changes are processed in a state machine, and since there are four varieties of power state changes, there are
155 four major paths through the state machine:
157 The fourth is nearly trivial. In this path, the parent is changing the domain state, but we are not changing the device state.
158 The change starts when the parent calls powerDomainWillChange. All we do is acknowledge the parent.
159 When the parent calls powerStateDidChange, we acknowledge the parent again, and we're done.
161 The first is fairly simple. It starts when a power domain child calls requestPowerDomainState and we decide to change power states
162 to accomodate the child, or if our power-controlling driver calls changePowerStateTo, or if some other driver which is using our
163 device calls makeUsable, or if a subclassed object calls changePowerStateToPriv. These are all power changes initiated by us, not
164 forced upon us by the parent. We start by notifying interested parties. If they all acknowledge via return code, we can go
165 on to state "our_prechange_1". Otherwise, we start the ack timer and wait for the stragglers to acknowlege by calling
166 acknowledgePowerChange. We move on to state "our_prechange_1" when all the stragglers have acknowledged,
167 or when the ack timer expires on all those which didn't acknowledge. In "our_prechange_1" we call the power-controlling
168 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".
169 Otherwise, we have to wait for it, so we set the ack timer and wait. When it calls acknowledgeSetPowerState, or when the
170 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
171 when changing from our current state to the new state. If not, we go right away to "our_prechange_3". Otherwise, we
172 set the settle timer and wait. When it expires, we move on. In "our_prechange_3" state, we notify all our interested parties
173 via their powerStateDidChange methods that we have finished changing power state. If they all acknowledge via return
174 code, we move on to "our_prechange_4". Otherwise we set the ack timer and wait. When they have all acknowledged, or
175 when the ack timer has expired for those that didn't, we move on to "our_prechange_4", where we remove the used
176 change note from the head of the queue and start the next one if one exists.
178 Parent-initiated changes are more complex in the state machine. First, power going up and power going down are handled
179 differently, so they have different paths throught the state machine. Second, we can acknowledge the parent's notification
180 in two different ways, so each of the parent paths is really two.
182 When the parent calls our powerDomainWillChange method, notifying us that it will lower power in the domain, we decide
183 what state that will put our device in. Then we embark on the state machine path "IOPMparent_down_1"
184 and "IOPMparent_down_2", in which we notify interested parties of the upcoming change, instruct our driver to make
185 the change, check for settle time, and notify interested parties of the completed change. If we get to the end of this path without
186 stalling due to an interested party which didn't acknowledge via return code, due to the controlling driver not able to change
187 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.
188 If we do stall in any of those states, we return IOPMWillAckLater to the parent and enter the parallel path "IOPMparent_down_4"
189 "IOPMparent_down_5", and "IOPMparent_down_3", where we continue with the same processing, except that at the end we
190 acknowledge the parent explicitly via acknowledgePowerChange, and we're done with the change.
191 Then when the parent calls us at powerStateDidChange we acknowledging via return code, because we have already made
192 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.
194 The case of the parent raising power in the domain is handled similarly in that there are parallel paths, one for no-stall
195 that ends in implicit acknowleging the parent, and one that has stalled at least once that ends in explicit acknowledging
196 the parent. This case is different, though in that our device changes state in the second half, after the parent calls
197 powerStateDidChange rather than before, as in the power-lowering case.
199 When the parent calls our powerDomainWillChange method, notifying us that it will raise power in the domain, we acknowledge
200 via return code, because there's really nothing we can do until the power is actually raised in the domain.
201 When the parent calls us at powerStateDidChange, we start by notifying our interested parties. If they all acknowledge via return code,
202 we go on to" IOPMparent_up_1" to instruct the driver to raise its power level. After that, we check for any
203 necessary settling time in "IOPMparent_up_2", and we notify all interested parties that power has changed
204 in "IOPMparent_up_3". If none of these operations stall, we acknowledge the parent via return code, release
205 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",
206 "IOPMparent_up_4", "IOPMparent_up_5", and "IOPMparent_up_6", which ends with
207 our explicit acknowledgement to the parent.
212 const char priv_key
[ ] = "Power Management private data";
213 const char prot_key
[ ] = "Power Management protected data";
216 void IOService::PMinit ( void )
218 if ( ! initialized
) {
220 pm_vars
= new IOPMprot
; // make space for our variables
225 setProperty(prot_key
, (OSObject
*) pm_vars
); // add these to the properties
226 setProperty(priv_key
, (OSObject
*) priv
);
229 pm_vars
->theNumberOfPowerStates
= 0; // then initialize them
230 priv
->we_are_root
= false;
231 pm_vars
->theControllingDriver
= NULL
;
232 priv
->our_lock
= IOLockAlloc();
233 priv
->flags_lock
= IOLockAlloc();
234 priv
->queue_lock
= IOLockAlloc();
235 pm_vars
->childLock
= IOLockAlloc();
236 pm_vars
->parentLock
= IOLockAlloc();
237 priv
->interestedDrivers
= new IOPMinformeeList
;
238 priv
->interestedDrivers
->initialize();
239 priv
->changeList
= new IOPMchangeNoteList
;
240 priv
->changeList
->initialize();
241 pm_vars
->aggressiveness
= 0;
242 for (unsigned int i
= 0; i
<= kMaxType
; i
++) {
243 pm_vars
->current_aggressiveness_values
[i
] = 0;
244 pm_vars
->current_aggressiveness_valid
[i
] = false;
246 pm_vars
->myCurrentState
= 0;
247 priv
->imminentState
= 0;
248 priv
->ourDesiredPowerState
= 0;
249 pm_vars
->parentsCurrentPowerFlags
= 0;
250 pm_vars
->maxCapability
= 0;
251 priv
->driverDesire
= 0;
252 priv
->deviceDesire
= 0;
253 priv
->initial_change
= true;
254 priv
->need_to_become_usable
= false;
255 priv
->previousRequest
= 0;
256 priv
->device_overrides
= false;
257 priv
->machine_state
= IOPMfinished
;
258 pm_vars
->commandQueue
= NULL
;
259 priv
->timerEventSrc
= NULL
;
260 priv
->clampTimerEventSrc
= NULL
;
261 pm_vars
->PMworkloop
= NULL
;
262 priv
->activityLock
= NULL
;
263 pm_vars
->ourName
= getName();
264 pm_vars
->thePlatform
= getPlatform();
265 pm_vars
->parentsKnowState
= false;
266 assert( pm_vars
->thePlatform
!= 0 );
267 priv
->clampOn
= false;
268 pm_vars
->serialNumber
= 0;
269 pm_vars
->responseFlags
= NULL
;
270 pm_vars
->doNotPowerDown
= true;
271 pm_vars
->PMcommandGate
= NULL
;
272 priv
->ackTimer
= thread_call_allocate((thread_call_func_t
)ack_timer_expired
, (thread_call_param_t
)this);
273 priv
->settleTimer
= thread_call_allocate((thread_call_func_t
)settle_timer_expired
, (thread_call_param_t
)this);
279 //*********************************************************************************
282 // Free up the data created in PMinit, if it exists.
283 //*********************************************************************************
284 void IOService::PMfree ( void )
287 if ( priv
->clampTimerEventSrc
!= NULL
) {
288 getPMworkloop()->removeEventSource(priv
->clampTimerEventSrc
);
289 priv
->clampTimerEventSrc
->release();
290 priv
->clampTimerEventSrc
= NULL
;
292 if ( priv
->timerEventSrc
!= NULL
) {
293 pm_vars
->PMworkloop
->removeEventSource(priv
->timerEventSrc
);
294 priv
->timerEventSrc
->release();
295 priv
->timerEventSrc
= NULL
;
297 if ( priv
->settleTimer
) {
298 thread_call_cancel(priv
->settleTimer
);
299 thread_call_free(priv
->settleTimer
);
300 priv
->settleTimer
= NULL
;
302 if ( priv
->ackTimer
) {
303 thread_call_cancel(priv
->ackTimer
);
304 thread_call_free(priv
->ackTimer
);
305 priv
->ackTimer
= NULL
;
307 if ( priv
->our_lock
) {
308 IOLockFree(priv
->our_lock
);
309 priv
->our_lock
= NULL
;
311 if ( priv
->flags_lock
) {
312 IOLockFree(priv
->flags_lock
);
313 priv
->flags_lock
= NULL
;
315 if ( priv
->activityLock
) {
316 IOLockFree(priv
->activityLock
);
317 priv
->activityLock
= NULL
;
319 priv
->interestedDrivers
->release();
320 priv
->changeList
->release();
321 priv
->release(); // remove instance variables
325 if ( pm_vars
->commandQueue
) {
326 pm_vars
->commandQueue
->release();
327 pm_vars
->commandQueue
= NULL
;
329 if ( pm_vars
->PMcommandGate
) {
330 pm_vars
->PMcommandGate
->release();
331 pm_vars
->PMcommandGate
= NULL
;
333 if ( pm_vars
->PMworkloop
) {
334 // The work loop object returned from getPMworkLoop() is
335 // never retained, therefore it should not be released.
336 // pm_vars->PMworkloop->release();
337 pm_vars
->PMworkloop
= NULL
;
339 if ( pm_vars
->responseFlags
) {
340 pm_vars
->responseFlags
->release();
341 pm_vars
->responseFlags
= NULL
;
343 pm_vars
->release(); // remove instance variables
348 //*********************************************************************************
351 // Disconnect the node from its parents and children in the Power Plane.
352 //*********************************************************************************
353 void IOService::PMstop ( void )
357 IOPowerConnection
* connection
;
358 IOService
* theChild
;
359 IOService
* theParent
;
361 removeProperty(prot_key
); // remove the properties
362 removeProperty(priv_key
);
364 iter
= getParentIterator(gIOPowerPlane
); // detach parents
367 while ( (next
= iter
->getNextObject()) ) {
368 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
369 theParent
= (IOService
*)connection
->copyParentEntry(gIOPowerPlane
);
371 theParent
->removePowerChild(connection
);
372 theParent
->release();
378 detachAbove( gIOPowerPlane
); // detach IOConnections
380 pm_vars
->parentsKnowState
= false; // no more power state changes
382 iter
= getChildIterator(gIOPowerPlane
); // detach children
385 while ( (next
= iter
->getNextObject()) ) {
386 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
387 theChild
= ((IOService
*)(connection
->copyChildEntry(gIOPowerPlane
)));
389 connection
->detachFromChild(theChild
,gIOPowerPlane
); // detach nub from child
392 detachFromChild(connection
,gIOPowerPlane
); // detach us from nub
398 // Remove all interested drivers from the list, including the power
399 // controlling driver.
401 // Usually, the controlling driver and the policy-maker functionality
402 // are implemented by the same object, and without the deregistration,
403 // the object will be holding an extra retain on itself, and cannot
406 if ( priv
&& priv
->interestedDrivers
)
408 IOPMinformee
* informee
;
410 while (( informee
= priv
->interestedDrivers
->firstInList() ))
411 deRegisterInterestedDriver( informee
->whatObject
);
416 //*********************************************************************************
419 // A policy-maker calls its nub here when initializing, to be attached into
420 // the power management hierarchy. The default function is to call the
421 // platform expert, which knows how to do it. This method is overridden
422 // by a nub subclass which may either know how to do it, or may need
423 // to take other action.
425 // This may be the only "power management" method used in a nub,
426 // meaning it may not be initialized for power management.
427 //*********************************************************************************
428 void IOService::joinPMtree ( IOService
* driver
)
430 IOPlatformExpert
* thePlatform
;
432 thePlatform
= getPlatform();
433 assert(thePlatform
!= 0 );
434 thePlatform
->PMRegisterDevice(this,driver
);
438 //*********************************************************************************
441 // Power Managment is informing us that we are the root power domain.
442 // The only difference between us and any other power domain is that
443 // we have no parent and therefore never call it.
444 //*********************************************************************************
445 IOReturn
IOService::youAreRoot ( void )
447 priv
-> we_are_root
= true;
448 pm_vars
->parentsKnowState
= true;
449 attachToParent( getRegistryRoot(),gIOPowerPlane
);
455 //*********************************************************************************
458 // Power Management is informing us who our parent is.
459 // If we have a controlling driver, find out, given our newly-informed
460 // power domain state, what state it would be in, and then tell it
461 // to assume that state.
462 //*********************************************************************************
463 IOReturn
IOService::setPowerParent ( IOPowerConnection
* theParent
, bool stateKnown
, IOPMPowerFlags currentState
)
467 IOPowerConnection
* connection
;
468 unsigned long tempDesire
;
470 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogSetParent
,stateKnown
,currentState
);
472 IOLockLock(pm_vars
->parentLock
);
474 if ( stateKnown
&& ((pm_vars
->PMworkloop
== NULL
) || (pm_vars
->PMcommandGate
== NULL
)) ) {
475 getPMworkloop(); // we have a path to the root
476 if ( pm_vars
->PMworkloop
!= NULL
) { // find out the workloop
477 if ( pm_vars
->PMcommandGate
== NULL
) { // and make our command gate
478 pm_vars
->PMcommandGate
= IOCommandGate::commandGate((OSObject
*)this);
479 if ( pm_vars
->PMcommandGate
!= NULL
) {
480 pm_vars
->PMworkloop
->addEventSource(pm_vars
->PMcommandGate
);
486 IOLockUnlock(pm_vars
->parentLock
);
488 theParent
->setParentCurrentPowerFlags(currentState
); // set our connection data
489 theParent
->setParentKnowsState(stateKnown
);
491 pm_vars
->parentsKnowState
= true; // combine parent knowledge
492 pm_vars
->parentsCurrentPowerFlags
= 0;
494 iter
= getParentIterator(gIOPowerPlane
);
497 while ( (next
= iter
->getNextObject()) ) {
498 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
499 pm_vars
->parentsKnowState
&= connection
->parentKnowsState();
500 pm_vars
->parentsCurrentPowerFlags
|= connection
->parentCurrentPowerFlags();
506 if ( (pm_vars
->theControllingDriver
!= NULL
) &&
507 (pm_vars
->parentsKnowState
) ) {
508 pm_vars
->maxCapability
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(pm_vars
->parentsCurrentPowerFlags
);
509 tempDesire
= priv
->deviceDesire
; // initially change into the state we are already in
510 priv
->deviceDesire
= pm_vars
->theControllingDriver
->initialPowerStateForDomainState(pm_vars
->parentsCurrentPowerFlags
);
511 computeDesiredState();
512 priv
->previousRequest
= 0xffffffff;
514 priv
->deviceDesire
= tempDesire
; // put this back like before
521 //*********************************************************************************
524 // Power Management is informing us who our children are.
525 //*********************************************************************************
526 IOReturn
IOService::addPowerChild ( IOService
* theChild
)
528 IOPowerConnection
* connection
;
531 if ( ! initialized
) {
532 return IOPMNotYetInitialized
; // we're not a power-managed IOService
535 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAddChild
,0,0);
537 connection
= new IOPowerConnection
; // make a nub
540 connection
->start(this);
541 connection
->setAwaitingAck(false);
543 attachToChild( connection
,gIOPowerPlane
); // connect it up
544 connection
->attachToChild( theChild
,gIOPowerPlane
);
545 connection
->release();
547 if ( (pm_vars
->theControllingDriver
== NULL
) || // tell it the current state of the power domain
548 ! (inPlane(gIOPowerPlane
)) ||
549 ! (pm_vars
->parentsKnowState
) ) {
550 theChild
->setPowerParent(connection
,false,0);
551 if ( inPlane(gIOPowerPlane
) ) {
552 for (i
= 0; i
<= kMaxType
; i
++) {
553 if ( pm_vars
->current_aggressiveness_valid
[i
] ) {
554 theChild
->setAggressiveness (i
, pm_vars
->current_aggressiveness_values
[i
]);
560 theChild
->setPowerParent(connection
,true,pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].outputPowerCharacter
);
561 for (i
= 0; i
<= kMaxType
; i
++) {
562 if ( pm_vars
->current_aggressiveness_valid
[i
] ) {
563 theChild
->setAggressiveness (i
, pm_vars
->current_aggressiveness_values
[i
]);
566 add_child_to_active_change(connection
); // catch it up if change is in progress
573 //*********************************************************************************
576 //*********************************************************************************
577 IOReturn
IOService::removePowerChild ( IOPowerConnection
* theNub
)
579 IORegistryEntry
* theChild
;
581 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRemoveChild
,0,0);
585 theChild
= theNub
->copyChildEntry(gIOPowerPlane
); // detach nub from child
587 theNub
->detachFromChild(theChild
, gIOPowerPlane
);
590 detachFromChild(theNub
,gIOPowerPlane
); // detach from the nub
592 if ( theNub
->getAwaitingAck() ) { // are we awaiting an ack from this child?
593 theNub
->setAwaitingAck(false); // yes, pretend we got one
594 if ( acquire_lock() ) {
595 if (priv
->head_note_pendingAcks
!= 0 ) {
596 priv
->head_note_pendingAcks
-= 1; // that's one fewer ack to worry about
597 if ( priv
->head_note_pendingAcks
== 0 ) { // is that the last?
598 stop_ack_timer(); // yes, stop the timer
599 IOUnlock(priv
->our_lock
);
600 all_acked(); // and now we can continue our power change
603 IOUnlock(priv
->our_lock
);
607 IOUnlock(priv
->our_lock
);
614 if ( (pm_vars
->theControllingDriver
== NULL
) || // if not fully initialized
615 ! (inPlane(gIOPowerPlane
)) ||
616 ! (pm_vars
->parentsKnowState
) ) {
617 return IOPMNoErr
; // we can do no more
620 computeDesiredState(); // this may be different now
621 changeState(); // change state if we can now tolerate lower power
627 //*********************************************************************************
628 // registerPowerDriver
630 // A driver has called us volunteering to control power to our device.
631 // If the power state array it provides is richer than the one we already
632 // know about (supplied by an earlier volunteer), then accept the offer.
633 // Notify all interested parties of our power state, which we now know.
634 //*********************************************************************************
636 IOReturn
IOService::registerPowerDriver ( IOService
* controllingDriver
, IOPMPowerState
* powerStates
, unsigned long numberOfStates
)
639 unsigned long tempDesire
;
641 if ( (numberOfStates
> pm_vars
->theNumberOfPowerStates
) && (numberOfStates
> 1) ) {
642 if ( priv
->changeList
->currentChange() == -1 ) {
643 if ( controllingDriver
!= NULL
) {
644 if ( numberOfStates
<= IOPMMaxPowerStates
) {
645 switch ( powerStates
[0].version
) {
647 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriver
,
648 (unsigned long)numberOfStates
, (unsigned long)powerStates
[0].version
);
649 for ( i
= 0; i
< numberOfStates
; i
++ ) {
650 pm_vars
->thePowerStates
[i
] = powerStates
[i
];
654 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriver
,
655 (unsigned long) numberOfStates
,(unsigned long) powerStates
[0].version
);
656 for ( i
= 0; i
< numberOfStates
; i
++ ) {
657 pm_vars
->thePowerStates
[i
].version
= powerStates
[i
].version
;
658 pm_vars
->thePowerStates
[i
].capabilityFlags
= powerStates
[i
].capabilityFlags
;
659 pm_vars
->thePowerStates
[i
].outputPowerCharacter
= powerStates
[i
].outputPowerCharacter
;
660 pm_vars
->thePowerStates
[i
].inputPowerRequirement
= powerStates
[i
].inputPowerRequirement
;
661 pm_vars
->thePowerStates
[i
].staticPower
= powerStates
[i
].staticPower
;
662 pm_vars
->thePowerStates
[i
].unbudgetedPower
= powerStates
[i
].unbudgetedPower
;
663 pm_vars
->thePowerStates
[i
].powerToAttain
= powerStates
[i
].powerToAttain
;
664 pm_vars
->thePowerStates
[i
].timeToAttain
= powerStates
[i
].timeToAttain
;
665 pm_vars
->thePowerStates
[i
].settleUpTime
= powerStates
[i
].settleUpTime
;
666 pm_vars
->thePowerStates
[i
].timeToLower
= powerStates
[i
].timeToLower
;
667 pm_vars
->thePowerStates
[i
].settleDownTime
= powerStates
[i
].settleDownTime
;
668 pm_vars
->thePowerStates
[i
].powerDomainBudget
= powerStates
[i
].powerDomainBudget
;
672 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr1
,
673 (unsigned long)powerStates
[0].version
,0);
677 pm_vars
->myCharacterFlags
= 0; // make a mask of all the character bits we know about
678 for ( i
= 0; i
< numberOfStates
; i
++ ) {
679 pm_vars
->myCharacterFlags
|= pm_vars
->thePowerStates
[i
].outputPowerCharacter
;
682 pm_vars
->theNumberOfPowerStates
= numberOfStates
;
683 pm_vars
->theControllingDriver
= controllingDriver
;
684 if ( priv
->interestedDrivers
->findItem(controllingDriver
) == NULL
) { // register it as interested
685 registerInterestedDriver (controllingDriver
); // unless already done
687 if ( priv
->need_to_become_usable
) {
688 priv
->need_to_become_usable
= false;
689 priv
->deviceDesire
= pm_vars
->theNumberOfPowerStates
- 1;
692 if ( inPlane(gIOPowerPlane
) &&
693 (pm_vars
->parentsKnowState
) ) {
694 pm_vars
->maxCapability
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(pm_vars
->parentsCurrentPowerFlags
);
695 tempDesire
= priv
->deviceDesire
; // initially change into the state we are already in
696 priv
->deviceDesire
= pm_vars
->theControllingDriver
->initialPowerStateForDomainState(pm_vars
->parentsCurrentPowerFlags
);
697 computeDesiredState();
699 priv
->deviceDesire
= tempDesire
; // put this back like before
703 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr2
,(unsigned long)numberOfStates
,0);
707 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr4
,0,0);
712 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr5
,(unsigned long)numberOfStates
,0);
717 //*********************************************************************************
718 // registerInterestedDriver
720 // Add the caller to our list of interested drivers and return our current
721 // power state. If we don't have a power-controlling driver yet, we will
722 // call this interested driver again later when we do get a driver and find
723 // out what the current power state of the device is.
724 //*********************************************************************************
726 IOPMPowerFlags
IOService::registerInterestedDriver ( IOService
* theDriver
)
728 IOPMinformee
* newInformee
;
729 IOPMPowerFlags futureCapability
;
731 if (theDriver
== NULL
) {
735 newInformee
= new IOPMinformee
; // make new driver node
736 newInformee
->initialize(theDriver
);
737 priv
->interestedDrivers
->addToList(newInformee
); // add it to list of drivers
739 if ( (pm_vars
->theControllingDriver
== NULL
) ||
740 ! (inPlane(gIOPowerPlane
)) ||
741 ! (pm_vars
->parentsKnowState
) ) {
742 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInterestedDriver
,IOPMNotPowerManaged
,0);
743 return IOPMNotPowerManaged
; // can't tell it a state yet
746 switch (priv
->machine_state
) { // can we notify new driver of a change in progress?
747 case IOPMour_prechange_1
:
748 case IOPMour_prechange_4
:
749 case IOPMparent_down_4
:
750 case IOPMparent_down_6
:
751 case IOPMparent_up_0
:
752 case IOPMparent_up_6
:
753 futureCapability
= priv
->head_note_capabilityFlags
; // yes, remember what we tell it
754 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInterestedDriver
,(unsigned long)futureCapability
,1);
755 add_driver_to_active_change(newInformee
); // notify it
756 return futureCapability
; // and return the same thing
759 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInterestedDriver
,
760 (unsigned long) pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
,2);
761 return pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
; // no, return current capability
765 //*********************************************************************************
766 // deRegisterInterestedDriver
768 //*********************************************************************************
769 IOReturn
IOService::deRegisterInterestedDriver ( IOService
* theDriver
)
771 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRemoveDriver
,0,0);
773 priv
->interestedDrivers
->removeFromList(theDriver
); // remove the departing driver
779 //*********************************************************************************
780 // acknowledgePowerChange
782 // After we notified one of the interested drivers or a power-domain child
783 // of an impending change in power, it has called to say it is now
784 // prepared for the change. If this object is the last to
785 // acknowledge this change, we take whatever action we have been waiting
787 // That may include acknowledging to our parent. In this case, we do it
788 // last of all to insure that this doesn't cause the parent to call us some-
789 // where else and alter data we are relying on here (like the very existance
790 // of a "current change note".)
791 //*********************************************************************************
793 IOReturn
IOService::acknowledgePowerChange ( IOService
* whichObject
)
795 IOPMinformee
* ackingObject
;
796 unsigned long childPower
= kIOPMUnknown
;
797 IOService
* theChild
;
799 ackingObject
= priv
->interestedDrivers
->findItem(whichObject
); // one of our interested drivers?
800 if ( ackingObject
== NULL
) {
801 if ( ! isChild(whichObject
,gIOPowerPlane
) ) {
802 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr1
,0,0);
803 kprintf("errant driver: %s\n",whichObject
->getName());
804 return IOPMNoErr
; // no, just return
807 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChildAcknowledge
,priv
->head_note_pendingAcks
,0);
811 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogDriverAcknowledge
,priv
->head_note_pendingAcks
,0);
814 if (! acquire_lock() ) {
818 if (priv
->head_note_pendingAcks
!= 0 ) { // yes, make sure we're expecting acks
819 if ( ackingObject
!= NULL
) { // it's an interested driver
820 if ( ackingObject
->timer
!= 0 ) { // make sure we're expecting this ack
821 ackingObject
->timer
= 0; // mark it acked
822 priv
->head_note_pendingAcks
-= 1; // that's one fewer to worry about
823 if ( priv
->head_note_pendingAcks
== 0 ) { // is that the last?
824 stop_ack_timer(); // yes, stop the timer
825 IOUnlock(priv
->our_lock
);
826 all_acked(); // and now we can continue
831 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr2
,0,0); // this driver has already acked
832 kprintf("errant driver: %s\n",whichObject
->getName());
835 else { // it's a child
836 if ( ((IOPowerConnection
*)whichObject
)->getAwaitingAck() ) { // make sure we're expecting this ack
837 priv
->head_note_pendingAcks
-= 1; // that's one fewer to worry about
838 ((IOPowerConnection
*)whichObject
)->setAwaitingAck(false);
839 theChild
= (IOService
*)whichObject
->copyChildEntry(gIOPowerPlane
);
841 childPower
= theChild
->currentPowerConsumption();
844 if ( childPower
== kIOPMUnknown
) {
845 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
= kIOPMUnknown
;
848 if ( pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
!= kIOPMUnknown
) {
849 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
+= childPower
;
852 if ( priv
->head_note_pendingAcks
== 0 ) { // is that the last?
853 stop_ack_timer(); // yes, stop the timer
854 IOUnlock(priv
->our_lock
);
855 all_acked(); // and now we can continue
862 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr3
,0,0); // not expecting anybody to ack
863 kprintf("errant driver: %s\n",whichObject
->getName());
865 IOUnlock(priv
->our_lock
);
869 //*********************************************************************************
870 // acknowledgeSetPowerState
872 // After we instructed our controlling driver to change power states,
873 // it has called to say it has finished doing so.
874 // We continue to process the power state change.
875 //*********************************************************************************
877 IOReturn
IOService::acknowledgeSetPowerState ( void )
879 if (! acquire_lock() ) {
882 if ( priv
->driver_timer
== -1 ) {
883 priv
->driver_timer
= 0; // driver is acking instead of using return code
886 if ( priv
->driver_timer
> 0 ) { // are we expecting this?
887 stop_ack_timer(); // yes, stop the timer
888 priv
->driver_timer
= 0;
889 IOUnlock(priv
->our_lock
);
890 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogDriverAcknowledgeSet
,0,0);
895 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr4
,0,0); // no
898 IOUnlock(priv
->our_lock
);
903 //*********************************************************************************
906 // Either the controlling driver has called acknowledgeSetPowerState
907 // or the acknowledgement timer has expired while waiting for that.
908 // We carry on processing the current change note.
909 //*********************************************************************************
911 void IOService::driver_acked ( void )
913 switch (priv
->machine_state
) {
914 case IOPMour_prechange_2
:
917 case IOPMparent_down_5
:
920 case IOPMparent_up_4
:
927 //*********************************************************************************
928 // powerDomainWillChangeTo
930 // Called by the power-hierarchy parent notifying of a new power state
931 // in the power domain.
932 // We enqueue a parent power-change to our queue of power changes.
933 // This may or may not cause us to change power, depending on what
934 // kind of change is occuring in the domain.
935 //*********************************************************************************
937 IOReturn
IOService::powerDomainWillChangeTo ( IOPMPowerFlags newPowerStateFlags
, IOPowerConnection
* whichParent
)
941 IOPowerConnection
* connection
;
942 unsigned long newStateNumber
;
943 IOPMPowerFlags combinedPowerFlags
;
945 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogWillChange
,(unsigned long)newPowerStateFlags
,0);
947 if ( ! inPlane(gIOPowerPlane
) ) {
948 return IOPMAckImplied
; // somebody goofed
951 IOLockLock(pm_vars
->parentLock
);
953 if ( (pm_vars
->PMworkloop
== NULL
) || (pm_vars
->PMcommandGate
== NULL
) ) {
954 getPMworkloop(); // we have a path to the root,
955 if ( pm_vars
->PMworkloop
!= NULL
) { // so find out the workloop
956 if ( pm_vars
->PMcommandGate
== NULL
) { // and make our command gate
957 pm_vars
->PMcommandGate
= IOCommandGate::commandGate((OSObject
*)this);
958 if ( pm_vars
->PMcommandGate
!= NULL
) {
959 pm_vars
->PMworkloop
->addEventSource(pm_vars
->PMcommandGate
);
965 IOLockUnlock(pm_vars
->parentLock
);
967 combinedPowerFlags
= 0; // combine parents' power states
969 iter
= getParentIterator(gIOPowerPlane
);
972 while ( (next
= iter
->getNextObject()) ) {
973 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
974 if ( connection
== whichParent
){
975 combinedPowerFlags
|= newPowerStateFlags
;
978 combinedPowerFlags
|= connection
->parentCurrentPowerFlags();
985 if ( pm_vars
->theControllingDriver
== NULL
) { // we can't take any more action
986 return IOPMAckImplied
;
988 newStateNumber
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(combinedPowerFlags
);
989 return enqueuePowerChange(IOPMParentInitiated
| IOPMDomainWillChange
,
990 newStateNumber
,combinedPowerFlags
,whichParent
,newPowerStateFlags
); //make the change
994 //*********************************************************************************
995 // powerDomainDidChangeTo
997 // Called by the power-hierarchy parent after the power state of the power domain
998 // has settled at a new level.
999 // We enqueue a parent power-change to our queue of power changes.
1000 // This may or may not cause us to change power, depending on what
1001 // kind of change is occuring in the domain.
1002 //*********************************************************************************
1004 IOReturn
IOService::powerDomainDidChangeTo ( IOPMPowerFlags newPowerStateFlags
, IOPowerConnection
* whichParent
)
1006 unsigned long newStateNumber
;
1008 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogDidChange
,newPowerStateFlags
,0);
1010 setParentInfo(newPowerStateFlags
,whichParent
);
1012 if ( pm_vars
->theControllingDriver
== NULL
) {
1013 return IOPMAckImplied
;
1016 newStateNumber
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(pm_vars
->parentsCurrentPowerFlags
);
1017 return enqueuePowerChange(IOPMParentInitiated
| IOPMDomainDidChange
,
1018 newStateNumber
,pm_vars
->parentsCurrentPowerFlags
,whichParent
,0); // tell interested parties about it
1022 //*********************************************************************************
1025 // Set our connection data for one specific parent, and then combine all the parent
1027 //*********************************************************************************
1029 void IOService::setParentInfo ( IOPMPowerFlags newPowerStateFlags
, IOPowerConnection
* whichParent
)
1033 IOPowerConnection
* connection
;
1035 whichParent
->setParentCurrentPowerFlags(newPowerStateFlags
); // set our connection data
1036 whichParent
->setParentKnowsState(true);
1038 IOLockLock(pm_vars
->parentLock
);
1040 pm_vars
->parentsCurrentPowerFlags
= 0; // recompute our parent info
1041 pm_vars
->parentsKnowState
= true;
1043 iter
= getParentIterator(gIOPowerPlane
);
1046 while ( (next
= iter
->getNextObject()) ) {
1047 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1048 pm_vars
->parentsKnowState
&= connection
->parentKnowsState();
1049 pm_vars
->parentsCurrentPowerFlags
|= connection
->parentCurrentPowerFlags();
1054 IOLockUnlock(pm_vars
->parentLock
);
1058 //*********************************************************************************
1059 // requestPowerDomainState
1061 // The kIOPMPreventIdleSleep and/or kIOPMPreventIdleSleep bits may be be set in the parameter.
1062 // It is not considered part of the state specification.
1063 //*********************************************************************************
1064 IOReturn
IOService::requestPowerDomainState ( IOPMPowerFlags desiredState
, IOPowerConnection
* whichChild
, unsigned long specification
)
1067 unsigned long computedState
;
1068 unsigned long theDesiredState
= desiredState
& ~(kIOPMPreventIdleSleep
| kIOPMPreventSystemSleep
);
1071 IOPowerConnection
* connection
;
1073 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRequestDomain
,
1074 (unsigned long)desiredState
,(unsigned long)specification
);
1076 if ( pm_vars
->theControllingDriver
== NULL
) {
1077 return IOPMNotYetInitialized
;
1080 switch (specification
) {
1081 case IOPMLowestState
:
1083 while ( i
< pm_vars
->theNumberOfPowerStates
) {
1084 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& theDesiredState
) == (theDesiredState
& pm_vars
->myCharacterFlags
) ) {
1089 if ( i
>= pm_vars
->theNumberOfPowerStates
) {
1090 return IOPMNoSuchState
;
1094 case IOPMNextLowerState
:
1095 i
= pm_vars
->myCurrentState
- 1;
1097 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& theDesiredState
) == (theDesiredState
& pm_vars
->myCharacterFlags
) ) {
1103 return IOPMNoSuchState
;
1107 case IOPMHighestState
:
1108 i
= pm_vars
->theNumberOfPowerStates
;
1111 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& theDesiredState
) == (theDesiredState
& pm_vars
->myCharacterFlags
) ) {
1116 return IOPMNoSuchState
;
1120 case IOPMNextHigherState
:
1121 i
= pm_vars
->myCurrentState
+ 1;
1122 while ( i
< pm_vars
->theNumberOfPowerStates
) {
1123 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& theDesiredState
) == (theDesiredState
& pm_vars
->myCharacterFlags
) ) {
1128 if ( i
== pm_vars
->theNumberOfPowerStates
) {
1129 return IOPMNoSuchState
;
1134 return IOPMBadSpecification
;
1139 IOLockLock(pm_vars
->childLock
);
1141 // A child's desires has changed. We need to rebuild the child-clamp bits in our
1142 // power state array. Start by clearing the bits in each power state.
1144 for ( i
= 0; i
< pm_vars
->theNumberOfPowerStates
; i
++ ) {
1145 pm_vars
->thePowerStates
[i
].capabilityFlags
&= ~(kIOPMChildClamp
| kIOPMChildClamp2
);
1148 // Now loop through the children. When we encounter the calling child, save
1149 // the computed state as this child's desire. And while we're at it, set the ChildClamp bits
1150 // in any of our states that some child has requested with clamp on.
1152 iter
= getChildIterator(gIOPowerPlane
);
1155 while ( (next
= iter
->getNextObject()) ) {
1156 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1157 if ( connection
== whichChild
) {
1158 connection
->setDesiredDomainState(computedState
);
1159 connection
->setPreventIdleSleepFlag(desiredState
& kIOPMPreventIdleSleep
);
1160 connection
->setPreventSystemSleepFlag(desiredState
& kIOPMPreventSystemSleep
);
1161 connection
->setChildHasRequestedPower();
1163 if ( connection
->getPreventIdleSleepFlag() ) {
1164 pm_vars
->thePowerStates
[connection
->getDesiredDomainState()].capabilityFlags
|= kIOPMChildClamp
;
1166 if ( connection
->getPreventSystemSleepFlag() ) {
1167 pm_vars
->thePowerStates
[connection
->getDesiredDomainState()].capabilityFlags
|= kIOPMChildClamp2
;
1174 IOLockUnlock(pm_vars
->childLock
);
1176 computeDesiredState(); // this may be different now
1178 if ( inPlane(gIOPowerPlane
) &&
1179 (pm_vars
->parentsKnowState
) ) {
1180 changeState(); // change state if all children can now tolerate lower power
1183 if ( priv
->clampOn
) { // are we clamped on, waiting for this child?
1184 priv
->clampOn
= false; // yes, remove the clamp
1185 changePowerStateToPriv(0);
1192 //*********************************************************************************
1193 // temporaryPowerClampOn
1195 // A power domain wants to clamp its power on till it has children which
1196 // will thendetermine the power domain state.
1198 // We enter the highest state until addPowerChild is called.
1199 //*********************************************************************************
1201 IOReturn
IOService::temporaryPowerClampOn ( void )
1203 priv
->clampOn
= true;
1209 //*********************************************************************************
1212 // Some client of our device is asking that we become usable. Although
1213 // this has not come from a subclassed device object, treat it exactly
1214 // as if it had. In this way, subsequent requests for lower power from
1215 // a subclassed device object will pre-empt this request.
1217 // We treat this as a subclass object request to switch to the
1218 // highest power state.
1219 //*********************************************************************************
1221 IOReturn
IOService::makeUsable ( void )
1223 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogMakeUsable
,0,0);
1225 if ( pm_vars
->theControllingDriver
== NULL
) {
1226 priv
->need_to_become_usable
= true;
1229 priv
->deviceDesire
= pm_vars
->theNumberOfPowerStates
- 1;
1230 computeDesiredState();
1231 if ( inPlane(gIOPowerPlane
) && (pm_vars
->parentsKnowState
) ) {
1232 return changeState();
1238 //*********************************************************************************
1239 // currentCapability
1241 //*********************************************************************************
1243 IOPMPowerFlags
IOService::currentCapability ( void )
1245 if ( pm_vars
->theControllingDriver
== NULL
) {
1249 return pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
;
1254 //*********************************************************************************
1255 // changePowerStateTo
1257 // For some reason, our power-controlling driver has decided it needs to change
1258 // power state. We enqueue the power change so that appropriate parties
1259 // will be notified, and then we will instruct the driver to make the change.
1260 //*********************************************************************************
1262 IOReturn
IOService::changePowerStateTo ( unsigned long ordinal
)
1264 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeStateTo
,ordinal
,0);
1266 if ( ordinal
>= pm_vars
->theNumberOfPowerStates
) {
1267 return IOPMParameterError
;
1269 priv
->driverDesire
= ordinal
;
1270 computeDesiredState();
1271 if ( inPlane(gIOPowerPlane
) && (pm_vars
->parentsKnowState
) ) {
1272 return changeState();
1278 //*********************************************************************************
1279 // changePowerStateToPriv
1281 // For some reason, a subclassed device object has decided it needs to change
1282 // power state. We enqueue the power change so that appropriate parties
1283 // will be notified, and then we will instruct the driver to make the change.
1284 //*********************************************************************************
1286 IOReturn
IOService::changePowerStateToPriv ( unsigned long ordinal
)
1288 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeStateToPriv
,ordinal
,0);
1290 if ( pm_vars
->theControllingDriver
== NULL
) {
1291 return IOPMNotYetInitialized
;
1293 if ( ordinal
>= pm_vars
->theNumberOfPowerStates
) {
1294 return IOPMParameterError
;
1296 priv
->deviceDesire
= ordinal
;
1297 computeDesiredState();
1298 if ( inPlane(gIOPowerPlane
) && (pm_vars
->parentsKnowState
) ) {
1299 return changeState();
1306 //*********************************************************************************
1307 // computeDesiredState
1309 //*********************************************************************************
1311 void IOService::computeDesiredState ( void )
1315 IOPowerConnection
* connection
;
1316 unsigned long newDesiredState
= 0;
1318 // Compute the maximum of our children's desires, our controlling driver's desire, and the subclass device's desire.
1320 if ( ! priv
->device_overrides
) {
1321 iter
= getChildIterator(gIOPowerPlane
);
1324 while ( (next
= iter
->getNextObject()) ) {
1325 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1326 if ( connection
->getDesiredDomainState() > newDesiredState
) {
1327 newDesiredState
= connection
->getDesiredDomainState();
1334 if ( priv
->driverDesire
> newDesiredState
) {
1335 newDesiredState
= priv
->driverDesire
;
1339 if ( priv
->deviceDesire
> newDesiredState
) {
1340 newDesiredState
= priv
->deviceDesire
;
1343 priv
->ourDesiredPowerState
= newDesiredState
;
1347 //*********************************************************************************
1350 // A subclass object, our controlling driver, or a power domain child
1351 // has asked for a different power state. Here we compute what new
1352 // state we should enter and enqueue the change (or start it).
1353 //*********************************************************************************
1355 IOReturn
IOService::changeState ( void )
1357 if ( (pm_vars
->theControllingDriver
== NULL
) || // if not fully initialized
1358 ! (inPlane(gIOPowerPlane
)) ||
1359 ! (pm_vars
->parentsKnowState
) ) {
1360 return IOPMNoErr
; // we can do no more
1363 return enqueuePowerChange(IOPMWeInitiated
,priv
->ourDesiredPowerState
,0,0,0);
1367 //*********************************************************************************
1368 // currentPowerConsumption
1370 //*********************************************************************************
1372 unsigned long IOService::currentPowerConsumption ( void )
1374 if ( pm_vars
->theControllingDriver
== NULL
) {
1375 return kIOPMUnknown
;
1377 if ( pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
& kIOPMStaticPowerValid
) {
1378 return pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].staticPower
;
1380 return kIOPMUnknown
;
1383 //*********************************************************************************
1386 // The activity tickle with parameter kIOPMSubclassPolicyis not handled
1387 // here and should have been intercepted by the subclass.
1388 // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
1389 // flag to be set, and the device state checked. If the device has been
1390 // powered down, it is powered up again.
1391 //*********************************************************************************
1393 bool IOService::activityTickle ( unsigned long type
, unsigned long stateNumber
=0 )
1395 AbsoluteTime uptime
;
1397 if ( type
== kIOPMSuperclassPolicy1
) {
1398 if ( (priv
->activityLock
== NULL
) ||
1399 (pm_vars
->theControllingDriver
== NULL
) ||
1400 (pm_vars
->commandQueue
== NULL
) ) {
1403 IOTakeLock(priv
->activityLock
);
1404 priv
->device_active
= true;
1406 clock_get_uptime(&uptime
);
1407 priv
->device_active_timestamp
= uptime
;
1409 if ( pm_vars
->myCurrentState
>= stateNumber
) {
1410 IOUnlock(priv
->activityLock
);
1413 IOUnlock(priv
->activityLock
); // send a message on the command queue
1414 pm_vars
->commandQueue
->enqueueCommand(true, (void *)kIOPMUnidleDevice
, (void *)stateNumber
);
1420 //*********************************************************************************
1423 // A child is calling to get a pointer to the Power Management workloop.
1424 // We got it or get it from one of our parents.
1425 //*********************************************************************************
1427 IOWorkLoop
* IOService::getPMworkloop ( void )
1432 if ( ! inPlane(gIOPowerPlane
) ) {
1435 if ( pm_vars
->PMworkloop
== NULL
) { // we have no workloop yet
1436 nub
= (IOService
*)copyParentEntry(gIOPowerPlane
);
1438 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
1440 if ( parent
) { // ask one of our parents for the workloop
1441 pm_vars
->PMworkloop
= parent
->getPMworkloop();
1446 return pm_vars
->PMworkloop
;
1450 //*********************************************************************************
1451 // setIdleTimerPeriod
1453 // A subclass policy-maker is going to use our standard idleness
1454 // detection service. Make a command queue and an idle timer and
1455 // connect them to the power management workloop. Finally,
1457 //*********************************************************************************
1459 IOReturn
IOService::setIdleTimerPeriod ( unsigned long period
)
1461 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMsetIdleTimerPeriod
,period
, 0);
1463 priv
->idle_timer_period
= period
;
1466 if ( getPMworkloop() == NULL
) {
1467 return kIOReturnError
;
1470 if (pm_vars
->commandQueue
== NULL
) { // make the command queue
1471 pm_vars
->commandQueue
= IOCommandQueue::commandQueue(this, PMreceiveCmd
);
1472 if (! pm_vars
->commandQueue
||
1473 ( pm_vars
->PMworkloop
->addEventSource( pm_vars
->commandQueue
) != kIOReturnSuccess
) ) {
1474 return kIOReturnError
;
1477 // make the timer event
1478 if ( priv
->timerEventSrc
== NULL
) {
1479 priv
->timerEventSrc
= IOTimerEventSource::timerEventSource(this,
1480 PM_idle_timer_expired
);
1481 if ( ! priv
->timerEventSrc
||
1482 ( pm_vars
->PMworkloop
->addEventSource( priv
->timerEventSrc
) != kIOReturnSuccess
) ) {
1483 return kIOReturnError
;
1487 if ( priv
->activityLock
== NULL
) {
1488 priv
->activityLock
= IOLockAlloc();
1491 start_PM_idle_timer();
1497 //*********************************************************************************
1498 // start_PM_idle_timer
1500 // The parameter is a pointer to us. Use it to call our timeout method.
1501 //*********************************************************************************
1502 void IOService::start_PM_idle_timer ( void )
1504 AbsoluteTime uptime
;
1510 IOLockLock(priv
->activityLock
);
1512 clock_get_uptime(&uptime
);
1514 /* Calculate time difference using funky macro from clock.h.
1517 SUB_ABSOLUTETIME(&delta
, &(priv
->device_active_timestamp
));
1519 /* Figure it in seconds.
1521 absolutetime_to_nanoseconds(delta
, &delta_ns
);
1522 delta_secs
= delta_ns
/ NSEC_PER_SEC
;
1524 /* Be paranoid about delta somehow exceeding timer period.
1526 if (delta_secs
< priv
->idle_timer_period
) {
1527 delay_secs
= priv
->idle_timer_period
- delta_secs
;
1529 delay_secs
= priv
->idle_timer_period
;
1532 priv
->timerEventSrc
->setTimeout(delay_secs
, NSEC_PER_SEC
);
1534 IOLockUnlock(priv
->activityLock
);
1539 //*********************************************************************************
1540 // PM_idle_timer_expired
1542 // The parameter is a pointer to us. Use it to call our timeout method.
1543 //*********************************************************************************
1545 void PM_idle_timer_expired(OSObject
* ourSelves
, IOTimerEventSource
*)
1547 ((IOService
*)ourSelves
)->PM_idle_timer_expiration();
1551 //*********************************************************************************
1552 // PM_idle_timer_expiration
1554 // The idle timer has expired. If there has been activity since the last
1555 // expiration, just restart the timer and return. If there has not been
1556 // activity, switch to the next lower power state and restart the timer.
1557 //*********************************************************************************
1559 void IOService::PM_idle_timer_expiration ( void )
1561 if ( ! initialized
) {
1562 return; // we're unloading
1565 if ( priv
->idle_timer_period
> 0 ) {
1566 IOTakeLock(priv
->activityLock
);
1567 if ( priv
->device_active
) {
1568 priv
->device_active
= false;
1569 IOUnlock(priv
->activityLock
);
1570 start_PM_idle_timer();
1573 if ( pm_vars
->myCurrentState
> 0 ) {
1574 IOUnlock(priv
->activityLock
);
1575 changePowerStateToPriv(pm_vars
->myCurrentState
- 1);
1576 start_PM_idle_timer();
1579 IOUnlock(priv
->activityLock
);
1580 start_PM_idle_timer();
1586 // **********************************************************************************
1591 // **********************************************************************************
1592 void PMreceiveCmd ( OSObject
* theDriver
, void * command
, void * param1
, void * param2
, void *param3
)
1594 ((IOService
*)theDriver
)->command_received(command
,param1
,param2
,param3
);
1598 // **********************************************************************************
1601 // We have received a command from ourselves on the command queue.
1602 // This is to prevent races with timer-expiration code.
1603 // **********************************************************************************
1604 void IOService::command_received ( void * command
, void *stateNumber
, void * , void *)
1606 if ( ! initialized
) {
1607 return; // we're unloading
1610 if ( command
== (void *)kIOPMUnidleDevice
) {
1611 if ( (pm_vars
->myCurrentState
< (unsigned long)stateNumber
) &&
1612 (priv
->imminentState
< (unsigned long)stateNumber
) ) {
1613 changePowerStateToPriv((unsigned long)stateNumber
);
1619 //*********************************************************************************
1620 // setAggressiveness
1622 // Pass on the input parameters to all power domain children. All those which are
1623 // power domains will pass it on to their children, etc.
1624 //*********************************************************************************
1626 IOReturn
IOService::setAggressiveness ( unsigned long type
, unsigned long newLevel
)
1630 IOPowerConnection
* connection
;
1633 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogSetAggressiveness
,type
, newLevel
);
1635 if ( type
<= kMaxType
) {
1636 pm_vars
->current_aggressiveness_values
[type
] = newLevel
;
1637 pm_vars
->current_aggressiveness_valid
[type
] = true;
1640 iter
= getChildIterator(gIOPowerPlane
);
1643 while ( (next
= iter
->getNextObject()) ) {
1644 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1645 child
= ((IOService
*)(connection
->copyChildEntry(gIOPowerPlane
)));
1647 child
->setAggressiveness(type
, newLevel
);
1658 //*********************************************************************************
1659 // getAggressiveness
1661 // Called by the user client.
1662 //*********************************************************************************
1664 IOReturn
IOService::getAggressiveness ( unsigned long type
, unsigned long * currentLevel
)
1666 if ( type
<= kMaxType
) {
1667 *currentLevel
= pm_vars
->current_aggressiveness_values
[type
];
1669 return kIOReturnSuccess
;
1672 //*********************************************************************************
1675 // Pass this to all power domain children. All those which are
1676 // power domains will pass it on to their children, etc.
1677 //*********************************************************************************
1679 IOReturn
IOService::systemWake ( void )
1683 IOPowerConnection
* connection
;
1684 IOService
* theChild
;
1686 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogSystemWake
,0, 0);
1688 iter
= getChildIterator(gIOPowerPlane
);
1691 while ( (next
= iter
->getNextObject()) ) {
1692 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1693 theChild
= (IOService
*)connection
->copyChildEntry(gIOPowerPlane
);
1695 theChild
->systemWake();
1696 theChild
->release();
1703 if ( pm_vars
->theControllingDriver
!= NULL
) {
1704 if ( pm_vars
->theControllingDriver
->didYouWakeSystem() ) {
1713 //*********************************************************************************
1714 // temperatureCriticalForZone
1716 //*********************************************************************************
1718 IOReturn
IOService::temperatureCriticalForZone ( IOService
* whichZone
)
1720 IOService
* theParent
;
1723 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogCriticalTemp
,0,0);
1725 if ( inPlane(gIOPowerPlane
) && ! (priv
->we_are_root
) ) {
1726 theNub
= (IOService
*)copyParentEntry(gIOPowerPlane
);
1728 theParent
= (IOService
*)theNub
->copyParentEntry(gIOPowerPlane
);
1731 theParent
->temperatureCriticalForZone(whichZone
);
1732 theParent
->release();
1740 //*********************************************************************************
1741 // powerOverrideOnPriv
1743 //*********************************************************************************
1746 IOReturn
IOService::powerOverrideOnPriv ( void )
1748 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogOverrideOn
,0,0);
1750 priv
->device_overrides
= true; // turn on the override
1751 computeDesiredState();
1752 return changeState(); // change state if that changed something
1756 //*********************************************************************************
1757 // powerOverrideOffPriv
1759 //*********************************************************************************
1760 IOReturn
IOService::powerOverrideOffPriv ( void )
1762 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogOverrideOff
,0,0);
1764 priv
->device_overrides
= false; // turn off the override
1765 computeDesiredState();
1767 return makeUsable();
1769 return changeState(); // change state if that changed something
1773 //*********************************************************************************
1774 // enqueuePowerChange
1776 // Allocate a new state change notification, initialize it with fields from the
1777 // caller, and add it to the tail of the list of pending power changes.
1779 // If it is early enough in the list, and almost all the time it is the only one in
1780 // the list, start the power change.
1782 // In rare instances, this change will preempt the previous change in the list.
1783 // If the previous change is un-actioned in any way (because we are still
1784 // processing an even earlier power change), and if both the previous change
1785 // in the list and this change are initiated by us (not the parent), then we
1786 // needn't perform the previous change, so we collapse the list a little.
1787 //*********************************************************************************
1789 IOReturn
IOService::enqueuePowerChange ( unsigned long flags
, unsigned long whatStateOrdinal
, unsigned long domainState
, IOPowerConnection
* whichParent
, unsigned long singleParentState
)
1794 // Create and initialize the new change note
1796 IOLockLock(priv
->queue_lock
);
1797 newNote
= priv
->changeList
->createChangeNote();
1798 if ( newNote
== -1 ) {
1799 IOLockUnlock(priv
->queue_lock
);
1800 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogEnqueueErr
,0,0);
1801 return IOPMAckImplied
; // uh-oh, our list is full
1804 priv
->changeList
->changeNote
[newNote
].newStateNumber
= whatStateOrdinal
;
1805 priv
->changeList
->changeNote
[newNote
].outputPowerCharacter
= pm_vars
->thePowerStates
[whatStateOrdinal
].outputPowerCharacter
;
1806 priv
->changeList
->changeNote
[newNote
].inputPowerRequirement
= pm_vars
->thePowerStates
[whatStateOrdinal
].inputPowerRequirement
;
1807 priv
->changeList
->changeNote
[newNote
].capabilityFlags
= pm_vars
->thePowerStates
[whatStateOrdinal
].capabilityFlags
;
1808 priv
->changeList
->changeNote
[newNote
].flags
= flags
;
1809 if (flags
& IOPMParentInitiated
) {
1810 priv
->changeList
->changeNote
[newNote
].domainState
= domainState
;
1811 priv
->changeList
->changeNote
[newNote
].parent
= whichParent
;
1812 whichParent
->retain();
1813 priv
->changeList
->changeNote
[newNote
].singleParentState
= singleParentState
;
1816 previousNote
= priv
->changeList
->previousChangeNote(newNote
);
1818 if ( previousNote
== -1 ) {
1820 // Queue is empty, we can start this change.
1822 if (flags
& IOPMWeInitiated
) {
1823 IOLockUnlock(priv
->queue_lock
);
1824 start_our_change(newNote
);
1828 IOLockUnlock(priv
->queue_lock
);
1829 return start_parent_change(newNote
);
1833 // The queue is not empty. Try to collapse this new change and the previous one in queue into one change.
1834 // This is possible only if both changes are initiated by us, and neither has been started yet.
1835 // Do this more than once if possible.
1837 // (A change is started iff it is at the head of the queue)
1839 while ( (previousNote
!= priv
->head_note
) && (previousNote
!= -1) &&
1840 (priv
->changeList
->changeNote
[newNote
].flags
& priv
->changeList
->changeNote
[previousNote
].flags
& IOPMWeInitiated
) ) {
1841 priv
->changeList
->changeNote
[previousNote
].outputPowerCharacter
= priv
->changeList
->changeNote
[newNote
].outputPowerCharacter
;
1842 priv
->changeList
->changeNote
[previousNote
].inputPowerRequirement
= priv
->changeList
->changeNote
[newNote
].inputPowerRequirement
;
1843 priv
->changeList
->changeNote
[previousNote
].capabilityFlags
=priv
-> changeList
->changeNote
[newNote
].capabilityFlags
;
1844 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogCollapseQueue
,priv
->changeList
->changeNote
[newNote
].newStateNumber
,
1845 priv
->changeList
->changeNote
[previousNote
].newStateNumber
);
1846 priv
->changeList
->changeNote
[previousNote
].newStateNumber
= priv
->changeList
->changeNote
[newNote
].newStateNumber
;
1847 priv
->changeList
->releaseTailChangeNote();
1848 newNote
= previousNote
;
1849 previousNote
= priv
->changeList
->previousChangeNote(newNote
);
1851 IOLockUnlock(priv
->queue_lock
);
1852 return IOPMWillAckLater
; // in any case, we can't start yet
1855 //*********************************************************************************
1858 // Notify all interested parties either that a change is impending or that the
1859 // previously-notified change is done and power has settled.
1860 // The parameter identifies whether this is the
1861 // pre-change notification or the post-change notification.
1863 //*********************************************************************************
1865 IOReturn
IOService::notifyAll ( bool is_prechange
)
1867 IOPMinformee
* nextObject
;
1870 IOPowerConnection
* connection
;
1872 // To prevent acknowledgePowerChange from finishing the change note and removing it from the queue if
1873 // some driver calls it, we inflate the number of pending acks so it cannot become zero. We'll fix it later.
1875 priv
->head_note_pendingAcks
=1;
1877 // OK, we will go through the lists of interested drivers and power domain children
1878 // and notify each one of this change.
1879 nextObject
= priv
->interestedDrivers
->firstInList(); // notify interested drivers
1880 while ( nextObject
!= NULL
) {
1881 priv
->head_note_pendingAcks
+=1;
1882 if (! inform(nextObject
, is_prechange
) ) {
1884 nextObject
= priv
->interestedDrivers
->nextInList(nextObject
);
1887 if (! acquire_lock() ) {
1890 if ( priv
->head_note_pendingAcks
> 1 ) { // did they all ack?
1891 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0); // no
1894 IOUnlock(priv
->our_lock
); // either way
1896 iter
= getChildIterator(gIOPowerPlane
); // notify children
1897 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
= 0; // summing their power consumption
1900 while ( (next
= iter
->getNextObject()) ) {
1901 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1902 priv
->head_note_pendingAcks
+=1;
1903 notifyChild(connection
, is_prechange
);
1909 if (! acquire_lock() ) {
1912 priv
->head_note_pendingAcks
-= 1; // now make this real
1913 if (priv
->head_note_pendingAcks
== 0 ) { // is it all acked?
1914 IOUnlock(priv
->our_lock
); // yes
1915 return IOPMAckImplied
; // return ack to parent
1917 IOUnlock(priv
->our_lock
); // no
1918 return IOPMWillAckLater
;
1922 //*********************************************************************************
1925 // Notify a power domain child of an upcoming power change.
1927 // If the object acknowledges the current change, we return TRUE.
1928 //*********************************************************************************
1930 bool IOService::notifyChild ( IOPowerConnection
* theNub
, bool is_prechange
)
1932 IOReturn k
= IOPMAckImplied
;
1933 unsigned long childPower
;
1934 IOService
* theChild
= (IOService
*)(theNub
->copyChildEntry(gIOPowerPlane
));
1936 theNub
->setAwaitingAck(true); // in case they don't ack
1942 if ( is_prechange
) {
1943 k
= theChild
->powerDomainWillChangeTo(priv
->head_note_outputFlags
,theNub
);
1946 k
= theChild
->powerDomainDidChangeTo(priv
->head_note_outputFlags
,theNub
);
1949 if ( k
== IOPMAckImplied
) { // did the return code ack?
1950 priv
->head_note_pendingAcks
-=1; // yes
1951 theNub
->setAwaitingAck(false);
1952 childPower
= theChild
->currentPowerConsumption();
1953 if ( childPower
== kIOPMUnknown
) {
1954 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
= kIOPMUnknown
;
1957 if ( pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
!= kIOPMUnknown
) {
1958 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
+= childPower
;
1961 theChild
->release();
1964 theChild
->release();
1969 //*********************************************************************************
1972 // Notify an interested driver of an upcoming power change.
1974 // If the object acknowledges the current change, we return TRUE.
1975 //*********************************************************************************
1977 bool IOService::inform ( IOPMinformee
* nextObject
, bool is_prechange
)
1979 IOReturn k
= IOPMAckImplied
;
1981 nextObject
->timer
= -1; // initialize this
1983 if ( is_prechange
) {
1984 pm_vars
->thePlatform
->PMLog (pm_vars
->ourName
,PMlogInformDriverPreChange
,
1985 (unsigned long)priv
->head_note_capabilityFlags
,(unsigned long)priv
->head_note_state
);
1986 k
= nextObject
->whatObject
->powerStateWillChangeTo( priv
->head_note_capabilityFlags
,priv
->head_note_state
,this);
1989 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInformDriverPostChange
,
1990 (unsigned long)priv
->head_note_capabilityFlags
,(unsigned long)priv
->head_note_state
);
1991 k
= nextObject
->whatObject
->powerStateDidChangeTo(priv
->head_note_capabilityFlags
,priv
->head_note_state
,this);
1993 if ( nextObject
->timer
== 0 ) { // did it ack behind our back?
1996 if ( k
==IOPMAckImplied
) { // no, did the return code ack?
1997 nextObject
->timer
= 0; // yes
1998 priv
->head_note_pendingAcks
-= 1;
2002 nextObject
->timer
= 0; // somebody goofed
2003 priv
-> head_note_pendingAcks
-= 1;
2006 nextObject
->timer
= (k
* ns_per_us
/ ACK_TIMER_PERIOD
) + 1; // no, it's a timer
2011 //*********************************************************************************
2014 // All registered applications and kernel clients have positively acknowledged our
2015 // intention of lowering power. Here we notify them all that we will definitely
2016 // lower the power. If we don't have to wait for any of them to acknowledge, we
2017 // carry on by notifying interested drivers. Otherwise, we do wait.
2018 //*********************************************************************************
2020 void IOService::our_prechange_03 ( void )
2022 priv
->machine_state
= IOPMour_prechange_04
; // next state
2023 if ( tellChangeDown1(priv
->head_note_state
) ) { // are we waiting for responses?
2024 our_prechange_04(); // no, notify priority clients
2029 //*********************************************************************************
2032 // All registered applications and kernel clients have positively acknowledged our
2033 // intention of lowering power. Here we notify "priority" clients that we are
2034 // lowering power. If we don't have to wait for any of them to acknowledge, we
2035 // carry on by notifying interested drivers. Otherwise, we do wait.
2036 //*********************************************************************************
2038 void IOService::our_prechange_04 ( void )
2040 priv
->machine_state
= IOPMour_prechange_05
; // next state
2041 if ( tellChangeDown2(priv
->head_note_state
) ) { // are we waiting for responses?
2042 return our_prechange_05(); // no, notify interested drivers
2047 //*********************************************************************************
2050 // All registered applications and kernel clients have acknowledged our notification
2051 // that we are lowering power. Here we notify interested drivers. If we don't have
2052 // to wait for any of them to acknowledge, we instruct our power driver to make the change.
2053 // Otherwise, we do wait.
2054 //*********************************************************************************
2056 void IOService::our_prechange_05 ( void )
2058 priv
->machine_state
= IOPMour_prechange_1
; // no, in case they don't all ack
2059 if ( notifyAll(true) == IOPMAckImplied
) {
2065 //*********************************************************************************
2068 // All interested drivers have acknowledged our pre-change notification of a power
2069 // change we initiated. Here we instruct our controlling driver to make
2070 // the change to the hardware. If it does so, we continue processing
2071 // (waiting for settle and notifying interested parties post-change.)
2072 // If it doesn't, we have to wait for it to acknowledge and then continue.
2073 //*********************************************************************************
2075 void IOService::our_prechange_1 ( void )
2077 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
) {
2078 our_prechange_2(); // it's done, carry on
2081 priv
->machine_state
= IOPMour_prechange_2
; // it's not, wait for it
2082 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2088 //*********************************************************************************
2091 // Our controlling driver has changed power state on the hardware
2092 // during a power change we initiated. Here we see if we need to wait
2093 // for power to settle before continuing. If not, we continue processing
2094 // (notifying interested parties post-change). If so, we wait and
2096 //*********************************************************************************
2098 void IOService::our_prechange_2 ( void )
2100 priv
->settle_time
= compute_settle_time();
2101 if ( priv
->settle_time
== 0 ) {
2105 priv
->machine_state
= IOPMour_prechange_3
;
2106 startSettleTimer(priv
->settle_time
);
2111 //*********************************************************************************
2114 // Power has settled on a power change we initiated. Here we notify
2115 // all our interested parties post-change. If they all acknowledge, we're
2116 // done with this change note, and we can start on the next one.
2117 // Otherwise we have to wait for acknowledgements and finish up later.
2118 //*********************************************************************************
2120 void IOService::our_prechange_3 ( void )
2122 priv
->machine_state
= IOPMour_prechange_4
; // in case they don't all ack
2123 if ( notifyAll(false) == IOPMAckImplied
) {
2129 //*********************************************************************************
2132 // Power has settled on a power change we initiated, and
2133 // all our interested parties have acknowledged. We're
2134 // done with this change note, and we can start on the next one.
2135 //*********************************************************************************
2137 void IOService::our_prechange_4 ( void )
2143 //*********************************************************************************
2146 // All applications and kernel clients have been notified of a power lowering
2147 // initiated by the parent and we didn't have to wait for any responses. Here
2148 // we notify any priority clients. If they all ack, we continue with the power change.
2149 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
2150 //*********************************************************************************
2152 IOReturn
IOService::parent_down_0 ( void )
2154 priv
->machine_state
= IOPMparent_down_05
; // in case they don't all ack
2155 if ( tellChangeDown2(priv
->head_note_state
) ) { // are we waiting for responses?
2156 return parent_down_02(); // no, notify interested drivers
2158 return IOPMWillAckLater
; // they didn't
2162 //*********************************************************************************
2165 // All priority kernel clients have been notified of a power lowering
2166 // initiated by the parent and we didn't have to wait for any responses. Here
2167 // we notify any interested drivers and power domain children. If they all ack,
2168 // we continue with the power change.
2169 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
2170 //*********************************************************************************
2172 IOReturn
IOService::parent_down_02 ( void )
2174 priv
->machine_state
= IOPMparent_down_4
; // in case they don't all ack
2175 if ( notifyAll(true) == IOPMAckImplied
) {
2176 return parent_down_1(); // they did
2178 return IOPMWillAckLater
; // they didn't
2182 //*********************************************************************************
2185 // All applications and kernel clients have been notified of a power lowering
2186 // initiated by the parent and we had to wait for responses. Here
2187 // we notify any priority clients. If they all ack, we continue with the power change.
2188 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
2189 //*********************************************************************************
2191 void IOService::parent_down_04 ( void )
2193 priv
->machine_state
= IOPMparent_down_05
; // in case they don't all ack
2194 if ( tellChangeDown2(priv
->head_note_state
) ) { // are we waiting for responses?
2195 parent_down_05(); // no, notify interested drivers
2200 //*********************************************************************************
2203 // All applications and kernel clients have been notified of a power lowering
2204 // initiated by the parent and we had to wait for their responses. Here we notify
2205 // any interested drivers and power domain children. If they all ack, we continue
2206 // with the power change.
2207 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
2208 //*********************************************************************************
2210 void IOService::parent_down_05 ( void )
2212 priv
->machine_state
= IOPMparent_down_4
; // in case they don't all ack
2213 if ( notifyAll(true) == IOPMAckImplied
) {
2214 parent_down_4(); // they did
2219 //*********************************************************************************
2222 // All parties have acknowledged our pre-change notification of a power
2223 // lowering initiated by the parent. Here we instruct our controlling driver
2224 // to put the hardware in the state it needs to be in when the domain is
2225 // lowered. If it does so, we continue processing
2226 // (waiting for settle and acknowledging the parent.)
2227 // If it doesn't, we have to wait for it to acknowledge and then continue.
2228 //*********************************************************************************
2230 IOReturn
IOService::parent_down_1 ( void )
2232 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
) {
2233 return parent_down_2(); // it's done, carry on
2235 priv
->machine_state
= IOPMparent_down_5
; // it's not, wait for it
2236 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2238 return IOPMWillAckLater
;
2242 //*********************************************************************************
2245 // We had to wait for it, but all parties have acknowledged our pre-change
2246 // notification of a power lowering initiated by the parent.
2247 // Here we instruct our controlling driver
2248 // to put the hardware in the state it needs to be in when the domain is
2249 // lowered. If it does so, we continue processing
2250 // (waiting for settle and acknowledging the parent.)
2251 // If it doesn't, we have to wait for it to acknowledge and then continue.
2252 //*********************************************************************************
2254 void IOService::parent_down_4 ( void )
2256 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
) {
2257 parent_down_5(); // it's done, carry on
2260 priv
-> machine_state
= IOPMparent_down_5
; // it's not, wait for it
2261 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2267 //*********************************************************************************
2270 // Our controlling driver has changed power state on the hardware
2271 // during a power change initiated by our parent. Here we see if we need
2272 // to wait for power to settle before continuing. If not, we continue
2273 // processing (acknowledging our preparedness to the parent).
2274 // If so, we wait and continue later.
2275 //*********************************************************************************
2277 IOReturn
IOService::parent_down_2 ( void )
2281 priv
->settle_time
= compute_settle_time();
2282 if ( priv
->settle_time
== 0 ) {
2283 priv
->machine_state
= IOPMparent_down_6
; // in case they don't all ack
2284 if ( notifyAll(false) == IOPMAckImplied
) {
2285 nub
= priv
->head_note_parent
;
2288 return IOPMAckImplied
;
2290 return IOPMWillAckLater
; // they didn't
2293 priv
->machine_state
= IOPMparent_down_3
;
2294 startSettleTimer(priv
->settle_time
);
2295 return IOPMWillAckLater
;
2300 //*********************************************************************************
2303 // Our controlling driver has changed power state on the hardware
2304 // during a power change initiated by our parent. We have had to wait
2305 // for acknowledgement from interested parties, or we have had to wait
2306 // for the controlling driver to change the state. Here we see if we need
2307 // to wait for power to settle before continuing. If not, we continue
2308 // processing (acknowledging our preparedness to the parent).
2309 // If so, we wait and continue later.
2310 //*********************************************************************************
2312 void IOService::parent_down_5 ( void )
2314 priv
->settle_time
= compute_settle_time();
2315 if ( priv
->settle_time
== 0 ) {
2319 priv
->machine_state
= IOPMparent_down_3
;
2320 startSettleTimer(priv
->settle_time
);
2325 //*********************************************************************************
2328 // Power has settled on a power change initiated by our parent. Here we
2329 // notify interested parties.
2330 //*********************************************************************************
2332 void IOService::parent_down_3 ( void )
2334 IORegistryEntry
* nub
;
2337 priv
->machine_state
= IOPMparent_down_6
; // in case they don't all ack
2338 if ( notifyAll(false) == IOPMAckImplied
) {
2339 nub
= priv
->head_note_parent
;
2341 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
2343 parent
->acknowledgePowerChange((IOService
*)nub
);
2351 //*********************************************************************************
2354 // We had to wait for it, but all parties have acknowledged our post-change
2355 // notification of a power lowering initiated by the parent.
2356 // Here we acknowledge the parent.
2357 // We are done with this change note, and we can start on the next one.
2358 //*********************************************************************************
2360 void IOService::parent_down_6 ( void )
2362 IORegistryEntry
* nub
;
2365 nub
= priv
->head_note_parent
;
2367 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
2369 parent
->acknowledgePowerChange((IOService
*)nub
);
2376 //*********************************************************************************
2379 // Our parent has informed us via powerStateDidChange that it has
2380 // raised the power in our power domain, and we have had to wait
2381 // for some interested party to acknowledge our notification.
2382 // Here we instruct our controlling
2383 // driver to program the hardware to take advantage of the higher domain
2384 // power. If it does so, we continue processing
2385 // (waiting for settle and notifying interested parties post-change.)
2386 // If it doesn't, we have to wait for it to acknowledge and then continue.
2387 //*********************************************************************************
2389 void IOService::parent_up_0 ( void )
2391 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
) {
2392 parent_up_4(); // it did it, carry on
2395 priv
->machine_state
= IOPMparent_up_4
; // it didn't, wait for it
2396 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2402 //*********************************************************************************
2405 // Our parent has informed us via powerStateDidChange that it has
2406 // raised the power in our power domain. Here we instruct our controlling
2407 // driver to program the hardware to take advantage of the higher domain
2408 // power. If it does so, we continue processing
2409 // (waiting for settle and notifying interested parties post-change.)
2410 // If it doesn't, we have to wait for it to acknowledge and then continue.
2411 //*********************************************************************************
2413 IOReturn
IOService::parent_up_1 ( void )
2415 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
) {
2416 return parent_up_2(); // it did it, carry on
2419 priv
->machine_state
= IOPMparent_up_4
; // it didn't, wait for it
2420 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2422 return IOPMWillAckLater
;
2427 //*********************************************************************************
2430 // Our controlling driver has changed power state on the hardware
2431 // during a power raise initiated by the parent. Here we see if we need to wait
2432 // for power to settle before continuing. If not, we continue processing
2433 // (notifying interested parties post-change). If so, we wait and
2435 //*********************************************************************************
2437 IOReturn
IOService::parent_up_2 ( void )
2439 priv
->settle_time
= compute_settle_time();
2440 if ( priv
->settle_time
== 0 ) {
2441 return parent_up_3();
2444 priv
->machine_state
= IOPMparent_up_5
;
2445 startSettleTimer(priv
->settle_time
);
2446 return IOPMWillAckLater
;
2451 //*********************************************************************************
2454 // Our controlling driver has changed power state on the hardware
2455 // during a power raise initiated by the parent, but we had to wait for it.
2456 // Here we see if we need to wait for power to settle before continuing.
2457 // If not, we continue processing (notifying interested parties post-change).
2458 // If so, we wait and continue later.
2459 //*********************************************************************************
2461 void IOService::parent_up_4 ( void )
2463 priv
->settle_time
= compute_settle_time();
2464 if ( priv
->settle_time
== 0 ) {
2468 priv
->machine_state
= IOPMparent_up_5
;
2469 startSettleTimer(priv
->settle_time
);
2474 //*********************************************************************************
2477 // No power settling was required on a power raise initiated by the parent.
2478 // Here we notify all our interested parties post-change. If they all acknowledge,
2479 // we're done with this change note, and we can start on the next one.
2480 // Otherwise we have to wait for acknowledgements and finish up later.
2481 //*********************************************************************************
2483 IOReturn
IOService::parent_up_3 ( void )
2487 priv
->machine_state
= IOPMparent_up_6
; // in case they don't all ack
2488 if ( notifyAll(false) == IOPMAckImplied
) {
2489 nub
= priv
->head_note_parent
;
2492 return IOPMAckImplied
;
2494 return IOPMWillAckLater
; // they didn't
2498 //*********************************************************************************
2501 // Power has settled on a power raise initiated by the parent.
2502 // Here we notify all our interested parties post-change. If they all acknowledge,
2503 // we're done with this change note, and we can start on the next one.
2504 // Otherwise we have to wait for acknowledgements and finish up later.
2505 //*********************************************************************************
2507 void IOService::parent_up_5 ( void )
2509 priv
->machine_state
= IOPMparent_up_6
; // in case they don't all ack
2510 if ( notifyAll(false) == IOPMAckImplied
) {
2516 //*********************************************************************************
2519 // All parties have acknowledged our post-change notification of a power
2520 // raising initiated by the parent. Here we acknowledge the parent.
2521 // We are done with this change note, and we can start on the next one.
2522 //*********************************************************************************
2524 void IOService::parent_up_6 ( void )
2526 IORegistryEntry
* nub
;
2529 nub
= priv
->head_note_parent
;
2531 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
2533 parent
->acknowledgePowerChange((IOService
*)nub
);
2540 //*********************************************************************************
2543 // A power change is complete, and the used post-change note is at
2544 // the head of the queue. Remove it and set myCurrentState to the result
2545 // of the change. Start up the next change in queue.
2546 //*********************************************************************************
2548 void IOService::all_done ( void )
2550 unsigned long previous_state
;
2551 IORegistryEntry
* nub
;
2554 priv
->machine_state
= IOPMfinished
;
2556 if ( priv
->head_note_flags
& IOPMWeInitiated
) { // our power change
2557 if ( !( priv
->head_note_flags
& IOPMNotDone
) ) { // could our driver switch to the new state?
2558 if ( pm_vars
->myCurrentState
< priv
->head_note_state
) { // yes, did power raise?
2559 tellChangeUp (priv
->head_note_state
); // yes, inform clients and apps
2562 if ( ! priv
->we_are_root
) { // no, if this lowers our
2563 ask_parent(priv
->head_note_state
); // power requirements, tell the parent
2566 previous_state
= pm_vars
->myCurrentState
;
2567 pm_vars
->myCurrentState
= priv
->head_note_state
; // either way
2568 priv
->imminentState
= pm_vars
->myCurrentState
;
2569 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeDone
,(unsigned long)pm_vars
->myCurrentState
,0);
2570 powerChangeDone(previous_state
); // inform subclass policy-maker
2573 // pm_vars->myCurrentState = pm_vars->theControllingDriver->powerStateForDomainState(pm_vars->parentsCurrentPowerFlags);
2576 if ( priv
->head_note_flags
& IOPMParentInitiated
) { // parent's power change
2577 if ( ((priv
->head_note_flags
& IOPMDomainWillChange
) && (pm_vars
->myCurrentState
>= priv
->head_note_state
)) ||
2578 ((priv
->head_note_flags
& IOPMDomainDidChange
) && (pm_vars
->myCurrentState
< priv
->head_note_state
)) ) {
2579 if ( pm_vars
->myCurrentState
< priv
->head_note_state
) { // did power raise?
2580 tellChangeUp (priv
->head_note_state
); // yes, inform clients and apps
2582 previous_state
= pm_vars
->myCurrentState
; // either way
2583 pm_vars
->myCurrentState
= priv
->head_note_state
;
2584 priv
->imminentState
= pm_vars
->myCurrentState
;
2585 pm_vars
->maxCapability
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(priv
->head_note_domainState
);
2587 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeDone
,(unsigned long)pm_vars
->myCurrentState
,0);
2588 powerChangeDone(previous_state
); // inform subclass policy-maker
2592 IOLockLock(priv
->queue_lock
);
2593 priv
->changeList
->releaseHeadChangeNote(); // we're done with this
2595 priv
->head_note
= priv
->changeList
->currentChange(); // start next one in queue
2596 if ( priv
->head_note
!= -1 ) {
2598 IOLockUnlock(priv
->queue_lock
);
2599 if (priv
->changeList
->changeNote
[priv
->head_note
].flags
& IOPMWeInitiated
) {
2600 start_our_change(priv
->head_note
);
2603 nub
= priv
->changeList
->changeNote
[priv
->head_note
].parent
;
2604 if ( start_parent_change(priv
->head_note
) == IOPMAckImplied
) {
2605 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
2607 parent
->acknowledgePowerChange((IOService
*)nub
);
2613 IOLockUnlock(priv
->queue_lock
);
2618 //*********************************************************************************
2621 // A driver or child has acknowledged our notification of an upcoming power
2622 // change, and this acknowledgement is the last one pending
2623 // before we change power or after changing power.
2625 //*********************************************************************************
2627 void IOService::all_acked ( void )
2629 switch (priv
->machine_state
) {
2630 case IOPMour_prechange_1
:
2633 case IOPMour_prechange_4
:
2636 case IOPMparent_down_4
:
2639 case IOPMparent_down_6
:
2642 case IOPMparent_up_0
:
2645 case IOPMparent_up_6
:
2652 //*********************************************************************************
2653 // settleTimerExpired
2655 // Power has settled after our last change. Notify interested parties that
2656 // there is a new power state.
2657 //*********************************************************************************
2659 void IOService::settleTimerExpired ( void )
2661 if ( ! initialized
) {
2662 return; // we're unloading
2665 switch (priv
->machine_state
) {
2666 case IOPMour_prechange_3
:
2669 case IOPMparent_down_3
:
2672 case IOPMparent_up_5
:
2679 //*********************************************************************************
2680 // compute_settle_time
2682 // Compute the power-settling delay in microseconds for the
2683 // change from myCurrentState to head_note_state.
2684 //*********************************************************************************
2686 unsigned long IOService::compute_settle_time ( void )
2688 unsigned long totalTime
;
2691 totalTime
= 0; // compute total time to attain the new state
2692 i
= pm_vars
->myCurrentState
;
2693 if ( priv
->head_note_state
< pm_vars
->myCurrentState
) { // we're lowering power
2694 while ( i
> priv
->head_note_state
) {
2695 totalTime
+= pm_vars
->thePowerStates
[i
].settleDownTime
;
2700 if ( priv
->head_note_state
> pm_vars
->myCurrentState
) { // we're raising power
2701 while ( i
< priv
->head_note_state
) {
2702 totalTime
+= pm_vars
->thePowerStates
[i
+1].settleUpTime
;
2711 //*********************************************************************************
2714 // Enter with a power-settling delay in microseconds and start a nano-second
2715 // timer for that delay.
2716 //*********************************************************************************
2718 IOReturn
IOService::startSettleTimer ( unsigned long delay
)
2720 AbsoluteTime deadline
;
2722 clock_interval_to_deadline(delay
, kMicrosecondScale
, &deadline
);
2724 thread_call_enter_delayed(priv
->settleTimer
, deadline
);
2729 //*********************************************************************************
2732 // The acknowledgement timeout periodic timer has ticked.
2733 // If we are awaiting acks for a power change notification,
2734 // we decrement the timer word of each interested driver which hasn't acked.
2735 // If a timer word becomes zero, we pretend the driver aknowledged.
2736 // If we are waiting for the controlling driver to change the power
2737 // state of the hardware, we decrement its timer word, and if it becomes
2738 // zero, we pretend the driver acknowledged.
2739 //*********************************************************************************
2741 void IOService::ack_timer_ticked ( void )
2743 IOPMinformee
* nextObject
;
2745 if ( ! initialized
) {
2746 return; // we're unloading
2749 if (! acquire_lock() ) {
2753 switch (priv
->machine_state
) {
2754 case IOPMour_prechange_2
:
2755 case IOPMparent_down_5
:
2756 case IOPMparent_up_4
:
2757 if ( priv
->driver_timer
!= 0 ) { // are we waiting for our driver to make its change?
2758 priv
->driver_timer
-= 1; // yes, tick once
2759 if ( priv
->driver_timer
== 0 ) { // it's tardy, we'll go on without it
2760 IOUnlock(priv
->our_lock
);
2761 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogCtrlDriverTardy
,0,0);
2764 else { // still waiting, set timer again
2766 IOUnlock(priv
->our_lock
);
2770 IOUnlock(priv
->our_lock
);
2774 case IOPMour_prechange_1
:
2775 case IOPMour_prechange_4
:
2776 case IOPMparent_down_4
:
2777 case IOPMparent_down_6
:
2778 case IOPMparent_up_0
:
2779 case IOPMparent_up_6
:
2780 if (priv
->head_note_pendingAcks
!= 0 ) { // are we waiting for interested parties to acknowledge?
2781 nextObject
= priv
->interestedDrivers
->firstInList(); // yes, go through the list of interested drivers
2782 while ( nextObject
!= NULL
) { // and check each one
2783 if ( nextObject
->timer
> 0 ) {
2784 nextObject
->timer
-= 1;
2785 if ( nextObject
->timer
== 0 ) { // this one should have acked by now
2786 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogIntDriverTardy
,0,0);
2787 kprintf("interested driver tardy: %s\n",nextObject
->whatObject
->getName());
2788 priv
->head_note_pendingAcks
-= 1;
2791 nextObject
= priv
->interestedDrivers
->nextInList(nextObject
);
2793 if ( priv
->head_note_pendingAcks
== 0 ) { // is that the last?
2794 IOUnlock(priv
->our_lock
);
2795 all_acked(); // yes, we can continue
2797 else { // no, set timer again
2799 IOUnlock(priv
->our_lock
);
2803 IOUnlock(priv
->our_lock
);
2807 case IOPMparent_down_0
: // apps didn't respond to parent-down notification
2808 IOUnlock(priv
->our_lock
);
2809 IOLockLock(priv
->flags_lock
);
2810 if (pm_vars
->responseFlags
) {
2811 pm_vars
->responseFlags
->release(); // get rid of this stuff
2812 pm_vars
->responseFlags
= NULL
;
2814 IOLockUnlock(priv
->flags_lock
);
2815 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,5);
2816 parent_down_04(); // carry on with the change
2819 case IOPMparent_down_05
:
2820 IOUnlock(priv
->our_lock
);
2821 IOLockLock(priv
->flags_lock
);
2822 if (pm_vars
->responseFlags
) {
2823 pm_vars
->responseFlags
->release(); // get rid of this stuff
2824 pm_vars
->responseFlags
= NULL
;
2826 IOLockUnlock(priv
->flags_lock
);
2827 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,1);
2828 parent_down_05(); // carry on with the change
2831 case IOPMour_prechange_03
: // apps didn't respond to our power-down request
2832 IOUnlock(priv
->our_lock
);
2833 IOLockLock(priv
->flags_lock
);
2834 if (pm_vars
->responseFlags
) {
2835 pm_vars
->responseFlags
->release(); // get rid of this stuff
2836 pm_vars
->responseFlags
= NULL
;
2838 IOLockUnlock(priv
->flags_lock
);
2839 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,2);
2840 tellNoChangeDown(priv
->head_note_state
); // rescind the request
2841 priv
->head_note_flags
|= IOPMNotDone
; // mark the change note un-actioned
2842 all_done(); // and we're done
2845 case IOPMour_prechange_04
: // clients didn't respond to our power-down note
2846 IOUnlock(priv
->our_lock
);
2847 IOLockLock(priv
->flags_lock
);
2848 if (pm_vars
->responseFlags
) {
2849 pm_vars
->responseFlags
->release(); // get rid of this stuff
2850 pm_vars
->responseFlags
= NULL
;
2852 IOLockUnlock(priv
->flags_lock
);
2853 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,4);
2854 our_prechange_04(); // carry on with the change
2857 case IOPMour_prechange_05
: // apps didn't respond to our power-down notification
2858 IOUnlock(priv
->our_lock
);
2859 IOLockLock(priv
->flags_lock
);
2860 if (pm_vars
->responseFlags
) {
2861 pm_vars
->responseFlags
->release(); // get rid of this stuff
2862 pm_vars
->responseFlags
= NULL
;
2864 IOLockUnlock(priv
->flags_lock
);
2865 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,3);
2866 our_prechange_05(); // carry on with the change
2870 IOUnlock(priv
->our_lock
); // not waiting for acks
2876 //*********************************************************************************
2879 //*********************************************************************************
2881 void IOService::start_ack_timer ( void )
2883 AbsoluteTime deadline
;
2885 clock_interval_to_deadline(ACK_TIMER_PERIOD
, kNanosecondScale
, &deadline
);
2887 thread_call_enter_delayed(priv
->ackTimer
, deadline
);
2891 //*********************************************************************************
2894 //*********************************************************************************
2896 void IOService::stop_ack_timer ( void )
2898 thread_call_cancel(priv
->ackTimer
);
2902 //*********************************************************************************
2903 // c-language timer expiration functions
2905 //*********************************************************************************
2907 static void ack_timer_expired ( thread_call_param_t us
)
2909 ((IOService
*)us
)->ack_timer_ticked();
2913 static void settle_timer_expired ( thread_call_param_t us
)
2915 ((IOService
*)us
)->settleTimerExpired();
2919 //*********************************************************************************
2920 // add_child_to_active_change
2922 // A child has just registered with us. If there is
2923 // currently a change in progress, get the new party involved: if we
2924 // have notified all parties and are waiting for acks, notify the new
2926 //*********************************************************************************
2928 IOReturn
IOService::add_child_to_active_change ( IOPowerConnection
* newObject
)
2930 if (! acquire_lock() ) {
2934 switch (priv
->machine_state
) {
2935 case IOPMour_prechange_1
:
2936 case IOPMparent_down_4
:
2937 case IOPMparent_up_0
:
2938 priv
->head_note_pendingAcks
+= 2; // one for this child and one to prevent
2939 IOUnlock(priv
->our_lock
); // incoming acks from changing our state
2940 notifyChild(newObject
, true);
2941 if (! acquire_lock() ) {
2942 --priv
->head_note_pendingAcks
; // put it back
2945 if ( --priv
->head_note_pendingAcks
== 0 ) { // are we still waiting for acks?
2946 stop_ack_timer(); // no, stop the timer
2947 IOUnlock(priv
->our_lock
);
2948 all_acked(); // and now we can continue
2952 case IOPMour_prechange_4
:
2953 case IOPMparent_down_6
:
2954 case IOPMparent_up_6
:
2955 priv
->head_note_pendingAcks
+= 2; // one for this child and one to prevent
2956 IOUnlock(priv
->our_lock
); // incoming acks from changing our state
2957 notifyChild(newObject
, false);
2958 if (! acquire_lock() ) {
2959 --priv
->head_note_pendingAcks
; // put it back
2962 if ( --priv
->head_note_pendingAcks
== 0 ) { // are we still waiting for acks?
2963 stop_ack_timer(); // no, stop the timer
2964 IOUnlock(priv
->our_lock
);
2965 all_acked(); // and now we can continue
2970 IOUnlock(priv
->our_lock
);
2975 //*********************************************************************************
2976 // add_driver_to_active_change
2978 // An interested driver has just registered with us. If there is
2979 // currently a change in progress, get the new party involved: if we
2980 // have notified all parties and are waiting for acks, notify the new
2982 //*********************************************************************************
2984 IOReturn
IOService::add_driver_to_active_change ( IOPMinformee
* newObject
)
2986 if (! acquire_lock() ) {
2990 switch (priv
->machine_state
) {
2991 case IOPMour_prechange_1
:
2992 case IOPMparent_down_4
:
2993 case IOPMparent_up_0
:
2994 priv
->head_note_pendingAcks
+= 2; // one for this driver and one to prevent
2995 IOUnlock(priv
->our_lock
); // incoming acks from changing our state
2996 inform(newObject
, true); // inform the driver
2997 if (! acquire_lock() ) {
2998 --priv
->head_note_pendingAcks
; // put it back
3001 if ( --priv
->head_note_pendingAcks
== 0 ) { // are we still waiting for acks?
3002 stop_ack_timer(); // no, stop the timer
3003 IOUnlock(priv
->our_lock
);
3004 all_acked(); // and now we can continue
3008 case IOPMour_prechange_4
:
3009 case IOPMparent_down_6
:
3010 case IOPMparent_up_6
:
3011 priv
->head_note_pendingAcks
+= 2; // one for this driver and one to prevent
3012 IOUnlock(priv
->our_lock
); // incoming acks from changing our state
3013 inform(newObject
, false); // inform the driver
3014 if (! acquire_lock() ) {
3015 --priv
->head_note_pendingAcks
; // put it back
3018 if ( --priv
->head_note_pendingAcks
== 0 ) { // are we still waiting for acks?
3019 stop_ack_timer(); // no, stop the timer
3020 IOUnlock(priv
->our_lock
);
3021 all_acked(); // and now we can continue
3026 IOUnlock(priv
->our_lock
);
3031 //*********************************************************************************
3032 // start_parent_change
3034 // Here we begin the processing of a change note initiated by our parent
3035 // which is at the head of the queue.
3037 // It is possible for the change to be processed to completion and removed from the queue.
3038 // There are several possible interruptions to the processing, though, and they are:
3039 // we may have to wait for interested parties to acknowledge our pre-change notification,
3040 // we may have to wait for our controlling driver to change the hardware power state,
3041 // there may be a settling time after changing the hardware power state,
3042 // we may have to wait for interested parties to acknowledge our post-change notification,
3043 // we may have to wait for the acknowledgement timer expiration to substitute for the
3044 // acknowledgement from a failing driver.
3045 //*********************************************************************************
3047 IOReturn
IOService::start_parent_change ( unsigned long queue_head
)
3049 priv
->head_note
= queue_head
;
3050 priv
->head_note_flags
= priv
-> changeList
->changeNote
[priv
->head_note
].flags
;
3051 priv
->head_note_state
= priv
->changeList
->changeNote
[priv
->head_note
].newStateNumber
;
3052 priv
->imminentState
= priv
->head_note_state
;
3053 priv
->head_note_outputFlags
= priv
->changeList
->changeNote
[priv
->head_note
].outputPowerCharacter
;
3054 priv
->head_note_domainState
= priv
->changeList
->changeNote
[priv
->head_note
].domainState
;
3055 priv
->head_note_parent
= priv
->changeList
->changeNote
[priv
->head_note
].parent
;
3056 priv
->head_note_capabilityFlags
= priv
->changeList
->changeNote
[priv
->head_note
].capabilityFlags
;
3058 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartParentChange
,
3059 (unsigned long)priv
->head_note_state
,(unsigned long)pm_vars
->myCurrentState
);
3061 ask_parent( priv
->ourDesiredPowerState
); // if we need something and haven't told the parent, do so
3063 if ( priv
->head_note_state
< pm_vars
->myCurrentState
) { // power domain is lowering
3064 setParentInfo(priv
->changeList
->changeNote
[priv
->head_note
].singleParentState
,priv
->head_note_parent
);
3065 priv
->initial_change
= false;
3066 priv
->machine_state
= IOPMparent_down_0
; // tell apps and kernel clients
3067 if ( tellChangeDown1(priv
->head_note_state
) ) { // are we waiting for responses?
3068 return parent_down_0(); // no, notify priority clients
3070 return IOPMWillAckLater
; // yes
3073 if ( priv
->head_note_state
> pm_vars
->myCurrentState
) { // parent is raising power, we may or may not
3074 if ( priv
->ourDesiredPowerState
> pm_vars
->myCurrentState
) {
3075 if ( priv
->ourDesiredPowerState
< priv
->head_note_state
) {
3076 priv
->head_note_state
= priv
->ourDesiredPowerState
; // we do, but not all the way
3077 priv
->imminentState
= priv
->head_note_state
;
3078 priv
->head_note_outputFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].outputPowerCharacter
;
3079 priv
->head_note_capabilityFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].capabilityFlags
;
3080 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAmendParentChange
,(unsigned long)priv
->head_note_state
,0);
3084 priv
->head_note_state
= pm_vars
->myCurrentState
; // we don't
3085 priv
->imminentState
= priv
->head_note_state
;
3086 priv
->head_note_outputFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].outputPowerCharacter
;
3087 priv
->head_note_capabilityFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].capabilityFlags
;
3088 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAmendParentChange
,(unsigned long)priv
->head_note_state
,0);
3092 if ( (priv
->head_note_state
> pm_vars
->myCurrentState
) &&
3093 (priv
->head_note_flags
& IOPMDomainDidChange
) ) { // changing up
3094 priv
->initial_change
= false;
3095 priv
->machine_state
= IOPMparent_up_0
;
3096 if ( notifyAll(true) == IOPMAckImplied
) {
3097 return parent_up_1();
3099 return IOPMWillAckLater
; // they didn't all ack
3103 return IOPMAckImplied
; // a null change or power will go up
3107 //*********************************************************************************
3110 // Here we begin the processing of a change note initiated by us
3111 // which is at the head of the queue.
3113 // It is possible for the change to be processed to completion and removed from the queue.
3114 // There are several possible interruptions to the processing, though, and they are:
3115 // we may have to wait for interested parties to acknowledge our pre-change notification,
3116 // changes initiated by the parent will wait in the middle for powerStateDidChange,
3117 // we may have to wait for our controlling driver to change the hardware power state,
3118 // there may be a settling time after changing the hardware power state,
3119 // we may have to wait for interested parties to acknowledge our post-change notification,
3120 // we may have to wait for the acknowledgement timer expiration to substitute for the
3121 // acknowledgement from a failing driver.
3122 //*********************************************************************************
3124 void IOService::start_our_change ( unsigned long queue_head
)
3126 priv
->head_note
= queue_head
;
3127 priv
->head_note_flags
= priv
->changeList
->changeNote
[priv
->head_note
].flags
;
3128 priv
->head_note_state
= priv
->changeList
->changeNote
[priv
->head_note
].newStateNumber
;
3129 priv
->imminentState
= priv
->head_note_state
;
3130 priv
->head_note_outputFlags
= priv
->changeList
->changeNote
[priv
->head_note
].outputPowerCharacter
;
3131 priv
->head_note_capabilityFlags
= priv
->changeList
->changeNote
[priv
->head_note
].capabilityFlags
;
3133 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartDeviceChange
,
3134 (unsigned long)priv
->head_note_state
,(unsigned long)pm_vars
->myCurrentState
);
3136 if ( priv
->head_note_capabilityFlags
& IOPMNotAttainable
) { // can our driver switch to the new state?
3137 if ( ! priv
->we_are_root
) { // no, ask the parent to do it then
3138 ask_parent(priv
->head_note_state
);
3140 priv
-> head_note_flags
|= IOPMNotDone
; // mark the change note un-actioned
3141 all_done(); // and we're done
3144 // is there enough power in the domain?
3145 if ( (pm_vars
->maxCapability
< priv
->head_note_state
) && (! priv
->we_are_root
) ) {
3146 if ( ! priv
->we_are_root
) { // no, ask the parent to raise it
3147 ask_parent(priv
->head_note_state
);
3149 priv
->head_note_flags
|= IOPMNotDone
; // no, mark the change note un-actioned
3150 all_done(); // and we're done
3151 return; // till the parent raises power
3154 if ( ! priv
->initial_change
) {
3155 if ( priv
->head_note_state
== pm_vars
->myCurrentState
) {
3156 all_done(); // we initiated a null change; forget it
3160 priv
->initial_change
= false;
3162 if ( priv
->head_note_state
< pm_vars
->myCurrentState
) { // dropping power?
3163 priv
->machine_state
= IOPMour_prechange_03
; // yes, in case we have to wait for acks
3164 pm_vars
->doNotPowerDown
= false;
3165 if ( askChangeDown(priv
->head_note_state
) ) { // ask apps and kernel clients if we can drop power
3166 if ( pm_vars
->doNotPowerDown
) { // don't have to wait, did any clients veto?
3167 tellNoChangeDown(priv
->head_note_state
); // yes, rescind the warning
3168 priv
-> head_note_flags
|= IOPMNotDone
; // mark the change note un-actioned
3169 all_done(); // and we're done
3172 our_prechange_03(); // no, tell'em we're dropping power
3177 if ( ! priv
->we_are_root
) { // we are raising power
3178 ask_parent(priv
->head_note_state
); // if this changes our power requirement, tell the parent
3180 priv
->machine_state
= IOPMour_prechange_1
; // in case they don't all ack
3181 if ( notifyAll(true) == IOPMAckImplied
) { // notify interested drivers and children
3188 //*********************************************************************************
3191 // Call the power domain parent to ask for a higher power state in the domain
3192 // or to suggest a lower power state.
3193 //*********************************************************************************
3195 IOReturn
IOService::ask_parent ( unsigned long requestedState
)
3199 IOPowerConnection
* connection
;
3201 unsigned long ourRequest
= pm_vars
->thePowerStates
[requestedState
].inputPowerRequirement
;
3203 if ( pm_vars
->thePowerStates
[requestedState
].capabilityFlags
& (kIOPMChildClamp
| kIOPMPreventIdleSleep
) ) {
3204 ourRequest
|= kIOPMPreventIdleSleep
;
3206 if ( pm_vars
->thePowerStates
[requestedState
].capabilityFlags
& (kIOPMChildClamp2
| kIOPMPreventSystemSleep
) ) {
3207 ourRequest
|= kIOPMPreventSystemSleep
;
3210 if ( priv
->previousRequest
== ourRequest
) { // is this a new desire?
3211 return IOPMNoErr
; // no, the parent knows already, just return
3214 if ( priv
->we_are_root
) {
3217 priv
->previousRequest
= ourRequest
;
3219 iter
= getParentIterator(gIOPowerPlane
);
3222 while ( (next
= iter
->getNextObject()) ) {
3223 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
3224 parent
= (IOService
*)connection
->copyParentEntry(gIOPowerPlane
);
3226 if ( parent
->requestPowerDomainState(ourRequest
,connection
,IOPMLowestState
)!= IOPMNoErr
) {
3227 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRequestDenied
,
3228 (unsigned long)priv
->previousRequest
,0);
3241 //*********************************************************************************
3244 // Call the controlling driver and have it change the power state of the
3245 // hardware. If it returns IOPMAckImplied, the change is complete, and
3246 // we return IOPMAckImplied. Otherwise, it will ack when the change
3247 // is done; we return IOPMWillAckLater.
3248 //*********************************************************************************
3249 IOReturn
IOService::instruct_driver ( unsigned long newState
)
3251 IOReturn return_code
;
3253 if ( pm_vars
->thePowerStates
[newState
].capabilityFlags
& IOPMNotAttainable
) { // can our driver switch to the desired state?
3254 return IOPMAckImplied
; // no, so don't try
3256 priv
->driver_timer
= -1;
3258 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogProgramHardware
,newState
,0);
3260 return_code
= pm_vars
->theControllingDriver
->setPowerState( newState
,this ); // yes, instruct it
3261 if ( return_code
== IOPMAckImplied
) { // it finished
3262 priv
->driver_timer
= 0;
3263 return IOPMAckImplied
;
3266 if ( priv
->driver_timer
== 0 ) { // it acked behind our back
3267 return IOPMAckImplied
;
3270 if ( return_code
< 0 ) { // somebody goofed
3271 return IOPMAckImplied
;
3273 priv
->driver_timer
= (return_code
* ns_per_us
/ ACK_TIMER_PERIOD
) + 1; // it didn't finish
3274 return IOPMWillAckLater
;
3278 //*********************************************************************************
3281 // We are acquiring the lock we use to protect our queue head from
3282 // simutaneous access by a thread which calls acknowledgePowerStateChange
3283 // or acknowledgeSetPowerState and the ack timer expiration thread.
3284 // Return TRUE if we acquire the lock, and the queue head didn't change
3285 // while we were acquiring the lock (and maybe blocked).
3286 // If there is no queue head, or it changes while we are blocked,
3287 // return FALSE with the lock unlocked.
3288 //*********************************************************************************
3290 bool IOService::acquire_lock ( void )
3292 long current_change_note
;
3294 current_change_note
= priv
->head_note
;
3295 if ( current_change_note
== -1 ) {
3299 IOTakeLock(priv
->our_lock
);
3300 if ( current_change_note
== priv
->head_note
) {
3303 else { // we blocked and something changed radically
3304 IOUnlock(priv
->our_lock
); // so there's nothing to do any more
3310 //*********************************************************************************
3313 // Ask registered applications and kernel clients if we can change to a lower
3316 // Subclass can override this to send a different message type. Parameter is
3317 // the destination state number.
3319 // Return true if we don't have to wait for acknowledgements
3320 //*********************************************************************************
3322 bool IOService::askChangeDown ( unsigned long stateNum
)
3324 return tellClientsWithResponse(kIOMessageCanDevicePowerOff
);
3328 //*********************************************************************************
3331 // Notify registered applications and kernel clients that we are definitely
3334 // Return true if we don't have to wait for acknowledgements
3335 //*********************************************************************************
3337 bool IOService::tellChangeDown1 ( unsigned long stateNum
)
3339 pm_vars
->outofbandparameter
= kNotifyApps
;
3340 return tellChangeDown(stateNum
);
3344 //*********************************************************************************
3347 // Notify priority clients that we are definitely dropping power.
3349 // Return true if we don't have to wait for acknowledgements
3350 //*********************************************************************************
3352 bool IOService::tellChangeDown2 ( unsigned long stateNum
)
3354 pm_vars
->outofbandparameter
= kNotifyPriority
;
3355 return tellChangeDown(stateNum
);
3359 //*********************************************************************************
3362 // Notify registered applications and kernel clients that we are definitely
3365 // Subclass can override this to send a different message type. Parameter is
3366 // the destination state number.
3368 // Return true if we don't have to wait for acknowledgements
3369 //*********************************************************************************
3371 bool IOService::tellChangeDown ( unsigned long stateNum
)
3373 return tellClientsWithResponse(kIOMessageDeviceWillPowerOff
);
3377 //*********************************************************************************
3378 // tellClientsWithResponse
3380 // Notify registered applications and kernel clients that we are definitely
3383 // Return true if we don't have to wait for acknowledgements
3384 //*********************************************************************************
3386 bool IOService::tellClientsWithResponse ( int messageType
)
3388 struct context theContext
;
3389 AbsoluteTime deadline
;
3392 pm_vars
->responseFlags
= OSArray::withCapacity( 1 );
3393 pm_vars
->serialNumber
+= 1;
3395 theContext
.responseFlags
= pm_vars
->responseFlags
;
3396 theContext
.serialNumber
= pm_vars
->serialNumber
;
3397 theContext
.flags_lock
= priv
->flags_lock
;
3398 theContext
.counter
= 1;
3399 theContext
.msgType
= messageType
;
3400 theContext
.us
= this;
3401 theContext
.maxTimeRequested
= 0;
3402 theContext
.stateNumber
= priv
->head_note_state
;
3403 theContext
.stateFlags
= priv
->head_note_capabilityFlags
;
3405 IOLockLock(priv
->flags_lock
);
3406 aBool
= OSBoolean::withBoolean(false); // position zero is false to
3407 theContext
.responseFlags
->setObject(0,aBool
); // prevent allowCancelCommon from succeeding
3409 IOLockUnlock(priv
->flags_lock
);
3411 switch ( pm_vars
->outofbandparameter
) {
3413 applyToInterested(gIOAppPowerStateInterest
,tellAppWithResponse
,(void *)&theContext
);
3414 applyToInterested(gIOGeneralInterest
,tellClientWithResponse
,(void *)&theContext
);
3416 case kNotifyPriority
:
3417 applyToInterested(gIOPriorityPowerStateInterest
,tellClientWithResponse
,(void *)&theContext
);
3421 if (! acquire_lock() ) {
3424 IOLockLock(priv
->flags_lock
);
3425 aBool
= OSBoolean::withBoolean(true); // now fix position zero
3426 theContext
.responseFlags
->replaceObject(0,aBool
);
3428 IOLockUnlock(priv
->flags_lock
);
3430 if ( ! checkForDone() ) { // we have to wait for somebody
3431 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,theContext
.maxTimeRequested
,0);
3432 clock_interval_to_deadline(theContext
.maxTimeRequested
/ 1000, kMillisecondScale
, &deadline
);
3434 thread_call_enter_delayed(priv
->ackTimer
, deadline
);
3436 IOUnlock(priv
->our_lock
); // yes
3440 IOUnlock(priv
->our_lock
);
3441 IOLockLock(priv
->flags_lock
);
3442 pm_vars
->responseFlags
->release(); // everybody responded
3443 pm_vars
->responseFlags
= NULL
;
3444 IOLockUnlock(priv
->flags_lock
);
3450 //*********************************************************************************
3451 // tellAppWithResponse
3453 // We send a message to an application, and we expect a response, so we compute a
3454 // cookie we can identify the response with.
3455 //*********************************************************************************
3456 void tellAppWithResponse ( OSObject
* object
, void * context
)
3458 struct context
* theContext
= (struct context
*)context
;
3462 if( OSDynamicCast( IOService
, object
) ) {
3463 IOLockLock(theContext
->flags_lock
);
3464 aBool
= OSBoolean::withBoolean(true);
3465 theContext
->responseFlags
->setObject(theContext
->counter
,aBool
);
3467 IOLockUnlock(theContext
->flags_lock
);
3470 refcon
= ((theContext
->serialNumber
& 0xFFFF)<<16) + (theContext
->counter
& 0xFFFF);
3471 IOLockLock(theContext
->flags_lock
);
3472 aBool
= OSBoolean::withBoolean(false);
3473 theContext
->responseFlags
->setObject(theContext
->counter
,aBool
);
3475 IOLockUnlock(theContext
->flags_lock
);
3476 theContext
->us
->messageClient(theContext
->msgType
,object
,(void *)refcon
);
3477 if ( theContext
->maxTimeRequested
< k30seconds
) {
3478 theContext
->maxTimeRequested
= k30seconds
;
3481 theContext
->counter
+= 1;
3485 //*********************************************************************************
3486 // tellClientWithResponse
3488 // We send a message to an in-kernel client, and we expect a response, so we compute a
3489 // cookie we can identify the response with.
3490 // If it doesn't understand the notification (it is not power-management savvy)
3491 // we won't wait for it to prepare for sleep. If it tells us via a return code
3492 // in the passed struct that it is currently ready, we won't wait for it to prepare.
3493 // If it tells us via the return code in the struct that it does need time, we will chill.
3494 //*********************************************************************************
3495 void tellClientWithResponse ( OSObject
* object
, void * context
)
3497 struct context
* theContext
= (struct context
*)context
;
3498 IOPowerStateChangeNotification notify
;
3504 refcon
= ((theContext
->serialNumber
& 0xFFFF)<<16) + (theContext
->counter
& 0xFFFF);
3505 IOLockLock(theContext
->flags_lock
);
3506 aBool
= OSBoolean::withBoolean(false);
3507 theContext
->responseFlags
->setObject(theContext
->counter
,aBool
);
3509 IOLockUnlock(theContext
->flags_lock
);
3511 notify
.powerRef
= (void *)refcon
;
3512 notify
.returnValue
= 0;
3513 notify
.stateNumber
= theContext
->stateNumber
;
3514 notify
.stateFlags
= theContext
->stateFlags
;
3515 retCode
= theContext
->us
->messageClient(theContext
->msgType
,object
,(void *)¬ify
);
3516 if ( retCode
== kIOReturnSuccess
) {
3517 if ( notify
.returnValue
== 0 ) { // client doesn't want time to respond
3518 IOLockLock(theContext
->flags_lock
);
3519 aBool
= OSBoolean::withBoolean(true);
3520 theContext
->responseFlags
->replaceObject(theContext
->counter
,aBool
); // so set its flag true
3522 IOLockUnlock(theContext
->flags_lock
);
3525 IOLockLock(theContext
->flags_lock
);
3526 theFlag
= theContext
->responseFlags
->getObject(theContext
->counter
); // it does want time, and it hasn't
3527 if ( theFlag
!= 0 ) { // responded yet
3528 if ( ((OSBoolean
*)theFlag
)->isFalse() ) { // so note its time requirement
3529 if ( theContext
->maxTimeRequested
< notify
.returnValue
) {
3530 theContext
->maxTimeRequested
= notify
.returnValue
;
3534 IOLockUnlock(theContext
->flags_lock
);
3537 else { // not a client of ours
3538 IOLockLock(theContext
->flags_lock
);
3539 aBool
= OSBoolean::withBoolean(true); // so we won't be waiting for response
3540 theContext
->responseFlags
->replaceObject(theContext
->counter
,aBool
);
3542 IOLockUnlock(theContext
->flags_lock
);
3544 theContext
->counter
+= 1;
3548 //*********************************************************************************
3551 // Notify registered applications and kernel clients that we are not
3554 // Subclass can override this to send a different message type. Parameter is
3555 // the aborted destination state number.
3556 //*********************************************************************************
3558 void IOService::tellNoChangeDown ( unsigned long )
3560 return tellClients(kIOMessageDeviceWillNotPowerOff
);
3564 //*********************************************************************************
3567 // Notify registered applications and kernel clients that we are raising power.
3569 // Subclass can override this to send a different message type. Parameter is
3570 // the aborted destination state number.
3571 //*********************************************************************************
3573 void IOService::tellChangeUp ( unsigned long )
3575 return tellClients(kIOMessageDeviceHasPoweredOn
);
3579 //*********************************************************************************
3582 // Notify registered applications and kernel clients of something.
3583 //*********************************************************************************
3585 void IOService::tellClients ( int messageType
)
3587 struct context theContext
;
3589 theContext
.msgType
= messageType
;
3590 theContext
.us
= this;
3591 theContext
.stateNumber
= priv
->head_note_state
;
3592 theContext
.stateFlags
= priv
->head_note_capabilityFlags
;
3594 applyToInterested(gIOAppPowerStateInterest
,tellClient
,(void *)&theContext
);
3595 applyToInterested(gIOGeneralInterest
,tellClient
,(void *)&theContext
);
3599 //*********************************************************************************
3602 // Notify a registered application or kernel client of something.
3603 //*********************************************************************************
3604 void tellClient ( OSObject
* object
, void * context
)
3606 struct context
* theContext
= (struct context
*)context
;
3607 IOPowerStateChangeNotification notify
;
3609 notify
.powerRef
= (void *) 0;
3610 notify
.returnValue
= 0;
3611 notify
.stateNumber
= theContext
->stateNumber
;
3612 notify
.stateFlags
= theContext
->stateFlags
;
3614 theContext
->us
->messageClient(theContext
->msgType
,object
, ¬ify
);
3618 // **********************************************************************************
3621 // **********************************************************************************
3622 bool IOService::checkForDone ( void )
3627 IOLockLock(priv
->flags_lock
);
3628 if ( pm_vars
->responseFlags
== NULL
) {
3629 IOLockUnlock(priv
->flags_lock
);
3632 for ( i
= 0; ; i
++ ) {
3633 theFlag
= pm_vars
->responseFlags
->getObject(i
);
3634 if ( theFlag
== NULL
) {
3637 if ( ((OSBoolean
*)theFlag
)->isFalse() ) {
3638 IOLockUnlock(priv
->flags_lock
);
3642 IOLockUnlock(priv
->flags_lock
);
3647 // **********************************************************************************
3650 // **********************************************************************************
3651 bool IOService::responseValid ( unsigned long x
)
3653 UInt16 serialComponent
;
3654 UInt16 ordinalComponent
;
3656 unsigned long refcon
= (unsigned long)x
;
3659 serialComponent
= (refcon
>>16) & 0xFFFF;
3660 ordinalComponent
= refcon
& 0xFFFF;
3662 if ( serialComponent
!= pm_vars
->serialNumber
) {
3666 IOLockLock(priv
->flags_lock
);
3667 if ( pm_vars
->responseFlags
== NULL
) {
3668 IOLockUnlock(priv
->flags_lock
);
3672 theFlag
= pm_vars
->responseFlags
->getObject(ordinalComponent
);
3674 if ( theFlag
== 0 ) {
3675 IOLockUnlock(priv
->flags_lock
);
3679 if ( ((OSBoolean
*)theFlag
)->isFalse() ) {
3680 aBool
= OSBoolean::withBoolean(true);
3681 pm_vars
->responseFlags
->replaceObject(ordinalComponent
,aBool
);
3685 IOLockUnlock(priv
->flags_lock
);
3690 // **********************************************************************************
3693 // Our power state is about to lower, and we have notified applications
3694 // and kernel clients, and one of them has acknowledged. If this is the last to do
3695 // so, and all acknowledgements are positive, we continue with the power change.
3697 // We serialize this processing with timer expiration with a command gate on the
3698 // power management workloop, which the timer expiration is command gated to as well.
3699 // **********************************************************************************
3700 IOReturn
IOService::allowPowerChange ( unsigned long refcon
)
3702 if ( ! initialized
) {
3703 return kIOReturnSuccess
; // we're unloading
3706 return pm_vars
->PMcommandGate
->runAction(serializedAllowPowerChange
,(void *)refcon
);
3710 IOReturn
serializedAllowPowerChange ( OSObject
*owner
, void * refcon
, void *, void *, void *)
3712 return ((IOService
*)owner
)->serializedAllowPowerChange2((unsigned long)refcon
);
3715 IOReturn
IOService::serializedAllowPowerChange2 ( unsigned long refcon
)
3717 if ( ! responseValid(refcon
) ) { // response valid?
3718 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr5
,refcon
,0);
3719 return kIOReturnSuccess
; // no, just return
3721 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientAcknowledge
,refcon
,0);
3723 return allowCancelCommon();
3727 // **********************************************************************************
3728 // cancelPowerChange
3730 // Our power state is about to lower, and we have notified applications
3731 // and kernel clients, and one of them has vetoed the change. If this is the last
3732 // client to respond, we abandon the power change.
3734 // We serialize this processing with timer expiration with a command gate on the
3735 // power management workloop, which the timer expiration is command gated to as well.
3736 // **********************************************************************************
3737 IOReturn
IOService::cancelPowerChange ( unsigned long refcon
)
3739 if ( ! initialized
) {
3740 return kIOReturnSuccess
; // we're unloading
3743 return pm_vars
->PMcommandGate
->runAction(serializedCancelPowerChange
,(void *)refcon
);
3747 IOReturn
serializedCancelPowerChange ( OSObject
*owner
, void * refcon
, void *, void *, void *)
3749 return ((IOService
*)owner
)->serializedCancelPowerChange2((unsigned long)refcon
);
3752 IOReturn
IOService::serializedCancelPowerChange2 ( unsigned long refcon
)
3754 if ( ! responseValid(refcon
) ) { // response valid?
3755 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr5
,refcon
,0);
3756 return kIOReturnSuccess
; // no, just return
3758 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientCancel
,refcon
,0);
3760 pm_vars
->doNotPowerDown
= true;
3762 return allowCancelCommon();
3766 // **********************************************************************************
3767 // allowCancelCommon
3769 // **********************************************************************************
3770 IOReturn
IOService::allowCancelCommon ( void )
3772 if (! acquire_lock() ) {
3773 return kIOReturnSuccess
;
3776 if ( checkForDone() ) { // is this the last response?
3777 stop_ack_timer(); // yes, stop the timer
3778 IOUnlock(priv
->our_lock
);
3779 IOLockLock(priv
->flags_lock
);
3780 if ( pm_vars
->responseFlags
) {
3781 pm_vars
->responseFlags
->release();
3782 pm_vars
->responseFlags
= NULL
;
3784 IOLockUnlock(priv
->flags_lock
);
3785 switch (priv
->machine_state
) {
3786 case IOPMour_prechange_03
: // our change, was it vetoed?
3787 if ( ! pm_vars
->doNotPowerDown
) {
3788 our_prechange_03(); // no, we can continue
3791 tellNoChangeDown(priv
->head_note_state
); // yes, rescind the warning
3792 priv
->head_note_flags
|= IOPMNotDone
; // mark the change note un-actioned
3793 all_done(); // and we're done
3796 case IOPMour_prechange_04
:
3799 case IOPMour_prechange_05
:
3800 our_prechange_05(); // our change, continue
3802 case IOPMparent_down_0
:
3803 parent_down_04(); // parent change, continue
3805 case IOPMparent_down_05
:
3806 parent_down_05(); // parent change, continue
3811 IOUnlock(priv
->our_lock
); // not done yet
3812 return kIOReturnSuccess
;
3816 //*********************************************************************************
3819 // Set to highest available power state for a minimum of duration milliseconds
3820 //*********************************************************************************
3822 #define kFiveMinutesInNanoSeconds (300 * NSEC_PER_SEC)
3824 void IOService::clampPowerOn (unsigned long duration
)
3826 changePowerStateToPriv (pm_vars
->theNumberOfPowerStates
-1);
3828 if ( priv
->clampTimerEventSrc
== NULL
) {
3829 priv
->clampTimerEventSrc
= IOTimerEventSource::timerEventSource(this,
3830 c_PM_Clamp_Timer_Expired
);
3832 IOWorkLoop
* workLoop
= getPMworkloop ();
3834 if ( !priv
->clampTimerEventSrc
|| !workLoop
||
3835 ( workLoop
->addEventSource( priv
->clampTimerEventSrc
) != kIOReturnSuccess
) ) {
3840 priv
->clampTimerEventSrc
->setTimeout(kFiveMinutesInNanoSeconds
, NSEC_PER_SEC
);
3843 //*********************************************************************************
3844 // PM_Clamp_Timer_Expired
3846 // called when clamp timer expires...set power state to 0.
3847 //*********************************************************************************
3849 void IOService::PM_Clamp_Timer_Expired (void)
3851 if ( ! initialized
) {
3852 return; // we're unloading
3855 changePowerStateToPriv (0);
3858 //*********************************************************************************
3859 // c_PM_clamp_Timer_Expired (C Func)
3861 // Called when our clamp timer expires...we will call the object method.
3862 //*********************************************************************************
3864 void c_PM_Clamp_Timer_Expired (OSObject
* client
, IOTimerEventSource
*)
3867 ((IOService
*)client
)->PM_Clamp_Timer_Expired ();
3871 //*********************************************************************************
3874 // Does nothing here. This should be implemented in a subclass driver.
3875 //*********************************************************************************
3877 IOReturn
IOService::setPowerState ( unsigned long powerStateOrdinal
, IOService
* whatDevice
)
3883 //*********************************************************************************
3884 // maxCapabilityForDomainState
3886 // Finds the highest power state in the array whose input power
3887 // requirement is equal to the input parameter. Where a more intelligent
3888 // decision is possible, override this in the subclassed driver.
3889 //*********************************************************************************
3891 unsigned long IOService::maxCapabilityForDomainState ( IOPMPowerFlags domainState
)
3895 if (pm_vars
->theNumberOfPowerStates
== 0 ) {
3898 for ( i
= (pm_vars
->theNumberOfPowerStates
)-1; i
>= 0; i
-- ) {
3899 if ( (domainState
& pm_vars
->thePowerStates
[i
].inputPowerRequirement
) == pm_vars
->thePowerStates
[i
].inputPowerRequirement
) {
3907 //*********************************************************************************
3908 // initialPowerStateForDomainState
3910 // Finds the highest power state in the array whose input power
3911 // requirement is equal to the input parameter. Where a more intelligent
3912 // decision is possible, override this in the subclassed driver.
3913 //*********************************************************************************
3915 unsigned long IOService::initialPowerStateForDomainState ( IOPMPowerFlags domainState
)
3919 if (pm_vars
->theNumberOfPowerStates
== 0 ) {
3922 for ( i
= (pm_vars
->theNumberOfPowerStates
)-1; i
>= 0; i
-- ) {
3923 if ( (domainState
& pm_vars
->thePowerStates
[i
].inputPowerRequirement
) == pm_vars
->thePowerStates
[i
].inputPowerRequirement
) {
3931 //*********************************************************************************
3932 // powerStateForDomainState
3934 // Finds the highest power state in the array whose input power
3935 // requirement is equal to the input parameter. Where a more intelligent
3936 // decision is possible, override this in the subclassed driver.
3937 //*********************************************************************************
3939 unsigned long IOService::powerStateForDomainState ( IOPMPowerFlags domainState
)
3943 if (pm_vars
->theNumberOfPowerStates
== 0 ) {
3946 for ( i
= (pm_vars
->theNumberOfPowerStates
)-1; i
>= 0; i
-- ) {
3947 if ( (domainState
& pm_vars
->thePowerStates
[i
].inputPowerRequirement
) == pm_vars
->thePowerStates
[i
].inputPowerRequirement
) {
3955 //*********************************************************************************
3958 // Does nothing here. This should be implemented in a subclass driver.
3959 //*********************************************************************************
3961 bool IOService::didYouWakeSystem ( void )
3967 //*********************************************************************************
3968 // powerStateWillChangeTo
3970 // Does nothing here. This should be implemented in a subclass driver.
3971 //*********************************************************************************
3973 IOReturn
IOService::powerStateWillChangeTo ( IOPMPowerFlags
, unsigned long, IOService
*)
3979 //*********************************************************************************
3980 // powerStateDidChangeTo
3982 // Does nothing here. This should be implemented in a subclass driver.
3983 //*********************************************************************************
3985 IOReturn
IOService::powerStateDidChangeTo ( IOPMPowerFlags
, unsigned long, IOService
*)
3991 //*********************************************************************************
3994 // Does nothing here. This should be implemented in a subclass policy-maker.
3995 //*********************************************************************************
3997 void IOService::powerChangeDone ( unsigned long )
4002 //*********************************************************************************
4005 // Does nothing here. This should be implemented in a subclass driver.
4006 //*********************************************************************************
4008 IOReturn
IOService::newTemperature ( long currentTemp
, IOService
* whichZone
)
4016 #define super OSObject
4018 OSDefineMetaClassAndStructors(IOPMprot
, OSObject
)
4019 //*********************************************************************************
4022 // Serialize protected instance variables for debug output.
4023 //*********************************************************************************
4024 bool IOPMprot::serialize(OSSerialize
*s
) const
4026 OSString
* theOSString
;
4032 buffer
= ptr
= IONew(char, 2000);
4036 ptr
+= sprintf(ptr
,"{ theNumberOfPowerStates = %d, ",(unsigned int)theNumberOfPowerStates
);
4038 if ( theNumberOfPowerStates
!= 0 ) {
4039 ptr
+= sprintf(ptr
,"version %d, ",(unsigned int)thePowerStates
[0].version
);
4042 if ( theNumberOfPowerStates
!= 0 ) {
4043 for ( i
= 0; i
< (int)theNumberOfPowerStates
; i
++ ) {
4044 ptr
+= sprintf(ptr
,"power state %d = { ",i
);
4045 ptr
+= sprintf(ptr
,"capabilityFlags %08x, ",(unsigned int)thePowerStates
[i
].capabilityFlags
);
4046 ptr
+= sprintf(ptr
,"outputPowerCharacter %08x, ",(unsigned int)thePowerStates
[i
].outputPowerCharacter
);
4047 ptr
+= sprintf(ptr
,"inputPowerRequirement %08x, ",(unsigned int)thePowerStates
[i
].inputPowerRequirement
);
4048 ptr
+= sprintf(ptr
,"staticPower %d, ",(unsigned int)thePowerStates
[i
].staticPower
);
4049 ptr
+= sprintf(ptr
,"unbudgetedPower %d, ",(unsigned int)thePowerStates
[i
].unbudgetedPower
);
4050 ptr
+= sprintf(ptr
,"powerToAttain %d, ",(unsigned int)thePowerStates
[i
].powerToAttain
);
4051 ptr
+= sprintf(ptr
,"timeToAttain %d, ",(unsigned int)thePowerStates
[i
].timeToAttain
);
4052 ptr
+= sprintf(ptr
,"settleUpTime %d, ",(unsigned int)thePowerStates
[i
].settleUpTime
);
4053 ptr
+= sprintf(ptr
,"timeToLower %d, ",(unsigned int)thePowerStates
[i
].timeToLower
);
4054 ptr
+= sprintf(ptr
,"settleDownTime %d, ",(unsigned int)thePowerStates
[i
].settleDownTime
);
4055 ptr
+= sprintf(ptr
,"powerDomainBudget %d }, ",(unsigned int)thePowerStates
[i
].powerDomainBudget
);
4059 ptr
+= sprintf(ptr
,"aggressiveness = %d, ",(unsigned int)aggressiveness
);
4060 ptr
+= sprintf(ptr
,"myCurrentState = %d, ",(unsigned int)myCurrentState
);
4061 ptr
+= sprintf(ptr
,"parentsCurrentPowerFlags = %08x, ",(unsigned int)parentsCurrentPowerFlags
);
4062 ptr
+= sprintf(ptr
,"maxCapability = %d }",(unsigned int)maxCapability
);
4064 theOSString
= OSString::withCString(buffer
);
4065 rtn_code
= theOSString
->serialize(s
);
4066 theOSString
->release();
4067 IODelete(buffer
, char, 2000);
4074 #define super OSObject
4076 OSDefineMetaClassAndStructors(IOPMpriv
, OSObject
)
4077 //*********************************************************************************
4080 // Serialize private instance variables for debug output.
4081 //*********************************************************************************
4082 bool IOPMpriv::serialize(OSSerialize
*s
) const
4084 OSString
* theOSString
;
4088 IOPMinformee
* nextObject
;
4090 buffer
= ptr
= IONew(char, 2000);
4094 ptr
+= sprintf(ptr
,"{ this object = %08x",(unsigned int)owner
);
4095 if ( we_are_root
) {
4096 ptr
+= sprintf(ptr
," (root)");
4098 ptr
+= sprintf(ptr
,", ");
4100 nextObject
= interestedDrivers
->firstInList(); // display interested drivers
4101 while ( nextObject
!= NULL
) {
4102 ptr
+= sprintf(ptr
,"interested driver = %08x, ",(unsigned int)nextObject
->whatObject
);
4103 nextObject
= interestedDrivers
->nextInList(nextObject
);
4106 if ( machine_state
!= IOPMfinished
) {
4107 ptr
+= sprintf(ptr
,"machine_state = %d, ",(unsigned int)machine_state
);
4108 ptr
+= sprintf(ptr
,"driver_timer = %d, ",(unsigned int)driver_timer
);
4109 ptr
+= sprintf(ptr
,"settle_time = %d, ",(unsigned int)settle_time
);
4110 ptr
+= sprintf(ptr
,"head_note_flags = %08x, ",(unsigned int)head_note_flags
);
4111 ptr
+= sprintf(ptr
,"head_note_state = %d, ",(unsigned int)head_note_state
);
4112 ptr
+= sprintf(ptr
,"head_note_outputFlags = %08x, ",(unsigned int)head_note_outputFlags
);
4113 ptr
+= sprintf(ptr
,"head_note_domainState = %08x, ",(unsigned int)head_note_domainState
);
4114 ptr
+= sprintf(ptr
,"head_note_capabilityFlags = %08x, ",(unsigned int)head_note_capabilityFlags
);
4115 ptr
+= sprintf(ptr
,"head_note_pendingAcks = %d, ",(unsigned int)head_note_pendingAcks
);
4118 if ( device_overrides
) {
4119 ptr
+= sprintf(ptr
,"device overrides, ");
4121 ptr
+= sprintf(ptr
,"driverDesire = %d, ",(unsigned int)driverDesire
);
4122 ptr
+= sprintf(ptr
,"deviceDesire = %d, ",(unsigned int)deviceDesire
);
4123 ptr
+= sprintf(ptr
,"ourDesiredPowerState = %d, ",(unsigned int)ourDesiredPowerState
);
4124 ptr
+= sprintf(ptr
,"previousRequest = %d }",(unsigned int)previousRequest
);
4126 theOSString
= OSString::withCString(buffer
);
4127 rtn_code
= theOSString
->serialize(s
);
4128 theOSString
->release();
4129 IODelete(buffer
, char, 2000);