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/IOCommandGate.h>
26 #include <IOKit/IOTimerEventSource.h>
27 #include <IOKit/IOWorkLoop.h>
28 #include <IOKit/IOPlatformExpert.h>
29 #include <IOKit/assert.h>
30 #include <IOKit/IOMessage.h>
31 #include <IOKit/IOKitDebug.h>
32 #include <IOKit/IOTimeStamp.h>
33 #include <IOKit/pwr_mgt/IOPMinformee.h>
34 #include "IOKit/pwr_mgt/IOPMinformeeList.h"
35 #include "IOKit/pwr_mgt/IOPMchangeNoteList.h"
36 #include "IOKit/pwr_mgt/IOPMlog.h"
37 #include "IOKit/pwr_mgt/IOPowerConnection.h"
38 #include <kern/clock.h>
40 #define super IORegistryEntry
42 // Some debug functions
44 ioSPMTrace(unsigned int csc
,
45 unsigned int a
= 0, unsigned int b
= 0,
46 unsigned int c
= 0, unsigned int d
= 0)
48 if (gIOKitDebug
& kIOLogTracePower
)
49 IOTimeStampConstant(IODBG_POWER(csc
), a
, b
, c
, d
);
53 ioSPMTraceStart(unsigned int csc
,
54 unsigned int a
= 0, unsigned int b
= 0,
55 unsigned int c
= 0, unsigned int d
= 0)
57 if (gIOKitDebug
& kIOLogTracePower
)
58 IOTimeStampConstant(IODBG_POWER(csc
)|DBG_FUNC_START
, a
, b
, c
, d
);
62 ioSPMTraceEnd(unsigned int csc
,
63 unsigned int a
= 0, unsigned int b
= 0,
64 unsigned int c
= 0, unsigned int d
= 0)
66 if (gIOKitDebug
& kIOLogTracePower
)
67 IOTimeStampConstant(IODBG_POWER(csc
)|DBG_FUNC_END
, a
, b
, c
, d
);
71 static void ack_timer_expired(thread_call_param_t
);
72 static void settle_timer_expired(thread_call_param_t
);
73 IOReturn
unIdleDevice ( OSObject
*, void *, void *, void *, void * );
74 static void PM_idle_timer_expired(OSObject
*, IOTimerEventSource
*);
75 static void c_PM_Clamp_Timer_Expired (OSObject
* client
,IOTimerEventSource
*);
76 void tellAppWithResponse ( OSObject
* object
, void * context
);
77 void tellClientWithResponse ( OSObject
* object
, void * context
);
78 void tellClient ( OSObject
* object
, void * context
);
79 IOReturn
serializedAllowPowerChange ( OSObject
*, void *, void *, void *, void *);
80 IOReturn
serializedCancelPowerChange ( OSObject
*, void *, void *, void *, void *);
82 extern const IORegistryPlane
* gIOPowerPlane
;
85 // and there's 1000 nanoseconds in a microsecond:
86 #define ns_per_us 1000
89 // The current change note is processed by a state machine.
90 // Inputs are acks from interested parties, ack from the controlling driver,
91 // ack timeouts, settle timeout, and powerStateDidChange from the parent.
92 // These are the states:
95 IOPMour_prechange_03
= 1,
117 enum { // values of outofbandparameter
122 struct context
{ // used for applyToInterested
123 OSArray
* responseFlags
;
126 UInt32 maxTimeRequested
;
130 unsigned long stateNumber
;
131 IOPMPowerFlags stateFlags
;
134 // five minutes in microseconds
135 #define FIVE_MINUTES 5*60*1000000
136 #define k30seconds 30*1000000
139 There are two different kinds of power state changes. One is initiated by a subclassed device object which has either
140 decided to change power state, or its controlling driver has suggested it, or some other driver wants to use the
141 idle device and has asked it to become usable. The second kind of power state change is initiated by the power
142 domain parent. The two are handled slightly differently.
144 There is a queue of so-called change notifications, or change notes for short. Usually the queue is empty, and when
145 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
146 at one time, a queue is implemented. Example: the subclass device decides it's idle and initiates a change to a lower
147 power state. This causes interested parties to be notified, but they don't all acknowledge right away. This causes the
148 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
149 wants to raise power back up again. This change can't be started, however, because the previous one isn't complete yet,
150 so the second one waits in the queue. During this time, the parent decides to lower or raise the power state of the entire
151 power domain and notifies the device, and that notification goes into the queue, too, and can't be actioned until the
154 This is how a power change initiated by the subclass device is handled:
155 First, all interested parties are notified of the change via their powerStateWillChangeTo method. If they all don't
156 acknowledge via return code, then we have to wait. If they do, or when they finally all acknowledge via our
157 acknowledgePowerChange method, then we can continue. We call the controlling driver, instructing it to change to
158 the new state. Then we wait for power to settle. If there is no settling-time, or after it has passed, we notify
159 interested parties again, this time via their powerStateDidChangeTo methods. When they have all acked, we're done.
160 If we lowered power and don't need the power domain to be in its current power state, we suggest to the parent that
161 it lower the power domain state.
163 This is how a change to a lower power domain state initiated by the parent is handled:
164 First, we figure out what power state we will be in when the new domain state is reached. Then all interested parties are
165 notified that we are moving to that new state. When they have acknowledged, we call the controlling driver to assume
166 that state and we wait for power to settle. Then we acknowledge our preparedness to our parent. When all its interested
167 parties have acknowledged, it lowers power and then notifies its interested parties again. When we get this call, we notify
168 our interested parties that the power state has changed, and when they have all acknowledged, we're done.
170 This is how a change to a higher power domain state initiated by the parent is handled:
171 We figure out what power state we will be in when the new domain state is reached. If it is different from our current
172 state we acknowledge the parent. When all the parent's interested parties have acknowledged, it raises power in the
173 domain and waits for power to settle. Then it notifies everyone that the new state has been reached. When we get this call,
174 we call the controlling driver, instructing it to assume the new state, and wait for power to settle. Then we notify our interested
175 parties. When they all acknowledge we are done.
177 In either of the two cases above, it is possible that we will not be changing state even though the domain is. Examples:
178 A change to a lower domain state may not affect us because we are already in a low enough state, and
179 We will not take advantage of a change to a higher domain state, because we have no need of the higher power.
180 In such a case, there is nothing to do but acknowledge the parent. So when the parent calls our powerDomainWillChange
181 method, and we decide that we will not be changing state, we merely acknowledge the parent, via return code, and wait.
182 When the parent subsequently calls powerStateDidChange, we acknowledge again via return code, and the change is complete.
184 Power state changes are processed in a state machine, and since there are four varieties of power state changes, there are
185 four major paths through the state machine:
187 The fourth is nearly trivial. In this path, the parent is changing the domain state, but we are not changing the device state.
188 The change starts when the parent calls powerDomainWillChange. All we do is acknowledge the parent.
189 When the parent calls powerStateDidChange, we acknowledge the parent again, and we're done.
191 The first is fairly simple. It starts when a power domain child calls requestPowerDomainState and we decide to change power states
192 to accomodate the child, or if our power-controlling driver calls changePowerStateTo, or if some other driver which is using our
193 device calls makeUsable, or if a subclassed object calls changePowerStateToPriv. These are all power changes initiated by us, not
194 forced upon us by the parent. We start by notifying interested parties. If they all acknowledge via return code, we can go
195 on to state "our_prechange_1". Otherwise, we start the ack timer and wait for the stragglers to acknowlege by calling
196 acknowledgePowerChange. We move on to state "our_prechange_1" when all the stragglers have acknowledged,
197 or when the ack timer expires on all those which didn't acknowledge. In "our_prechange_1" we call the power-controlling
198 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".
199 Otherwise, we have to wait for it, so we set the ack timer and wait. When it calls acknowledgeSetPowerState, or when the
200 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
201 when changing from our current state to the new state. If not, we go right away to "our_prechange_3". Otherwise, we
202 set the settle timer and wait. When it expires, we move on. In "our_prechange_3" state, we notify all our interested parties
203 via their powerStateDidChange methods that we have finished changing power state. If they all acknowledge via return
204 code, we move on to "our_prechange_4". Otherwise we set the ack timer and wait. When they have all acknowledged, or
205 when the ack timer has expired for those that didn't, we move on to "our_prechange_4", where we remove the used
206 change note from the head of the queue and start the next one if one exists.
208 Parent-initiated changes are more complex in the state machine. First, power going up and power going down are handled
209 differently, so they have different paths throught the state machine. Second, we can acknowledge the parent's notification
210 in two different ways, so each of the parent paths is really two.
212 When the parent calls our powerDomainWillChange method, notifying us that it will lower power in the domain, we decide
213 what state that will put our device in. Then we embark on the state machine path "IOPMparent_down_1"
214 and "IOPMparent_down_2", in which we notify interested parties of the upcoming change, instruct our driver to make
215 the change, check for settle time, and notify interested parties of the completed change. If we get to the end of this path without
216 stalling due to an interested party which didn't acknowledge via return code, due to the controlling driver not able to change
217 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.
218 If we do stall in any of those states, we return IOPMWillAckLater to the parent and enter the parallel path "IOPMparent_down_4"
219 "IOPMparent_down_5", and "IOPMparent_down_3", where we continue with the same processing, except that at the end we
220 acknowledge the parent explicitly via acknowledgePowerChange, and we're done with the change.
221 Then when the parent calls us at powerStateDidChange we acknowledging via return code, because we have already made
222 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.
224 The case of the parent raising power in the domain is handled similarly in that there are parallel paths, one for no-stall
225 that ends in implicit acknowleging the parent, and one that has stalled at least once that ends in explicit acknowledging
226 the parent. This case is different, though in that our device changes state in the second half, after the parent calls
227 powerStateDidChange rather than before, as in the power-lowering case.
229 When the parent calls our powerDomainWillChange method, notifying us that it will raise power in the domain, we acknowledge
230 via return code, because there's really nothing we can do until the power is actually raised in the domain.
231 When the parent calls us at powerStateDidChange, we start by notifying our interested parties. If they all acknowledge via return code,
232 we go on to" IOPMparent_up_1" to instruct the driver to raise its power level. After that, we check for any
233 necessary settling time in "IOPMparent_up_2", and we notify all interested parties that power has changed
234 in "IOPMparent_up_3". If none of these operations stall, we acknowledge the parent via return code, release
235 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",
236 "IOPMparent_up_4", "IOPMparent_up_5", and "IOPMparent_up_6", which ends with
237 our explicit acknowledgement to the parent.
242 const char priv_key
[ ] = "Power Management private data";
243 const char prot_key
[ ] = "Power Management protected data";
246 void IOService::PMinit ( void )
248 if ( ! initialized
) {
250 pm_vars
= new IOPMprot
; // make space for our variables
255 setProperty(prot_key
, (OSObject
*) pm_vars
); // add these to the properties
256 setProperty(priv_key
, (OSObject
*) priv
);
259 pm_vars
->theNumberOfPowerStates
= 0; // then initialize them
260 priv
->we_are_root
= false;
261 pm_vars
->theControllingDriver
= NULL
;
262 priv
->our_lock
= IOLockAlloc();
263 priv
->flags_lock
= IOLockAlloc();
264 priv
->queue_lock
= IOLockAlloc();
265 pm_vars
->childLock
= IOLockAlloc();
266 pm_vars
->parentLock
= IOLockAlloc();
267 priv
->interestedDrivers
= new IOPMinformeeList
;
268 priv
->interestedDrivers
->initialize();
269 priv
->changeList
= new IOPMchangeNoteList
;
270 priv
->changeList
->initialize();
271 pm_vars
->aggressiveness
= 0;
272 for (unsigned int i
= 0; i
<= kMaxType
; i
++) {
273 pm_vars
->current_aggressiveness_values
[i
] = 0;
274 pm_vars
->current_aggressiveness_valid
[i
] = false;
276 pm_vars
->myCurrentState
= 0;
277 priv
->imminentState
= 0;
278 priv
->ourDesiredPowerState
= 0;
279 pm_vars
->parentsCurrentPowerFlags
= 0;
280 pm_vars
->maxCapability
= 0;
281 priv
->driverDesire
= 0;
282 priv
->deviceDesire
= 0;
283 priv
->initial_change
= true;
284 priv
->need_to_become_usable
= false;
285 priv
->previousRequest
= 0;
286 priv
->device_overrides
= false;
287 priv
->machine_state
= IOPMfinished
;
288 priv
->timerEventSrc
= NULL
;
289 priv
->clampTimerEventSrc
= NULL
;
290 pm_vars
->PMworkloop
= NULL
;
291 priv
->activityLock
= NULL
;
292 pm_vars
->ourName
= getName();
293 pm_vars
->thePlatform
= getPlatform();
294 pm_vars
->parentsKnowState
= false;
295 assert( pm_vars
->thePlatform
!= 0 );
296 priv
->clampOn
= false;
297 pm_vars
->serialNumber
= 0;
298 pm_vars
->responseFlags
= NULL
;
299 pm_vars
->doNotPowerDown
= true;
300 pm_vars
->PMcommandGate
= NULL
;
301 priv
->ackTimer
= thread_call_allocate((thread_call_func_t
)ack_timer_expired
, (thread_call_param_t
)this);
302 priv
->settleTimer
= thread_call_allocate((thread_call_func_t
)settle_timer_expired
, (thread_call_param_t
)this);
308 //*********************************************************************************
311 // Free up the data created in PMinit, if it exists.
312 //*********************************************************************************
313 void IOService::PMfree ( void )
316 if ( priv
->clampTimerEventSrc
!= NULL
) {
317 getPMworkloop()->removeEventSource(priv
->clampTimerEventSrc
);
318 priv
->clampTimerEventSrc
->release();
319 priv
->clampTimerEventSrc
= NULL
;
321 if ( priv
->timerEventSrc
!= NULL
) {
322 pm_vars
->PMworkloop
->removeEventSource(priv
->timerEventSrc
);
323 priv
->timerEventSrc
->release();
324 priv
->timerEventSrc
= NULL
;
326 if ( priv
->settleTimer
) {
327 thread_call_cancel(priv
->settleTimer
);
328 thread_call_free(priv
->settleTimer
);
329 priv
->settleTimer
= NULL
;
331 if ( priv
->ackTimer
) {
332 thread_call_cancel(priv
->ackTimer
);
333 thread_call_free(priv
->ackTimer
);
334 priv
->ackTimer
= NULL
;
336 if ( priv
->our_lock
) {
337 IOLockFree(priv
->our_lock
);
338 priv
->our_lock
= NULL
;
340 if ( priv
->flags_lock
) {
341 IOLockFree(priv
->flags_lock
);
342 priv
->flags_lock
= NULL
;
344 if ( priv
->activityLock
) {
345 IOLockFree(priv
->activityLock
);
346 priv
->activityLock
= NULL
;
348 priv
->interestedDrivers
->release();
349 priv
->changeList
->release();
350 priv
->release(); // remove instance variables
354 if ( pm_vars
->PMcommandGate
) {
355 pm_vars
->PMcommandGate
->release();
356 pm_vars
->PMcommandGate
= NULL
;
358 if ( pm_vars
->PMworkloop
) {
359 // The work loop object returned from getPMworkLoop() is
360 // never retained, therefore it should not be released.
361 // pm_vars->PMworkloop->release();
362 pm_vars
->PMworkloop
= NULL
;
364 if ( pm_vars
->responseFlags
) {
365 pm_vars
->responseFlags
->release();
366 pm_vars
->responseFlags
= NULL
;
368 pm_vars
->release(); // remove instance variables
373 //*********************************************************************************
376 // Disconnect the node from its parents and children in the Power Plane.
377 //*********************************************************************************
378 void IOService::PMstop ( void )
382 IOPowerConnection
* connection
;
383 IOService
* theChild
;
384 IOService
* theParent
;
386 removeProperty(prot_key
); // remove the properties
387 removeProperty(priv_key
);
389 iter
= getParentIterator(gIOPowerPlane
); // detach parents
392 while ( (next
= iter
->getNextObject()) ) {
393 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
394 theParent
= (IOService
*)connection
->copyParentEntry(gIOPowerPlane
);
396 theParent
->removePowerChild(connection
);
397 theParent
->release();
403 detachAbove( gIOPowerPlane
); // detach IOConnections
405 pm_vars
->parentsKnowState
= false; // no more power state changes
407 iter
= getChildIterator(gIOPowerPlane
); // detach children
410 while ( (next
= iter
->getNextObject()) ) {
411 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
412 theChild
= ((IOService
*)(connection
->copyChildEntry(gIOPowerPlane
)));
414 connection
->detachFromChild(theChild
,gIOPowerPlane
); // detach nub from child
417 detachFromChild(connection
,gIOPowerPlane
); // detach us from nub
423 // Remove all interested drivers from the list, including the power
424 // controlling driver.
426 // Usually, the controlling driver and the policy-maker functionality
427 // are implemented by the same object, and without the deregistration,
428 // the object will be holding an extra retain on itself, and cannot
431 if ( priv
&& priv
->interestedDrivers
)
433 IOPMinformee
* informee
;
435 while (( informee
= priv
->interestedDrivers
->firstInList() ))
436 deRegisterInterestedDriver( informee
->whatObject
);
441 //*********************************************************************************
444 // A policy-maker calls its nub here when initializing, to be attached into
445 // the power management hierarchy. The default function is to call the
446 // platform expert, which knows how to do it. This method is overridden
447 // by a nub subclass which may either know how to do it, or may need
448 // to take other action.
450 // This may be the only "power management" method used in a nub,
451 // meaning it may not be initialized for power management.
452 //*********************************************************************************
453 void IOService::joinPMtree ( IOService
* driver
)
455 IOPlatformExpert
* thePlatform
;
457 thePlatform
= getPlatform();
458 assert(thePlatform
!= 0 );
459 thePlatform
->PMRegisterDevice(this,driver
);
463 //*********************************************************************************
466 // Power Managment is informing us that we are the root power domain.
467 // The only difference between us and any other power domain is that
468 // we have no parent and therefore never call it.
469 //*********************************************************************************
470 IOReturn
IOService::youAreRoot ( void )
472 priv
-> we_are_root
= true;
473 pm_vars
->parentsKnowState
= true;
474 attachToParent( getRegistryRoot(),gIOPowerPlane
);
480 //*********************************************************************************
483 // Power Management is informing us who our parent is.
484 // If we have a controlling driver, find out, given our newly-informed
485 // power domain state, what state it would be in, and then tell it
486 // to assume that state.
487 //*********************************************************************************
488 IOReturn
IOService::setPowerParent ( IOPowerConnection
* theParent
, bool stateKnown
, IOPMPowerFlags currentState
)
492 IOPowerConnection
* connection
;
493 unsigned long tempDesire
;
495 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogSetParent
,stateKnown
,currentState
);
497 IOLockLock(pm_vars
->parentLock
);
499 if ( stateKnown
&& ((pm_vars
->PMworkloop
== NULL
) || (pm_vars
->PMcommandGate
== NULL
)) ) {
500 getPMworkloop(); // we have a path to the root
501 if ( pm_vars
->PMworkloop
!= NULL
) { // find out the workloop
502 if ( pm_vars
->PMcommandGate
== NULL
) { // and make our command gate
503 pm_vars
->PMcommandGate
= IOCommandGate::commandGate((OSObject
*)this);
504 if ( pm_vars
->PMcommandGate
!= NULL
) {
505 pm_vars
->PMworkloop
->addEventSource(pm_vars
->PMcommandGate
);
511 IOLockUnlock(pm_vars
->parentLock
);
513 theParent
->setParentCurrentPowerFlags(currentState
); // set our connection data
514 theParent
->setParentKnowsState(stateKnown
);
516 pm_vars
->parentsKnowState
= true; // combine parent knowledge
517 pm_vars
->parentsCurrentPowerFlags
= 0;
519 iter
= getParentIterator(gIOPowerPlane
);
522 while ( (next
= iter
->getNextObject()) ) {
523 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
524 pm_vars
->parentsKnowState
&= connection
->parentKnowsState();
525 pm_vars
->parentsCurrentPowerFlags
|= connection
->parentCurrentPowerFlags();
531 if ( (pm_vars
->theControllingDriver
!= NULL
) &&
532 (pm_vars
->parentsKnowState
) ) {
533 pm_vars
->maxCapability
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(pm_vars
->parentsCurrentPowerFlags
);
534 tempDesire
= priv
->deviceDesire
; // initially change into the state we are already in
535 priv
->deviceDesire
= pm_vars
->theControllingDriver
->initialPowerStateForDomainState(pm_vars
->parentsCurrentPowerFlags
);
536 computeDesiredState();
537 priv
->previousRequest
= 0xffffffff;
539 priv
->deviceDesire
= tempDesire
; // put this back like before
546 //*********************************************************************************
549 // Power Management is informing us who our children are.
550 //*********************************************************************************
551 IOReturn
IOService::addPowerChild ( IOService
* theChild
)
553 IOPowerConnection
* connection
;
556 if ( ! initialized
) {
557 return IOPMNotYetInitialized
; // we're not a power-managed IOService
560 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAddChild
,0,0);
562 connection
= new IOPowerConnection
; // make a nub
565 connection
->start(this);
566 connection
->setAwaitingAck(false);
568 attachToChild( connection
,gIOPowerPlane
); // connect it up
569 connection
->attachToChild( theChild
,gIOPowerPlane
);
570 connection
->release();
572 if ( (pm_vars
->theControllingDriver
== NULL
) || // tell it the current state of the power domain
573 ! (inPlane(gIOPowerPlane
)) ||
574 ! (pm_vars
->parentsKnowState
) ) {
575 theChild
->setPowerParent(connection
,false,0);
576 if ( inPlane(gIOPowerPlane
) ) {
577 for (i
= 0; i
<= kMaxType
; i
++) {
578 if ( pm_vars
->current_aggressiveness_valid
[i
] ) {
579 theChild
->setAggressiveness (i
, pm_vars
->current_aggressiveness_values
[i
]);
585 theChild
->setPowerParent(connection
,true,pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].outputPowerCharacter
);
586 for (i
= 0; i
<= kMaxType
; i
++) {
587 if ( pm_vars
->current_aggressiveness_valid
[i
] ) {
588 theChild
->setAggressiveness (i
, pm_vars
->current_aggressiveness_values
[i
]);
591 add_child_to_active_change(connection
); // catch it up if change is in progress
598 //*********************************************************************************
601 //*********************************************************************************
602 IOReturn
IOService::removePowerChild ( IOPowerConnection
* theNub
)
604 IORegistryEntry
* theChild
;
606 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRemoveChild
,0,0);
610 theChild
= theNub
->copyChildEntry(gIOPowerPlane
); // detach nub from child
612 theNub
->detachFromChild(theChild
, gIOPowerPlane
);
615 detachFromChild(theNub
,gIOPowerPlane
); // detach from the nub
617 if ( theNub
->getAwaitingAck() ) { // are we awaiting an ack from this child?
618 theNub
->setAwaitingAck(false); // yes, pretend we got one
619 if ( acquire_lock() ) {
620 if (priv
->head_note_pendingAcks
!= 0 ) {
621 priv
->head_note_pendingAcks
-= 1; // that's one fewer ack to worry about
622 if ( priv
->head_note_pendingAcks
== 0 ) { // is that the last?
623 stop_ack_timer(); // yes, stop the timer
624 IOUnlock(priv
->our_lock
);
625 all_acked(); // and now we can continue our power change
628 IOUnlock(priv
->our_lock
);
632 IOUnlock(priv
->our_lock
);
639 if ( (pm_vars
->theControllingDriver
== NULL
) || // if not fully initialized
640 ! (inPlane(gIOPowerPlane
)) ||
641 ! (pm_vars
->parentsKnowState
) ) {
642 return IOPMNoErr
; // we can do no more
645 computeDesiredState(); // this may be different now
646 changeState(); // change state if we can now tolerate lower power
652 //*********************************************************************************
653 // registerPowerDriver
655 // A driver has called us volunteering to control power to our device.
656 // If the power state array it provides is richer than the one we already
657 // know about (supplied by an earlier volunteer), then accept the offer.
658 // Notify all interested parties of our power state, which we now know.
659 //*********************************************************************************
661 IOReturn
IOService::registerPowerDriver ( IOService
* controllingDriver
, IOPMPowerState
* powerStates
, unsigned long numberOfStates
)
664 unsigned long tempDesire
;
666 if ( (numberOfStates
> pm_vars
->theNumberOfPowerStates
) && (numberOfStates
> 1) ) {
667 if ( priv
->changeList
->currentChange() == -1 ) {
668 if ( controllingDriver
!= NULL
) {
669 if ( numberOfStates
<= IOPMMaxPowerStates
) {
670 switch ( powerStates
[0].version
) {
672 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriver
,
673 (unsigned long)numberOfStates
, (unsigned long)powerStates
[0].version
);
674 for ( i
= 0; i
< numberOfStates
; i
++ ) {
675 pm_vars
->thePowerStates
[i
] = powerStates
[i
];
679 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriver
,
680 (unsigned long) numberOfStates
,(unsigned long) powerStates
[0].version
);
681 for ( i
= 0; i
< numberOfStates
; i
++ ) {
682 pm_vars
->thePowerStates
[i
].version
= powerStates
[i
].version
;
683 pm_vars
->thePowerStates
[i
].capabilityFlags
= powerStates
[i
].capabilityFlags
;
684 pm_vars
->thePowerStates
[i
].outputPowerCharacter
= powerStates
[i
].outputPowerCharacter
;
685 pm_vars
->thePowerStates
[i
].inputPowerRequirement
= powerStates
[i
].inputPowerRequirement
;
686 pm_vars
->thePowerStates
[i
].staticPower
= powerStates
[i
].staticPower
;
687 pm_vars
->thePowerStates
[i
].unbudgetedPower
= powerStates
[i
].unbudgetedPower
;
688 pm_vars
->thePowerStates
[i
].powerToAttain
= powerStates
[i
].powerToAttain
;
689 pm_vars
->thePowerStates
[i
].timeToAttain
= powerStates
[i
].timeToAttain
;
690 pm_vars
->thePowerStates
[i
].settleUpTime
= powerStates
[i
].settleUpTime
;
691 pm_vars
->thePowerStates
[i
].timeToLower
= powerStates
[i
].timeToLower
;
692 pm_vars
->thePowerStates
[i
].settleDownTime
= powerStates
[i
].settleDownTime
;
693 pm_vars
->thePowerStates
[i
].powerDomainBudget
= powerStates
[i
].powerDomainBudget
;
697 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr1
,
698 (unsigned long)powerStates
[0].version
,0);
702 pm_vars
->myCharacterFlags
= 0; // make a mask of all the character bits we know about
703 for ( i
= 0; i
< numberOfStates
; i
++ ) {
704 pm_vars
->myCharacterFlags
|= pm_vars
->thePowerStates
[i
].outputPowerCharacter
;
707 pm_vars
->theNumberOfPowerStates
= numberOfStates
;
708 pm_vars
->theControllingDriver
= controllingDriver
;
709 if ( priv
->interestedDrivers
->findItem(controllingDriver
) == NULL
) { // register it as interested
710 registerInterestedDriver (controllingDriver
); // unless already done
712 if ( priv
->need_to_become_usable
) {
713 priv
->need_to_become_usable
= false;
714 priv
->deviceDesire
= pm_vars
->theNumberOfPowerStates
- 1;
717 if ( inPlane(gIOPowerPlane
) &&
718 (pm_vars
->parentsKnowState
) ) {
719 pm_vars
->maxCapability
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(pm_vars
->parentsCurrentPowerFlags
);
720 tempDesire
= priv
->deviceDesire
; // initially change into the state we are already in
721 priv
->deviceDesire
= pm_vars
->theControllingDriver
->initialPowerStateForDomainState(pm_vars
->parentsCurrentPowerFlags
);
722 computeDesiredState();
724 priv
->deviceDesire
= tempDesire
; // put this back like before
728 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr2
,(unsigned long)numberOfStates
,0);
732 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr4
,0,0);
737 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr5
,(unsigned long)numberOfStates
,0);
742 //*********************************************************************************
743 // registerInterestedDriver
745 // Add the caller to our list of interested drivers and return our current
746 // power state. If we don't have a power-controlling driver yet, we will
747 // call this interested driver again later when we do get a driver and find
748 // out what the current power state of the device is.
749 //*********************************************************************************
751 IOPMPowerFlags
IOService::registerInterestedDriver ( IOService
* theDriver
)
753 IOPMinformee
* newInformee
;
754 IOPMPowerFlags futureCapability
;
756 if (theDriver
== NULL
) {
760 newInformee
= new IOPMinformee
; // make new driver node
761 newInformee
->initialize(theDriver
);
762 priv
->interestedDrivers
->addToList(newInformee
); // add it to list of drivers
764 if ( (pm_vars
->theControllingDriver
== NULL
) ||
765 ! (inPlane(gIOPowerPlane
)) ||
766 ! (pm_vars
->parentsKnowState
) ) {
767 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInterestedDriver
,IOPMNotPowerManaged
,0);
768 return IOPMNotPowerManaged
; // can't tell it a state yet
771 switch (priv
->machine_state
) { // can we notify new driver of a change in progress?
772 case IOPMour_prechange_1
:
773 case IOPMour_prechange_4
:
774 case IOPMparent_down_4
:
775 case IOPMparent_down_6
:
776 case IOPMparent_up_0
:
777 case IOPMparent_up_6
:
778 futureCapability
= priv
->head_note_capabilityFlags
; // yes, remember what we tell it
779 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInterestedDriver
,(unsigned long)futureCapability
,1);
780 add_driver_to_active_change(newInformee
); // notify it
781 return futureCapability
; // and return the same thing
784 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInterestedDriver
,
785 (unsigned long) pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
,2);
786 return pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
; // no, return current capability
790 //*********************************************************************************
791 // deRegisterInterestedDriver
793 //*********************************************************************************
794 IOReturn
IOService::deRegisterInterestedDriver ( IOService
* theDriver
)
796 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRemoveDriver
,0,0);
798 priv
->interestedDrivers
->removeFromList(theDriver
); // remove the departing driver
804 //*********************************************************************************
805 // acknowledgePowerChange
807 // After we notified one of the interested drivers or a power-domain child
808 // of an impending change in power, it has called to say it is now
809 // prepared for the change. If this object is the last to
810 // acknowledge this change, we take whatever action we have been waiting
812 // That may include acknowledging to our parent. In this case, we do it
813 // last of all to insure that this doesn't cause the parent to call us some-
814 // where else and alter data we are relying on here (like the very existance
815 // of a "current change note".)
816 //*********************************************************************************
818 IOReturn
IOService::acknowledgePowerChange ( IOService
* whichObject
)
820 IOPMinformee
* ackingObject
;
821 unsigned long childPower
= kIOPMUnknown
;
822 IOService
* theChild
;
824 ackingObject
= priv
->interestedDrivers
->findItem(whichObject
); // one of our interested drivers?
825 if ( ackingObject
== NULL
) {
826 if ( ! isChild(whichObject
,gIOPowerPlane
) ) {
827 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr1
,0,0);
828 kprintf("errant driver: %s\n",whichObject
->getName());
829 return IOPMNoErr
; // no, just return
832 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChildAcknowledge
,priv
->head_note_pendingAcks
,0);
836 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogDriverAcknowledge
,priv
->head_note_pendingAcks
,0);
839 if (! acquire_lock() ) {
843 if (priv
->head_note_pendingAcks
!= 0 ) { // yes, make sure we're expecting acks
844 if ( ackingObject
!= NULL
) { // it's an interested driver
845 if ( ackingObject
->timer
!= 0 ) { // make sure we're expecting this ack
846 ackingObject
->timer
= 0; // mark it acked
847 priv
->head_note_pendingAcks
-= 1; // that's one fewer to worry about
848 if ( priv
->head_note_pendingAcks
== 0 ) { // is that the last?
849 stop_ack_timer(); // yes, stop the timer
850 IOUnlock(priv
->our_lock
);
851 all_acked(); // and now we can continue
856 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr2
,0,0); // this driver has already acked
857 kprintf("errant driver: %s\n",whichObject
->getName());
860 else { // it's a child
861 if ( ((IOPowerConnection
*)whichObject
)->getAwaitingAck() ) { // make sure we're expecting this ack
862 priv
->head_note_pendingAcks
-= 1; // that's one fewer to worry about
863 ((IOPowerConnection
*)whichObject
)->setAwaitingAck(false);
864 theChild
= (IOService
*)whichObject
->copyChildEntry(gIOPowerPlane
);
866 childPower
= theChild
->currentPowerConsumption();
869 if ( childPower
== kIOPMUnknown
) {
870 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
= kIOPMUnknown
;
873 if ( pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
!= kIOPMUnknown
) {
874 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
+= childPower
;
877 if ( priv
->head_note_pendingAcks
== 0 ) { // is that the last?
878 stop_ack_timer(); // yes, stop the timer
879 IOUnlock(priv
->our_lock
);
880 all_acked(); // and now we can continue
887 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr3
,0,0); // not expecting anybody to ack
888 kprintf("errant driver: %s\n",whichObject
->getName());
890 IOUnlock(priv
->our_lock
);
894 //*********************************************************************************
895 // acknowledgeSetPowerState
897 // After we instructed our controlling driver to change power states,
898 // it has called to say it has finished doing so.
899 // We continue to process the power state change.
900 //*********************************************************************************
902 IOReturn
IOService::acknowledgeSetPowerState ( void )
904 if (! acquire_lock() ) {
908 ioSPMTrace(IOPOWER_ACK
, * (int *) this);
910 if ( priv
->driver_timer
== -1 ) {
911 priv
->driver_timer
= 0; // driver is acking instead of using return code
914 if ( priv
->driver_timer
> 0 ) { // are we expecting this?
915 stop_ack_timer(); // yes, stop the timer
916 priv
->driver_timer
= 0;
917 IOUnlock(priv
->our_lock
);
918 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogDriverAcknowledgeSet
,0,0);
923 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr4
,0,0); // no
926 IOUnlock(priv
->our_lock
);
931 //*********************************************************************************
934 // Either the controlling driver has called acknowledgeSetPowerState
935 // or the acknowledgement timer has expired while waiting for that.
936 // We carry on processing the current change note.
937 //*********************************************************************************
939 void IOService::driver_acked ( void )
941 switch (priv
->machine_state
) {
942 case IOPMour_prechange_2
:
945 case IOPMparent_down_5
:
948 case IOPMparent_up_4
:
955 //*********************************************************************************
956 // powerDomainWillChangeTo
958 // Called by the power-hierarchy parent notifying of a new power state
959 // in the power domain.
960 // We enqueue a parent power-change to our queue of power changes.
961 // This may or may not cause us to change power, depending on what
962 // kind of change is occuring in the domain.
963 //*********************************************************************************
965 IOReturn
IOService::powerDomainWillChangeTo ( IOPMPowerFlags newPowerStateFlags
, IOPowerConnection
* whichParent
)
969 IOPowerConnection
* connection
;
970 unsigned long newStateNumber
;
971 IOPMPowerFlags combinedPowerFlags
;
973 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogWillChange
,(unsigned long)newPowerStateFlags
,0);
975 if ( ! inPlane(gIOPowerPlane
) ) {
976 return IOPMAckImplied
; // somebody goofed
979 IOLockLock(pm_vars
->parentLock
);
981 if ( (pm_vars
->PMworkloop
== NULL
) || (pm_vars
->PMcommandGate
== NULL
) ) {
982 getPMworkloop(); // we have a path to the root,
983 if ( pm_vars
->PMworkloop
!= NULL
) { // so find out the workloop
984 if ( pm_vars
->PMcommandGate
== NULL
) { // and make our command gate
985 pm_vars
->PMcommandGate
= IOCommandGate::commandGate((OSObject
*)this);
986 if ( pm_vars
->PMcommandGate
!= NULL
) {
987 pm_vars
->PMworkloop
->addEventSource(pm_vars
->PMcommandGate
);
993 IOLockUnlock(pm_vars
->parentLock
);
995 combinedPowerFlags
= 0; // combine parents' power states
997 iter
= getParentIterator(gIOPowerPlane
);
1000 while ( (next
= iter
->getNextObject()) ) {
1001 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1002 if ( connection
== whichParent
){
1003 combinedPowerFlags
|= newPowerStateFlags
;
1006 combinedPowerFlags
|= connection
->parentCurrentPowerFlags();
1013 if ( pm_vars
->theControllingDriver
== NULL
) { // we can't take any more action
1014 return IOPMAckImplied
;
1016 newStateNumber
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(combinedPowerFlags
);
1017 return enqueuePowerChange(IOPMParentInitiated
| IOPMDomainWillChange
,
1018 newStateNumber
,combinedPowerFlags
,whichParent
,newPowerStateFlags
); //make the change
1022 //*********************************************************************************
1023 // powerDomainDidChangeTo
1025 // Called by the power-hierarchy parent after the power state of the power domain
1026 // has settled at a new level.
1027 // We enqueue a parent power-change to our queue of power changes.
1028 // This may or may not cause us to change power, depending on what
1029 // kind of change is occuring in the domain.
1030 //*********************************************************************************
1032 IOReturn
IOService::powerDomainDidChangeTo ( IOPMPowerFlags newPowerStateFlags
, IOPowerConnection
* whichParent
)
1034 unsigned long newStateNumber
;
1036 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogDidChange
,newPowerStateFlags
,0);
1038 setParentInfo(newPowerStateFlags
,whichParent
);
1040 if ( pm_vars
->theControllingDriver
== NULL
) {
1041 return IOPMAckImplied
;
1044 newStateNumber
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(pm_vars
->parentsCurrentPowerFlags
);
1045 return enqueuePowerChange(IOPMParentInitiated
| IOPMDomainDidChange
,
1046 newStateNumber
,pm_vars
->parentsCurrentPowerFlags
,whichParent
,0); // tell interested parties about it
1050 //*********************************************************************************
1053 // Set our connection data for one specific parent, and then combine all the parent
1055 //*********************************************************************************
1057 void IOService::setParentInfo ( IOPMPowerFlags newPowerStateFlags
, IOPowerConnection
* whichParent
)
1061 IOPowerConnection
* connection
;
1063 whichParent
->setParentCurrentPowerFlags(newPowerStateFlags
); // set our connection data
1064 whichParent
->setParentKnowsState(true);
1066 IOLockLock(pm_vars
->parentLock
);
1068 pm_vars
->parentsCurrentPowerFlags
= 0; // recompute our parent info
1069 pm_vars
->parentsKnowState
= true;
1071 iter
= getParentIterator(gIOPowerPlane
);
1074 while ( (next
= iter
->getNextObject()) ) {
1075 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1076 pm_vars
->parentsKnowState
&= connection
->parentKnowsState();
1077 pm_vars
->parentsCurrentPowerFlags
|= connection
->parentCurrentPowerFlags();
1082 IOLockUnlock(pm_vars
->parentLock
);
1086 //*********************************************************************************
1087 // requestPowerDomainState
1089 // The kIOPMPreventIdleSleep and/or kIOPMPreventIdleSleep bits may be be set in the parameter.
1090 // It is not considered part of the state specification.
1091 //*********************************************************************************
1092 IOReturn
IOService::requestPowerDomainState ( IOPMPowerFlags desiredState
, IOPowerConnection
* whichChild
, unsigned long specification
)
1095 unsigned long computedState
;
1096 unsigned long theDesiredState
= desiredState
& ~(kIOPMPreventIdleSleep
| kIOPMPreventSystemSleep
);
1099 IOPowerConnection
* connection
;
1101 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRequestDomain
,
1102 (unsigned long)desiredState
,(unsigned long)specification
);
1104 if ( pm_vars
->theControllingDriver
== NULL
) {
1105 return IOPMNotYetInitialized
;
1108 switch (specification
) {
1109 case IOPMLowestState
:
1111 while ( i
< pm_vars
->theNumberOfPowerStates
) {
1112 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& theDesiredState
) == (theDesiredState
& pm_vars
->myCharacterFlags
) ) {
1117 if ( i
>= pm_vars
->theNumberOfPowerStates
) {
1118 return IOPMNoSuchState
;
1122 case IOPMNextLowerState
:
1123 i
= pm_vars
->myCurrentState
- 1;
1125 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& theDesiredState
) == (theDesiredState
& pm_vars
->myCharacterFlags
) ) {
1131 return IOPMNoSuchState
;
1135 case IOPMHighestState
:
1136 i
= pm_vars
->theNumberOfPowerStates
;
1139 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& theDesiredState
) == (theDesiredState
& pm_vars
->myCharacterFlags
) ) {
1144 return IOPMNoSuchState
;
1148 case IOPMNextHigherState
:
1149 i
= pm_vars
->myCurrentState
+ 1;
1150 while ( i
< pm_vars
->theNumberOfPowerStates
) {
1151 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& theDesiredState
) == (theDesiredState
& pm_vars
->myCharacterFlags
) ) {
1156 if ( i
== pm_vars
->theNumberOfPowerStates
) {
1157 return IOPMNoSuchState
;
1162 return IOPMBadSpecification
;
1167 IOLockLock(pm_vars
->childLock
);
1169 // A child's desires has changed. We need to rebuild the child-clamp bits in our
1170 // power state array. Start by clearing the bits in each power state.
1172 for ( i
= 0; i
< pm_vars
->theNumberOfPowerStates
; i
++ ) {
1173 pm_vars
->thePowerStates
[i
].capabilityFlags
&= ~(kIOPMChildClamp
| kIOPMChildClamp2
);
1176 // Now loop through the children. When we encounter the calling child, save
1177 // the computed state as this child's desire. And while we're at it, set the ChildClamp bits
1178 // in any of our states that some child has requested with clamp on.
1180 iter
= getChildIterator(gIOPowerPlane
);
1183 while ( (next
= iter
->getNextObject()) ) {
1184 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1185 if ( connection
== whichChild
) {
1186 connection
->setDesiredDomainState(computedState
);
1187 connection
->setPreventIdleSleepFlag(desiredState
& kIOPMPreventIdleSleep
);
1188 connection
->setPreventSystemSleepFlag(desiredState
& kIOPMPreventSystemSleep
);
1189 connection
->setChildHasRequestedPower();
1191 if ( connection
->getPreventIdleSleepFlag() ) {
1192 pm_vars
->thePowerStates
[connection
->getDesiredDomainState()].capabilityFlags
|= kIOPMChildClamp
;
1194 if ( connection
->getPreventSystemSleepFlag() ) {
1195 pm_vars
->thePowerStates
[connection
->getDesiredDomainState()].capabilityFlags
|= kIOPMChildClamp2
;
1202 IOLockUnlock(pm_vars
->childLock
);
1204 computeDesiredState(); // this may be different now
1206 if ( inPlane(gIOPowerPlane
) &&
1207 (pm_vars
->parentsKnowState
) ) {
1208 changeState(); // change state if all children can now tolerate lower power
1211 if ( priv
->clampOn
) { // are we clamped on, waiting for this child?
1212 priv
->clampOn
= false; // yes, remove the clamp
1213 changePowerStateToPriv(0);
1220 //*********************************************************************************
1221 // temporaryPowerClampOn
1223 // A power domain wants to clamp its power on till it has children which
1224 // will thendetermine the power domain state.
1226 // We enter the highest state until addPowerChild is called.
1227 //*********************************************************************************
1229 IOReturn
IOService::temporaryPowerClampOn ( void )
1231 priv
->clampOn
= true;
1237 //*********************************************************************************
1240 // Some client of our device is asking that we become usable. Although
1241 // this has not come from a subclassed device object, treat it exactly
1242 // as if it had. In this way, subsequent requests for lower power from
1243 // a subclassed device object will pre-empt this request.
1245 // We treat this as a subclass object request to switch to the
1246 // highest power state.
1247 //*********************************************************************************
1249 IOReturn
IOService::makeUsable ( void )
1251 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogMakeUsable
,0,0);
1253 if ( pm_vars
->theControllingDriver
== NULL
) {
1254 priv
->need_to_become_usable
= true;
1257 priv
->deviceDesire
= pm_vars
->theNumberOfPowerStates
- 1;
1258 computeDesiredState();
1259 if ( inPlane(gIOPowerPlane
) && (pm_vars
->parentsKnowState
) ) {
1260 return changeState();
1266 //*********************************************************************************
1267 // currentCapability
1269 //*********************************************************************************
1271 IOPMPowerFlags
IOService::currentCapability ( void )
1273 if ( pm_vars
->theControllingDriver
== NULL
) {
1277 return pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
;
1282 //*********************************************************************************
1283 // changePowerStateTo
1285 // For some reason, our power-controlling driver has decided it needs to change
1286 // power state. We enqueue the power change so that appropriate parties
1287 // will be notified, and then we will instruct the driver to make the change.
1288 //*********************************************************************************
1290 IOReturn
IOService::changePowerStateTo ( unsigned long ordinal
)
1292 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeStateTo
,ordinal
,0);
1294 if ( ordinal
>= pm_vars
->theNumberOfPowerStates
) {
1295 return IOPMParameterError
;
1297 priv
->driverDesire
= ordinal
;
1298 computeDesiredState();
1299 if ( inPlane(gIOPowerPlane
) && (pm_vars
->parentsKnowState
) ) {
1300 return changeState();
1306 //*********************************************************************************
1307 // changePowerStateToPriv
1309 // For some reason, a subclassed device object has decided it needs to change
1310 // power state. We enqueue the power change so that appropriate parties
1311 // will be notified, and then we will instruct the driver to make the change.
1312 //*********************************************************************************
1314 IOReturn
IOService::changePowerStateToPriv ( unsigned long ordinal
)
1316 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeStateToPriv
,ordinal
,0);
1318 if ( pm_vars
->theControllingDriver
== NULL
) {
1319 return IOPMNotYetInitialized
;
1321 if ( ordinal
>= pm_vars
->theNumberOfPowerStates
) {
1322 return IOPMParameterError
;
1324 priv
->deviceDesire
= ordinal
;
1325 computeDesiredState();
1326 if ( inPlane(gIOPowerPlane
) && (pm_vars
->parentsKnowState
) ) {
1327 return changeState();
1334 //*********************************************************************************
1335 // computeDesiredState
1337 //*********************************************************************************
1339 void IOService::computeDesiredState ( void )
1343 IOPowerConnection
* connection
;
1344 unsigned long newDesiredState
= 0;
1346 // Compute the maximum of our children's desires, our controlling driver's desire, and the subclass device's desire.
1348 if ( ! priv
->device_overrides
) {
1349 iter
= getChildIterator(gIOPowerPlane
);
1352 while ( (next
= iter
->getNextObject()) ) {
1353 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1354 if ( connection
->getDesiredDomainState() > newDesiredState
) {
1355 newDesiredState
= connection
->getDesiredDomainState();
1362 if ( priv
->driverDesire
> newDesiredState
) {
1363 newDesiredState
= priv
->driverDesire
;
1367 if ( priv
->deviceDesire
> newDesiredState
) {
1368 newDesiredState
= priv
->deviceDesire
;
1371 priv
->ourDesiredPowerState
= newDesiredState
;
1375 //*********************************************************************************
1378 // A subclass object, our controlling driver, or a power domain child
1379 // has asked for a different power state. Here we compute what new
1380 // state we should enter and enqueue the change (or start it).
1381 //*********************************************************************************
1383 IOReturn
IOService::changeState ( void )
1385 if ( (pm_vars
->theControllingDriver
== NULL
) || // if not fully initialized
1386 ! (inPlane(gIOPowerPlane
)) ||
1387 ! (pm_vars
->parentsKnowState
) ) {
1388 return IOPMNoErr
; // we can do no more
1391 return enqueuePowerChange(IOPMWeInitiated
,priv
->ourDesiredPowerState
,0,0,0);
1395 //*********************************************************************************
1396 // currentPowerConsumption
1398 //*********************************************************************************
1400 unsigned long IOService::currentPowerConsumption ( void )
1402 if ( pm_vars
->theControllingDriver
== NULL
) {
1403 return kIOPMUnknown
;
1405 if ( pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
& kIOPMStaticPowerValid
) {
1406 return pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].staticPower
;
1408 return kIOPMUnknown
;
1411 //*********************************************************************************
1414 // The activity tickle with parameter kIOPMSubclassPolicyis not handled
1415 // here and should have been intercepted by the subclass.
1416 // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
1417 // flag to be set, and the device state checked. If the device has been
1418 // powered down, it is powered up again.
1419 //*********************************************************************************
1421 bool IOService::activityTickle ( unsigned long type
, unsigned long stateNumber
=0 )
1423 AbsoluteTime uptime
;
1425 if ( type
== kIOPMSuperclassPolicy1
) {
1426 if ( (priv
->activityLock
== NULL
) ||
1427 (pm_vars
->theControllingDriver
== NULL
) ) {
1430 IOTakeLock(priv
->activityLock
);
1431 priv
->device_active
= true;
1433 clock_get_uptime(&uptime
);
1434 priv
->device_active_timestamp
= uptime
;
1436 if ( pm_vars
->myCurrentState
>= stateNumber
) {
1437 IOUnlock(priv
->activityLock
);
1440 IOUnlock(priv
->activityLock
);
1441 pm_vars
->PMcommandGate
->runAction(unIdleDevice
,(void *)stateNumber
);
1447 //*********************************************************************************
1450 // A child is calling to get a pointer to the Power Management workloop.
1451 // We got it or get it from one of our parents.
1452 //*********************************************************************************
1454 IOWorkLoop
* IOService::getPMworkloop ( void )
1459 if ( ! inPlane(gIOPowerPlane
) ) {
1462 if ( pm_vars
->PMworkloop
== NULL
) { // we have no workloop yet
1463 nub
= (IOService
*)copyParentEntry(gIOPowerPlane
);
1465 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
1467 if ( parent
) { // ask one of our parents for the workloop
1468 pm_vars
->PMworkloop
= parent
->getPMworkloop();
1473 return pm_vars
->PMworkloop
;
1477 //*********************************************************************************
1478 // setIdleTimerPeriod
1480 // A subclass policy-maker is going to use our standard idleness
1481 // detection service. Make a command queue and an idle timer and
1482 // connect them to the power management workloop. Finally,
1484 //*********************************************************************************
1486 IOReturn
IOService::setIdleTimerPeriod ( unsigned long period
)
1488 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMsetIdleTimerPeriod
,period
, 0);
1490 priv
->idle_timer_period
= period
;
1493 if ( getPMworkloop() == NULL
) {
1494 return kIOReturnError
;
1496 // make the timer event
1497 if ( priv
->timerEventSrc
== NULL
) {
1498 priv
->timerEventSrc
= IOTimerEventSource::timerEventSource(this,
1499 PM_idle_timer_expired
);
1500 if ( ! priv
->timerEventSrc
||
1501 ( pm_vars
->PMworkloop
->addEventSource( priv
->timerEventSrc
) != kIOReturnSuccess
) ) {
1502 return kIOReturnError
;
1506 if ( priv
->activityLock
== NULL
) {
1507 priv
->activityLock
= IOLockAlloc();
1510 start_PM_idle_timer();
1516 //*********************************************************************************
1517 // start_PM_idle_timer
1519 // The parameter is a pointer to us. Use it to call our timeout method.
1520 //*********************************************************************************
1521 void IOService::start_PM_idle_timer ( void )
1523 AbsoluteTime uptime
;
1529 IOLockLock(priv
->activityLock
);
1531 clock_get_uptime(&uptime
);
1533 /* Calculate time difference using funky macro from clock.h.
1536 SUB_ABSOLUTETIME(&delta
, &(priv
->device_active_timestamp
));
1538 /* Figure it in seconds.
1540 absolutetime_to_nanoseconds(delta
, &delta_ns
);
1541 delta_secs
= delta_ns
/ NSEC_PER_SEC
;
1543 /* Be paranoid about delta somehow exceeding timer period.
1545 if (delta_secs
< priv
->idle_timer_period
) {
1546 delay_secs
= priv
->idle_timer_period
- delta_secs
;
1548 delay_secs
= priv
->idle_timer_period
;
1551 priv
->timerEventSrc
->setTimeout(delay_secs
, NSEC_PER_SEC
);
1553 IOLockUnlock(priv
->activityLock
);
1558 //*********************************************************************************
1559 // PM_idle_timer_expired
1561 // The parameter is a pointer to us. Use it to call our timeout method.
1562 //*********************************************************************************
1564 void PM_idle_timer_expired(OSObject
* ourSelves
, IOTimerEventSource
*)
1566 ((IOService
*)ourSelves
)->PM_idle_timer_expiration();
1570 //*********************************************************************************
1571 // PM_idle_timer_expiration
1573 // The idle timer has expired. If there has been activity since the last
1574 // expiration, just restart the timer and return. If there has not been
1575 // activity, switch to the next lower power state and restart the timer.
1576 //*********************************************************************************
1578 void IOService::PM_idle_timer_expiration ( void )
1580 if ( ! initialized
) {
1581 return; // we're unloading
1584 if ( priv
->idle_timer_period
> 0 ) {
1585 IOTakeLock(priv
->activityLock
);
1586 if ( priv
->device_active
) {
1587 priv
->device_active
= false;
1588 IOUnlock(priv
->activityLock
);
1589 start_PM_idle_timer();
1592 if ( pm_vars
->myCurrentState
> 0 ) {
1593 IOUnlock(priv
->activityLock
);
1594 changePowerStateToPriv(pm_vars
->myCurrentState
- 1);
1595 start_PM_idle_timer();
1598 IOUnlock(priv
->activityLock
);
1599 start_PM_idle_timer();
1605 // **********************************************************************************
1608 // We are behind the command gate. This serializes with respect to timer expiration.
1609 // **********************************************************************************
1610 IOReturn
unIdleDevice ( OSObject
* theDriver
, void * param1
, void * param2
, void * param3
, void * param4
)
1612 ((IOService
*)theDriver
)->command_received(param1
,param2
,param3
,param4
);
1613 return kIOReturnSuccess
;
1617 // **********************************************************************************
1620 // We are un-idling a device due to its activity tickle.
1621 // **********************************************************************************
1622 void IOService::command_received ( void * stateNumber
, void *, void * , void * )
1624 if ( ! initialized
) {
1625 return; // we're unloading
1628 if ( (pm_vars
->myCurrentState
< (unsigned long)stateNumber
) &&
1629 (priv
->imminentState
< (unsigned long)stateNumber
) ) {
1630 changePowerStateToPriv((unsigned long)stateNumber
);
1635 //*********************************************************************************
1636 // setAggressiveness
1638 // Pass on the input parameters to all power domain children. All those which are
1639 // power domains will pass it on to their children, etc.
1640 //*********************************************************************************
1642 IOReturn
IOService::setAggressiveness ( unsigned long type
, unsigned long newLevel
)
1646 IOPowerConnection
* connection
;
1649 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogSetAggressiveness
,type
, newLevel
);
1651 if ( type
<= kMaxType
) {
1652 pm_vars
->current_aggressiveness_values
[type
] = newLevel
;
1653 pm_vars
->current_aggressiveness_valid
[type
] = true;
1656 iter
= getChildIterator(gIOPowerPlane
);
1659 while ( (next
= iter
->getNextObject()) ) {
1660 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1661 child
= ((IOService
*)(connection
->copyChildEntry(gIOPowerPlane
)));
1663 child
->setAggressiveness(type
, newLevel
);
1674 //*********************************************************************************
1675 // getAggressiveness
1677 // Called by the user client.
1678 //*********************************************************************************
1680 IOReturn
IOService::getAggressiveness ( unsigned long type
, unsigned long * currentLevel
)
1682 if ( type
<= kMaxType
) {
1683 *currentLevel
= pm_vars
->current_aggressiveness_values
[type
];
1685 return kIOReturnSuccess
;
1688 //*********************************************************************************
1691 // Pass this to all power domain children. All those which are
1692 // power domains will pass it on to their children, etc.
1693 //*********************************************************************************
1695 IOReturn
IOService::systemWake ( void )
1699 IOPowerConnection
* connection
;
1700 IOService
* theChild
;
1702 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogSystemWake
,0, 0);
1704 iter
= getChildIterator(gIOPowerPlane
);
1707 while ( (next
= iter
->getNextObject()) ) {
1708 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1709 theChild
= (IOService
*)connection
->copyChildEntry(gIOPowerPlane
);
1711 theChild
->systemWake();
1712 theChild
->release();
1719 if ( pm_vars
->theControllingDriver
!= NULL
) {
1720 if ( pm_vars
->theControllingDriver
->didYouWakeSystem() ) {
1729 //*********************************************************************************
1730 // temperatureCriticalForZone
1732 //*********************************************************************************
1734 IOReturn
IOService::temperatureCriticalForZone ( IOService
* whichZone
)
1736 IOService
* theParent
;
1739 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogCriticalTemp
,0,0);
1741 if ( inPlane(gIOPowerPlane
) && ! (priv
->we_are_root
) ) {
1742 theNub
= (IOService
*)copyParentEntry(gIOPowerPlane
);
1744 theParent
= (IOService
*)theNub
->copyParentEntry(gIOPowerPlane
);
1747 theParent
->temperatureCriticalForZone(whichZone
);
1748 theParent
->release();
1756 //*********************************************************************************
1757 // powerOverrideOnPriv
1759 //*********************************************************************************
1762 IOReturn
IOService::powerOverrideOnPriv ( void )
1764 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogOverrideOn
,0,0);
1766 priv
->device_overrides
= true; // turn on the override
1767 computeDesiredState();
1768 return changeState(); // change state if that changed something
1772 //*********************************************************************************
1773 // powerOverrideOffPriv
1775 //*********************************************************************************
1776 IOReturn
IOService::powerOverrideOffPriv ( void )
1778 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogOverrideOff
,0,0);
1780 priv
->device_overrides
= false; // turn off the override
1781 computeDesiredState();
1783 return makeUsable();
1785 return changeState(); // change state if that changed something
1789 //*********************************************************************************
1790 // enqueuePowerChange
1792 // Allocate a new state change notification, initialize it with fields from the
1793 // caller, and add it to the tail of the list of pending power changes.
1795 // If it is early enough in the list, and almost all the time it is the only one in
1796 // the list, start the power change.
1798 // In rare instances, this change will preempt the previous change in the list.
1799 // If the previous change is un-actioned in any way (because we are still
1800 // processing an even earlier power change), and if both the previous change
1801 // in the list and this change are initiated by us (not the parent), then we
1802 // needn't perform the previous change, so we collapse the list a little.
1803 //*********************************************************************************
1805 IOReturn
IOService::enqueuePowerChange ( unsigned long flags
, unsigned long whatStateOrdinal
, unsigned long domainState
, IOPowerConnection
* whichParent
, unsigned long singleParentState
)
1810 // Create and initialize the new change note
1812 IOLockLock(priv
->queue_lock
);
1813 newNote
= priv
->changeList
->createChangeNote();
1814 if ( newNote
== -1 ) {
1815 IOLockUnlock(priv
->queue_lock
);
1816 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogEnqueueErr
,0,0);
1817 return IOPMAckImplied
; // uh-oh, our list is full
1820 priv
->changeList
->changeNote
[newNote
].newStateNumber
= whatStateOrdinal
;
1821 priv
->changeList
->changeNote
[newNote
].outputPowerCharacter
= pm_vars
->thePowerStates
[whatStateOrdinal
].outputPowerCharacter
;
1822 priv
->changeList
->changeNote
[newNote
].inputPowerRequirement
= pm_vars
->thePowerStates
[whatStateOrdinal
].inputPowerRequirement
;
1823 priv
->changeList
->changeNote
[newNote
].capabilityFlags
= pm_vars
->thePowerStates
[whatStateOrdinal
].capabilityFlags
;
1824 priv
->changeList
->changeNote
[newNote
].flags
= flags
;
1825 if (flags
& IOPMParentInitiated
) {
1826 priv
->changeList
->changeNote
[newNote
].domainState
= domainState
;
1827 priv
->changeList
->changeNote
[newNote
].parent
= whichParent
;
1828 whichParent
->retain();
1829 priv
->changeList
->changeNote
[newNote
].singleParentState
= singleParentState
;
1832 previousNote
= priv
->changeList
->previousChangeNote(newNote
);
1834 if ( previousNote
== -1 ) {
1836 // Queue is empty, we can start this change.
1838 if (flags
& IOPMWeInitiated
) {
1839 IOLockUnlock(priv
->queue_lock
);
1840 start_our_change(newNote
);
1844 IOLockUnlock(priv
->queue_lock
);
1845 return start_parent_change(newNote
);
1849 // The queue is not empty. Try to collapse this new change and the previous one in queue into one change.
1850 // This is possible only if both changes are initiated by us, and neither has been started yet.
1851 // Do this more than once if possible.
1853 // (A change is started iff it is at the head of the queue)
1855 while ( (previousNote
!= priv
->head_note
) && (previousNote
!= -1) &&
1856 (priv
->changeList
->changeNote
[newNote
].flags
& priv
->changeList
->changeNote
[previousNote
].flags
& IOPMWeInitiated
) ) {
1857 priv
->changeList
->changeNote
[previousNote
].outputPowerCharacter
= priv
->changeList
->changeNote
[newNote
].outputPowerCharacter
;
1858 priv
->changeList
->changeNote
[previousNote
].inputPowerRequirement
= priv
->changeList
->changeNote
[newNote
].inputPowerRequirement
;
1859 priv
->changeList
->changeNote
[previousNote
].capabilityFlags
=priv
-> changeList
->changeNote
[newNote
].capabilityFlags
;
1860 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogCollapseQueue
,priv
->changeList
->changeNote
[newNote
].newStateNumber
,
1861 priv
->changeList
->changeNote
[previousNote
].newStateNumber
);
1862 priv
->changeList
->changeNote
[previousNote
].newStateNumber
= priv
->changeList
->changeNote
[newNote
].newStateNumber
;
1863 priv
->changeList
->releaseTailChangeNote();
1864 newNote
= previousNote
;
1865 previousNote
= priv
->changeList
->previousChangeNote(newNote
);
1867 IOLockUnlock(priv
->queue_lock
);
1868 return IOPMWillAckLater
; // in any case, we can't start yet
1871 //*********************************************************************************
1874 // Notify all interested parties either that a change is impending or that the
1875 // previously-notified change is done and power has settled.
1876 // The parameter identifies whether this is the
1877 // pre-change notification or the post-change notification.
1879 //*********************************************************************************
1881 IOReturn
IOService::notifyAll ( bool is_prechange
)
1883 IOPMinformee
* nextObject
;
1886 IOPowerConnection
* connection
;
1888 // To prevent acknowledgePowerChange from finishing the change note and removing it from the queue if
1889 // some driver calls it, we inflate the number of pending acks so it cannot become zero. We'll fix it later.
1891 priv
->head_note_pendingAcks
=1;
1893 // OK, we will go through the lists of interested drivers and power domain children
1894 // and notify each one of this change.
1895 nextObject
= priv
->interestedDrivers
->firstInList(); // notify interested drivers
1896 while ( nextObject
!= NULL
) {
1897 priv
->head_note_pendingAcks
+=1;
1898 if (! inform(nextObject
, is_prechange
) ) {
1900 nextObject
= priv
->interestedDrivers
->nextInList(nextObject
);
1903 if (! acquire_lock() ) {
1906 if ( priv
->head_note_pendingAcks
> 1 ) { // did they all ack?
1907 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0); // no
1910 IOUnlock(priv
->our_lock
); // either way
1912 iter
= getChildIterator(gIOPowerPlane
); // notify children
1913 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
= 0; // summing their power consumption
1916 while ( (next
= iter
->getNextObject()) ) {
1917 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1918 priv
->head_note_pendingAcks
+=1;
1919 notifyChild(connection
, is_prechange
);
1925 if (! acquire_lock() ) {
1928 priv
->head_note_pendingAcks
-= 1; // now make this real
1929 if (priv
->head_note_pendingAcks
== 0 ) { // is it all acked?
1930 IOUnlock(priv
->our_lock
); // yes
1931 return IOPMAckImplied
; // return ack to parent
1933 IOUnlock(priv
->our_lock
); // no
1934 return IOPMWillAckLater
;
1938 //*********************************************************************************
1941 // Notify a power domain child of an upcoming power change.
1943 // If the object acknowledges the current change, we return TRUE.
1944 //*********************************************************************************
1946 bool IOService::notifyChild ( IOPowerConnection
* theNub
, bool is_prechange
)
1948 IOReturn k
= IOPMAckImplied
;
1949 unsigned long childPower
;
1950 IOService
* theChild
= (IOService
*)(theNub
->copyChildEntry(gIOPowerPlane
));
1952 theNub
->setAwaitingAck(true); // in case they don't ack
1958 if ( is_prechange
) {
1959 k
= theChild
->powerDomainWillChangeTo(priv
->head_note_outputFlags
,theNub
);
1962 k
= theChild
->powerDomainDidChangeTo(priv
->head_note_outputFlags
,theNub
);
1965 if ( k
== IOPMAckImplied
) { // did the return code ack?
1966 priv
->head_note_pendingAcks
-=1; // yes
1967 theNub
->setAwaitingAck(false);
1968 childPower
= theChild
->currentPowerConsumption();
1969 if ( childPower
== kIOPMUnknown
) {
1970 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
= kIOPMUnknown
;
1973 if ( pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
!= kIOPMUnknown
) {
1974 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
+= childPower
;
1977 theChild
->release();
1980 theChild
->release();
1985 //*********************************************************************************
1988 // Notify an interested driver of an upcoming power change.
1990 // If the object acknowledges the current change, we return TRUE.
1991 //*********************************************************************************
1993 bool IOService::inform ( IOPMinformee
* nextObject
, bool is_prechange
)
1995 IOReturn k
= IOPMAckImplied
;
1997 nextObject
->timer
= -1; // initialize this
1999 if ( is_prechange
) {
2000 pm_vars
->thePlatform
->PMLog (pm_vars
->ourName
,PMlogInformDriverPreChange
,
2001 (unsigned long)priv
->head_note_capabilityFlags
,(unsigned long)priv
->head_note_state
);
2002 k
= nextObject
->whatObject
->powerStateWillChangeTo( priv
->head_note_capabilityFlags
,priv
->head_note_state
,this);
2005 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInformDriverPostChange
,
2006 (unsigned long)priv
->head_note_capabilityFlags
,(unsigned long)priv
->head_note_state
);
2007 k
= nextObject
->whatObject
->powerStateDidChangeTo(priv
->head_note_capabilityFlags
,priv
->head_note_state
,this);
2009 if ( nextObject
->timer
== 0 ) { // did it ack behind our back?
2012 if ( k
==IOPMAckImplied
) { // no, did the return code ack?
2013 nextObject
->timer
= 0; // yes
2014 priv
->head_note_pendingAcks
-= 1;
2018 nextObject
->timer
= 0; // somebody goofed
2019 priv
-> head_note_pendingAcks
-= 1;
2022 nextObject
->timer
= (k
* ns_per_us
/ ACK_TIMER_PERIOD
) + 1; // no, it's a timer
2027 //*********************************************************************************
2030 // All registered applications and kernel clients have positively acknowledged our
2031 // intention of lowering power. Here we notify them all that we will definitely
2032 // lower the power. If we don't have to wait for any of them to acknowledge, we
2033 // carry on by notifying interested drivers. Otherwise, we do wait.
2034 //*********************************************************************************
2036 void IOService::our_prechange_03 ( void )
2038 priv
->machine_state
= IOPMour_prechange_04
; // next state
2039 if ( tellChangeDown1(priv
->head_note_state
) ) { // are we waiting for responses?
2040 our_prechange_04(); // no, notify priority clients
2045 //*********************************************************************************
2048 // All registered applications and kernel clients have positively acknowledged our
2049 // intention of lowering power. Here we notify "priority" clients that we are
2050 // lowering power. If we don't have to wait for any of them to acknowledge, we
2051 // carry on by notifying interested drivers. Otherwise, we do wait.
2052 //*********************************************************************************
2054 void IOService::our_prechange_04 ( void )
2056 priv
->machine_state
= IOPMour_prechange_05
; // next state
2057 if ( tellChangeDown2(priv
->head_note_state
) ) { // are we waiting for responses?
2058 return our_prechange_05(); // no, notify interested drivers
2063 //*********************************************************************************
2066 // All registered applications and kernel clients have acknowledged our notification
2067 // that we are lowering power. Here we notify interested drivers. If we don't have
2068 // to wait for any of them to acknowledge, we instruct our power driver to make the change.
2069 // Otherwise, we do wait.
2070 //*********************************************************************************
2072 void IOService::our_prechange_05 ( void )
2074 priv
->machine_state
= IOPMour_prechange_1
; // no, in case they don't all ack
2075 if ( notifyAll(true) == IOPMAckImplied
) {
2081 //*********************************************************************************
2084 // All interested drivers have acknowledged our pre-change notification of a power
2085 // change we initiated. Here we instruct our controlling driver to make
2086 // the change to the hardware. If it does so, we continue processing
2087 // (waiting for settle and notifying interested parties post-change.)
2088 // If it doesn't, we have to wait for it to acknowledge and then continue.
2089 //*********************************************************************************
2091 void IOService::our_prechange_1 ( void )
2093 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
) {
2094 our_prechange_2(); // it's done, carry on
2097 priv
->machine_state
= IOPMour_prechange_2
; // it's not, wait for it
2098 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2104 //*********************************************************************************
2107 // Our controlling driver has changed power state on the hardware
2108 // during a power change we initiated. Here we see if we need to wait
2109 // for power to settle before continuing. If not, we continue processing
2110 // (notifying interested parties post-change). If so, we wait and
2112 //*********************************************************************************
2114 void IOService::our_prechange_2 ( void )
2116 priv
->settle_time
= compute_settle_time();
2117 if ( priv
->settle_time
== 0 ) {
2121 priv
->machine_state
= IOPMour_prechange_3
;
2122 startSettleTimer(priv
->settle_time
);
2127 //*********************************************************************************
2130 // Power has settled on a power change we initiated. Here we notify
2131 // all our interested parties post-change. If they all acknowledge, we're
2132 // done with this change note, and we can start on the next one.
2133 // Otherwise we have to wait for acknowledgements and finish up later.
2134 //*********************************************************************************
2136 void IOService::our_prechange_3 ( void )
2138 priv
->machine_state
= IOPMour_prechange_4
; // in case they don't all ack
2139 if ( notifyAll(false) == IOPMAckImplied
) {
2145 //*********************************************************************************
2148 // Power has settled on a power change we initiated, and
2149 // all our interested parties have acknowledged. We're
2150 // done with this change note, and we can start on the next one.
2151 //*********************************************************************************
2153 void IOService::our_prechange_4 ( void )
2159 //*********************************************************************************
2162 // All applications and kernel clients have been notified of a power lowering
2163 // initiated by the parent and we didn't have to wait for any responses. Here
2164 // we notify any priority clients. If they all ack, we continue with the power change.
2165 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
2166 //*********************************************************************************
2168 IOReturn
IOService::parent_down_0 ( void )
2170 priv
->machine_state
= IOPMparent_down_05
; // in case they don't all ack
2171 if ( tellChangeDown2(priv
->head_note_state
) ) { // are we waiting for responses?
2172 return parent_down_02(); // no, notify interested drivers
2174 return IOPMWillAckLater
; // they didn't
2178 //*********************************************************************************
2181 // All priority kernel clients have been notified of a power lowering
2182 // initiated by the parent and we didn't have to wait for any responses. Here
2183 // we notify any interested drivers and power domain children. If they all ack,
2184 // we continue with the power change.
2185 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
2186 //*********************************************************************************
2188 IOReturn
IOService::parent_down_02 ( void )
2190 priv
->machine_state
= IOPMparent_down_4
; // in case they don't all ack
2191 if ( notifyAll(true) == IOPMAckImplied
) {
2192 return parent_down_1(); // they did
2194 return IOPMWillAckLater
; // they didn't
2198 //*********************************************************************************
2201 // All applications and kernel clients have been notified of a power lowering
2202 // initiated by the parent and we had to wait for responses. Here
2203 // we notify any priority clients. If they all ack, we continue with the power change.
2204 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
2205 //*********************************************************************************
2207 void IOService::parent_down_04 ( void )
2209 priv
->machine_state
= IOPMparent_down_05
; // in case they don't all ack
2210 if ( tellChangeDown2(priv
->head_note_state
) ) { // are we waiting for responses?
2211 parent_down_05(); // no, notify interested drivers
2216 //*********************************************************************************
2219 // All applications and kernel clients have been notified of a power lowering
2220 // initiated by the parent and we had to wait for their responses. Here we notify
2221 // any interested drivers and power domain children. If they all ack, we continue
2222 // with the power change.
2223 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
2224 //*********************************************************************************
2226 void IOService::parent_down_05 ( void )
2228 priv
->machine_state
= IOPMparent_down_4
; // in case they don't all ack
2229 if ( notifyAll(true) == IOPMAckImplied
) {
2230 parent_down_4(); // they did
2235 //*********************************************************************************
2238 // All parties have acknowledged our pre-change notification of a power
2239 // lowering initiated by the parent. Here we instruct our controlling driver
2240 // to put the hardware in the state it needs to be in when the domain is
2241 // lowered. If it does so, we continue processing
2242 // (waiting for settle and acknowledging the parent.)
2243 // If it doesn't, we have to wait for it to acknowledge and then continue.
2244 //*********************************************************************************
2246 IOReturn
IOService::parent_down_1 ( void )
2248 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
) {
2249 return parent_down_2(); // it's done, carry on
2251 priv
->machine_state
= IOPMparent_down_5
; // it's not, wait for it
2252 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2254 return IOPMWillAckLater
;
2258 //*********************************************************************************
2261 // We had to wait for it, but all parties have acknowledged our pre-change
2262 // notification of a power lowering initiated by the parent.
2263 // Here we instruct our controlling driver
2264 // to put the hardware in the state it needs to be in when the domain is
2265 // lowered. If it does so, we continue processing
2266 // (waiting for settle and acknowledging the parent.)
2267 // If it doesn't, we have to wait for it to acknowledge and then continue.
2268 //*********************************************************************************
2270 void IOService::parent_down_4 ( void )
2272 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
) {
2273 parent_down_5(); // it's done, carry on
2276 priv
-> machine_state
= IOPMparent_down_5
; // it's not, wait for it
2277 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2283 //*********************************************************************************
2286 // Our controlling driver has changed power state on the hardware
2287 // during a power change initiated by our parent. Here we see if we need
2288 // to wait for power to settle before continuing. If not, we continue
2289 // processing (acknowledging our preparedness to the parent).
2290 // If so, we wait and continue later.
2291 //*********************************************************************************
2293 IOReturn
IOService::parent_down_2 ( void )
2297 priv
->settle_time
= compute_settle_time();
2298 if ( priv
->settle_time
== 0 ) {
2299 priv
->machine_state
= IOPMparent_down_6
; // in case they don't all ack
2300 if ( notifyAll(false) == IOPMAckImplied
) {
2301 nub
= priv
->head_note_parent
;
2304 return IOPMAckImplied
;
2306 return IOPMWillAckLater
; // they didn't
2309 priv
->machine_state
= IOPMparent_down_3
;
2310 startSettleTimer(priv
->settle_time
);
2311 return IOPMWillAckLater
;
2316 //*********************************************************************************
2319 // Our controlling driver has changed power state on the hardware
2320 // during a power change initiated by our parent. We have had to wait
2321 // for acknowledgement from interested parties, or we have had to wait
2322 // for the controlling driver to change the state. Here we see if we need
2323 // to wait for power to settle before continuing. If not, we continue
2324 // processing (acknowledging our preparedness to the parent).
2325 // If so, we wait and continue later.
2326 //*********************************************************************************
2328 void IOService::parent_down_5 ( void )
2330 priv
->settle_time
= compute_settle_time();
2331 if ( priv
->settle_time
== 0 ) {
2335 priv
->machine_state
= IOPMparent_down_3
;
2336 startSettleTimer(priv
->settle_time
);
2341 //*********************************************************************************
2344 // Power has settled on a power change initiated by our parent. Here we
2345 // notify interested parties.
2346 //*********************************************************************************
2348 void IOService::parent_down_3 ( void )
2350 IORegistryEntry
* nub
;
2353 priv
->machine_state
= IOPMparent_down_6
; // in case they don't all ack
2354 if ( notifyAll(false) == IOPMAckImplied
) {
2355 nub
= priv
->head_note_parent
;
2357 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
2359 parent
->acknowledgePowerChange((IOService
*)nub
);
2367 //*********************************************************************************
2370 // We had to wait for it, but all parties have acknowledged our post-change
2371 // notification of a power lowering initiated by the parent.
2372 // Here we acknowledge the parent.
2373 // We are done with this change note, and we can start on the next one.
2374 //*********************************************************************************
2376 void IOService::parent_down_6 ( void )
2378 IORegistryEntry
* nub
;
2381 nub
= priv
->head_note_parent
;
2383 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
2385 parent
->acknowledgePowerChange((IOService
*)nub
);
2392 //*********************************************************************************
2395 // Our parent has informed us via powerStateDidChange that it has
2396 // raised the power in our power domain, and we have had to wait
2397 // for some interested party to acknowledge our notification.
2398 // Here we instruct our controlling
2399 // driver to program the hardware to take advantage of the higher domain
2400 // power. If it does so, we continue processing
2401 // (waiting for settle and notifying interested parties post-change.)
2402 // If it doesn't, we have to wait for it to acknowledge and then continue.
2403 //*********************************************************************************
2405 void IOService::parent_up_0 ( void )
2407 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
) {
2408 parent_up_4(); // it did it, carry on
2411 priv
->machine_state
= IOPMparent_up_4
; // it didn't, wait for it
2412 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2418 //*********************************************************************************
2421 // Our parent has informed us via powerStateDidChange that it has
2422 // raised the power in our power domain. Here we instruct our controlling
2423 // driver to program the hardware to take advantage of the higher domain
2424 // power. If it does so, we continue processing
2425 // (waiting for settle and notifying interested parties post-change.)
2426 // If it doesn't, we have to wait for it to acknowledge and then continue.
2427 //*********************************************************************************
2429 IOReturn
IOService::parent_up_1 ( void )
2431 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
) {
2432 return parent_up_2(); // it did it, carry on
2435 priv
->machine_state
= IOPMparent_up_4
; // it didn't, wait for it
2436 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2438 return IOPMWillAckLater
;
2443 //*********************************************************************************
2446 // Our controlling driver has changed power state on the hardware
2447 // during a power raise initiated by the parent. Here we see if we need to wait
2448 // for power to settle before continuing. If not, we continue processing
2449 // (notifying interested parties post-change). If so, we wait and
2451 //*********************************************************************************
2453 IOReturn
IOService::parent_up_2 ( void )
2455 priv
->settle_time
= compute_settle_time();
2456 if ( priv
->settle_time
== 0 ) {
2457 return parent_up_3();
2460 priv
->machine_state
= IOPMparent_up_5
;
2461 startSettleTimer(priv
->settle_time
);
2462 return IOPMWillAckLater
;
2467 //*********************************************************************************
2470 // Our controlling driver has changed power state on the hardware
2471 // during a power raise initiated by the parent, but we had to wait for it.
2472 // Here we see if we need to wait for power to settle before continuing.
2473 // If not, we continue processing (notifying interested parties post-change).
2474 // If so, we wait and continue later.
2475 //*********************************************************************************
2477 void IOService::parent_up_4 ( void )
2479 priv
->settle_time
= compute_settle_time();
2480 if ( priv
->settle_time
== 0 ) {
2484 priv
->machine_state
= IOPMparent_up_5
;
2485 startSettleTimer(priv
->settle_time
);
2490 //*********************************************************************************
2493 // No power settling was required on a power raise initiated by the parent.
2494 // Here we notify all our interested parties post-change. If they all acknowledge,
2495 // we're done with this change note, and we can start on the next one.
2496 // Otherwise we have to wait for acknowledgements and finish up later.
2497 //*********************************************************************************
2499 IOReturn
IOService::parent_up_3 ( void )
2503 priv
->machine_state
= IOPMparent_up_6
; // in case they don't all ack
2504 if ( notifyAll(false) == IOPMAckImplied
) {
2505 nub
= priv
->head_note_parent
;
2508 return IOPMAckImplied
;
2510 return IOPMWillAckLater
; // they didn't
2514 //*********************************************************************************
2517 // Power has settled on a power raise initiated by the parent.
2518 // Here we notify all our interested parties post-change. If they all acknowledge,
2519 // we're done with this change note, and we can start on the next one.
2520 // Otherwise we have to wait for acknowledgements and finish up later.
2521 //*********************************************************************************
2523 void IOService::parent_up_5 ( void )
2525 priv
->machine_state
= IOPMparent_up_6
; // in case they don't all ack
2526 if ( notifyAll(false) == IOPMAckImplied
) {
2532 //*********************************************************************************
2535 // All parties have acknowledged our post-change notification of a power
2536 // raising initiated by the parent. Here we acknowledge the parent.
2537 // We are done with this change note, and we can start on the next one.
2538 //*********************************************************************************
2540 void IOService::parent_up_6 ( void )
2542 IORegistryEntry
* nub
;
2545 nub
= priv
->head_note_parent
;
2547 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
2549 parent
->acknowledgePowerChange((IOService
*)nub
);
2556 //*********************************************************************************
2559 // A power change is complete, and the used post-change note is at
2560 // the head of the queue. Remove it and set myCurrentState to the result
2561 // of the change. Start up the next change in queue.
2562 //*********************************************************************************
2564 void IOService::all_done ( void )
2566 unsigned long previous_state
;
2567 IORegistryEntry
* nub
;
2570 priv
->machine_state
= IOPMfinished
;
2572 if ( priv
->head_note_flags
& IOPMWeInitiated
) { // our power change
2573 if ( !( priv
->head_note_flags
& IOPMNotDone
) ) { // could our driver switch to the new state?
2574 if ( pm_vars
->myCurrentState
< priv
->head_note_state
) { // yes, did power raise?
2575 tellChangeUp (priv
->head_note_state
); // yes, inform clients and apps
2578 if ( ! priv
->we_are_root
) { // no, if this lowers our
2579 ask_parent(priv
->head_note_state
); // power requirements, tell the parent
2582 previous_state
= pm_vars
->myCurrentState
;
2583 pm_vars
->myCurrentState
= priv
->head_note_state
; // either way
2584 priv
->imminentState
= pm_vars
->myCurrentState
;
2585 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeDone
,(unsigned long)pm_vars
->myCurrentState
,0);
2586 powerChangeDone(previous_state
); // inform subclass policy-maker
2589 // pm_vars->myCurrentState = pm_vars->theControllingDriver->powerStateForDomainState(pm_vars->parentsCurrentPowerFlags);
2592 if ( priv
->head_note_flags
& IOPMParentInitiated
) { // parent's power change
2593 if ( ((priv
->head_note_flags
& IOPMDomainWillChange
) && (pm_vars
->myCurrentState
>= priv
->head_note_state
)) ||
2594 ((priv
->head_note_flags
& IOPMDomainDidChange
) && (pm_vars
->myCurrentState
< priv
->head_note_state
)) ) {
2595 if ( pm_vars
->myCurrentState
< priv
->head_note_state
) { // did power raise?
2596 tellChangeUp (priv
->head_note_state
); // yes, inform clients and apps
2598 previous_state
= pm_vars
->myCurrentState
; // either way
2599 pm_vars
->myCurrentState
= priv
->head_note_state
;
2600 priv
->imminentState
= pm_vars
->myCurrentState
;
2601 pm_vars
->maxCapability
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(priv
->head_note_domainState
);
2603 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeDone
,(unsigned long)pm_vars
->myCurrentState
,0);
2604 powerChangeDone(previous_state
); // inform subclass policy-maker
2608 IOLockLock(priv
->queue_lock
);
2609 priv
->changeList
->releaseHeadChangeNote(); // we're done with this
2611 priv
->head_note
= priv
->changeList
->currentChange(); // start next one in queue
2612 if ( priv
->head_note
!= -1 ) {
2614 IOLockUnlock(priv
->queue_lock
);
2615 if (priv
->changeList
->changeNote
[priv
->head_note
].flags
& IOPMWeInitiated
) {
2616 start_our_change(priv
->head_note
);
2619 nub
= priv
->changeList
->changeNote
[priv
->head_note
].parent
;
2620 if ( start_parent_change(priv
->head_note
) == IOPMAckImplied
) {
2621 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
2623 parent
->acknowledgePowerChange((IOService
*)nub
);
2629 IOLockUnlock(priv
->queue_lock
);
2634 //*********************************************************************************
2637 // A driver or child has acknowledged our notification of an upcoming power
2638 // change, and this acknowledgement is the last one pending
2639 // before we change power or after changing power.
2641 //*********************************************************************************
2643 void IOService::all_acked ( void )
2645 switch (priv
->machine_state
) {
2646 case IOPMour_prechange_1
:
2649 case IOPMour_prechange_4
:
2652 case IOPMparent_down_4
:
2655 case IOPMparent_down_6
:
2658 case IOPMparent_up_0
:
2661 case IOPMparent_up_6
:
2668 //*********************************************************************************
2669 // settleTimerExpired
2671 // Power has settled after our last change. Notify interested parties that
2672 // there is a new power state.
2673 //*********************************************************************************
2675 void IOService::settleTimerExpired ( void )
2677 if ( ! initialized
) {
2678 return; // we're unloading
2681 switch (priv
->machine_state
) {
2682 case IOPMour_prechange_3
:
2685 case IOPMparent_down_3
:
2688 case IOPMparent_up_5
:
2695 //*********************************************************************************
2696 // compute_settle_time
2698 // Compute the power-settling delay in microseconds for the
2699 // change from myCurrentState to head_note_state.
2700 //*********************************************************************************
2702 unsigned long IOService::compute_settle_time ( void )
2704 unsigned long totalTime
;
2707 totalTime
= 0; // compute total time to attain the new state
2708 i
= pm_vars
->myCurrentState
;
2709 if ( priv
->head_note_state
< pm_vars
->myCurrentState
) { // we're lowering power
2710 while ( i
> priv
->head_note_state
) {
2711 totalTime
+= pm_vars
->thePowerStates
[i
].settleDownTime
;
2716 if ( priv
->head_note_state
> pm_vars
->myCurrentState
) { // we're raising power
2717 while ( i
< priv
->head_note_state
) {
2718 totalTime
+= pm_vars
->thePowerStates
[i
+1].settleUpTime
;
2727 //*********************************************************************************
2730 // Enter with a power-settling delay in microseconds and start a nano-second
2731 // timer for that delay.
2732 //*********************************************************************************
2734 IOReturn
IOService::startSettleTimer ( unsigned long delay
)
2736 AbsoluteTime deadline
;
2738 clock_interval_to_deadline(delay
, kMicrosecondScale
, &deadline
);
2740 thread_call_enter_delayed(priv
->settleTimer
, deadline
);
2745 //*********************************************************************************
2748 // The acknowledgement timeout periodic timer has ticked.
2749 // If we are awaiting acks for a power change notification,
2750 // we decrement the timer word of each interested driver which hasn't acked.
2751 // If a timer word becomes zero, we pretend the driver aknowledged.
2752 // If we are waiting for the controlling driver to change the power
2753 // state of the hardware, we decrement its timer word, and if it becomes
2754 // zero, we pretend the driver acknowledged.
2755 //*********************************************************************************
2757 void IOService::ack_timer_ticked ( void )
2759 IOPMinformee
* nextObject
;
2761 if ( ! initialized
) {
2762 return; // we're unloading
2765 if (! acquire_lock() ) {
2769 switch (priv
->machine_state
) {
2770 case IOPMour_prechange_2
:
2771 case IOPMparent_down_5
:
2772 case IOPMparent_up_4
:
2773 if ( priv
->driver_timer
!= 0 ) { // are we waiting for our driver to make its change?
2774 priv
->driver_timer
-= 1; // yes, tick once
2775 if ( priv
->driver_timer
== 0 ) { // it's tardy, we'll go on without it
2776 IOUnlock(priv
->our_lock
);
2777 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogCtrlDriverTardy
,0,0);
2780 else { // still waiting, set timer again
2782 IOUnlock(priv
->our_lock
);
2786 IOUnlock(priv
->our_lock
);
2790 case IOPMour_prechange_1
:
2791 case IOPMour_prechange_4
:
2792 case IOPMparent_down_4
:
2793 case IOPMparent_down_6
:
2794 case IOPMparent_up_0
:
2795 case IOPMparent_up_6
:
2796 if (priv
->head_note_pendingAcks
!= 0 ) { // are we waiting for interested parties to acknowledge?
2797 nextObject
= priv
->interestedDrivers
->firstInList(); // yes, go through the list of interested drivers
2798 while ( nextObject
!= NULL
) { // and check each one
2799 if ( nextObject
->timer
> 0 ) {
2800 nextObject
->timer
-= 1;
2801 if ( nextObject
->timer
== 0 ) { // this one should have acked by now
2802 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogIntDriverTardy
,0,0);
2803 kprintf("interested driver tardy: %s\n",nextObject
->whatObject
->getName());
2804 priv
->head_note_pendingAcks
-= 1;
2807 nextObject
= priv
->interestedDrivers
->nextInList(nextObject
);
2809 if ( priv
->head_note_pendingAcks
== 0 ) { // is that the last?
2810 IOUnlock(priv
->our_lock
);
2811 all_acked(); // yes, we can continue
2813 else { // no, set timer again
2815 IOUnlock(priv
->our_lock
);
2819 IOUnlock(priv
->our_lock
);
2823 case IOPMparent_down_0
: // apps didn't respond to parent-down notification
2824 IOUnlock(priv
->our_lock
);
2825 IOLockLock(priv
->flags_lock
);
2826 if (pm_vars
->responseFlags
) {
2827 pm_vars
->responseFlags
->release(); // get rid of this stuff
2828 pm_vars
->responseFlags
= NULL
;
2830 IOLockUnlock(priv
->flags_lock
);
2831 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,5);
2832 parent_down_04(); // carry on with the change
2835 case IOPMparent_down_05
:
2836 IOUnlock(priv
->our_lock
);
2837 IOLockLock(priv
->flags_lock
);
2838 if (pm_vars
->responseFlags
) {
2839 pm_vars
->responseFlags
->release(); // get rid of this stuff
2840 pm_vars
->responseFlags
= NULL
;
2842 IOLockUnlock(priv
->flags_lock
);
2843 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,1);
2844 parent_down_05(); // carry on with the change
2847 case IOPMour_prechange_03
: // apps didn't respond to our power-down request
2848 IOUnlock(priv
->our_lock
);
2849 IOLockLock(priv
->flags_lock
);
2850 if (pm_vars
->responseFlags
) {
2851 pm_vars
->responseFlags
->release(); // get rid of this stuff
2852 pm_vars
->responseFlags
= NULL
;
2854 IOLockUnlock(priv
->flags_lock
);
2855 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,2);
2856 tellNoChangeDown(priv
->head_note_state
); // rescind the request
2857 priv
->head_note_flags
|= IOPMNotDone
; // mark the change note un-actioned
2858 all_done(); // and we're done
2861 case IOPMour_prechange_04
: // clients didn't respond to our power-down note
2862 IOUnlock(priv
->our_lock
);
2863 IOLockLock(priv
->flags_lock
);
2864 if (pm_vars
->responseFlags
) {
2865 pm_vars
->responseFlags
->release(); // get rid of this stuff
2866 pm_vars
->responseFlags
= NULL
;
2868 IOLockUnlock(priv
->flags_lock
);
2869 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,4);
2870 our_prechange_04(); // carry on with the change
2873 case IOPMour_prechange_05
: // apps didn't respond to our power-down notification
2874 IOUnlock(priv
->our_lock
);
2875 IOLockLock(priv
->flags_lock
);
2876 if (pm_vars
->responseFlags
) {
2877 pm_vars
->responseFlags
->release(); // get rid of this stuff
2878 pm_vars
->responseFlags
= NULL
;
2880 IOLockUnlock(priv
->flags_lock
);
2881 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,3);
2882 our_prechange_05(); // carry on with the change
2886 IOUnlock(priv
->our_lock
); // not waiting for acks
2892 //*********************************************************************************
2895 //*********************************************************************************
2897 void IOService::start_ack_timer ( void )
2899 AbsoluteTime deadline
;
2901 clock_interval_to_deadline(ACK_TIMER_PERIOD
, kNanosecondScale
, &deadline
);
2903 thread_call_enter_delayed(priv
->ackTimer
, deadline
);
2907 //*********************************************************************************
2910 //*********************************************************************************
2912 void IOService::stop_ack_timer ( void )
2914 thread_call_cancel(priv
->ackTimer
);
2918 //*********************************************************************************
2919 // c-language timer expiration functions
2921 //*********************************************************************************
2923 static void ack_timer_expired ( thread_call_param_t us
)
2925 ((IOService
*)us
)->ack_timer_ticked();
2929 static void settle_timer_expired ( thread_call_param_t us
)
2931 ((IOService
*)us
)->settleTimerExpired();
2935 //*********************************************************************************
2936 // add_child_to_active_change
2938 // A child has just registered with us. If there is
2939 // currently a change in progress, get the new party involved: if we
2940 // have notified all parties and are waiting for acks, notify the new
2942 //*********************************************************************************
2944 IOReturn
IOService::add_child_to_active_change ( IOPowerConnection
* newObject
)
2946 if (! acquire_lock() ) {
2950 switch (priv
->machine_state
) {
2951 case IOPMour_prechange_1
:
2952 case IOPMparent_down_4
:
2953 case IOPMparent_up_0
:
2954 priv
->head_note_pendingAcks
+= 2; // one for this child and one to prevent
2955 IOUnlock(priv
->our_lock
); // incoming acks from changing our state
2956 notifyChild(newObject
, true);
2957 if (! acquire_lock() ) {
2958 --priv
->head_note_pendingAcks
; // put it back
2961 if ( --priv
->head_note_pendingAcks
== 0 ) { // are we still waiting for acks?
2962 stop_ack_timer(); // no, stop the timer
2963 IOUnlock(priv
->our_lock
);
2964 all_acked(); // and now we can continue
2968 case IOPMour_prechange_4
:
2969 case IOPMparent_down_6
:
2970 case IOPMparent_up_6
:
2971 priv
->head_note_pendingAcks
+= 2; // one for this child and one to prevent
2972 IOUnlock(priv
->our_lock
); // incoming acks from changing our state
2973 notifyChild(newObject
, false);
2974 if (! acquire_lock() ) {
2975 --priv
->head_note_pendingAcks
; // put it back
2978 if ( --priv
->head_note_pendingAcks
== 0 ) { // are we still waiting for acks?
2979 stop_ack_timer(); // no, stop the timer
2980 IOUnlock(priv
->our_lock
);
2981 all_acked(); // and now we can continue
2986 IOUnlock(priv
->our_lock
);
2991 //*********************************************************************************
2992 // add_driver_to_active_change
2994 // An interested driver has just registered with us. If there is
2995 // currently a change in progress, get the new party involved: if we
2996 // have notified all parties and are waiting for acks, notify the new
2998 //*********************************************************************************
3000 IOReturn
IOService::add_driver_to_active_change ( IOPMinformee
* newObject
)
3002 if (! acquire_lock() ) {
3006 switch (priv
->machine_state
) {
3007 case IOPMour_prechange_1
:
3008 case IOPMparent_down_4
:
3009 case IOPMparent_up_0
:
3010 priv
->head_note_pendingAcks
+= 2; // one for this driver and one to prevent
3011 IOUnlock(priv
->our_lock
); // incoming acks from changing our state
3012 inform(newObject
, true); // inform the driver
3013 if (! acquire_lock() ) {
3014 --priv
->head_note_pendingAcks
; // put it back
3017 if ( --priv
->head_note_pendingAcks
== 0 ) { // are we still waiting for acks?
3018 stop_ack_timer(); // no, stop the timer
3019 IOUnlock(priv
->our_lock
);
3020 all_acked(); // and now we can continue
3024 case IOPMour_prechange_4
:
3025 case IOPMparent_down_6
:
3026 case IOPMparent_up_6
:
3027 priv
->head_note_pendingAcks
+= 2; // one for this driver and one to prevent
3028 IOUnlock(priv
->our_lock
); // incoming acks from changing our state
3029 inform(newObject
, false); // inform the driver
3030 if (! acquire_lock() ) {
3031 --priv
->head_note_pendingAcks
; // put it back
3034 if ( --priv
->head_note_pendingAcks
== 0 ) { // are we still waiting for acks?
3035 stop_ack_timer(); // no, stop the timer
3036 IOUnlock(priv
->our_lock
);
3037 all_acked(); // and now we can continue
3042 IOUnlock(priv
->our_lock
);
3047 //*********************************************************************************
3048 // start_parent_change
3050 // Here we begin the processing of a change note initiated by our parent
3051 // which is at the head of the queue.
3053 // It is possible for the change to be processed to completion and removed from the queue.
3054 // There are several possible interruptions to the processing, though, and they are:
3055 // we may have to wait for interested parties to acknowledge our pre-change notification,
3056 // we may have to wait for our controlling driver to change the hardware power state,
3057 // there may be a settling time after changing the hardware power state,
3058 // we may have to wait for interested parties to acknowledge our post-change notification,
3059 // we may have to wait for the acknowledgement timer expiration to substitute for the
3060 // acknowledgement from a failing driver.
3061 //*********************************************************************************
3063 IOReturn
IOService::start_parent_change ( unsigned long queue_head
)
3065 priv
->head_note
= queue_head
;
3066 priv
->head_note_flags
= priv
-> changeList
->changeNote
[priv
->head_note
].flags
;
3067 priv
->head_note_state
= priv
->changeList
->changeNote
[priv
->head_note
].newStateNumber
;
3068 priv
->imminentState
= priv
->head_note_state
;
3069 priv
->head_note_outputFlags
= priv
->changeList
->changeNote
[priv
->head_note
].outputPowerCharacter
;
3070 priv
->head_note_domainState
= priv
->changeList
->changeNote
[priv
->head_note
].domainState
;
3071 priv
->head_note_parent
= priv
->changeList
->changeNote
[priv
->head_note
].parent
;
3072 priv
->head_note_capabilityFlags
= priv
->changeList
->changeNote
[priv
->head_note
].capabilityFlags
;
3074 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartParentChange
,
3075 (unsigned long)priv
->head_note_state
,(unsigned long)pm_vars
->myCurrentState
);
3077 ask_parent( priv
->ourDesiredPowerState
); // if we need something and haven't told the parent, do so
3079 if ( priv
->head_note_state
< pm_vars
->myCurrentState
) { // power domain is lowering
3080 setParentInfo(priv
->changeList
->changeNote
[priv
->head_note
].singleParentState
,priv
->head_note_parent
);
3081 priv
->initial_change
= false;
3082 priv
->machine_state
= IOPMparent_down_0
; // tell apps and kernel clients
3083 if ( tellChangeDown1(priv
->head_note_state
) ) { // are we waiting for responses?
3084 return parent_down_0(); // no, notify priority clients
3086 return IOPMWillAckLater
; // yes
3089 if ( priv
->head_note_state
> pm_vars
->myCurrentState
) { // parent is raising power, we may or may not
3090 if ( priv
->ourDesiredPowerState
> pm_vars
->myCurrentState
) {
3091 if ( priv
->ourDesiredPowerState
< priv
->head_note_state
) {
3092 priv
->head_note_state
= priv
->ourDesiredPowerState
; // we do, but not all the way
3093 priv
->imminentState
= priv
->head_note_state
;
3094 priv
->head_note_outputFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].outputPowerCharacter
;
3095 priv
->head_note_capabilityFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].capabilityFlags
;
3096 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAmendParentChange
,(unsigned long)priv
->head_note_state
,0);
3100 priv
->head_note_state
= pm_vars
->myCurrentState
; // we don't
3101 priv
->imminentState
= priv
->head_note_state
;
3102 priv
->head_note_outputFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].outputPowerCharacter
;
3103 priv
->head_note_capabilityFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].capabilityFlags
;
3104 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAmendParentChange
,(unsigned long)priv
->head_note_state
,0);
3108 if ( (priv
->head_note_state
> pm_vars
->myCurrentState
) &&
3109 (priv
->head_note_flags
& IOPMDomainDidChange
) ) { // changing up
3110 priv
->initial_change
= false;
3111 priv
->machine_state
= IOPMparent_up_0
;
3112 if ( notifyAll(true) == IOPMAckImplied
) {
3113 return parent_up_1();
3115 return IOPMWillAckLater
; // they didn't all ack
3119 return IOPMAckImplied
; // a null change or power will go up
3123 //*********************************************************************************
3126 // Here we begin the processing of a change note initiated by us
3127 // which is at the head of the queue.
3129 // It is possible for the change to be processed to completion and removed from the queue.
3130 // There are several possible interruptions to the processing, though, and they are:
3131 // we may have to wait for interested parties to acknowledge our pre-change notification,
3132 // changes initiated by the parent will wait in the middle for powerStateDidChange,
3133 // we may have to wait for our controlling driver to change the hardware power state,
3134 // there may be a settling time after changing the hardware power state,
3135 // we may have to wait for interested parties to acknowledge our post-change notification,
3136 // we may have to wait for the acknowledgement timer expiration to substitute for the
3137 // acknowledgement from a failing driver.
3138 //*********************************************************************************
3140 void IOService::start_our_change ( unsigned long queue_head
)
3142 priv
->head_note
= queue_head
;
3143 priv
->head_note_flags
= priv
->changeList
->changeNote
[priv
->head_note
].flags
;
3144 priv
->head_note_state
= priv
->changeList
->changeNote
[priv
->head_note
].newStateNumber
;
3145 priv
->imminentState
= priv
->head_note_state
;
3146 priv
->head_note_outputFlags
= priv
->changeList
->changeNote
[priv
->head_note
].outputPowerCharacter
;
3147 priv
->head_note_capabilityFlags
= priv
->changeList
->changeNote
[priv
->head_note
].capabilityFlags
;
3149 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartDeviceChange
,
3150 (unsigned long)priv
->head_note_state
,(unsigned long)pm_vars
->myCurrentState
);
3152 if ( priv
->head_note_capabilityFlags
& IOPMNotAttainable
) { // can our driver switch to the new state?
3153 if ( ! priv
->we_are_root
) { // no, ask the parent to do it then
3154 ask_parent(priv
->head_note_state
);
3156 priv
-> head_note_flags
|= IOPMNotDone
; // mark the change note un-actioned
3157 all_done(); // and we're done
3160 // is there enough power in the domain?
3161 if ( (pm_vars
->maxCapability
< priv
->head_note_state
) && (! priv
->we_are_root
) ) {
3162 if ( ! priv
->we_are_root
) { // no, ask the parent to raise it
3163 ask_parent(priv
->head_note_state
);
3165 priv
->head_note_flags
|= IOPMNotDone
; // no, mark the change note un-actioned
3166 all_done(); // and we're done
3167 return; // till the parent raises power
3170 if ( ! priv
->initial_change
) {
3171 if ( priv
->head_note_state
== pm_vars
->myCurrentState
) {
3172 all_done(); // we initiated a null change; forget it
3176 priv
->initial_change
= false;
3178 if ( priv
->head_note_state
< pm_vars
->myCurrentState
) { // dropping power?
3179 priv
->machine_state
= IOPMour_prechange_03
; // yes, in case we have to wait for acks
3180 pm_vars
->doNotPowerDown
= false;
3181 pm_vars
->outofbandparameter
= kNotifyApps
; // ask apps and kernel clients if we can drop power
3182 if ( askChangeDown(priv
->head_note_state
) ) {
3183 if ( pm_vars
->doNotPowerDown
) { // don't have to wait, did any clients veto?
3184 tellNoChangeDown(priv
->head_note_state
); // yes, rescind the warning
3185 priv
-> head_note_flags
|= IOPMNotDone
; // mark the change note un-actioned
3186 all_done(); // and we're done
3189 our_prechange_03(); // no, tell'em we're dropping power
3194 if ( ! priv
->we_are_root
) { // we are raising power
3195 ask_parent(priv
->head_note_state
); // if this changes our power requirement, tell the parent
3197 priv
->machine_state
= IOPMour_prechange_1
; // in case they don't all ack
3198 if ( notifyAll(true) == IOPMAckImplied
) { // notify interested drivers and children
3205 //*********************************************************************************
3208 // Call the power domain parent to ask for a higher power state in the domain
3209 // or to suggest a lower power state.
3210 //*********************************************************************************
3212 IOReturn
IOService::ask_parent ( unsigned long requestedState
)
3216 IOPowerConnection
* connection
;
3218 unsigned long ourRequest
= pm_vars
->thePowerStates
[requestedState
].inputPowerRequirement
;
3220 if ( pm_vars
->thePowerStates
[requestedState
].capabilityFlags
& (kIOPMChildClamp
| kIOPMPreventIdleSleep
) ) {
3221 ourRequest
|= kIOPMPreventIdleSleep
;
3223 if ( pm_vars
->thePowerStates
[requestedState
].capabilityFlags
& (kIOPMChildClamp2
| kIOPMPreventSystemSleep
) ) {
3224 ourRequest
|= kIOPMPreventSystemSleep
;
3227 if ( priv
->previousRequest
== ourRequest
) { // is this a new desire?
3228 return IOPMNoErr
; // no, the parent knows already, just return
3231 if ( priv
->we_are_root
) {
3234 priv
->previousRequest
= ourRequest
;
3236 iter
= getParentIterator(gIOPowerPlane
);
3239 while ( (next
= iter
->getNextObject()) ) {
3240 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
3241 parent
= (IOService
*)connection
->copyParentEntry(gIOPowerPlane
);
3243 if ( parent
->requestPowerDomainState(ourRequest
,connection
,IOPMLowestState
)!= IOPMNoErr
) {
3244 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRequestDenied
,
3245 (unsigned long)priv
->previousRequest
,0);
3258 //*********************************************************************************
3261 // Call the controlling driver and have it change the power state of the
3262 // hardware. If it returns IOPMAckImplied, the change is complete, and
3263 // we return IOPMAckImplied. Otherwise, it will ack when the change
3264 // is done; we return IOPMWillAckLater.
3265 //*********************************************************************************
3266 IOReturn
IOService::instruct_driver ( unsigned long newState
)
3268 IOReturn return_code
;
3270 if ( pm_vars
->thePowerStates
[newState
].capabilityFlags
& IOPMNotAttainable
) { // can our driver switch to the desired state?
3271 return IOPMAckImplied
; // no, so don't try
3273 priv
->driver_timer
= -1;
3275 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogProgramHardware
,newState
,0);
3277 ioSPMTraceStart(IOPOWER_STATE
, * (int *) this, (int) newState
);
3278 return_code
= pm_vars
->theControllingDriver
->setPowerState( newState
,this ); // yes, instruct it
3279 ioSPMTraceEnd(IOPOWER_STATE
, * (int *) this, (int) newState
, (int) return_code
);
3281 if ( return_code
== IOPMAckImplied
) { // it finished
3282 priv
->driver_timer
= 0;
3283 return IOPMAckImplied
;
3286 if ( priv
->driver_timer
== 0 ) { // it acked behind our back
3287 return IOPMAckImplied
;
3290 if ( return_code
< 0 ) { // somebody goofed
3291 return IOPMAckImplied
;
3293 priv
->driver_timer
= (return_code
* ns_per_us
/ ACK_TIMER_PERIOD
) + 1; // it didn't finish
3294 return IOPMWillAckLater
;
3298 //*********************************************************************************
3301 // We are acquiring the lock we use to protect our queue head from
3302 // simutaneous access by a thread which calls acknowledgePowerStateChange
3303 // or acknowledgeSetPowerState and the ack timer expiration thread.
3304 // Return TRUE if we acquire the lock, and the queue head didn't change
3305 // while we were acquiring the lock (and maybe blocked).
3306 // If there is no queue head, or it changes while we are blocked,
3307 // return FALSE with the lock unlocked.
3308 //*********************************************************************************
3310 bool IOService::acquire_lock ( void )
3312 long current_change_note
;
3314 current_change_note
= priv
->head_note
;
3315 if ( current_change_note
== -1 ) {
3319 IOTakeLock(priv
->our_lock
);
3320 if ( current_change_note
== priv
->head_note
) {
3323 else { // we blocked and something changed radically
3324 IOUnlock(priv
->our_lock
); // so there's nothing to do any more
3330 //*********************************************************************************
3333 // Ask registered applications and kernel clients if we can change to a lower
3336 // Subclass can override this to send a different message type. Parameter is
3337 // the destination state number.
3339 // Return true if we don't have to wait for acknowledgements
3340 //*********************************************************************************
3342 bool IOService::askChangeDown ( unsigned long stateNum
)
3344 return tellClientsWithResponse(kIOMessageCanDevicePowerOff
);
3348 //*********************************************************************************
3351 // Notify registered applications and kernel clients that we are definitely
3354 // Return true if we don't have to wait for acknowledgements
3355 //*********************************************************************************
3357 bool IOService::tellChangeDown1 ( unsigned long stateNum
)
3359 pm_vars
->outofbandparameter
= kNotifyApps
;
3360 return tellChangeDown(stateNum
);
3364 //*********************************************************************************
3367 // Notify priority clients that we are definitely dropping power.
3369 // Return true if we don't have to wait for acknowledgements
3370 //*********************************************************************************
3372 bool IOService::tellChangeDown2 ( unsigned long stateNum
)
3374 pm_vars
->outofbandparameter
= kNotifyPriority
;
3375 return tellChangeDown(stateNum
);
3379 //*********************************************************************************
3382 // Notify registered applications and kernel clients that we are definitely
3385 // Subclass can override this to send a different message type. Parameter is
3386 // the destination state number.
3388 // Return true if we don't have to wait for acknowledgements
3389 //*********************************************************************************
3391 bool IOService::tellChangeDown ( unsigned long stateNum
)
3393 return tellClientsWithResponse(kIOMessageDeviceWillPowerOff
);
3397 //*********************************************************************************
3398 // tellClientsWithResponse
3400 // Notify registered applications and kernel clients that we are definitely
3403 // Return true if we don't have to wait for acknowledgements
3404 //*********************************************************************************
3406 bool IOService::tellClientsWithResponse ( int messageType
)
3408 struct context theContext
;
3409 AbsoluteTime deadline
;
3412 pm_vars
->responseFlags
= OSArray::withCapacity( 1 );
3413 pm_vars
->serialNumber
+= 1;
3415 theContext
.responseFlags
= pm_vars
->responseFlags
;
3416 theContext
.serialNumber
= pm_vars
->serialNumber
;
3417 theContext
.flags_lock
= priv
->flags_lock
;
3418 theContext
.counter
= 1;
3419 theContext
.msgType
= messageType
;
3420 theContext
.us
= this;
3421 theContext
.maxTimeRequested
= 0;
3422 theContext
.stateNumber
= priv
->head_note_state
;
3423 theContext
.stateFlags
= priv
->head_note_capabilityFlags
;
3425 IOLockLock(priv
->flags_lock
);
3426 aBool
= OSBoolean::withBoolean(false); // position zero is false to
3427 theContext
.responseFlags
->setObject(0,aBool
); // prevent allowCancelCommon from succeeding
3429 IOLockUnlock(priv
->flags_lock
);
3431 switch ( pm_vars
->outofbandparameter
) {
3433 applyToInterested(gIOAppPowerStateInterest
,tellAppWithResponse
,(void *)&theContext
);
3434 applyToInterested(gIOGeneralInterest
,tellClientWithResponse
,(void *)&theContext
);
3436 case kNotifyPriority
:
3437 applyToInterested(gIOPriorityPowerStateInterest
,tellClientWithResponse
,(void *)&theContext
);
3441 if (! acquire_lock() ) {
3444 IOLockLock(priv
->flags_lock
);
3445 aBool
= OSBoolean::withBoolean(true); // now fix position zero
3446 theContext
.responseFlags
->replaceObject(0,aBool
);
3448 IOLockUnlock(priv
->flags_lock
);
3450 if ( ! checkForDone() ) { // we have to wait for somebody
3451 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,theContext
.maxTimeRequested
,0);
3452 clock_interval_to_deadline(theContext
.maxTimeRequested
/ 1000, kMillisecondScale
, &deadline
);
3454 thread_call_enter_delayed(priv
->ackTimer
, deadline
);
3456 IOUnlock(priv
->our_lock
); // yes
3460 IOUnlock(priv
->our_lock
);
3461 IOLockLock(priv
->flags_lock
);
3462 pm_vars
->responseFlags
->release(); // everybody responded
3463 pm_vars
->responseFlags
= NULL
;
3464 IOLockUnlock(priv
->flags_lock
);
3470 //*********************************************************************************
3471 // tellAppWithResponse
3473 // We send a message to an application, and we expect a response, so we compute a
3474 // cookie we can identify the response with.
3475 //*********************************************************************************
3476 void tellAppWithResponse ( OSObject
* object
, void * context
)
3478 struct context
* theContext
= (struct context
*)context
;
3482 if( OSDynamicCast( IOService
, object
) ) {
3483 IOLockLock(theContext
->flags_lock
);
3484 aBool
= OSBoolean::withBoolean(true);
3485 theContext
->responseFlags
->setObject(theContext
->counter
,aBool
);
3487 IOLockUnlock(theContext
->flags_lock
);
3490 refcon
= ((theContext
->serialNumber
& 0xFFFF)<<16) + (theContext
->counter
& 0xFFFF);
3491 IOLockLock(theContext
->flags_lock
);
3492 aBool
= OSBoolean::withBoolean(false);
3493 theContext
->responseFlags
->setObject(theContext
->counter
,aBool
);
3495 IOLockUnlock(theContext
->flags_lock
);
3496 theContext
->us
->messageClient(theContext
->msgType
,object
,(void *)refcon
);
3497 if ( theContext
->maxTimeRequested
< k30seconds
) {
3498 theContext
->maxTimeRequested
= k30seconds
;
3501 theContext
->counter
+= 1;
3505 //*********************************************************************************
3506 // tellClientWithResponse
3508 // We send a message to an in-kernel client, and we expect a response, so we compute a
3509 // cookie we can identify the response with.
3510 // If it doesn't understand the notification (it is not power-management savvy)
3511 // we won't wait for it to prepare for sleep. If it tells us via a return code
3512 // in the passed struct that it is currently ready, we won't wait for it to prepare.
3513 // If it tells us via the return code in the struct that it does need time, we will chill.
3514 //*********************************************************************************
3515 void tellClientWithResponse ( OSObject
* object
, void * context
)
3517 struct context
* theContext
= (struct context
*)context
;
3518 IOPowerStateChangeNotification notify
;
3524 refcon
= ((theContext
->serialNumber
& 0xFFFF)<<16) + (theContext
->counter
& 0xFFFF);
3525 IOLockLock(theContext
->flags_lock
);
3526 aBool
= OSBoolean::withBoolean(false);
3527 theContext
->responseFlags
->setObject(theContext
->counter
,aBool
);
3529 IOLockUnlock(theContext
->flags_lock
);
3531 notify
.powerRef
= (void *)refcon
;
3532 notify
.returnValue
= 0;
3533 notify
.stateNumber
= theContext
->stateNumber
;
3534 notify
.stateFlags
= theContext
->stateFlags
;
3535 retCode
= theContext
->us
->messageClient(theContext
->msgType
,object
,(void *)¬ify
);
3536 if ( retCode
== kIOReturnSuccess
) {
3537 if ( notify
.returnValue
== 0 ) { // client doesn't want time to respond
3538 IOLockLock(theContext
->flags_lock
);
3539 aBool
= OSBoolean::withBoolean(true);
3540 theContext
->responseFlags
->replaceObject(theContext
->counter
,aBool
); // so set its flag true
3542 IOLockUnlock(theContext
->flags_lock
);
3545 IOLockLock(theContext
->flags_lock
);
3546 theFlag
= theContext
->responseFlags
->getObject(theContext
->counter
); // it does want time, and it hasn't
3547 if ( theFlag
!= 0 ) { // responded yet
3548 if ( ((OSBoolean
*)theFlag
)->isFalse() ) { // so note its time requirement
3549 if ( theContext
->maxTimeRequested
< notify
.returnValue
) {
3550 theContext
->maxTimeRequested
= notify
.returnValue
;
3554 IOLockUnlock(theContext
->flags_lock
);
3557 else { // not a client of ours
3558 IOLockLock(theContext
->flags_lock
);
3559 aBool
= OSBoolean::withBoolean(true); // so we won't be waiting for response
3560 theContext
->responseFlags
->replaceObject(theContext
->counter
,aBool
);
3562 IOLockUnlock(theContext
->flags_lock
);
3564 theContext
->counter
+= 1;
3568 //*********************************************************************************
3571 // Notify registered applications and kernel clients that we are not
3574 // Subclass can override this to send a different message type. Parameter is
3575 // the aborted destination state number.
3576 //*********************************************************************************
3578 void IOService::tellNoChangeDown ( unsigned long )
3580 return tellClients(kIOMessageDeviceWillNotPowerOff
);
3584 //*********************************************************************************
3587 // Notify registered applications and kernel clients that we are raising power.
3589 // Subclass can override this to send a different message type. Parameter is
3590 // the aborted destination state number.
3591 //*********************************************************************************
3593 void IOService::tellChangeUp ( unsigned long )
3595 return tellClients(kIOMessageDeviceHasPoweredOn
);
3599 //*********************************************************************************
3602 // Notify registered applications and kernel clients of something.
3603 //*********************************************************************************
3605 void IOService::tellClients ( int messageType
)
3607 struct context theContext
;
3609 theContext
.msgType
= messageType
;
3610 theContext
.us
= this;
3611 theContext
.stateNumber
= priv
->head_note_state
;
3612 theContext
.stateFlags
= priv
->head_note_capabilityFlags
;
3614 applyToInterested(gIOAppPowerStateInterest
,tellClient
,(void *)&theContext
);
3615 applyToInterested(gIOGeneralInterest
,tellClient
,(void *)&theContext
);
3619 //*********************************************************************************
3622 // Notify a registered application or kernel client of something.
3623 //*********************************************************************************
3624 void tellClient ( OSObject
* object
, void * context
)
3626 struct context
* theContext
= (struct context
*)context
;
3627 IOPowerStateChangeNotification notify
;
3629 notify
.powerRef
= (void *) 0;
3630 notify
.returnValue
= 0;
3631 notify
.stateNumber
= theContext
->stateNumber
;
3632 notify
.stateFlags
= theContext
->stateFlags
;
3634 theContext
->us
->messageClient(theContext
->msgType
,object
, ¬ify
);
3638 // **********************************************************************************
3641 // **********************************************************************************
3642 bool IOService::checkForDone ( void )
3647 IOLockLock(priv
->flags_lock
);
3648 if ( pm_vars
->responseFlags
== NULL
) {
3649 IOLockUnlock(priv
->flags_lock
);
3652 for ( i
= 0; ; i
++ ) {
3653 theFlag
= pm_vars
->responseFlags
->getObject(i
);
3654 if ( theFlag
== NULL
) {
3657 if ( ((OSBoolean
*)theFlag
)->isFalse() ) {
3658 IOLockUnlock(priv
->flags_lock
);
3662 IOLockUnlock(priv
->flags_lock
);
3667 // **********************************************************************************
3670 // **********************************************************************************
3671 bool IOService::responseValid ( unsigned long x
)
3673 UInt16 serialComponent
;
3674 UInt16 ordinalComponent
;
3676 unsigned long refcon
= (unsigned long)x
;
3679 serialComponent
= (refcon
>>16) & 0xFFFF;
3680 ordinalComponent
= refcon
& 0xFFFF;
3682 if ( serialComponent
!= pm_vars
->serialNumber
) {
3686 IOLockLock(priv
->flags_lock
);
3687 if ( pm_vars
->responseFlags
== NULL
) {
3688 IOLockUnlock(priv
->flags_lock
);
3692 theFlag
= pm_vars
->responseFlags
->getObject(ordinalComponent
);
3694 if ( theFlag
== 0 ) {
3695 IOLockUnlock(priv
->flags_lock
);
3699 if ( ((OSBoolean
*)theFlag
)->isFalse() ) {
3700 aBool
= OSBoolean::withBoolean(true);
3701 pm_vars
->responseFlags
->replaceObject(ordinalComponent
,aBool
);
3705 IOLockUnlock(priv
->flags_lock
);
3710 // **********************************************************************************
3713 // Our power state is about to lower, and we have notified applications
3714 // and kernel clients, and one of them has acknowledged. If this is the last to do
3715 // so, and all acknowledgements are positive, we continue with the power change.
3717 // We serialize this processing with timer expiration with a command gate on the
3718 // power management workloop, which the timer expiration is command gated to as well.
3719 // **********************************************************************************
3720 IOReturn
IOService::allowPowerChange ( unsigned long refcon
)
3722 if ( ! initialized
) {
3723 return kIOReturnSuccess
; // we're unloading
3726 return pm_vars
->PMcommandGate
->runAction(serializedAllowPowerChange
,(void *)refcon
);
3730 IOReturn
serializedAllowPowerChange ( OSObject
*owner
, void * refcon
, void *, void *, void *)
3732 return ((IOService
*)owner
)->serializedAllowPowerChange2((unsigned long)refcon
);
3735 IOReturn
IOService::serializedAllowPowerChange2 ( unsigned long refcon
)
3737 if ( ! responseValid(refcon
) ) { // response valid?
3738 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr5
,refcon
,0);
3739 return kIOReturnSuccess
; // no, just return
3741 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientAcknowledge
,refcon
,0);
3743 return allowCancelCommon();
3747 // **********************************************************************************
3748 // cancelPowerChange
3750 // Our power state is about to lower, and we have notified applications
3751 // and kernel clients, and one of them has vetoed the change. If this is the last
3752 // client to respond, we abandon the power change.
3754 // We serialize this processing with timer expiration with a command gate on the
3755 // power management workloop, which the timer expiration is command gated to as well.
3756 // **********************************************************************************
3757 IOReturn
IOService::cancelPowerChange ( unsigned long refcon
)
3759 if ( ! initialized
) {
3760 return kIOReturnSuccess
; // we're unloading
3763 return pm_vars
->PMcommandGate
->runAction(serializedCancelPowerChange
,(void *)refcon
);
3767 IOReturn
serializedCancelPowerChange ( OSObject
*owner
, void * refcon
, void *, void *, void *)
3769 return ((IOService
*)owner
)->serializedCancelPowerChange2((unsigned long)refcon
);
3772 IOReturn
IOService::serializedCancelPowerChange2 ( unsigned long refcon
)
3774 if ( ! responseValid(refcon
) ) { // response valid?
3775 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr5
,refcon
,0);
3776 return kIOReturnSuccess
; // no, just return
3778 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientCancel
,refcon
,0);
3780 pm_vars
->doNotPowerDown
= true;
3782 return allowCancelCommon();
3786 // **********************************************************************************
3787 // allowCancelCommon
3789 // **********************************************************************************
3790 IOReturn
IOService::allowCancelCommon ( void )
3792 if (! acquire_lock() ) {
3793 return kIOReturnSuccess
;
3796 if ( checkForDone() ) { // is this the last response?
3797 stop_ack_timer(); // yes, stop the timer
3798 IOUnlock(priv
->our_lock
);
3799 IOLockLock(priv
->flags_lock
);
3800 if ( pm_vars
->responseFlags
) {
3801 pm_vars
->responseFlags
->release();
3802 pm_vars
->responseFlags
= NULL
;
3804 IOLockUnlock(priv
->flags_lock
);
3805 switch (priv
->machine_state
) {
3806 case IOPMour_prechange_03
: // our change, was it vetoed?
3807 if ( ! pm_vars
->doNotPowerDown
) {
3808 our_prechange_03(); // no, we can continue
3811 tellNoChangeDown(priv
->head_note_state
); // yes, rescind the warning
3812 priv
->head_note_flags
|= IOPMNotDone
; // mark the change note un-actioned
3813 all_done(); // and we're done
3816 case IOPMour_prechange_04
:
3819 case IOPMour_prechange_05
:
3820 our_prechange_05(); // our change, continue
3822 case IOPMparent_down_0
:
3823 parent_down_04(); // parent change, continue
3825 case IOPMparent_down_05
:
3826 parent_down_05(); // parent change, continue
3831 IOUnlock(priv
->our_lock
); // not done yet
3832 return kIOReturnSuccess
;
3836 //*********************************************************************************
3839 // Set to highest available power state for a minimum of duration milliseconds
3840 //*********************************************************************************
3842 #define kFiveMinutesInNanoSeconds (300 * NSEC_PER_SEC)
3844 void IOService::clampPowerOn (unsigned long duration
)
3847 changePowerStateToPriv (pm_vars->theNumberOfPowerStates-1);
3849 if ( priv->clampTimerEventSrc == NULL ) {
3850 priv->clampTimerEventSrc = IOTimerEventSource::timerEventSource(this,
3851 c_PM_Clamp_Timer_Expired);
3853 IOWorkLoop * workLoop = getPMworkloop ();
3855 if ( !priv->clampTimerEventSrc || !workLoop ||
3856 ( workLoop->addEventSource( priv->clampTimerEventSrc) != kIOReturnSuccess) ) {
3861 priv->clampTimerEventSrc->setTimeout(300*USEC_PER_SEC, USEC_PER_SEC);
3865 //*********************************************************************************
3866 // PM_Clamp_Timer_Expired
3868 // called when clamp timer expires...set power state to 0.
3869 //*********************************************************************************
3871 void IOService::PM_Clamp_Timer_Expired (void)
3873 if ( ! initialized
) {
3874 return; // we're unloading
3877 changePowerStateToPriv (0);
3880 //*********************************************************************************
3881 // c_PM_clamp_Timer_Expired (C Func)
3883 // Called when our clamp timer expires...we will call the object method.
3884 //*********************************************************************************
3886 void c_PM_Clamp_Timer_Expired (OSObject
* client
, IOTimerEventSource
*)
3889 ((IOService
*)client
)->PM_Clamp_Timer_Expired ();
3893 //*********************************************************************************
3896 // Does nothing here. This should be implemented in a subclass driver.
3897 //*********************************************************************************
3899 IOReturn
IOService::setPowerState ( unsigned long powerStateOrdinal
, IOService
* whatDevice
)
3905 //*********************************************************************************
3906 // maxCapabilityForDomainState
3908 // Finds the highest power state in the array whose input power
3909 // requirement is equal to the input parameter. Where a more intelligent
3910 // decision is possible, override this in the subclassed driver.
3911 //*********************************************************************************
3913 unsigned long IOService::maxCapabilityForDomainState ( IOPMPowerFlags domainState
)
3917 if (pm_vars
->theNumberOfPowerStates
== 0 ) {
3920 for ( i
= (pm_vars
->theNumberOfPowerStates
)-1; i
>= 0; i
-- ) {
3921 if ( (domainState
& pm_vars
->thePowerStates
[i
].inputPowerRequirement
) == pm_vars
->thePowerStates
[i
].inputPowerRequirement
) {
3929 //*********************************************************************************
3930 // initialPowerStateForDomainState
3932 // Finds the highest power state in the array whose input power
3933 // requirement is equal to the input parameter. Where a more intelligent
3934 // decision is possible, override this in the subclassed driver.
3935 //*********************************************************************************
3937 unsigned long IOService::initialPowerStateForDomainState ( IOPMPowerFlags domainState
)
3941 if (pm_vars
->theNumberOfPowerStates
== 0 ) {
3944 for ( i
= (pm_vars
->theNumberOfPowerStates
)-1; i
>= 0; i
-- ) {
3945 if ( (domainState
& pm_vars
->thePowerStates
[i
].inputPowerRequirement
) == pm_vars
->thePowerStates
[i
].inputPowerRequirement
) {
3953 //*********************************************************************************
3954 // powerStateForDomainState
3956 // Finds the highest power state in the array whose input power
3957 // requirement is equal to the input parameter. Where a more intelligent
3958 // decision is possible, override this in the subclassed driver.
3959 //*********************************************************************************
3961 unsigned long IOService::powerStateForDomainState ( IOPMPowerFlags domainState
)
3965 if (pm_vars
->theNumberOfPowerStates
== 0 ) {
3968 for ( i
= (pm_vars
->theNumberOfPowerStates
)-1; i
>= 0; i
-- ) {
3969 if ( (domainState
& pm_vars
->thePowerStates
[i
].inputPowerRequirement
) == pm_vars
->thePowerStates
[i
].inputPowerRequirement
) {
3977 //*********************************************************************************
3980 // Does nothing here. This should be implemented in a subclass driver.
3981 //*********************************************************************************
3983 bool IOService::didYouWakeSystem ( void )
3989 //*********************************************************************************
3990 // powerStateWillChangeTo
3992 // Does nothing here. This should be implemented in a subclass driver.
3993 //*********************************************************************************
3995 IOReturn
IOService::powerStateWillChangeTo ( IOPMPowerFlags
, unsigned long, IOService
*)
4001 //*********************************************************************************
4002 // powerStateDidChangeTo
4004 // Does nothing here. This should be implemented in a subclass driver.
4005 //*********************************************************************************
4007 IOReturn
IOService::powerStateDidChangeTo ( IOPMPowerFlags
, unsigned long, IOService
*)
4013 //*********************************************************************************
4016 // Does nothing here. This should be implemented in a subclass policy-maker.
4017 //*********************************************************************************
4019 void IOService::powerChangeDone ( unsigned long )
4024 //*********************************************************************************
4027 // Does nothing here. This should be implemented in a subclass driver.
4028 //*********************************************************************************
4030 IOReturn
IOService::newTemperature ( long currentTemp
, IOService
* whichZone
)
4038 #define super OSObject
4040 OSDefineMetaClassAndStructors(IOPMprot
, OSObject
)
4041 //*********************************************************************************
4044 // Serialize protected instance variables for debug output.
4045 //*********************************************************************************
4046 bool IOPMprot::serialize(OSSerialize
*s
) const
4048 OSString
* theOSString
;
4054 buffer
= ptr
= IONew(char, 2000);
4058 ptr
+= sprintf(ptr
,"{ theNumberOfPowerStates = %d, ",(unsigned int)theNumberOfPowerStates
);
4060 if ( theNumberOfPowerStates
!= 0 ) {
4061 ptr
+= sprintf(ptr
,"version %d, ",(unsigned int)thePowerStates
[0].version
);
4064 if ( theNumberOfPowerStates
!= 0 ) {
4065 for ( i
= 0; i
< (int)theNumberOfPowerStates
; i
++ ) {
4066 ptr
+= sprintf(ptr
,"power state %d = { ",i
);
4067 ptr
+= sprintf(ptr
,"capabilityFlags %08x, ",(unsigned int)thePowerStates
[i
].capabilityFlags
);
4068 ptr
+= sprintf(ptr
,"outputPowerCharacter %08x, ",(unsigned int)thePowerStates
[i
].outputPowerCharacter
);
4069 ptr
+= sprintf(ptr
,"inputPowerRequirement %08x, ",(unsigned int)thePowerStates
[i
].inputPowerRequirement
);
4070 ptr
+= sprintf(ptr
,"staticPower %d, ",(unsigned int)thePowerStates
[i
].staticPower
);
4071 ptr
+= sprintf(ptr
,"unbudgetedPower %d, ",(unsigned int)thePowerStates
[i
].unbudgetedPower
);
4072 ptr
+= sprintf(ptr
,"powerToAttain %d, ",(unsigned int)thePowerStates
[i
].powerToAttain
);
4073 ptr
+= sprintf(ptr
,"timeToAttain %d, ",(unsigned int)thePowerStates
[i
].timeToAttain
);
4074 ptr
+= sprintf(ptr
,"settleUpTime %d, ",(unsigned int)thePowerStates
[i
].settleUpTime
);
4075 ptr
+= sprintf(ptr
,"timeToLower %d, ",(unsigned int)thePowerStates
[i
].timeToLower
);
4076 ptr
+= sprintf(ptr
,"settleDownTime %d, ",(unsigned int)thePowerStates
[i
].settleDownTime
);
4077 ptr
+= sprintf(ptr
,"powerDomainBudget %d }, ",(unsigned int)thePowerStates
[i
].powerDomainBudget
);
4081 ptr
+= sprintf(ptr
,"aggressiveness = %d, ",(unsigned int)aggressiveness
);
4082 ptr
+= sprintf(ptr
,"myCurrentState = %d, ",(unsigned int)myCurrentState
);
4083 ptr
+= sprintf(ptr
,"parentsCurrentPowerFlags = %08x, ",(unsigned int)parentsCurrentPowerFlags
);
4084 ptr
+= sprintf(ptr
,"maxCapability = %d }",(unsigned int)maxCapability
);
4086 theOSString
= OSString::withCString(buffer
);
4087 rtn_code
= theOSString
->serialize(s
);
4088 theOSString
->release();
4089 IODelete(buffer
, char, 2000);
4096 #define super OSObject
4098 OSDefineMetaClassAndStructors(IOPMpriv
, OSObject
)
4099 //*********************************************************************************
4102 // Serialize private instance variables for debug output.
4103 //*********************************************************************************
4104 bool IOPMpriv::serialize(OSSerialize
*s
) const
4106 OSString
* theOSString
;
4110 IOPMinformee
* nextObject
;
4112 buffer
= ptr
= IONew(char, 2000);
4116 ptr
+= sprintf(ptr
,"{ this object = %08x",(unsigned int)owner
);
4117 if ( we_are_root
) {
4118 ptr
+= sprintf(ptr
," (root)");
4120 ptr
+= sprintf(ptr
,", ");
4122 nextObject
= interestedDrivers
->firstInList(); // display interested drivers
4123 while ( nextObject
!= NULL
) {
4124 ptr
+= sprintf(ptr
,"interested driver = %08x, ",(unsigned int)nextObject
->whatObject
);
4125 nextObject
= interestedDrivers
->nextInList(nextObject
);
4128 if ( machine_state
!= IOPMfinished
) {
4129 ptr
+= sprintf(ptr
,"machine_state = %d, ",(unsigned int)machine_state
);
4130 ptr
+= sprintf(ptr
,"driver_timer = %d, ",(unsigned int)driver_timer
);
4131 ptr
+= sprintf(ptr
,"settle_time = %d, ",(unsigned int)settle_time
);
4132 ptr
+= sprintf(ptr
,"head_note_flags = %08x, ",(unsigned int)head_note_flags
);
4133 ptr
+= sprintf(ptr
,"head_note_state = %d, ",(unsigned int)head_note_state
);
4134 ptr
+= sprintf(ptr
,"head_note_outputFlags = %08x, ",(unsigned int)head_note_outputFlags
);
4135 ptr
+= sprintf(ptr
,"head_note_domainState = %08x, ",(unsigned int)head_note_domainState
);
4136 ptr
+= sprintf(ptr
,"head_note_capabilityFlags = %08x, ",(unsigned int)head_note_capabilityFlags
);
4137 ptr
+= sprintf(ptr
,"head_note_pendingAcks = %d, ",(unsigned int)head_note_pendingAcks
);
4140 if ( device_overrides
) {
4141 ptr
+= sprintf(ptr
,"device overrides, ");
4143 ptr
+= sprintf(ptr
,"driverDesire = %d, ",(unsigned int)driverDesire
);
4144 ptr
+= sprintf(ptr
,"deviceDesire = %d, ",(unsigned int)deviceDesire
);
4145 ptr
+= sprintf(ptr
,"ourDesiredPowerState = %d, ",(unsigned int)ourDesiredPowerState
);
4146 ptr
+= sprintf(ptr
,"previousRequest = %d }",(unsigned int)previousRequest
);
4148 theOSString
= OSString::withCString(buffer
);
4149 rtn_code
= theOSString
->serialize(s
);
4150 theOSString
->release();
4151 IODelete(buffer
, char, 2000);