]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOServicePM.cpp
xnu-124.1.tar.gz
[apple/xnu.git] / iokit / Kernel / IOServicePM.cpp
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
11 *
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
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23#include <IOKit/IOService.h>
24#include <IOKit/IOLib.h>
25#include <IOKit/IOCommandQueue.h>
26#include <IOKit/IOCommandGate.h>
27#include <IOKit/IOTimerEventSource.h>
28#include <IOKit/IOWorkLoop.h>
29#include <IOKit/IOPlatformExpert.h>
30#include <IOKit/assert.h>
31#include <IOKit/IOMessage.h>
32#include <IOKit/pwr_mgt/IOPMinformee.h>
33#include "IOKit/pwr_mgt/IOPMinformeeList.h"
34#include "IOKit/pwr_mgt/IOPMchangeNoteList.h"
35#include "IOKit/pwr_mgt/IOPMlog.h"
36#include "IOKit/pwr_mgt/IOPowerConnection.h"
37
38static void ack_timer_expired(thread_call_param_t);
39static void settle_timer_expired(thread_call_param_t);
40void PMreceiveCmd ( OSObject *, void *, void *, void *, void * );
41static void PM_idle_timer_expired(OSObject *, IOTimerEventSource *);
42static void c_PM_Clamp_Timer_Expired (OSObject * client,IOTimerEventSource *);
43void tellAppWithResponse ( OSObject * object, void * context);
44void tellClientWithResponse ( OSObject * object, void * context);
45void tellClient ( OSObject * object, void * context);
46IOReturn serializedAllowPowerChange ( OSObject *, void *, void *, void *, void *);
47IOReturn serializedCancelPowerChange ( OSObject *, void *, void *, void *, void *);
48
49extern const IORegistryPlane * gIOPowerPlane;
50
51
52// and there's 1000 nanoseconds in a microsecond:
53#define ns_per_us 1000
54
55
56// The current change note is processed by a state machine.
57// Inputs are acks from interested parties, ack from the controlling driver,
58// ack timeouts, settle timeout, and powerStateDidChange from the parent.
59// These are the states:
60
61enum {
62 IOPMour_prechange_03 = 1,
63 IOPMour_prechange_05,
64 IOPMour_prechange_1,
65 IOPMour_prechange_2,
66 IOPMour_prechange_3,
67 IOPMour_prechange_4,
68 IOPMparent_down_0,
69 IOPMparent_down_2,
70 IOPMparent_down_3,
71 IOPMparent_down_4,
72 IOPMparent_down_5,
73 IOPMparent_down_6,
74 IOPMparent_up_0,
75 IOPMparent_up_1,
76 IOPMparent_up_4,
77 IOPMparent_up_5,
78 IOPMparent_up_6,
79 IOPMfinished
80 };
81
82struct context { // used for applyToInterested
83 OSArray * responseFlags;
84 UInt16 serialNumber;
85 UInt16 counter;
86 UInt32 maxTimeRequested;
87 int msgType;
88 IOService * us;
89 IOLock * flags_lock;
90};
91
92 // five minutes in microseconds
93#define FIVE_MINUTES 5*60*1000000
94#define k15seconds 15*1000000
95
96/*
97 There are two different kinds of power state changes. One is initiated by a subclassed device object which has either
98 decided to change power state, or its controlling driver has suggested it, or some other driver wants to use the
99 idle device and has asked it to become usable. The second kind of power state change is initiated by the power
100 domain parent. The two are handled slightly differently.
101
102There is a queue of so-called change notifications, or change notes for short. Usually the queue is empty, and when
103 it isn't, usually there is one change note in it, but since it's possible to have more than one power state change pending
104 at one time, a queue is implemented. Example: the subclass device decides it's idle and initiates a change to a lower
105 power state. This causes interested parties to be notified, but they don't all acknowledge right away. This causes the
106 change note to sit in the queue until all the acks are received. During this time, the device decides it isn't idle anymore and
107 wants to raise power back up again. This change can't be started, however, because the previous one isn't complete yet,
108 so the second one waits in the queue. During this time, the parent decides to lower or raise the power state of the entire
109 power domain and notifies the device, and that notification goes into the queue, too, and can't be actioned until the
110 others are.
111
112 This is how a power change initiated by the subclass device is handled:
113 First, all interested parties are notified of the change via their powerStateWillChangeTo method. If they all don't
114 acknowledge via return code, then we have to wait. If they do, or when they finally all acknowledge via our
115 acknowledgePowerChange method, then we can continue. We call the controlling driver, instructing it to change to
116 the new state. Then we wait for power to settle. If there is no settling-time, or after it has passed, we notify
117 interested parties again, this time via their powerStateDidChangeTo methods. When they have all acked, we're done.
118 If we lowered power and don't need the power domain to be in its current power state, we suggest to the parent that
119 it lower the power domain state.
120
121 This is how a change to a lower power domain state initiated by the parent is handled:
122 First, we figure out what power state we will be in when the new domain state is reached. Then all interested parties are
123 notified that we are moving to that new state. When they have acknowledged, we call the controlling driver to assume
124 that state and we wait for power to settle. Then we acknowledge our preparedness to our parent. When all its interested
125 parties have acknowledged, it lowers power and then notifies its interested parties again. When we get this call, we notify
126 our interested parties that the power state has changed, and when they have all acknowledged, we're done.
127
128 This is how a change to a higher power domain state initiated by the parent is handled:
129 We figure out what power state we will be in when the new domain state is reached. If it is different from our current
130 state we acknowledge the parent. When all the parent's interested parties have acknowledged, it raises power in the
131domain and waits for power to settle. Then it notifies everyone that the new state has been reached. When we get this call,
132 we call the controlling driver, instructing it to assume the new state, and wait for power to settle. Then we notify our interested
133 parties. When they all acknowledge we are done.
134
135 In either of the two cases above, it is possible that we will not be changing state even though the domain is. Examples:
136 A change to a lower domain state may not affect us because we are already in a low enough state, and
137 We will not take advantage of a change to a higher domain state, because we have no need of the higher power.
138 In such a case, there is nothing to do but acknowledge the parent. So when the parent calls our powerDomainWillChange
139 method, and we decide that we will not be changing state, we merely acknowledge the parent, via return code, and wait.
140 When the parent subsequently calls powerStateDidChange, we acknowledge again via return code, and the change is complete.
141
142 Power state changes are processed in a state machine, and since there are four varieties of power state changes, there are
143 four major paths through the state machine:
144
145 The fourth is nearly trivial. In this path, the parent is changing the domain state, but we are not changing the device state.
146 The change starts when the parent calls powerDomainWillChange. All we do is acknowledge the parent.
147When the parent calls powerStateDidChange, we acknowledge the parent again, and we're done.
148
149 The first is fairly simple. It starts when a power domain child calls requestPowerDomainState and we decide to change power states
150 to accomodate the child, or if our power-controlling driver calls changePowerStateTo, or if some other driver which is using our
151 device calls makeUsable, or if a subclassed object calls changePowerStateToPriv. These are all power changes initiated by us, not
152 forced upon us by the parent. We start by notifying interested parties. If they all acknowledge via return code, we can go
153 on to state "our_prechange_1". Otherwise, we start the ack timer and wait for the stragglers to acknowlege by calling
154 acknowledgePowerChange. We move on to state "our_prechange_1" when all the stragglers have acknowledged,
155 or when the ack timer expires on all those which didn't acknowledge. In "our_prechange_1" we call the power-controlling
156 driver to change the power state of the hardware. If it returns saying it has done so, we go on to state "our_prechange_2".
157 Otherwise, we have to wait for it, so we set the ack timer and wait. When it calls acknowledgeSetPowerState, or when the
158 ack timer expires, we go on. In "our_prechange_2", we look in the power state array to see if there is any settle time required
159 when changing from our current state to the new state. If not, we go right away to "our_prechange_3". Otherwise, we
160 set the settle timer and wait. When it expires, we move on. In "our_prechange_3" state, we notify all our interested parties
161 via their powerStateDidChange methods that we have finished changing power state. If they all acknowledge via return
162 code, we move on to "our_prechange_4". Otherwise we set the ack timer and wait. When they have all acknowledged, or
163 when the ack timer has expired for those that didn't, we move on to "our_prechange_4", where we remove the used
164 change note from the head of the queue and start the next one if one exists.
165
166 Parent-initiated changes are more complex in the state machine. First, power going up and power going down are handled
167 differently, so they have different paths throught the state machine. Second, we can acknowledge the parent's notification
168 in two different ways, so each of the parent paths is really two.
169
170 When the parent calls our powerDomainWillChange method, notifying us that it will lower power in the domain, we decide
171 what state that will put our device in. Then we embark on the state machine path "IOPMparent_down_1"
172 and "IOPMparent_down_2", in which we notify interested parties of the upcoming change, instruct our driver to make
173 the change, check for settle time, and notify interested parties of the completed change. If we get to the end of this path without
174 stalling due to an interested party which didn't acknowledge via return code, due to the controlling driver not able to change
175 state right away, or due to a non-zero settling time, then we return IOPMAckImplied to the parent, and we're done with the change.
176 If we do stall in any of those states, we return IOPMWillAckLater to the parent and enter the parallel path "IOPMparent_down_4"
177 "IOPMparent_down_5", and "IOPMparent_down_3", where we continue with the same processing, except that at the end we
178 acknowledge the parent explicitly via acknowledgePowerChange, and we're done with the change.
179Then when the parent calls us at powerStateDidChange we acknowledging via return code, because we have already made
180 the power change. In any case, when we are done we remove the used change note from the head of the queue and start on the next one.
181
182 The case of the parent raising power in the domain is handled similarly in that there are parallel paths, one for no-stall
183 that ends in implicit acknowleging the parent, and one that has stalled at least once that ends in explicit acknowledging
184 the parent. This case is different, though in that our device changes state in the second half, after the parent calls
185 powerStateDidChange rather than before, as in the power-lowering case.
186
187 When the parent calls our powerDomainWillChange method, notifying us that it will raise power in the domain, we acknowledge
188 via return code, because there's really nothing we can do until the power is actually raised in the domain.
189 When the parent calls us at powerStateDidChange, we start by notifying our interested parties. If they all acknowledge via return code,
190 we go on to" IOPMparent_up_1" to instruct the driver to raise its power level. After that, we check for any
191 necessary settling time in "IOPMparent_up_2", and we notify all interested parties that power has changed
192 in "IOPMparent_up_3". If none of these operations stall, we acknowledge the parent via return code, release
193 the change note, and start the next, if there is one. If one of them does stall, we enter the parallel path "IOPMparent_up_0",
194 "IOPMparent_up_4", "IOPMparent_up_5", and "IOPMparent_up_6", which ends with
195 our explicit acknowledgement to the parent.
196
197*/
198
199
200const char priv_key[ ] = "Power Management private data";
201const char prot_key[ ] = "Power Management protected data";
202
203
204void IOService::PMinit ( void )
205{
206 if ( ! initialized ) {
207
208 pm_vars = new IOPMprot; // make space for our variables
209 priv = new IOPMpriv;
210 pm_vars->init();
211 priv->init();
212
213 setProperty(prot_key, (OSObject *) pm_vars); // add these to the properties
214 setProperty(priv_key, (OSObject *) priv);
215
216 priv->owner = this;
217 pm_vars->theNumberOfPowerStates = 0; // then initialize them
218 priv->we_are_root = false;
219 pm_vars->theControllingDriver = NULL;
220 priv->our_lock = IOLockAlloc();
221 priv->flags_lock = IOLockAlloc();
222 priv->interestedDrivers = new IOPMinformeeList;
223 priv->interestedDrivers->initialize();
224 priv->changeList = new IOPMchangeNoteList;
225 priv->changeList->initialize();
226 pm_vars->aggressiveness = 0;
227 for (unsigned int i = 0; i <= kMaxType; i++) {
228 pm_vars->current_aggressiveness_values[i] = 0;
229 pm_vars->current_aggressiveness_valid[i] = false;
230 }
231 pm_vars->myCurrentState = 0;
232 priv->imminentState = 0;
233 priv->askingFor = 0;
234 priv->ourDesiredPowerState = 0;
235 pm_vars->parentsCurrentPowerFlags = 0;
236 pm_vars->maxCapability = 0;
237 priv->driverDesire = 0;
238 priv->deviceDesire = 0;
239 priv->initial_change = true;
240 priv->need_to_become_usable = false;
241 priv->previousRequest = 0;
242 priv->device_overrides = false;
243 priv->machine_state = IOPMfinished;
244 pm_vars->commandQueue = NULL;
245 priv->timerEventSrc = NULL;
246 priv->clampTimerEventSrc = NULL;
247 pm_vars->PMworkloop = NULL;
248 priv->activityLock = NULL;
249 pm_vars->ourName = getName();
250 pm_vars->thePlatform = getPlatform();
251 pm_vars->parentsKnowState = false;
252 assert( pm_vars->thePlatform != 0 );
253 priv->clampOn = false;
254 pm_vars->serialNumber = 0;
255 pm_vars->responseFlags = NULL;
256 pm_vars->doNotPowerDown = true;
257 pm_vars->PMcommandGate = NULL;
258 priv->ackTimer = thread_call_allocate((thread_call_func_t)ack_timer_expired, (thread_call_param_t)this);
259 priv->settleTimer = thread_call_allocate((thread_call_func_t)settle_timer_expired, (thread_call_param_t)this);
260 initialized = true;
261 }
262}
263
264
265//*********************************************************************************
266// PMstop
267//
268// Free up the data created in PMinit.
269//*********************************************************************************
270void IOService::PMstop ( void )
271{
272 OSIterator * iter;
273 OSObject * next;
274 IOPowerConnection * connection;
275
276 initialized = false;
277
278 removeProperty(prot_key); // remove the properties
279 removeProperty(priv_key);
280
281 iter = getParentIterator(gIOPowerPlane); // detach parents
282
283 if ( iter ) {
284 while ( (next = iter->getNextObject()) ) {
285 if ( (connection = OSDynamicCast(IOPowerConnection,next)) ) {
286 ((IOService *)(connection->getParentEntry(gIOPowerPlane)))->removePowerChild(connection);
287 }
288 }
289 iter->release();
290 }
291 detachAbove( gIOPowerPlane ); // detach IOConnections
292
293 pm_vars->parentsKnowState = false; // no more power state changes
294#if 0
295
296// This loop is insufficient. Currently only leaf nodes are removed, and it's not clear today what
297// it means to remove a subtree from the tree. Should the IOPowerConnection at the top of it stay
298// or go? Should its child be notified of a change in the domain state?
299
300 iter = getChildIterator(gIOPowerPlane); // detach children
301
302 if ( iter ) {
303 while ( (next = iter->getNextObject()) ) {
304 if ( (connection = OSDynamicCast(IOPowerConnection,next)) ) {
305 removePowerChild(connection);
306 }
307 }
308 iter->release();
309 }
310#endif
311
312 if ( priv->clampTimerEventSrc != NULL ) {
313 getPMworkloop()->removeEventSource(priv->clampTimerEventSrc);
314 priv->clampTimerEventSrc->release();
315 priv->clampTimerEventSrc = NULL;
316 }
317 if ( priv->timerEventSrc != NULL ) {
318 pm_vars->PMworkloop->removeEventSource(priv->timerEventSrc);
319 priv->timerEventSrc->release();
320 priv->timerEventSrc = NULL;
321 }
322 thread_call_free(priv->settleTimer);
323 thread_call_free(priv->ackTimer);
324
325 priv->interestedDrivers->release(); // remove lists
326 priv->changeList->release();
327 pm_vars->release(); // remove the instance variables
328 priv->release();
329 pm_vars = NULL;
330 priv = NULL;
331}
332
333
334//*********************************************************************************
335// joinPMtree
336//
337// A policy-maker calls its nub here when initializing, to be attached into
338// the power management hierarchy. The default function is to call the
339// platform expert, which knows how to do it. This method is overridden
340// by a nub subclass which may either know how to do it, or may need
341// to take other action.
342//
343// This may be the only "power management" method used in a nub,
344// meaning it may not be initialized for power management.
345//*********************************************************************************
346void IOService::joinPMtree ( IOService * driver )
347{
348 IOPlatformExpert * thePlatform;
349
350 thePlatform = getPlatform();
351 assert(thePlatform != 0 );
352 thePlatform->PMRegisterDevice(this,driver);
353}
354
355
356//*********************************************************************************
357// youAreRoot
358//
359// Power Managment is informing us that we are the root power domain.
360// The only difference between us and any other power domain is that
361// we have no parent and therefore never call it.
362//*********************************************************************************
363IOReturn IOService::youAreRoot ( void )
364{
365 priv-> we_are_root = true;
366 pm_vars->parentsKnowState = true;
367 attachToParent( getRegistryRoot(),gIOPowerPlane );
368
369 return IOPMNoErr;
370}
371
372
373//*********************************************************************************
374// setPowerParent
375//
376// Power Management is informing us who our parent is.
377// If we have a controlling driver, find out, given our newly-informed
378// power domain state, what state it would be in, and then tell it
379// to assume that state.
380//*********************************************************************************
381IOReturn IOService::setPowerParent ( IOPowerConnection * theParent, bool stateKnown, IOPMPowerFlags currentState )
382{
383 OSIterator * iter;
384 OSObject * next;
385 IOPowerConnection * connection;
386 unsigned long tempDesire;
387
388 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogSetParent,stateKnown,currentState);
389
390 if ( stateKnown && ((pm_vars->PMworkloop == NULL) || (pm_vars->PMcommandGate == NULL)) ) {
391 getPMworkloop(); // we have a path to the root
392 if ( pm_vars->PMworkloop != NULL ) { // find out the workloop
393 if ( pm_vars->PMcommandGate == NULL ) { // and make our command gate
394 pm_vars->PMcommandGate = IOCommandGate::commandGate((OSObject *)this);
395 if ( pm_vars->PMcommandGate != NULL ) {
396 pm_vars->PMworkloop->addEventSource(pm_vars->PMcommandGate);
397 }
398 }
399 }
400 }
401
402 theParent->setParentCurrentPowerFlags(currentState); // set our connection data
403 theParent->setParentKnowsState(stateKnown);
404
405 pm_vars->parentsKnowState = true; // combine parent knowledge
406 pm_vars->parentsCurrentPowerFlags = 0;
407
408 iter = getParentIterator(gIOPowerPlane);
409
410 if ( iter ) {
411 while ( (next = iter->getNextObject()) ) {
412 if ( (connection = OSDynamicCast(IOPowerConnection,next)) ) {
413 pm_vars->parentsKnowState &= connection->parentKnowsState();
414 pm_vars->parentsCurrentPowerFlags |= connection->parentCurrentPowerFlags();
415 }
416 }
417 iter->release();
418 }
419
420 if ( (pm_vars->theControllingDriver != NULL) &&
421 (pm_vars->parentsKnowState) ) {
422 pm_vars->maxCapability = pm_vars->theControllingDriver->maxCapabilityForDomainState(pm_vars->parentsCurrentPowerFlags);
423 tempDesire = priv->deviceDesire; // initially change into the state we are already in
424 priv->deviceDesire = pm_vars->theControllingDriver->initialPowerStateForDomainState(pm_vars->parentsCurrentPowerFlags);
425 changeState();
426 priv->deviceDesire = tempDesire; // put this back like before
427 }
428 return IOPMNoErr;
429}
430
431
432//*********************************************************************************
433// addPowerChild
434//
435// Power Management is informing us who our children are.
436//*********************************************************************************
437IOReturn IOService::addPowerChild ( IOService * theChild )
438{
439 IOPowerConnection * connection;
440 unsigned int i;
441
442 if ( ! initialized ) {
443 return IOPMNotYetInitialized; // we're not a power-managed IOService
444 }
445
446 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAddChild,0,0);
447
448 connection = new IOPowerConnection; // make a nub
449
450 connection->init();
451 connection->start(this);
452
453 attachToChild( connection,gIOPowerPlane ); // connect it up
454 connection->attachToChild( theChild,gIOPowerPlane );
455 connection->release();
456
457 if ( (pm_vars->theControllingDriver == NULL) || // tell it the current state of the power domain
458 ! (inPlane(gIOPowerPlane)) ||
459 ! (pm_vars->parentsKnowState) ) {
460 theChild->setPowerParent(connection,false,0);
461 if ( inPlane(gIOPowerPlane) ) {
462 for (i = 0; i <= kMaxType; i++) {
463 if ( pm_vars->current_aggressiveness_valid[i] ) {
464 theChild->setAggressiveness (i, pm_vars->current_aggressiveness_values[i]);
465 }
466 }
467 }
468 }
469 else {
470 theChild->setPowerParent(connection,true,pm_vars->thePowerStates[pm_vars->myCurrentState].outputPowerCharacter);
471 for (i = 0; i <= kMaxType; i++) {
472 if ( pm_vars->current_aggressiveness_valid[i] ) {
473 theChild->setAggressiveness (i, pm_vars->current_aggressiveness_values[i]);
474 }
475 }
476 add_child_to_active_change(connection); // catch it up if change is in progress
477 }
478
479 return IOPMNoErr;
480}
481
482
483//*********************************************************************************
484// removePowerChild
485//
486//*********************************************************************************
487IOReturn IOService::removePowerChild ( IOPowerConnection * theChild )
488{
489 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogRemoveChild,0,0);
490
491 detachFromChild(theChild,gIOPowerPlane); // remove the departing child
492
493 if ( (pm_vars->theControllingDriver == NULL) || // if not fully initialized
494 ! (inPlane(gIOPowerPlane)) ||
495 ! (pm_vars->parentsKnowState) ) {
496 return IOPMNoErr; // we can do no more
497 }
498
499 changeState(); // change state if we can now tolerate lower power
500
501 return IOPMNoErr;
502}
503
504
505//*********************************************************************************
506// registerPowerDriver
507//
508// A driver has called us volunteering to control power to our device.
509// If the power state array it provides is richer than the one we already
510// know about (supplied by an earlier volunteer), then accept the offer.
511// Notify all interested parties of our power state, which we now know.
512//*********************************************************************************
513
514IOReturn IOService::registerPowerDriver ( IOService * controllingDriver, IOPMPowerState* powerStates, unsigned long numberOfStates )
515{
516 unsigned long i;
517 unsigned long tempDesire;
518
519 if ( (numberOfStates > pm_vars->theNumberOfPowerStates) && (numberOfStates > 1) ) {
520 if ( priv->changeList->currentChange() == -1 ) {
521 if ( controllingDriver != NULL ) {
522 if ( numberOfStates <= IOPMMaxPowerStates ) {
523 switch ( powerStates[0].version ) {
524 case 1:
525 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriver,
526 (unsigned long)numberOfStates, (unsigned long)powerStates[0].version);
527 for ( i = 0; i < numberOfStates; i++ ) {
528 pm_vars->thePowerStates[i] = powerStates[i];
529 }
530 break;
531 case 2:
532 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriver,
533 (unsigned long) numberOfStates,(unsigned long) powerStates[0].version);
534 for ( i = 0; i < numberOfStates; i++ ) {
535 pm_vars->thePowerStates[i].version = powerStates[i].version;
536 pm_vars->thePowerStates[i].capabilityFlags = powerStates[i].capabilityFlags;
537 pm_vars->thePowerStates[i].outputPowerCharacter = powerStates[i].outputPowerCharacter;
538 pm_vars->thePowerStates[i].inputPowerRequirement = powerStates[i].inputPowerRequirement;
539 pm_vars->thePowerStates[i].staticPower = powerStates[i].staticPower;
540 pm_vars->thePowerStates[i].unbudgetedPower = powerStates[i].unbudgetedPower;
541 pm_vars->thePowerStates[i].powerToAttain = powerStates[i].powerToAttain;
542 pm_vars->thePowerStates[i].timeToAttain = powerStates[i].timeToAttain;
543 pm_vars->thePowerStates[i].settleUpTime = powerStates[i].settleUpTime;
544 pm_vars->thePowerStates[i].timeToLower = powerStates[i].timeToLower;
545 pm_vars->thePowerStates[i].settleDownTime = powerStates[i].settleDownTime;
546 pm_vars->thePowerStates[i].powerDomainBudget = powerStates[i].powerDomainBudget;
547 }
548 break;
549 default:
550 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriverErr1,
551 (unsigned long)powerStates[0].version,0);
552 return IOPMNoErr;
553 }
554
555 pm_vars->myCharacterFlags = 0; // make a mask of all the character bits we know about
556 for ( i = 0; i < numberOfStates; i++ ) {
557 pm_vars->myCharacterFlags |= pm_vars->thePowerStates[i].outputPowerCharacter;
558 }
559
560 pm_vars->theNumberOfPowerStates = numberOfStates;
561 pm_vars->theControllingDriver = controllingDriver;
562 if ( priv->interestedDrivers->findItem(controllingDriver) == NULL ) { // register it as interested
563 registerInterestedDriver (controllingDriver ); // unless already done
564 }
565 if ( priv->need_to_become_usable ) {
566 priv->need_to_become_usable = false;
567 priv->deviceDesire = pm_vars->theNumberOfPowerStates - 1;
568 }
569
570 if ( inPlane(gIOPowerPlane) &&
571 (pm_vars->parentsKnowState) ) {
572 pm_vars->maxCapability = pm_vars->theControllingDriver->maxCapabilityForDomainState(pm_vars->parentsCurrentPowerFlags);
573 tempDesire = priv->deviceDesire; // initially change into the state we are already in
574 priv->deviceDesire = pm_vars->theControllingDriver->initialPowerStateForDomainState(pm_vars->parentsCurrentPowerFlags);
575 changeState();
576 priv->deviceDesire = tempDesire; // put this back like before
577 }
578 }
579 else {
580 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriverErr2,(unsigned long)numberOfStates,0);
581 }
582 }
583 else {
584 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriverErr4,0,0);
585 }
586 }
587 }
588 else {
589 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriverErr5,(unsigned long)numberOfStates,0);
590 }
591 return IOPMNoErr;
592}
593
594//*********************************************************************************
595// registerInterestedDriver
596//
597// Add the caller to our list of interested drivers and return our current
598// power state. If we don't have a power-controlling driver yet, we will
599// call this interested driver again later when we do get a driver and find
600// out what the current power state of the device is.
601//*********************************************************************************
602
603IOPMPowerFlags IOService::registerInterestedDriver ( IOService * theDriver )
604{
605 IOPMinformee * newInformee;
606 IOPMPowerFlags futureCapability;
607
608 if (theDriver == NULL ) {
609 return 0;
610 }
611
612 newInformee = new IOPMinformee; // make new driver node
613 newInformee->initialize(theDriver);
614 priv->interestedDrivers->addToList(newInformee); // add it to list of drivers
615
616 if ( (pm_vars->theControllingDriver == NULL) ||
617 ! (inPlane(gIOPowerPlane)) ||
618 ! (pm_vars->parentsKnowState) ) {
619 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogInterestedDriver,IOPMNotPowerManaged,0);
620 return IOPMNotPowerManaged; // can't tell it a state yet
621 }
622
623 switch (priv->machine_state) { // can we notify new driver of a change in progress?
624 case IOPMour_prechange_1:
625 case IOPMour_prechange_4:
626 case IOPMparent_down_4:
627 case IOPMparent_down_6:
628 case IOPMparent_up_0:
629 case IOPMparent_up_6:
630 futureCapability = priv->head_note_capabilityFlags; // yes, remember what we tell it
631 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogInterestedDriver,(unsigned long)futureCapability,1);
632 add_driver_to_active_change(newInformee); // notify it
633 return futureCapability; // and return the same thing
634 }
635
636 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogInterestedDriver,
637 (unsigned long) pm_vars->thePowerStates[pm_vars->myCurrentState].capabilityFlags,2);
638 return pm_vars->thePowerStates[pm_vars->myCurrentState].capabilityFlags; // no, return current capability
639}
640
641
642//*********************************************************************************
643// deRegisterInterestedDriver
644//
645//*********************************************************************************
646IOReturn IOService::deRegisterInterestedDriver ( IOService * theDriver )
647{
648 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogRemoveDriver,0,0);
649
650 priv->interestedDrivers->removeFromList(theDriver); // remove the departing driver
651
652 return IOPMNoErr;
653}
654
655
656//*********************************************************************************
657// acknowledgePowerChange
658//
659// After we notified one of the interested drivers or a power-domain child
660// of an impending change in power, it has called to say it is now
661// prepared for the change. If this object is the last to
662// acknowledge this change, we take whatever action we have been waiting
663// for.
664// That may include acknowledging to our parent. In this case, we do it
665// last of all to insure that this doesn't cause the parent to call us some-
666// where else and alter data we are relying on here (like the very existance
667// of a "current change note".)
668//*********************************************************************************
669
670IOReturn IOService::acknowledgePowerChange ( IOService * whichObject )
671{
672 IOPMinformee * ackingObject;
673
674 ackingObject = priv->interestedDrivers->findItem(whichObject); // one of our interested drivers?
675 if ( ackingObject == NULL ) {
676 if ( ! isChild(whichObject,gIOPowerPlane) ) {
677 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr1,0,0);
678 kprintf("errant driver: %s\n",whichObject->getName());
679 return IOPMNoErr; // no, just return
680 }
681 else {
682 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChildAcknowledge,0,0);
683 }
684 }
685 else {
686 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogDriverAcknowledge,0,0);
687 }
688
689 if (! acquire_lock() ) {
690 return IOPMNoErr;
691 }
692
693 if (priv->head_note_pendingAcks != 0 ) { // yes, make sure we're expecting acks
694 if ( ackingObject != NULL ) { // it's an interested driver
695 if ( ackingObject->timer != 0 ) { // make sure we're expecting this ack
696 ackingObject->timer = 0; // mark it acked
697 priv->head_note_pendingAcks -= 1; // that's one fewer to worry about
698 if ( priv->head_note_pendingAcks == 0 ) { // is that the last?
699 stop_ack_timer(); // yes, stop the timer
700 IOUnlock(priv->our_lock);
701 all_acked(); // and now we can continue
702 return IOPMNoErr;
703 }
704 }
705 else {
706 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr2,0,0); // this driver has already acked
707 kprintf("errant driver: %s\n",whichObject->getName());
708 }
709 }
710 else { // it's a child
711 priv->head_note_pendingAcks -= 1; // that's one fewer to worry about
712 if ( priv->head_note_pendingAcks == 0 ) { // is that the last?
713 stop_ack_timer(); // yes, stop the timer
714 IOUnlock(priv->our_lock);
715 all_acked(); // and now we can continue
716 return IOPMNoErr;
717 }
718 }
719 }
720 else {
721 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr3,0,0); // not expecting anybody to ack
722 kprintf("errant driver: %s\n",whichObject->getName());
723 }
724 IOUnlock(priv->our_lock);
725 return IOPMNoErr;
726}
727
728//*********************************************************************************
729// acknowledgeSetPowerState
730//
731// After we instructed our controlling driver to change power states,
732// it has called to say it has finished doing so.
733// We continue to process the power state change.
734//*********************************************************************************
735
736IOReturn IOService::acknowledgeSetPowerState ( void )
737{
738 if (! acquire_lock() ) {
739 return IOPMNoErr;
740 }
741 if ( priv->driver_timer == -1 ) {
742 priv->driver_timer = 0; // driver is acking instead of using return code
743 }
744 else {
745 if ( priv->driver_timer > 0 ) { // are we expecting this?
746 stop_ack_timer(); // yes, stop the timer
747 priv->driver_timer = 0;
748 IOUnlock(priv->our_lock);
749 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogDriverAcknowledgeSet,0,0);
750 driver_acked();
751 return IOPMNoErr;
752 }
753 else {
754 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr4,0,0); // no
755 }
756 }
757 IOUnlock(priv->our_lock);
758 return IOPMNoErr;
759}
760
761
762//*********************************************************************************
763// driver_acked
764//
765// Either the controlling driver has called acknowledgeSetPowerState
766// or the acknowledgement timer has expired while waiting for that.
767// We carry on processing the current change note.
768//*********************************************************************************
769
770void IOService::driver_acked ( void )
771{
772 switch (priv->machine_state) {
773 case IOPMour_prechange_2:
774 our_prechange_2();
775 break;
776 case IOPMparent_down_5:
777 parent_down_5();
778 break;
779 case IOPMparent_up_4:
780 parent_up_4();
781 break;
782 }
783}
784
785
786//*********************************************************************************
787// powerDomainWillChangeTo
788//
789// Called by the power-hierarchy parent notifying of a new power state
790// in the power domain.
791// We enqueue a parent power-change to our queue of power changes.
792// This may or may not cause us to change power, depending on what
793// kind of change is occuring in the domain.
794//*********************************************************************************
795
796IOReturn IOService::powerDomainWillChangeTo ( IOPMPowerFlags newPowerStateFlags, IOPowerConnection * whichParent )
797{
798 OSIterator * iter;
799 OSObject * next;
800 IOPowerConnection * connection;
801 unsigned long newStateNumber;
802 IOPMPowerFlags combinedPowerFlags;
803
804 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogWillChange,(unsigned long)newPowerStateFlags,0);
805
806 if ( ! inPlane(gIOPowerPlane) ) {
807 return IOPMAckImplied; // somebody goofed
808 }
809
810 if ( (pm_vars->PMworkloop == NULL) || (pm_vars->PMcommandGate == NULL) ) {
811 getPMworkloop(); // we have a path to the root,
812 if ( pm_vars->PMworkloop != NULL ) { // so find out the workloop
813 if ( pm_vars->PMcommandGate == NULL ) { // and make our command gate
814 pm_vars->PMcommandGate = IOCommandGate::commandGate((OSObject *)this);
815 if ( pm_vars->PMcommandGate != NULL ) {
816 pm_vars->PMworkloop->addEventSource(pm_vars->PMcommandGate);
817 }
818 }
819 }
820 }
821
822 combinedPowerFlags = 0; // combine parents' power states
823
824 iter = getParentIterator(gIOPowerPlane);
825
826 if ( iter ) {
827 while ( (next = iter->getNextObject()) ) {
828 if ( (connection = OSDynamicCast(IOPowerConnection,next)) ) {
829 if ( connection == whichParent ){
830 combinedPowerFlags |= newPowerStateFlags;
831 }
832 else {
833 combinedPowerFlags |= connection->parentCurrentPowerFlags();
834 }
835 }
836 }
837 iter->release();
838 }
839
840 if ( pm_vars->theControllingDriver == NULL ) { // we can't take any more action
841 return IOPMAckImplied;
842 }
843 newStateNumber = pm_vars->theControllingDriver->maxCapabilityForDomainState(combinedPowerFlags);
844 return enqueuePowerChange(IOPMParentInitiated | IOPMDomainWillChange, newStateNumber,combinedPowerFlags,whichParent); //make the change
845}
846
847
848//*********************************************************************************
849// powerDomainDidChangeTo
850//
851// Called by the power-hierarchy parent after the power state of the power domain
852// has settled at a new level.
853// We enqueue a parent power-change to our queue of power changes.
854// This may or may not cause us to change power, depending on what
855// kind of change is occuring in the domain.
856//*********************************************************************************
857
858IOReturn IOService::powerDomainDidChangeTo ( IOPMPowerFlags newPowerStateFlags, IOPowerConnection * whichParent )
859{
860 OSIterator * iter;
861 OSObject * next;
862 IOPowerConnection * connection;
863 unsigned long newStateNumber;
864
865 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogDidChange,newPowerStateFlags,0);
866
867 whichParent->setParentCurrentPowerFlags(newPowerStateFlags); // set our connection data
868 whichParent->setParentKnowsState(true);
869
870 pm_vars->parentsCurrentPowerFlags = 0; // recompute our parent info
871 pm_vars->parentsKnowState = true;
872
873 iter = getParentIterator(gIOPowerPlane);
874
875 if ( iter ) {
876 while ( (next = iter->getNextObject()) ) {
877 if ( (connection = OSDynamicCast(IOPowerConnection,next)) ) {
878 pm_vars->parentsKnowState &= connection->parentKnowsState();
879 pm_vars->parentsCurrentPowerFlags |= connection->parentCurrentPowerFlags();
880 }
881 }
882 iter->release();
883 }
884
885 if ( pm_vars->theControllingDriver == NULL ) {
886 return IOPMAckImplied;
887 }
888
889 newStateNumber = pm_vars->theControllingDriver->maxCapabilityForDomainState(pm_vars->parentsCurrentPowerFlags);
890 return enqueuePowerChange(IOPMParentInitiated | IOPMDomainDidChange, newStateNumber,pm_vars->parentsCurrentPowerFlags,whichParent); // tell interested parties about it
891}
892
893
894//*********************************************************************************
895// requestPowerDomainState
896//
897//
898//*********************************************************************************
899IOReturn IOService::requestPowerDomainState ( IOPMPowerFlags desiredState, IOPowerConnection * whichChild, unsigned long specification )
900{
901 unsigned long i;
902 OSIterator * iter;
903 OSObject * next;
904 IOPowerConnection * connection;
905
906 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogRequestDomain,
907 (unsigned long)desiredState,(unsigned long)specification);
908
909 if ( pm_vars->theControllingDriver == NULL) {
910 return IOPMNotYetInitialized;
911 }
912
913 switch (specification) {
914 case IOPMLowestState:
915 i = 0;
916 while ( i < pm_vars->theNumberOfPowerStates ) {
917 if ( ( pm_vars->thePowerStates[i].outputPowerCharacter & desiredState) == (desiredState & pm_vars->myCharacterFlags) ) {
918 break;
919 }
920 i++;
921 }
922 if ( i >= pm_vars->theNumberOfPowerStates ) {
923 return IOPMNoSuchState;
924 }
925 break;
926
927 case IOPMNextLowerState:
928 i = pm_vars->myCurrentState - 1;
929 while ( i >= 0 ) {
930 if ( ( pm_vars->thePowerStates[i].outputPowerCharacter & desiredState) == (desiredState & pm_vars->myCharacterFlags) ) {
931 break;
932 }
933 i--;
934 }
935 if ( i < 0 ) {
936 return IOPMNoSuchState;
937 }
938 break;
939
940 case IOPMHighestState:
941 i = pm_vars->theNumberOfPowerStates;
942 while ( i >= 0 ) {
943 i--;
944 if ( ( pm_vars->thePowerStates[i].outputPowerCharacter & desiredState) == (desiredState & pm_vars->myCharacterFlags) ) {
945 break;
946 }
947 }
948 if ( i < 0 ) {
949 return IOPMNoSuchState;
950 }
951 break;
952
953 case IOPMNextHigherState:
954 i = pm_vars->myCurrentState + 1;
955 while ( i < pm_vars->theNumberOfPowerStates ) {
956 if ( ( pm_vars->thePowerStates[i].outputPowerCharacter & desiredState) == (desiredState & pm_vars->myCharacterFlags) ) {
957 break;
958 }
959 i++;
960 }
961 if ( i == pm_vars->theNumberOfPowerStates ) {
962 return IOPMNoSuchState;
963 }
964 break;
965
966 default:
967 return IOPMBadSpecification;
968 }
969
970// Now loop through the children. When we encounter the calling child, save
971// the new state as this child's desire. Then, compute a new maximum
972// of everybody's desires.
973
974 iter = getChildIterator(gIOPowerPlane);
975
976 if ( iter ) {
977 while ( (next = iter->getNextObject()) ) {
978 if ( (connection = OSDynamicCast(IOPowerConnection,next)) ) {
979 if ( connection == whichChild ) {
980 connection->setDesiredDomainState(i);
981 }
982 }
983 }
984 iter->release();
985 }
986
987 if ( inPlane(gIOPowerPlane) &&
988 (pm_vars->parentsKnowState) ) {
989 changeState(); // change state if all children can now tolerate lower power
990 }
991
992 if ( priv->clampOn ) { // are we clamped on, waiting for this child?
993 priv->clampOn = false; // yes, remove the clamp
994 changePowerStateToPriv(0);
995 }
996
997 return IOPMNoErr;
998}
999
1000
1001//*********************************************************************************
1002// temporaryPowerClampOn
1003//
1004// A power domain wants to clamp its power on till it has children which
1005// will thendetermine the power domain state.
1006//
1007// We enter the highest state until addPowerChild is called.
1008//*********************************************************************************
1009
1010IOReturn IOService::temporaryPowerClampOn ( void )
1011{
1012 priv->clampOn = true;
1013 makeUsable();
1014 return IOPMNoErr;
1015}
1016
1017
1018//*********************************************************************************
1019// makeUsable
1020//
1021// Some client of our device is asking that we become usable. Although
1022// this has not come from a subclassed device object, treat it exactly
1023// as if it had. In this way, subsequent requests for lower power from
1024// a subclassed device object will pre-empt this request.
1025//
1026// We treat this as a subclass object request to switch to the
1027// highest power state.
1028//*********************************************************************************
1029
1030IOReturn IOService::makeUsable ( void )
1031{
1032 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogMakeUsable,0,0);
1033
1034 if ( pm_vars->theControllingDriver == NULL ) {
1035 priv->need_to_become_usable = true;
1036 return IOPMNoErr;
1037 }
1038 priv->deviceDesire = pm_vars->theNumberOfPowerStates - 1;
1039 if ( inPlane(gIOPowerPlane) && (pm_vars->parentsKnowState) ) {
1040 return changeState();
1041 }
1042 return IOPMNoErr;
1043}
1044
1045
1046//*********************************************************************************
1047// currentCapability
1048//
1049//*********************************************************************************
1050
1051IOPMPowerFlags IOService::currentCapability ( void )
1052{
1053 if ( pm_vars->theControllingDriver == NULL ) {
1054 return 0;
1055 }
1056 else {
1057 return pm_vars->thePowerStates[pm_vars->myCurrentState].capabilityFlags;
1058 }
1059}
1060
1061
1062//*********************************************************************************
1063// changePowerStateTo
1064//
1065// For some reason, our power-controlling driver has decided it needs to change
1066// power state. We enqueue the power change so that appropriate parties
1067// will be notified, and then we will instruct the driver to make the change.
1068//*********************************************************************************
1069
1070IOReturn IOService::changePowerStateTo ( unsigned long ordinal )
1071{
1072 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChangeStateTo,ordinal,0);
1073
1074 if ( ordinal >= pm_vars->theNumberOfPowerStates ) {
1075 return IOPMParameterError;
1076 }
1077 priv->driverDesire = ordinal;
1078 if ( inPlane(gIOPowerPlane) && (pm_vars->parentsKnowState) ) {
1079 return changeState();
1080 }
1081
1082 return IOPMNoErr;
1083}
1084
1085//*********************************************************************************
1086// changePowerStateToPriv
1087//
1088// For some reason, a subclassed device object has decided it needs to change
1089// power state. We enqueue the power change so that appropriate parties
1090// will be notified, and then we will instruct the driver to make the change.
1091//*********************************************************************************
1092
1093IOReturn IOService::changePowerStateToPriv ( unsigned long ordinal )
1094{
1095 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChangeStateToPriv,ordinal,0);
1096
1097 if ( pm_vars->theControllingDriver == NULL) {
1098 return IOPMNotYetInitialized;
1099 }
1100 if ( ordinal >= pm_vars->theNumberOfPowerStates ) {
1101 return IOPMParameterError;
1102 }
1103 priv->deviceDesire = ordinal;
1104 if ( inPlane(gIOPowerPlane) && (pm_vars->parentsKnowState) ) {
1105 return changeState();
1106 }
1107
1108 return IOPMNoErr;
1109}
1110
1111
1112//*********************************************************************************
1113// changeState
1114//
1115// A subclass object, our controlling driver, or a power domain child
1116// has asked for a different power state. Here we compute what new
1117// state we should enter and enqueue the change (or start it).
1118//*********************************************************************************
1119
1120IOReturn IOService::changeState ( void )
1121{
1122 OSIterator * iter;
1123 OSObject * next;
1124 IOPowerConnection * connection;
1125 unsigned long newDesiredState = 0;
1126
1127 // Compute the maximum of our children's desires, our controlling driver's desire, and the subclass device's desire.
1128
1129 if ( ! priv->device_overrides ) {
1130 iter = getChildIterator(gIOPowerPlane);
1131
1132 if ( iter ) {
1133 while ( (next = iter->getNextObject()) ) {
1134 if ( (connection = OSDynamicCast(IOPowerConnection,next)) ) {
1135 if ( connection->getDesiredDomainState() > newDesiredState ) {
1136 newDesiredState = connection->getDesiredDomainState();
1137 }
1138 }
1139 }
1140 iter->release();
1141 }
1142
1143 if ( priv->driverDesire > newDesiredState ) {
1144 newDesiredState = priv->driverDesire;
1145 }
1146 }
1147
1148 if ( priv->deviceDesire > newDesiredState ) {
1149 newDesiredState = priv->deviceDesire;
1150 }
1151
1152 priv->ourDesiredPowerState = newDesiredState;
1153
1154 if ( (pm_vars->theControllingDriver == NULL) || // if not fully initialized
1155 ! (inPlane(gIOPowerPlane)) ||
1156 ! (pm_vars->parentsKnowState) ) {
1157 return IOPMNoErr; // we can do no more
1158 }
1159
1160 return enqueuePowerChange(IOPMWeInitiated,newDesiredState,0,0);
1161}
1162
1163
1164//*********************************************************************************
1165// currentPowerConsumption
1166//
1167//*********************************************************************************
1168
1169unsigned long IOService::currentPowerConsumption ( void )
1170{
1171 if ( pm_vars->theControllingDriver == NULL ) {
1172 return 0;
1173 }
1174 else {
1175 return pm_vars->thePowerStates[pm_vars->myCurrentState].staticPower;
1176 }
1177}
1178
1179//*********************************************************************************
1180// activityTickle
1181//
1182// The activity tickle with parameter kIOPMSubclassPolicyis not handled
1183// here and should have been intercepted by the subclass.
1184// The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
1185// flag to be set, and the device state checked. If the device has been
1186// powered down, it is powered up again.
1187//*********************************************************************************
1188
1189bool IOService::activityTickle ( unsigned long type, unsigned long stateNumber=0 )
1190{
1191 if ( type == kIOPMSuperclassPolicy1 ) {
1192 if ( (priv->activityLock == NULL) ||
1193 (pm_vars->theControllingDriver == NULL) ||
1194 ( pm_vars->commandQueue == NULL) ) {
1195 return true;
1196 }
1197 IOTakeLock(priv->activityLock);
1198 priv->device_active = true;
1199 if ( pm_vars->myCurrentState >= stateNumber) {
1200 IOUnlock(priv->activityLock);
1201 return true;
1202 }
1203 IOUnlock(priv->activityLock); // send a message on the command queue
1204 pm_vars->commandQueue->enqueueCommand(true, (void *)kPMunIdleDevice, (void *)stateNumber);
1205 return false;
1206 }
1207 return true;
1208}
1209
1210//*********************************************************************************
1211// getPMworkloop
1212//
1213// A child is calling to get a pointer to the Power Management workloop.
1214// We got it or get it from one of our parents.
1215//*********************************************************************************
1216
1217IOWorkLoop * IOService::getPMworkloop ( void )
1218{
1219IOService * aParent;
1220
1221 if ( ! inPlane(gIOPowerPlane) ) {
1222 return NULL;
1223 }
1224 if ( pm_vars->PMworkloop == NULL ) { // we have no workloop yet
1225 aParent = (IOService *)getParentEntry(gIOPowerPlane)->getParentEntry(gIOPowerPlane);
1226 if ( aParent != NULL ) { // ask one of our parents for the workloop
1227 pm_vars->PMworkloop = aParent->getPMworkloop();
1228 }
1229 }
1230 return pm_vars->PMworkloop;
1231}
1232
1233
1234//*********************************************************************************
1235// setIdleTimerPeriod
1236//
1237// A subclass policy-maker is going to use our standard idleness
1238// detection service. Make a command queue and an idle timer and
1239// connect them to the power management workloop. Finally,
1240// start the timer.
1241//*********************************************************************************
1242
1243IOReturn IOService::setIdleTimerPeriod ( unsigned long period )
1244{
1245 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMsetIdleTimerPeriod,period, 0);
1246
1247 priv->idle_timer_period = period;
1248
1249 if ( period > 0 ) {
1250 if ( getPMworkloop() == NULL ) {
1251 return kIOReturnError;
1252 }
1253
1254 if (pm_vars->commandQueue == NULL ) { // make the command queue
1255 pm_vars->commandQueue = IOCommandQueue::commandQueue(this, PMreceiveCmd);
1256 if (! pm_vars->commandQueue ||
1257 ( pm_vars->PMworkloop->addEventSource( pm_vars->commandQueue) != kIOReturnSuccess) ) {
1258 return kIOReturnError;
1259 }
1260 }
1261 // make the timer event
1262 if ( priv->timerEventSrc == NULL ) {
1263 priv->timerEventSrc = IOTimerEventSource::timerEventSource(this,
1264 PM_idle_timer_expired);
1265 if ( ! priv->timerEventSrc ||
1266 ( pm_vars->PMworkloop->addEventSource( priv->timerEventSrc) != kIOReturnSuccess) ) {
1267 return kIOReturnError;
1268 }
1269 }
1270
1271 if ( priv->activityLock == NULL ) {
1272 priv->activityLock = IOLockAlloc();
1273 }
1274
1275 start_PM_idle_timer();
1276 }
1277 return IOPMNoErr;
1278}
1279
1280
1281//*********************************************************************************
1282// start_PM_idle_timer
1283//
1284// The parameter is a pointer to us. Use it to call our timeout method.
1285//*********************************************************************************
1286void IOService::start_PM_idle_timer ( void )
1287{
1288 priv->timerEventSrc->setTimeout(priv->idle_timer_period, NSEC_PER_SEC);
1289}
1290
1291
1292//*********************************************************************************
1293// PM_idle_timer_expired
1294//
1295// The parameter is a pointer to us. Use it to call our timeout method.
1296//*********************************************************************************
1297
1298void PM_idle_timer_expired(OSObject * ourSelves, IOTimerEventSource *)
1299{
1300 ((IOService *)ourSelves)->PM_idle_timer_expiration();
1301}
1302
1303
1304//*********************************************************************************
1305// PM_idle_timer_expiration
1306//
1307// The idle timer has expired. If there has been activity since the last
1308// expiration, just restart the timer and return. If there has not been
1309// activity, switch to the next lower power state and restart the timer.
1310//*********************************************************************************
1311
1312void IOService::PM_idle_timer_expiration ( void )
1313{
1314 if ( ! initialized ) {
1315 return; // we're unloading
1316 }
1317
1318 if ( priv->idle_timer_period > 0 ) {
1319 IOTakeLock(priv->activityLock);
1320 if ( priv->device_active ) {
1321 priv->device_active = false;
1322 IOUnlock(priv->activityLock);
1323 start_PM_idle_timer();
1324 return;
1325 }
1326 if ( pm_vars->myCurrentState > 0 ) {
1327 IOUnlock(priv->activityLock);
1328 priv->askingFor = pm_vars->myCurrentState - 1;
1329 changePowerStateToPriv(pm_vars->myCurrentState - 1);
1330 start_PM_idle_timer();
1331 return;
1332 }
1333 IOUnlock(priv->activityLock);
1334 start_PM_idle_timer();
1335 }
1336}
1337
1338
1339
1340// **********************************************************************************
1341// PMreceiveCmd
1342//
1343//
1344//
1345// **********************************************************************************
1346void PMreceiveCmd ( OSObject * theDriver, void * command, void * param1, void * param2, void *param3 )
1347{
1348 ((IOService *)theDriver)->command_received(command,param1,param2,param3);
1349}
1350
1351
1352// **********************************************************************************
1353// command_received
1354//
1355// We have received a command from ourselves on the command queue.
1356// This is to prevent races with timer-expiration code.
1357// **********************************************************************************
1358void IOService::command_received ( void * command, void *stateNumber , void * , void *)
1359{
1360 if ( ! initialized ) {
1361 return; // we're unloading
1362 }
1363
1364 if ( command == (void *)kPMunIdleDevice ) {
1365 if ( (pm_vars->myCurrentState < (unsigned long)stateNumber) &&
1366 (priv->imminentState < (unsigned long)stateNumber ) &&
1367 ((unsigned long)stateNumber > priv->askingFor) ) {
1368 priv->askingFor = (unsigned long)stateNumber;
1369 changePowerStateToPriv((unsigned long)stateNumber);
1370 }
1371 }
1372}
1373
1374
1375//*********************************************************************************
1376// setAggressiveness
1377//
1378// Pass on the input parameters to all power domain children. All those which are
1379// power domains will pass it on to their children, etc.
1380//*********************************************************************************
1381
1382IOReturn IOService::setAggressiveness ( unsigned long type, unsigned long newLevel )
1383{
1384 OSIterator * iter;
1385 OSObject * next;
1386 IOPowerConnection * connection;
1387
1388 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogSetAggressiveness,type, newLevel);
1389
1390 if ( type <= kMaxType ) {
1391 pm_vars->current_aggressiveness_values[type] = newLevel;
1392 pm_vars->current_aggressiveness_valid[type] = true;
1393 }
1394
1395 iter = getChildIterator(gIOPowerPlane);
1396
1397 if ( iter ) {
1398 while ( (next = iter->getNextObject()) ) {
1399 if ( (connection = OSDynamicCast(IOPowerConnection,next)) ) {
1400 ((IOService *)(connection->getChildEntry(gIOPowerPlane)))->setAggressiveness(type, newLevel);
1401 }
1402 }
1403 iter->release();
1404 }
1405
1406 return IOPMNoErr;
1407}
1408
1409//*********************************************************************************
1410// getAggressiveness
1411//
1412// Called by the user client.
1413//*********************************************************************************
1414
1415IOReturn IOService::getAggressiveness ( unsigned long type, unsigned long * currentLevel )
1416{
1417 if ( type <= kMaxType ) {
1418 *currentLevel = pm_vars->current_aggressiveness_values[type];
1419 }
1420 return kIOReturnSuccess;
1421}
1422
1423//*********************************************************************************
1424// systemWake
1425//
1426// Pass this to all power domain children. All those which are
1427// power domains will pass it on to their children, etc.
1428//*********************************************************************************
1429
1430IOReturn IOService::systemWake ( void )
1431{
1432 OSIterator * iter;
1433 OSObject * next;
1434 IOPowerConnection * connection;
1435
1436 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogSystemWake,0, 0);
1437
1438 iter = getChildIterator(gIOPowerPlane);
1439
1440 if ( iter ) {
1441 while ( (next = iter->getNextObject()) ) {
1442 if ( (connection = OSDynamicCast(IOPowerConnection,next)) ) {
1443 ((IOService *)(connection->getChildEntry(gIOPowerPlane)))->systemWake();
1444 }
1445 }
1446 iter->release();
1447 }
1448
1449 if ( pm_vars->theControllingDriver != NULL ) {
1450 if ( pm_vars->theControllingDriver->didYouWakeSystem() ) {
1451 makeUsable();
1452 }
1453 }
1454
1455 return IOPMNoErr;
1456}
1457
1458
1459//*********************************************************************************
1460// temperatureCriticalForZone
1461//
1462//*********************************************************************************
1463
1464IOReturn IOService::temperatureCriticalForZone ( IOService * whichZone )
1465{
1466 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogCriticalTemp,0,0);
1467
1468 if ( inPlane(gIOPowerPlane) && ! (priv->we_are_root) ) {
1469 ((IOService *)(getParentEntry(gIOPowerPlane)->getParentEntry(gIOPowerPlane)))->temperatureCriticalForZone(whichZone);
1470 }
1471 return IOPMNoErr;
1472}
1473
1474
1475//*********************************************************************************
1476// powerOverrideOnPriv
1477//
1478//*********************************************************************************
1479
1480
1481IOReturn IOService::powerOverrideOnPriv ( void )
1482{
1483 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogOverrideOn,0,0);
1484
1485 priv->device_overrides = true; // turn on the override
1486 return changeState(); // change state if that changed something
1487}
1488
1489
1490//*********************************************************************************
1491// powerOverrideOffPriv
1492//
1493//*********************************************************************************
1494IOReturn IOService::powerOverrideOffPriv ( void )
1495{
1496 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogOverrideOff,0,0);
1497
1498 priv->device_overrides = false; // turn off the override
1499 return changeState(); // change state if that changed something
1500}
1501
1502
1503//*********************************************************************************
1504// enqueuePowerChange
1505//
1506// Allocate a new state change notification, initialize it with fields from the
1507// caller, and add it to the tail of the list of pending power changes.
1508//
1509// If it is early enough in the list, and almost all the time it is the only one in
1510// the list, start the power change.
1511//
1512// In rare instances, this change will preempt the previous change in the list.
1513// If the previous change is un-actioned in any way (because we are still
1514// processing an even earlier power change), and if both the previous change
1515// in the list and this change are initiated by us (not the parent), then we
1516// needn't perform the previous change, so we collapse the list a little.
1517//*********************************************************************************
1518
1519IOReturn IOService::enqueuePowerChange ( unsigned long flags, unsigned long whatStateOrdinal, unsigned long domainState, IOPowerConnection * whichParent )
1520{
1521 long newNote;
1522 long previousNote;
1523
1524// Create and initialize the new change note
1525
1526 newNote = priv->changeList->createChangeNote();
1527 if ( newNote == -1 ) {
1528 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogEnqueueErr,0,0);
1529 return IOPMAckImplied; // uh-oh, our list is full
1530 }
1531
1532 priv->changeList->changeNote[newNote].newStateNumber = whatStateOrdinal;
1533 priv->changeList->changeNote[newNote].outputPowerCharacter = pm_vars->thePowerStates[whatStateOrdinal].outputPowerCharacter;
1534 priv->changeList->changeNote[newNote].inputPowerRequirement = pm_vars->thePowerStates[whatStateOrdinal].inputPowerRequirement;
1535 priv->changeList->changeNote[newNote].capabilityFlags = pm_vars->thePowerStates[whatStateOrdinal].capabilityFlags;
1536 priv->changeList->changeNote[newNote].flags = flags;
1537 if (flags & IOPMParentInitiated ) {
1538 priv->changeList->changeNote[newNote].domainState = domainState;
1539 priv->changeList->changeNote[newNote].parent = whichParent;
1540 }
1541
1542 previousNote = priv->changeList->previousChangeNote(newNote);
1543
1544 if ( previousNote == -1 ) {
1545
1546 // Queue is empty, we can start this change.
1547
1548 if (flags & IOPMWeInitiated ) {
1549 start_our_change(newNote);
1550 return 0;
1551 }
1552 else {
1553 return start_parent_change(newNote);
1554 }
1555 }
1556
1557 // The queue is not empty. Try to collapse this new change and the previous one in queue into one change.
1558 // This is possible only if both changes are initiated by us, and neither has been started yet.
1559 // Do this more than once if possible.
1560
1561 // (A change is started iff it is at the head of the queue)
1562
1563 while ( (previousNote != priv->head_note) && (previousNote != -1) &&
1564 (priv->changeList->changeNote[newNote].flags & priv->changeList->changeNote[previousNote].flags & IOPMWeInitiated) ) {
1565 priv->changeList->changeNote[previousNote].outputPowerCharacter = priv->changeList->changeNote[newNote].outputPowerCharacter;
1566 priv->changeList->changeNote[previousNote].inputPowerRequirement = priv->changeList->changeNote[newNote].inputPowerRequirement;
1567 priv->changeList->changeNote[previousNote].capabilityFlags =priv-> changeList->changeNote[newNote].capabilityFlags;
1568 priv->changeList->changeNote[previousNote].newStateNumber = priv->changeList->changeNote[newNote].newStateNumber;
1569 priv->changeList->releaseTailChangeNote();
1570 newNote = previousNote;
1571 previousNote = priv->changeList->previousChangeNote(newNote);
1572 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogCollapseQueue,0,0);
1573 }
1574 return IOPMWillAckLater; // in any case, we can't start yet
1575}
1576
1577
1578//*********************************************************************************
1579// notifyAll
1580//
1581// Notify all interested parties either that a change is impending or that the
1582// previously-notified change is done and power has settled.
1583// The parameter identifies whether this is the
1584// pre-change notification or the post-change notification.
1585//
1586//*********************************************************************************
1587
1588IOReturn IOService::notifyAll ( bool is_prechange )
1589{
1590 IOPMinformee * nextObject;
1591 OSIterator * iter;
1592 OSObject * next;
1593 IOPowerConnection * connection;
1594
1595 // To prevent acknowledgePowerChange from finishing the change note and removing it from the queue if
1596 // some driver calls it, we inflate the number of pending acks so it cannot become zero. We'll fix it later.
1597
1598 priv->head_note_pendingAcks =1;
1599
1600 // OK, we will go through the lists of interested drivers and power domain children
1601 // and notify each one of this change.
1602
1603 nextObject = priv->interestedDrivers->firstInList(); // notify interested drivers
1604 while ( nextObject != NULL ) {
1605 priv->head_note_pendingAcks +=1;
1606 if (! inform(nextObject, is_prechange) ) {
1607 }
1608 nextObject = priv->interestedDrivers->nextInList(nextObject);
1609 }
1610
1611 if (! acquire_lock() ) {
1612 return IOPMNoErr;
1613 }
1614 if ( priv->head_note_pendingAcks > 1 ) { // did they all ack?
1615 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0); // no
1616 start_ack_timer();
1617 }
1618 IOUnlock(priv->our_lock); // either way
1619
1620 iter = getChildIterator(gIOPowerPlane);
1621
1622 if ( iter ) {
1623 while ( (next = iter->getNextObject()) ) {
1624 if ( (connection = OSDynamicCast(IOPowerConnection,next)) ) {
1625 priv->head_note_pendingAcks +=1;
1626 notifyChild(connection, is_prechange);
1627 }
1628 }
1629 iter->release();
1630 }
1631
1632 if (! acquire_lock() ) {
1633 return IOPMNoErr;
1634 }
1635 priv->head_note_pendingAcks -= 1; // now make this real
1636 if (priv->head_note_pendingAcks == 0 ) { // is it all acked?
1637 IOUnlock(priv->our_lock); // yes
1638 return IOPMAckImplied; // return ack to parent
1639 }
1640 IOUnlock(priv->our_lock); // no
1641 return IOPMWillAckLater;
1642}
1643
1644
1645//*********************************************************************************
1646// notifyChild
1647//
1648// Notify a power domain child of an upcoming power change.
1649//
1650// If the object acknowledges the current change, we return TRUE.
1651//*********************************************************************************
1652
1653bool IOService::notifyChild ( IOPowerConnection * theNub, bool is_prechange )
1654{
1655 IOReturn k = IOPMAckImplied;
1656
1657 if ( is_prechange ) {
1658 k =((IOService *)(theNub->getChildEntry(gIOPowerPlane)))->powerDomainWillChangeTo( priv->head_note_outputFlags,theNub);
1659 }
1660 else {
1661 k =((IOService *)(theNub->getChildEntry(gIOPowerPlane)))->powerDomainDidChangeTo( priv->head_note_outputFlags,theNub);
1662 }
1663
1664 if ( k == IOPMAckImplied ) { // did the return code ack?
1665 priv->head_note_pendingAcks -=1; // yes
1666 return true;
1667 }
1668 return false;
1669}
1670
1671
1672//*********************************************************************************
1673// inform
1674//
1675// Notify an interested driver of an upcoming power change.
1676//
1677// If the object acknowledges the current change, we return TRUE.
1678//*********************************************************************************
1679
1680bool IOService::inform ( IOPMinformee * nextObject, bool is_prechange )
1681{
1682 IOReturn k = IOPMAckImplied;
1683
1684 nextObject->timer = -1; // initialize this
1685
1686 if ( is_prechange ) {
1687 pm_vars->thePlatform->PMLog (pm_vars->ourName,PMlogInformDriverPreChange,
1688 (unsigned long)priv->head_note_capabilityFlags,(unsigned long)priv->head_note_state);
1689 k = nextObject->whatObject->powerStateWillChangeTo( priv->head_note_capabilityFlags,priv->head_note_state,this);
1690 }
1691 else {
1692 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogInformDriverPostChange,
1693 (unsigned long)priv->head_note_capabilityFlags,(unsigned long)priv->head_note_state);
1694 k = nextObject->whatObject->powerStateDidChangeTo(priv->head_note_capabilityFlags,priv->head_note_state,this);
1695 }
1696
1697 if ( nextObject->timer == 0 ) { // did it ack behind our back?
1698 return true; // yes
1699 }
1700 if ( k ==IOPMAckImplied ) { // no, did the return code ack?
1701 nextObject->timer = 0; // yes
1702 priv->head_note_pendingAcks -= 1;
1703 return true;
1704 }
1705 if ( k < 0 ) {
1706 nextObject->timer = 0; // somebody goofed
1707 priv-> head_note_pendingAcks -= 1;
1708 return true;
1709 }
1710 nextObject->timer = (k * ns_per_us / ACK_TIMER_PERIOD) + 1; // no, it's a timer
1711 return false;
1712}
1713
1714
1715//*********************************************************************************
1716// our_prechange_03
1717//
1718// All registered applications and kernel clients have positively acknowledged our
1719// intention of lowering power. Here we notify them all that we will definitely
1720// lower the power. If we don't have to wait for any of them to acknowledge, we
1721// carry on by notifying interested drivers. Otherwise, we do wait.
1722//*********************************************************************************
1723
1724void IOService::our_prechange_03 ( void )
1725{
1726 priv->machine_state = IOPMour_prechange_05; // next state
1727 if ( tellChangeDown(priv->head_note_state) ) { // are we waiting for responses?
1728 return our_prechange_05(); // no, notify interested drivers
1729 }
1730}
1731
1732
1733//*********************************************************************************
1734// our_prechange_05
1735//
1736// All registered applications and kernel clients have acknowledged our notification
1737// that we are lowering power. Here we notify interested drivers. If we don't have
1738// to wait for any of them to acknowledge, we instruct our power driver to make the change.
1739// Otherwise, we do wait.
1740//*********************************************************************************
1741
1742void IOService::our_prechange_05 ( void )
1743{
1744 priv->machine_state = IOPMour_prechange_1; // no, in case they don't all ack
1745 if ( notifyAll(true) == IOPMAckImplied ) {
1746 our_prechange_1();
1747 }
1748}
1749
1750
1751//*********************************************************************************
1752// our_prechange_1
1753//
1754// All interested drivers have acknowledged our pre-change notification of a power
1755// change we initiated. Here we instruct our controlling driver to make
1756// the change to the hardware. If it does so, we continue processing
1757// (waiting for settle and notifying interested parties post-change.)
1758// If it doesn't, we have to wait for it to acknowledge and then continue.
1759//*********************************************************************************
1760
1761void IOService::our_prechange_1 ( void )
1762{
1763 if ( instruct_driver(priv->head_note_state) == IOPMAckImplied ) {
1764 our_prechange_2(); // it's done, carry on
1765 }
1766 else {
1767 priv->machine_state = IOPMour_prechange_2; // it's not, wait for it
1768 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0);
1769 start_ack_timer();
1770 }
1771}
1772
1773
1774//*********************************************************************************
1775// our_prechange_2
1776//
1777// Our controlling driver has changed power state on the hardware
1778// during a power change we initiated. Here we see if we need to wait
1779// for power to settle before continuing. If not, we continue processing
1780// (notifying interested parties post-change). If so, we wait and
1781// continue later.
1782//*********************************************************************************
1783
1784void IOService::our_prechange_2 ( void )
1785{
1786 priv->settle_time = compute_settle_time();
1787 if ( priv->settle_time == 0 ) {
1788 our_prechange_3();
1789 }
1790 else {
1791 priv->machine_state = IOPMour_prechange_3;
1792 startSettleTimer(priv->settle_time);
1793 }
1794}
1795
1796
1797//*********************************************************************************
1798// our_prechange_3
1799//
1800// Power has settled on a power change we initiated. Here we notify
1801// all our interested parties post-change. If they all acknowledge, we're
1802// done with this change note, and we can start on the next one.
1803// Otherwise we have to wait for acknowledgements and finish up later.
1804//*********************************************************************************
1805
1806void IOService::our_prechange_3 ( void )
1807{
1808 priv->machine_state = IOPMour_prechange_4; // in case they don't all ack
1809 if ( notifyAll(false) == IOPMAckImplied ) {
1810 our_prechange_4();
1811 }
1812}
1813
1814
1815//*********************************************************************************
1816// our_prechange_4
1817//
1818// Power has settled on a power change we initiated, and
1819// all our interested parties have acknowledged. We're
1820// done with this change note, and we can start on the next one.
1821//*********************************************************************************
1822
1823void IOService::our_prechange_4 ( void )
1824{
1825 all_done();
1826}
1827
1828
1829//*********************************************************************************
1830// parent_down_0
1831//
1832// All applications and kernel clients have been notified of a power lowering
1833// initiated by the parent and we didn't have to wait for any responses. Here
1834// we notify any interested drivers and power domain children. If they all ack,
1835// we continue with the power change.
1836// If at least one doesn't, we have to wait for it to acknowledge and then continue.
1837//*********************************************************************************
1838
1839IOReturn IOService::parent_down_0 ( void )
1840{
1841 priv->machine_state = IOPMparent_down_4; // in case they don't all ack
1842 if ( notifyAll(true) == IOPMAckImplied ) {
1843 return parent_down_1(); // they did
1844 }
1845 return IOPMWillAckLater; // they didn't
1846}
1847
1848
1849//*********************************************************************************
1850// parent_down_05
1851//
1852// All applications and kernel clients have been notified of a power lowering
1853// initiated by the parent and we had to wait for their responses. Here we notify
1854// any interested drivers and power domain children. If they all ack, we continue
1855// with the power change.
1856// If at least one doesn't, we have to wait for it to acknowledge and then continue.
1857//*********************************************************************************
1858
1859void IOService::parent_down_05 ( void )
1860{
1861 priv->machine_state = IOPMparent_down_4; // in case they don't all ack
1862 if ( notifyAll(true) == IOPMAckImplied ) {
1863 parent_down_4(); // they did
1864 }
1865}
1866
1867
1868//*********************************************************************************
1869// parent_down_1
1870//
1871// All parties have acknowledged our pre-change notification of a power
1872// lowering initiated by the parent. Here we instruct our controlling driver
1873// to put the hardware in the state it needs to be in when the domain is
1874// lowered. If it does so, we continue processing
1875// (waiting for settle and acknowledging the parent.)
1876// If it doesn't, we have to wait for it to acknowledge and then continue.
1877//*********************************************************************************
1878
1879IOReturn IOService::parent_down_1 ( void )
1880{
1881 if ( instruct_driver(priv->head_note_state) == IOPMAckImplied ) {
1882 return parent_down_2(); // it's done, carry on
1883 }
1884 priv->machine_state = IOPMparent_down_5; // it's not, wait for it
1885 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0);
1886 start_ack_timer();
1887 return IOPMWillAckLater;
1888}
1889
1890
1891//*********************************************************************************
1892// parent_down_4
1893//
1894// We had to wait for it, but all parties have acknowledged our pre-change
1895// notification of a power lowering initiated by the parent.
1896// Here we instruct our controlling driver
1897// to put the hardware in the state it needs to be in when the domain is
1898// lowered. If it does so, we continue processing
1899// (waiting for settle and acknowledging the parent.)
1900// If it doesn't, we have to wait for it to acknowledge and then continue.
1901//*********************************************************************************
1902
1903void IOService::parent_down_4 ( void )
1904{
1905 if ( instruct_driver(priv->head_note_state) == IOPMAckImplied ) {
1906 parent_down_5(); // it's done, carry on
1907 }
1908 else {
1909 priv-> machine_state = IOPMparent_down_5; // it's not, wait for it
1910 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0);
1911 start_ack_timer();
1912 }
1913}
1914
1915
1916//*********************************************************************************
1917// parent_down_2
1918//
1919// Our controlling driver has changed power state on the hardware
1920// during a power change initiated by our parent. Here we see if we need
1921// to wait for power to settle before continuing. If not, we continue
1922// processing (acknowledging our preparedness to the parent).
1923// If so, we wait and continue later.
1924//*********************************************************************************
1925
1926IOReturn IOService::parent_down_2 ( void )
1927{
1928 priv->settle_time = compute_settle_time();
1929 if ( priv->settle_time == 0 ) {
1930 priv->machine_state = IOPMparent_down_6; // in case they don't all ack
1931 if ( notifyAll(false) == IOPMAckImplied ) {
1932 all_done();
1933 return IOPMAckImplied;
1934 }
1935 return IOPMWillAckLater; // they didn't
1936 }
1937 else {
1938 priv->machine_state = IOPMparent_down_3;
1939 startSettleTimer(priv->settle_time);
1940 return IOPMWillAckLater;
1941 }
1942}
1943
1944
1945//*********************************************************************************
1946// parent_down_5
1947//
1948// Our controlling driver has changed power state on the hardware
1949// during a power change initiated by our parent. We have had to wait
1950// for acknowledgement from interested parties, or we have had to wait
1951// for the controlling driver to change the state. Here we see if we need
1952// to wait for power to settle before continuing. If not, we continue
1953// processing (acknowledging our preparedness to the parent).
1954// If so, we wait and continue later.
1955//*********************************************************************************
1956
1957void IOService::parent_down_5 ( void )
1958{
1959 priv->settle_time = compute_settle_time();
1960 if ( priv->settle_time == 0 ) {
1961 parent_down_3();
1962 }
1963 else {
1964 priv->machine_state = IOPMparent_down_3;
1965 startSettleTimer(priv->settle_time);
1966 }
1967}
1968
1969
1970//*********************************************************************************
1971// parent_down_3
1972//
1973// Power has settled on a power change initiated by our parent. Here we
1974// notify interested parties.
1975//*********************************************************************************
1976
1977void IOService::parent_down_3 ( void )
1978{
1979 IOService * parent;
1980
1981 priv->machine_state = IOPMparent_down_6; // in case they don't all ack
1982 if ( notifyAll(false) == IOPMAckImplied ) {
1983 parent = priv->head_note_parent;
1984 all_done();
1985 ((IOService *)(parent->getParentEntry(gIOPowerPlane)))->acknowledgePowerChange(parent);
1986 }
1987}
1988
1989
1990//*********************************************************************************
1991// parent_down_6
1992//
1993// We had to wait for it, but all parties have acknowledged our post-change
1994// notification of a power lowering initiated by the parent.
1995// Here we acknowledge the parent.
1996// We are done with this change note, and we can start on the next one.
1997//*********************************************************************************
1998
1999void IOService::parent_down_6 ( void )
2000{
2001 IOService * parent;
2002
2003 parent = priv->head_note_parent;
2004 all_done();
2005 ((IOService *)(parent->getParentEntry(gIOPowerPlane)))->acknowledgePowerChange(parent);
2006}
2007
2008
2009//*********************************************************************************
2010// parent_up_0
2011//
2012// Our parent has informed us via powerStateDidChange that it has
2013// raised the power in our power domain, and we have had to wait
2014// for some interested party to acknowledge our notification.
2015// Here we instruct our controlling
2016// driver to program the hardware to take advantage of the higher domain
2017// power. If it does so, we continue processing
2018// (waiting for settle and notifying interested parties post-change.)
2019// If it doesn't, we have to wait for it to acknowledge and then continue.
2020//*********************************************************************************
2021
2022void IOService::parent_up_0 ( void )
2023{
2024 if ( instruct_driver(priv->head_note_state) == IOPMAckImplied ) {
2025 parent_up_4(); // it did it, carry on
2026 }
2027 else {
2028 priv->machine_state = IOPMparent_up_4; // it didn't, wait for it
2029 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0);
2030 start_ack_timer();
2031 }
2032}
2033
2034
2035//*********************************************************************************
2036// parent_up_1
2037//
2038// Our parent has informed us via powerStateDidChange that it has
2039// raised the power in our power domain. Here we instruct our controlling
2040// driver to program the hardware to take advantage of the higher domain
2041// power. If it does so, we continue processing
2042// (waiting for settle and notifying interested parties post-change.)
2043// If it doesn't, we have to wait for it to acknowledge and then continue.
2044//*********************************************************************************
2045
2046IOReturn IOService::parent_up_1 ( void )
2047{
2048 if ( instruct_driver(priv->head_note_state) == IOPMAckImplied ) {
2049 return parent_up_2(); // it did it, carry on
2050 }
2051 else {
2052 priv->machine_state = IOPMparent_up_4; // it didn't, wait for it
2053 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0);
2054 start_ack_timer();
2055 return IOPMWillAckLater;
2056 }
2057}
2058
2059
2060//*********************************************************************************
2061// parent_up_2
2062//
2063// Our controlling driver has changed power state on the hardware
2064// during a power raise initiated by the parent. Here we see if we need to wait
2065// for power to settle before continuing. If not, we continue processing
2066// (notifying interested parties post-change). If so, we wait and
2067// continue later.
2068//*********************************************************************************
2069
2070IOReturn IOService::parent_up_2 ( void )
2071{
2072 priv->settle_time = compute_settle_time();
2073 if ( priv->settle_time == 0 ) {
2074 return parent_up_3();
2075 }
2076 else {
2077 priv->machine_state = IOPMparent_up_5;
2078 startSettleTimer(priv->settle_time);
2079 return IOPMWillAckLater;
2080 }
2081}
2082
2083
2084//*********************************************************************************
2085// parent_up_4
2086//
2087// Our controlling driver has changed power state on the hardware
2088// during a power raise initiated by the parent, but we had to wait for it.
2089// Here we see if we need to wait for power to settle before continuing.
2090// If not, we continue processing (notifying interested parties post-change).
2091// If so, we wait and continue later.
2092//*********************************************************************************
2093
2094void IOService::parent_up_4 ( void )
2095{
2096 priv->settle_time = compute_settle_time();
2097 if ( priv->settle_time == 0 ) {
2098 parent_up_5();
2099 }
2100 else {
2101 priv->machine_state = IOPMparent_up_5;
2102 startSettleTimer(priv->settle_time);
2103 }
2104}
2105
2106
2107//*********************************************************************************
2108// parent_up_3
2109//
2110// No power settling was required on a power raise initiated by the parent.
2111// Here we notify all our interested parties post-change. If they all acknowledge,
2112// we're done with this change note, and we can start on the next one.
2113// Otherwise we have to wait for acknowledgements and finish up later.
2114//*********************************************************************************
2115
2116IOReturn IOService::parent_up_3 ( void )
2117{
2118 priv->machine_state = IOPMparent_up_6; // in case they don't all ack
2119 if ( notifyAll(false) == IOPMAckImplied ) {
2120 all_done();
2121 return IOPMAckImplied;
2122 }
2123 return IOPMWillAckLater; // they didn't
2124}
2125
2126
2127//*********************************************************************************
2128// parent_up_5
2129//
2130// Power has settled on a power raise initiated by the parent.
2131// Here we notify all our interested parties post-change. If they all acknowledge,
2132// we're done with this change note, and we can start on the next one.
2133// Otherwise we have to wait for acknowledgements and finish up later.
2134//*********************************************************************************
2135
2136void IOService::parent_up_5 ( void )
2137{
2138 priv->machine_state = IOPMparent_up_6; // in case they don't all ack
2139 if ( notifyAll(false) == IOPMAckImplied ) {
2140 parent_up_6();
2141 }
2142}
2143
2144
2145//*********************************************************************************
2146// parent_up_6
2147//
2148// All parties have acknowledged our post-change notification of a power
2149// raising initiated by the parent. Here we acknowledge the parent.
2150// We are done with this change note, and we can start on the next one.
2151//*********************************************************************************
2152
2153void IOService::parent_up_6 ( void )
2154{
2155 IOService * parent;
2156
2157 parent = priv->head_note_parent;
2158 all_done();
2159 ((IOService *)(parent->getParentEntry(gIOPowerPlane)))->acknowledgePowerChange(parent);
2160}
2161
2162
2163//*********************************************************************************
2164// all_done
2165//
2166// A power change is complete, and the used post-change note is at
2167// the head of the queue. Remove it and set myCurrentState to the result
2168// of the change. Start up the next change in queue.
2169//*********************************************************************************
2170
2171void IOService::all_done ( void )
2172{
2173 priv->machine_state = IOPMfinished;
2174
2175 if ( priv->head_note_flags & IOPMWeInitiated ) { // our power change
2176 if ( !( priv->head_note_flags & IOPMNotDone) ) { // could our driver switch to the new state?
2177 if ( pm_vars->myCurrentState < priv->head_note_state ) { // yes, did power raise?
2178 tellChangeUp (priv->head_note_state); // yes, inform clients and apps
2179 }
2180 else {
2181 if ( ! priv->we_are_root ) { // no, if this lowers our
2182 ask_parent(priv->head_note_state); // power requirements, tell the parent
2183 }
2184 }
2185 pm_vars->myCurrentState = priv->head_note_state; // either way
2186 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChangeDone,(unsigned long)pm_vars->myCurrentState,0);
2187 powerChangeDone(pm_vars->myCurrentState); // inform subclass policy-maker
2188 }
2189// else { // no
2190// pm_vars->myCurrentState = pm_vars->theControllingDriver->powerStateForDomainState(pm_vars->parentsCurrentPowerFlags);
2191// }
2192 }
2193 if ( priv->head_note_flags & IOPMParentInitiated) { // parent's power change
2194 if ( ((priv->head_note_flags & IOPMDomainWillChange) && (pm_vars->myCurrentState >= priv->head_note_state)) ||
2195 ((priv->head_note_flags & IOPMDomainDidChange) && (pm_vars->myCurrentState < priv->head_note_state)) ) {
2196 if ( pm_vars->myCurrentState < priv->head_note_state ) { // did power raise?
2197 tellChangeUp (priv->head_note_state); // yes, inform clients and apps
2198 }
2199 pm_vars->myCurrentState = priv->head_note_state; // either way
2200 pm_vars->maxCapability = pm_vars->theControllingDriver->maxCapabilityForDomainState(priv->head_note_domainState);
2201
2202 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChangeDone,(unsigned long)pm_vars->myCurrentState,0);
2203 powerChangeDone(pm_vars->myCurrentState); // inform subclass policy-maker
2204 }
2205 }
2206
2207 priv->changeList->releaseHeadChangeNote(); // we're done with this
2208
2209 priv->head_note = priv->changeList->currentChange(); // start next one in queue
2210 if ( priv->head_note != -1 ) {
2211
2212 if (priv->changeList->changeNote[priv->head_note].flags & IOPMWeInitiated ) {
2213 start_our_change(priv->head_note);
2214 }
2215 else {
2216 if ( start_parent_change(priv->head_note) == IOPMAckImplied ) {
2217 ((IOService *)(priv->head_note_parent->getParentEntry(gIOPowerPlane)))->acknowledgePowerChange(priv->head_note_parent);
2218 }
2219 }
2220 }
2221}
2222
2223
2224
2225//*********************************************************************************
2226// all_acked
2227//
2228// A driver or child has acknowledged our notification of an upcoming power
2229// change, and this acknowledgement is the last one pending
2230// before we change power or after changing power.
2231//
2232//*********************************************************************************
2233
2234void IOService::all_acked ( void )
2235{
2236 switch (priv->machine_state) {
2237 case IOPMour_prechange_1:
2238 our_prechange_1();
2239 break;
2240 case IOPMour_prechange_4:
2241 our_prechange_4();
2242 break;
2243 case IOPMparent_down_4:
2244 parent_down_4();
2245 break;
2246 case IOPMparent_down_6:
2247 parent_down_6();
2248 break;
2249 case IOPMparent_up_0:
2250 parent_up_0();
2251 break;
2252 case IOPMparent_up_6:
2253 parent_up_6();
2254 break;
2255 }
2256}
2257
2258
2259//*********************************************************************************
2260// settleTimerExpired
2261//
2262// Power has settled after our last change. Notify interested parties that
2263// there is a new power state.
2264//*********************************************************************************
2265
2266void IOService::settleTimerExpired ( void )
2267{
2268 if ( ! initialized ) {
2269 return; // we're unloading
2270 }
2271
2272 switch (priv->machine_state) {
2273 case IOPMour_prechange_3:
2274 our_prechange_3();
2275 break;
2276 case IOPMparent_down_3:
2277 parent_down_3();
2278 break;
2279 case IOPMparent_up_5:
2280 parent_up_5();
2281 break;
2282 }
2283}
2284
2285
2286//*********************************************************************************
2287// compute_settle_time
2288//
2289// Compute the power-settling delay in microseconds for the
2290// change from myCurrentState to head_note_state.
2291//*********************************************************************************
2292
2293unsigned long IOService::compute_settle_time ( void )
2294{
2295 unsigned long totalTime;
2296 unsigned long i;
2297
2298 totalTime = 0; // compute total time to attain the new state
2299 i = pm_vars->myCurrentState;
2300 if ( priv->head_note_state < pm_vars->myCurrentState ) { // we're lowering power
2301 while ( i > priv->head_note_state ) {
2302 totalTime += pm_vars->thePowerStates[i].settleDownTime;
2303 i--;
2304 }
2305 }
2306
2307 if ( priv->head_note_state > pm_vars->myCurrentState ) { // we're raising power
2308 while ( i < priv->head_note_state ) {
2309 totalTime += pm_vars->thePowerStates[i+1].settleUpTime;
2310 i++;
2311 }
2312 }
2313
2314 return totalTime;
2315}
2316
2317
2318//*********************************************************************************
2319// startSettleTimer
2320//
2321// Enter with a power-settling delay in microseconds and start a nano-second
2322// timer for that delay.
2323//*********************************************************************************
2324
2325IOReturn IOService::startSettleTimer ( unsigned long delay )
2326{
2327 AbsoluteTime deadline;
2328
2329 clock_interval_to_deadline(delay, kMicrosecondScale, &deadline);
2330
2331 thread_call_enter_delayed(priv->settleTimer, deadline);
2332
2333 return IOPMNoErr;
2334}
2335
2336//*********************************************************************************
2337// ack_timer_ticked
2338//
2339// The acknowledgement timeout periodic timer has ticked.
2340// If we are awaiting acks for a power change notification,
2341// we decrement the timer word of each interested driver which hasn't acked.
2342// If a timer word becomes zero, we pretend the driver aknowledged.
2343// If we are waiting for the controlling driver to change the power
2344// state of the hardware, we decrement its timer word, and if it becomes
2345// zero, we pretend the driver acknowledged.
2346//*********************************************************************************
2347
2348void IOService::ack_timer_ticked ( void )
2349{
2350 IOPMinformee * nextObject;
2351
2352 if ( ! initialized ) {
2353 return; // we're unloading
2354 }
2355
2356 if (! acquire_lock() ) {
2357 return;
2358 }
2359
2360 switch (priv->machine_state) {
2361 case IOPMour_prechange_2:
2362 case IOPMparent_down_5:
2363 case IOPMparent_up_4:
2364 if ( priv->driver_timer != 0 ) { // are we waiting for our driver to make its change?
2365 priv->driver_timer -= 1; // yes, tick once
2366 if ( priv->driver_timer == 0 ) { // it's tardy, we'll go on without it
2367 IOUnlock(priv->our_lock);
2368 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogCtrlDriverTardy,0,0);
2369 driver_acked();
2370 }
2371 else { // still waiting, set timer again
2372 start_ack_timer();
2373 IOUnlock(priv->our_lock);
2374 }
2375 }
2376 else {
2377 IOUnlock(priv->our_lock);
2378 }
2379 break;
2380
2381 case IOPMour_prechange_1:
2382 case IOPMour_prechange_4:
2383 case IOPMparent_down_4:
2384 case IOPMparent_down_6:
2385 case IOPMparent_up_0:
2386 case IOPMparent_up_6:
2387 if (priv->head_note_pendingAcks != 0 ) { // are we waiting for interested parties to acknowledge?
2388 nextObject = priv->interestedDrivers->firstInList(); // yes, go through the list of interested drivers
2389 while ( nextObject != NULL ) { // and check each one
2390 if ( nextObject->timer > 0 ) {
2391 nextObject->timer -= 1;
2392 if ( nextObject->timer == 0 ) { // this one should have acked by now
2393 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogIntDriverTardy,0,0);
2394 kprintf("interested driver tardy: %s\n",nextObject->whatObject->getName());
2395 priv->head_note_pendingAcks -= 1;
2396 }
2397 }
2398 nextObject = priv->interestedDrivers->nextInList(nextObject);
2399 }
2400 if ( priv->head_note_pendingAcks == 0 ) { // is that the last?
2401 IOUnlock(priv->our_lock);
2402 all_acked(); // yes, we can continue
2403 }
2404 else { // no, set timer again
2405 start_ack_timer();
2406 IOUnlock(priv->our_lock);
2407 }
2408 }
2409 else {
2410 IOUnlock(priv->our_lock);
2411 }
2412 break;
2413
2414 case IOPMparent_down_0: // apps didn't respond to parent-down notification
2415 IOUnlock(priv->our_lock);
2416 IOLockLock(priv->flags_lock);
2417 if (pm_vars->responseFlags) {
2418 pm_vars->responseFlags->release(); // get rid of this stuff
2419 pm_vars->responseFlags = NULL;
2420 }
2421 IOLockUnlock(priv->flags_lock);
2422 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogClientTardy,0,1);
2423 parent_down_05(); // carry on with the change
2424 break;
2425
2426 case IOPMour_prechange_03: // apps didn't respond to our power-down request
2427 IOUnlock(priv->our_lock);
2428 IOLockLock(priv->flags_lock);
2429 if (pm_vars->responseFlags) {
2430 pm_vars->responseFlags->release(); // get rid of this stuff
2431 pm_vars->responseFlags = NULL;
2432 }
2433 IOLockUnlock(priv->flags_lock);
2434 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogClientTardy,0,2);
2435 tellNoChangeDown(priv->head_note_state); // rescind the request
2436 priv->head_note_flags |= IOPMNotDone; // mark the change note un-actioned
2437 all_done(); // and we're done
2438 break;
2439
2440 case IOPMour_prechange_05: // apps didn't respond to our power-down notification
2441 IOUnlock(priv->our_lock);
2442 IOLockLock(priv->flags_lock);
2443 if (pm_vars->responseFlags) {
2444 pm_vars->responseFlags->release(); // get rid of this stuff
2445 pm_vars->responseFlags = NULL;
2446 }
2447 IOLockUnlock(priv->flags_lock);
2448 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogClientTardy,0,3);
2449 our_prechange_05(); // carry on with the change
2450 break;
2451
2452 default:
2453 IOUnlock(priv->our_lock); // not waiting for acks
2454 break;
2455 }
2456}
2457
2458
2459//*********************************************************************************
2460// start_ack_timer
2461//
2462//*********************************************************************************
2463
2464void IOService::start_ack_timer ( void )
2465{
2466 AbsoluteTime deadline;
2467
2468 clock_interval_to_deadline(ACK_TIMER_PERIOD, kNanosecondScale, &deadline);
2469
2470 thread_call_enter_delayed(priv->ackTimer, deadline);
2471}
2472
2473
2474//*********************************************************************************
2475// stop_ack_timer
2476//
2477//*********************************************************************************
2478
2479void IOService::stop_ack_timer ( void )
2480{
2481 thread_call_cancel(priv->ackTimer);
2482}
2483
2484
2485//*********************************************************************************
2486// c-language timer expiration functions
2487//
2488//*********************************************************************************
2489
2490static void ack_timer_expired ( thread_call_param_t us)
2491{
2492 ((IOService *)us)->ack_timer_ticked();
2493}
2494
2495
2496static void settle_timer_expired ( thread_call_param_t us)
2497{
2498 ((IOService *)us)->settleTimerExpired();
2499}
2500
2501
2502//*********************************************************************************
2503// add_child_to_active_change
2504//
2505// A child has just registered with us. If there is
2506// currently a change in progress, get the new party involved: if we
2507// have notified all parties and are waiting for acks, notify the new
2508// party.
2509//*********************************************************************************
2510
2511IOReturn IOService::add_child_to_active_change ( IOPowerConnection * newObject )
2512{
2513 if (! acquire_lock() ) {
2514 return IOPMNoErr;
2515 }
2516
2517 switch (priv->machine_state) {
2518 case IOPMour_prechange_1:
2519 case IOPMparent_down_4:
2520 case IOPMparent_up_0:
2521 priv->head_note_pendingAcks += 2; // one for this child and one to prevent
2522 IOUnlock(priv->our_lock); // incoming acks from changing our state
2523 notifyChild(newObject, true);
2524 if (! acquire_lock() ) {
2525 --priv->head_note_pendingAcks; // put it back
2526 return IOPMNoErr;
2527 }
2528 if ( --priv->head_note_pendingAcks == 0 ) { // are we still waiting for acks?
2529 stop_ack_timer(); // no, stop the timer
2530 IOUnlock(priv->our_lock);
2531 all_acked(); // and now we can continue
2532 return IOPMNoErr;
2533 }
2534 break;
2535 case IOPMour_prechange_4:
2536 case IOPMparent_down_6:
2537 case IOPMparent_up_6:
2538 priv->head_note_pendingAcks += 2; // one for this child and one to prevent
2539 IOUnlock(priv->our_lock); // incoming acks from changing our state
2540 notifyChild(newObject, false);
2541 if (! acquire_lock() ) {
2542 --priv->head_note_pendingAcks; // put it back
2543 return IOPMNoErr;
2544 }
2545 if ( --priv->head_note_pendingAcks == 0 ) { // are we still waiting for acks?
2546 stop_ack_timer(); // no, stop the timer
2547 IOUnlock(priv->our_lock);
2548 all_acked(); // and now we can continue
2549 return IOPMNoErr;
2550 }
2551 break;
2552 }
2553 IOUnlock(priv->our_lock);
2554 return IOPMNoErr;
2555}
2556
2557
2558//*********************************************************************************
2559// add_driver_to_active_change
2560//
2561// An interested driver has just registered with us. If there is
2562// currently a change in progress, get the new party involved: if we
2563// have notified all parties and are waiting for acks, notify the new
2564// party.
2565//*********************************************************************************
2566
2567IOReturn IOService::add_driver_to_active_change ( IOPMinformee * newObject )
2568{
2569 if (! acquire_lock() ) {
2570 return IOPMNoErr;
2571 }
2572
2573 switch (priv->machine_state) {
2574 case IOPMour_prechange_1:
2575 case IOPMparent_down_4:
2576 case IOPMparent_up_0:
2577 priv->head_note_pendingAcks += 2; // one for this driver and one to prevent
2578 IOUnlock(priv->our_lock); // incoming acks from changing our state
2579 inform(newObject, true); // inform the driver
2580 if (! acquire_lock() ) {
2581 --priv->head_note_pendingAcks; // put it back
2582 return IOPMNoErr;
2583 }
2584 if ( --priv->head_note_pendingAcks == 0 ) { // are we still waiting for acks?
2585 stop_ack_timer(); // no, stop the timer
2586 IOUnlock(priv->our_lock);
2587 all_acked(); // and now we can continue
2588 return IOPMNoErr;
2589 }
2590 break;
2591 case IOPMour_prechange_4:
2592 case IOPMparent_down_6:
2593 case IOPMparent_up_6:
2594 priv->head_note_pendingAcks += 2; // one for this driver and one to prevent
2595 IOUnlock(priv->our_lock); // incoming acks from changing our state
2596 inform(newObject, false); // inform the driver
2597 if (! acquire_lock() ) {
2598 --priv->head_note_pendingAcks; // put it back
2599 return IOPMNoErr;
2600 }
2601 if ( --priv->head_note_pendingAcks == 0 ) { // are we still waiting for acks?
2602 stop_ack_timer(); // no, stop the timer
2603 IOUnlock(priv->our_lock);
2604 all_acked(); // and now we can continue
2605 return IOPMNoErr;
2606 }
2607 break;
2608 }
2609 IOUnlock(priv->our_lock);
2610 return IOPMNoErr;
2611}
2612
2613
2614//*********************************************************************************
2615// start_parent_change
2616//
2617// Here we begin the processing of a change note initiated by our parent
2618// which is at the head of the queue.
2619//
2620// It is possible for the change to be processed to completion and removed from the queue.
2621// There are several possible interruptions to the processing, though, and they are:
2622// we may have to wait for interested parties to acknowledge our pre-change notification,
2623// we may have to wait for our controlling driver to change the hardware power state,
2624// there may be a settling time after changing the hardware power state,
2625// we may have to wait for interested parties to acknowledge our post-change notification,
2626// we may have to wait for the acknowledgement timer expiration to substitute for the
2627// acknowledgement from a failing driver.
2628//*********************************************************************************
2629
2630IOReturn IOService::start_parent_change ( unsigned long queue_head )
2631{
2632 priv->head_note = queue_head;
2633 priv->head_note_flags = priv-> changeList->changeNote[priv->head_note].flags;
2634 priv->head_note_state = priv->changeList->changeNote[priv->head_note].newStateNumber;
2635 priv->head_note_outputFlags = priv->changeList->changeNote[priv->head_note].outputPowerCharacter;
2636 priv->head_note_domainState = priv->changeList->changeNote[priv->head_note].domainState;
2637 priv->head_note_parent = priv->changeList->changeNote[priv->head_note].parent;
2638 priv->head_note_capabilityFlags = priv->changeList->changeNote[priv->head_note].capabilityFlags;
2639
2640 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartParentChange,
2641 (unsigned long)priv->head_note_state,(unsigned long)pm_vars->myCurrentState);
2642
2643 ask_parent( priv->ourDesiredPowerState); // if we need something and haven't told the parent, do so
2644
2645 if ( priv->head_note_state < pm_vars->myCurrentState ) { // power domain is lowering
2646 priv->initial_change = false;
2647 priv->machine_state = IOPMparent_down_0; // tell apps and kernel clients
2648 if ( tellChangeDown(priv->head_note_state) ) { // are we waiting for responses?
2649 return parent_down_0(); // no, notify interested drivers
2650 }
2651 return IOPMWillAckLater; // yes
2652 }
2653
2654 if ( priv->head_note_state > pm_vars->myCurrentState ) { // parent is raising power, we may or may not
2655 if ( priv->ourDesiredPowerState > pm_vars->myCurrentState ) {
2656 if ( priv->ourDesiredPowerState < priv->head_note_state ) {
2657 priv->head_note_state = priv->ourDesiredPowerState; // we do, but not all the way
2658 priv->head_note_outputFlags = pm_vars->thePowerStates[priv->head_note_state].outputPowerCharacter;
2659 priv->head_note_capabilityFlags = pm_vars->thePowerStates[priv->head_note_state].capabilityFlags;
2660 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAmendParentChange,(unsigned long)priv->head_note_state,0);
2661 }
2662 }
2663 else {
2664 priv-> head_note_state = pm_vars->myCurrentState; // we don't
2665 priv->head_note_outputFlags = pm_vars->thePowerStates[priv->head_note_state].outputPowerCharacter;
2666 priv->head_note_capabilityFlags = pm_vars->thePowerStates[priv->head_note_state].capabilityFlags;
2667 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAmendParentChange,(unsigned long)priv->head_note_state,0);
2668 }
2669 }
2670
2671 if ( (priv->head_note_state > pm_vars->myCurrentState) &&
2672 (priv->head_note_flags & IOPMDomainDidChange) ) { // changing up
2673 priv->initial_change = false;
2674 priv->machine_state = IOPMparent_up_0;
2675 if ( notifyAll(true) == IOPMAckImplied ) {
2676 return parent_up_1();
2677 }
2678 return IOPMWillAckLater; // they didn't all ack
2679 }
2680
2681 all_done();
2682 return IOPMAckImplied; // a null change or power will go up
2683}
2684
2685
2686//*********************************************************************************
2687// start_our_change
2688//
2689// Here we begin the processing of a change note initiated by us
2690// which is at the head of the queue.
2691//
2692// It is possible for the change to be processed to completion and removed from the queue.
2693// There are several possible interruptions to the processing, though, and they are:
2694// we may have to wait for interested parties to acknowledge our pre-change notification,
2695// changes initiated by the parent will wait in the middle for powerStateDidChange,
2696// we may have to wait for our controlling driver to change the hardware power state,
2697// there may be a settling time after changing the hardware power state,
2698// we may have to wait for interested parties to acknowledge our post-change notification,
2699// we may have to wait for the acknowledgement timer expiration to substitute for the
2700// acknowledgement from a failing driver.
2701//*********************************************************************************
2702
2703void IOService::start_our_change ( unsigned long queue_head )
2704{
2705 priv->head_note = queue_head;
2706 priv->head_note_flags = priv->changeList->changeNote[priv->head_note].flags;
2707 priv->head_note_state = priv->changeList->changeNote[priv->head_note].newStateNumber;
2708 priv->head_note_outputFlags = priv->changeList->changeNote[priv->head_note].outputPowerCharacter;
2709 priv->head_note_capabilityFlags = priv->changeList->changeNote[priv->head_note].capabilityFlags;
2710
2711 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartDeviceChange,
2712 (unsigned long)priv->head_note_state,(unsigned long)pm_vars->myCurrentState);
2713
2714 if ( priv->head_note_capabilityFlags & IOPMNotAttainable ) { // can our driver switch to the new state?
2715 if ( ! priv->we_are_root ) { // no, ask the parent to do it then
2716 ask_parent(priv->head_note_state);
2717 }
2718 priv-> head_note_flags |= IOPMNotDone; // mark the change note un-actioned
2719 all_done(); // and we're done
2720 return;
2721 }
2722 // is there enough power in the domain?
2723 if ( (pm_vars->maxCapability < priv->head_note_state) && (! priv->we_are_root) ) {
2724 if ( ! priv->we_are_root ) { // no, ask the parent to raise it
2725 ask_parent(priv->head_note_state);
2726 }
2727 priv->head_note_flags |= IOPMNotDone; // no, mark the change note un-actioned
2728 all_done(); // and we're done
2729 return; // till the parent raises power
2730 }
2731
2732 if ( ! priv->initial_change ) {
2733 if ( priv->head_note_state == pm_vars->myCurrentState ) {
2734 all_done(); // we initiated a null change; forget it
2735 return;
2736 }
2737 }
2738 priv->initial_change = false;
2739
2740 if ( priv->head_note_state < pm_vars->myCurrentState ) { // dropping power?
2741 priv->machine_state = IOPMour_prechange_03; // yes, in case we have to wait for acks
2742 pm_vars->doNotPowerDown = false;
2743 if ( askChangeDown(priv->head_note_state) ) { // ask apps and kernel clients if we can drop power
2744 if ( pm_vars->doNotPowerDown ) { // don't have to wait, did any clients veto?
2745 tellNoChangeDown(priv->head_note_state); // yes, rescind the warning
2746 priv-> head_note_flags |= IOPMNotDone; // mark the change note un-actioned
2747 all_done(); // and we're done
2748 }
2749 else {
2750 our_prechange_03(); // no, tell'em we're dropping power
2751 }
2752 }
2753 }
2754 else {
2755 if ( ! priv->we_are_root ) { // we are raising power
2756 ask_parent(priv->head_note_state); // if this changes our power requirement, tell the parent
2757 }
2758 priv->machine_state = IOPMour_prechange_1; // in case they don't all ack
2759 if ( notifyAll(true) == IOPMAckImplied ) { // notify interested drivers and children
2760 our_prechange_1();
2761 }
2762 }
2763}
2764
2765
2766//*********************************************************************************
2767// ask_parent
2768//
2769// Call the power domain parent to ask for a higher power state in the domain
2770// or to suggest a lower power state.
2771//*********************************************************************************
2772
2773IOReturn IOService::ask_parent ( unsigned long requestedState )
2774{
2775 OSIterator * iter;
2776 OSObject * next;
2777 IOPowerConnection * connection;
2778
2779 if ( priv->previousRequest == pm_vars->thePowerStates[requestedState].inputPowerRequirement ) { // is this a new desire?
2780 return IOPMNoErr; // no, the parent knows already, just return
2781 }
2782
2783 if ( priv->we_are_root ) {
2784 return IOPMNoErr;
2785 }
2786 priv->previousRequest = pm_vars->thePowerStates[requestedState].inputPowerRequirement;
2787
2788 iter = getParentIterator(gIOPowerPlane);
2789
2790 if ( iter ) {
2791 while ( (next = iter->getNextObject()) ) {
2792 if ( (connection = OSDynamicCast(IOPowerConnection,next)) ) {
2793 if ( ((IOService *)(connection->getParentEntry(gIOPowerPlane)))->requestPowerDomainState( priv->previousRequest,connection,IOPMLowestState)!= IOPMNoErr ) {
2794 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogRequestDenied,(unsigned long)priv->previousRequest,0);
2795 }
2796 }
2797 }
2798 iter->release();
2799 }
2800
2801 return IOPMNoErr;
2802}
2803
2804
2805//*********************************************************************************
2806// instruct_driver
2807//
2808// Call the controlling driver and have it change the power state of the
2809// hardware. If it returns IOPMAckImplied, the change is complete, and
2810// we return IOPMAckImplied. Otherwise, it will ack when the change
2811// is done; we return IOPMWillAckLater.
2812//*********************************************************************************
2813
2814IOReturn IOService::instruct_driver ( unsigned long newState )
2815{
2816 IOReturn return_code;
2817
2818 if ( pm_vars->thePowerStates[newState].capabilityFlags & IOPMNotAttainable ) { // can our driver switch to the desired state?
2819 return IOPMAckImplied; // no, so don't try
2820 }
2821 priv->driver_timer = -1;
2822
2823 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogProgramHardware,newState,0);
2824 return_code = pm_vars->theControllingDriver->setPowerState( newState,this ); // yes, instruct it
2825 if ( return_code == IOPMAckImplied ) { // it finished
2826 priv->driver_timer = 0;
2827 return IOPMAckImplied;
2828 }
2829
2830 if ( priv->driver_timer == 0 ) { // it acked behind our back
2831 return IOPMAckImplied;
2832 }
2833
2834 if ( return_code < 0 ) { // somebody goofed
2835 return IOPMAckImplied;
2836 }
2837
2838 priv->driver_timer = (return_code * ns_per_us / ACK_TIMER_PERIOD) + 1; // it didn't finish
2839 return IOPMWillAckLater;
2840}
2841
2842
2843//*********************************************************************************
2844// acquire_lock
2845//
2846// We are acquiring the lock we use to protect our queue head from
2847// simutaneous access by a thread which calls acknowledgePowerStateChange
2848// or acknowledgeSetPowerState and the ack timer expiration thread.
2849// Return TRUE if we acquire the lock, and the queue head didn't change
2850// while we were acquiring the lock (and maybe blocked).
2851// If there is no queue head, or it changes while we are blocked,
2852// return FALSE with the lock unlocked.
2853//*********************************************************************************
2854
2855bool IOService::acquire_lock ( void )
2856{
2857 long current_change_note;
2858
2859 current_change_note = priv->head_note;
2860 if ( current_change_note == -1 ) {
2861 return FALSE;
2862 }
2863
2864 IOTakeLock(priv->our_lock);
2865 if ( current_change_note == priv->head_note ) {
2866 return TRUE;
2867 }
2868 else { // we blocked and something changed radically
2869 IOUnlock(priv->our_lock); // so there's nothing to do any more
2870 return FALSE;
2871 }
2872}
2873
2874
2875//*********************************************************************************
2876// askChangeDown
2877//
2878// Ask registered applications and kernel clients if we can change to a lower
2879// power state.
2880//
2881// Subclass can override this to send a different message type. Parameter is
2882// the destination state number.
2883//
2884// Return true if we don't have to wait for acknowledgements
2885//*********************************************************************************
2886
2887bool IOService::askChangeDown ( unsigned long )
2888{
2889 return tellClientsWithResponse(kIOMessageCanDevicePowerOff);
2890}
2891
2892
2893//*********************************************************************************
2894// tellChangeDown
2895//
2896// Notify registered applications and kernel clients that we are definitely
2897// dropping power.
2898//
2899// Subclass can override this to send a different message type. Parameter is
2900// the destination state number.
2901//
2902// Return true if we don't have to wait for acknowledgements
2903//*********************************************************************************
2904
2905bool IOService::tellChangeDown ( unsigned long )
2906{
2907 return tellClientsWithResponse(kIOMessageDeviceWillPowerOff);
2908}
2909
2910
2911//*********************************************************************************
2912// tellClientsWithResponse
2913//
2914// Notify registered applications and kernel clients that we are definitely
2915// dropping power.
2916//
2917// Return true if we don't have to wait for acknowledgements
2918//*********************************************************************************
2919
2920bool IOService::tellClientsWithResponse ( int messageType )
2921{
2922 struct context theContext;
2923 AbsoluteTime deadline;
2924 OSBoolean * aBool;
2925
2926 pm_vars->responseFlags = OSArray::withCapacity( 1 );
2927 pm_vars->serialNumber += 1;
2928
2929 theContext.responseFlags = pm_vars->responseFlags;
2930 theContext.serialNumber = pm_vars->serialNumber;
2931 theContext.flags_lock = priv->flags_lock;
2932 theContext.counter = 1;
2933 theContext.msgType = messageType;
2934 theContext.us = this;
2935 theContext.maxTimeRequested = 0;
2936
2937 IOLockLock(priv->flags_lock);
2938 aBool = OSBoolean::withBoolean(false); // position zero is false to
2939 theContext.responseFlags->setObject(0,aBool); // prevent allowCancelCommon from succeeding
2940 aBool->release();
2941 IOLockUnlock(priv->flags_lock);
2942
2943 applyToInterested(gIOAppPowerStateInterest,tellAppWithResponse,(void *)&theContext);
2944 applyToInterested(gIOGeneralInterest,tellClientWithResponse,(void *)&theContext);
2945
2946 if (! acquire_lock() ) {
2947 return true;
2948 }
2949 IOLockLock(priv->flags_lock);
2950 aBool = OSBoolean::withBoolean(true); // now fix position zero
2951 theContext.responseFlags->replaceObject(0,aBool);
2952 aBool->release();
2953 IOLockUnlock(priv->flags_lock);
2954
2955 if ( ! checkForDone() ) { // we have to wait for somebody
2956 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,theContext.maxTimeRequested,0);
2957 clock_interval_to_deadline(theContext.maxTimeRequested / 1000, kMillisecondScale, &deadline);
2958
2959 thread_call_enter_delayed(priv->ackTimer, deadline);
2960
2961 IOUnlock(priv->our_lock); // yes
2962 return false;
2963 }
2964
2965 IOUnlock(priv->our_lock);
2966 IOLockLock(priv->flags_lock);
2967 pm_vars->responseFlags->release(); // everybody responded
2968 pm_vars->responseFlags = NULL;
2969 IOLockUnlock(priv->flags_lock);
2970
2971 return true;
2972}
2973
2974
2975//*********************************************************************************
2976// tellAppWithResponse
2977//
2978// We send a message to an application, and we expect a response, so we compute a
2979// cookie we can identify the response with.
2980//*********************************************************************************
2981void tellAppWithResponse ( OSObject * object, void * context)
2982{
2983 struct context * theContext = (struct context *)context;
2984 UInt32 refcon;
2985 OSBoolean * aBool;
2986
2987 if( OSDynamicCast( IOService, object) ) {
2988 IOLockLock(theContext->flags_lock);
2989 aBool = OSBoolean::withBoolean(true);
2990 theContext->responseFlags->setObject(theContext->counter,aBool);
2991 aBool->release();
2992 IOLockUnlock(theContext->flags_lock);
2993 }
2994 else {
2995 refcon = ((theContext->serialNumber & 0xFFFF)<<16) + (theContext->counter & 0xFFFF);
2996 IOLockLock(theContext->flags_lock);
2997 aBool = OSBoolean::withBoolean(false);
2998 theContext->responseFlags->setObject(theContext->counter,aBool);
2999 aBool->release();
3000 IOLockUnlock(theContext->flags_lock);
3001 theContext->us->messageClient(theContext->msgType,object,(void *)refcon);
3002 if ( theContext->maxTimeRequested < k15seconds ) {
3003 theContext->maxTimeRequested = k15seconds;
3004 }
3005 }
3006 theContext->counter += 1;
3007}
3008
3009
3010//*********************************************************************************
3011// tellClientWithResponse
3012//
3013// We send a message to an in-kernel client, and we expect a response, so we compute a
3014// cookie we can identify the response with.
3015// If it doesn't understand the notification (it is not power-management savvy)
3016// we won't wait for it to prepare for sleep. If it tells us via a return code
3017// in the passed struct that it is currently ready, we won't wait for it to prepare.
3018// If it tells us via the return code in the struct that it does need time, we will chill.
3019//*********************************************************************************
3020void tellClientWithResponse ( OSObject * object, void * context)
3021{
3022 struct context * theContext = (struct context *)context;
3023 sleepWakeNote paramBlock;
3024 UInt32 refcon;
3025 IOReturn retCode;
3026 OSBoolean * aBool;
3027 OSObject * theFlag;
3028
3029 refcon = ((theContext->serialNumber & 0xFFFF)<<16) + (theContext->counter & 0xFFFF);
3030 IOLockLock(theContext->flags_lock);
3031 aBool = OSBoolean::withBoolean(false);
3032 theContext->responseFlags->setObject(theContext->counter,aBool);
3033 aBool->release();
3034 IOLockUnlock(theContext->flags_lock);
3035 paramBlock.powerRef = (void *)refcon;
3036 paramBlock.returnValue = 0;
3037 retCode = theContext->us->messageClient(theContext->msgType,object,(void *)&paramBlock);
3038 if ( retCode == kIOReturnSuccess ) {
3039 if ( paramBlock.returnValue == 0 ) { // client doesn't want time to respond
3040 IOLockLock(theContext->flags_lock);
3041 aBool = OSBoolean::withBoolean(true);
3042 theContext->responseFlags->replaceObject(theContext->counter,aBool); // so set its flag true
3043 aBool->release();
3044 IOLockUnlock(theContext->flags_lock);
3045 }
3046 else {
3047 IOLockLock(theContext->flags_lock);
3048 theFlag = theContext->responseFlags->getObject(theContext->counter); // it does want time, and it hasn't
3049 if ( theFlag != 0 ) { // responded yet
3050 if ( ((OSBoolean *)theFlag)->isFalse() ) { // so note its time requirement
3051 if ( theContext->maxTimeRequested < paramBlock.returnValue ) {
3052 theContext->maxTimeRequested = paramBlock.returnValue;
3053 }
3054 }
3055 }
3056 IOLockUnlock(theContext->flags_lock);
3057 }
3058 }
3059 else { // not a client of ours
3060 IOLockLock(theContext->flags_lock);
3061 aBool = OSBoolean::withBoolean(true); // so we won't be waiting for response
3062 theContext->responseFlags->replaceObject(theContext->counter,aBool);
3063 aBool->release();
3064 IOLockUnlock(theContext->flags_lock);
3065 }
3066 theContext->counter += 1;
3067}
3068
3069
3070//*********************************************************************************
3071// tellNoChangeDown
3072//
3073// Notify registered applications and kernel clients that we are not
3074// dropping power.
3075//
3076// Subclass can override this to send a different message type. Parameter is
3077// the aborted destination state number.
3078//*********************************************************************************
3079
3080void IOService::tellNoChangeDown ( unsigned long )
3081{
3082 return tellClients(kIOMessageDeviceWillNotPowerOff);
3083}
3084
3085
3086//*********************************************************************************
3087// tellChangeUp
3088//
3089// Notify registered applications and kernel clients that we are raising power.
3090//
3091// Subclass can override this to send a different message type. Parameter is
3092// the aborted destination state number.
3093//*********************************************************************************
3094
3095void IOService::tellChangeUp ( unsigned long )
3096{
3097 return tellClients(kIOMessageDeviceHasPoweredOn);
3098}
3099
3100
3101//*********************************************************************************
3102// tellClients
3103//
3104// Notify registered applications and kernel clients of something.
3105//*********************************************************************************
3106
3107void IOService::tellClients ( int messageType )
3108{
3109 struct context theContext;
3110
3111 theContext.msgType = messageType;
3112 theContext.us = this;
3113
3114 applyToInterested(gIOAppPowerStateInterest,tellClient,(void *)&theContext);
3115 applyToInterested(gIOGeneralInterest,tellClient,(void *)&theContext);
3116}
3117
3118
3119//*********************************************************************************
3120// tellClient
3121//
3122// Notify a registered application or kernel client of something.
3123//*********************************************************************************
3124void tellClient ( OSObject * object, void * context)
3125{
3126 struct context * theContext = (struct context *)context;
3127
3128 theContext->us->messageClient(theContext->msgType,object,0);
3129}
3130
3131
3132// **********************************************************************************
3133// checkForDone
3134//
3135// **********************************************************************************
3136bool IOService::checkForDone ( void )
3137{
3138 int i = 0;
3139 OSObject * theFlag;
3140
3141 IOLockLock(priv->flags_lock);
3142 if ( pm_vars->responseFlags == NULL ) {
3143 IOLockUnlock(priv->flags_lock);
3144 return true;
3145 }
3146 for ( i = 0; ; i++ ) {
3147 theFlag = pm_vars->responseFlags->getObject(i);
3148 if ( theFlag == NULL ) {
3149 break;
3150 }
3151 if ( ((OSBoolean *)theFlag)->isFalse() ) {
3152 IOLockUnlock(priv->flags_lock);
3153 return false;
3154 }
3155 }
3156 IOLockUnlock(priv->flags_lock);
3157 return true;
3158}
3159
3160
3161// **********************************************************************************
3162// responseValid
3163//
3164// **********************************************************************************
3165bool IOService::responseValid ( unsigned long x )
3166{
3167 UInt16 serialComponent;
3168 UInt16 ordinalComponent;
3169 OSObject * theFlag;
3170 unsigned long refcon = (unsigned long)x;
3171 OSBoolean * aBool;
3172
3173 serialComponent = (refcon>>16) & 0xFFFF;
3174 ordinalComponent = refcon & 0xFFFF;
3175
3176 if ( serialComponent != pm_vars->serialNumber ) {
3177 return false;
3178 }
3179
3180 IOLockLock(priv->flags_lock);
3181 if ( pm_vars->responseFlags == NULL ) {
3182 IOLockUnlock(priv->flags_lock);
3183 return false;
3184 }
3185
3186 theFlag = pm_vars->responseFlags->getObject(ordinalComponent);
3187
3188 if ( theFlag == 0 ) {
3189 IOLockUnlock(priv->flags_lock);
3190 return false;
3191 }
3192
3193 if ( ((OSBoolean *)theFlag)->isFalse() ) {
3194 aBool = OSBoolean::withBoolean(true);
3195 pm_vars->responseFlags->replaceObject(ordinalComponent,aBool);
3196 aBool->release();
3197 }
3198
3199 IOLockUnlock(priv->flags_lock);
3200 return true;
3201}
3202
3203
3204// **********************************************************************************
3205// allowPowerChange
3206//
3207// Our power state is about to lower, and we have notified applications
3208// and kernel clients, and one of them has acknowledged. If this is the last to do
3209// so, and all acknowledgements are positive, we continue with the power change.
3210//
3211// We serialize this processing with timer expiration with a command gate on the
3212// power management workloop, which the timer expiration is command gated to as well.
3213// **********************************************************************************
3214IOReturn IOService::allowPowerChange ( unsigned long refcon )
3215{
3216 if ( ! initialized ) {
3217 return kIOReturnSuccess; // we're unloading
3218 }
3219
3220 return pm_vars->PMcommandGate->runAction(serializedAllowPowerChange,(void *)refcon);
3221}
3222
3223
3224IOReturn serializedAllowPowerChange ( OSObject *owner, void * refcon, void *, void *, void *)
3225{
3226 return ((IOService *)owner)->serializedAllowPowerChange2((unsigned long)refcon);
3227}
3228
3229IOReturn IOService::serializedAllowPowerChange2 ( unsigned long refcon )
3230{
3231 if ( ! responseValid(refcon) ) { // response valid?
3232 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr5,refcon,0);
3233 return kIOReturnSuccess; // no, just return
3234 }
3235 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogClientAcknowledge,refcon,0);
3236
3237 return allowCancelCommon();
3238}
3239
3240
3241// **********************************************************************************
3242// cancelPowerChange
3243//
3244// Our power state is about to lower, and we have notified applications
3245// and kernel clients, and one of them has vetoed the change. If this is the last
3246// client to respond, we abandon the power change.
3247//
3248// We serialize this processing with timer expiration with a command gate on the
3249// power management workloop, which the timer expiration is command gated to as well.
3250// **********************************************************************************
3251IOReturn IOService::cancelPowerChange ( unsigned long refcon )
3252{
3253 if ( ! initialized ) {
3254 return kIOReturnSuccess; // we're unloading
3255 }
3256
3257 return pm_vars->PMcommandGate->runAction(serializedCancelPowerChange,(void *)refcon);
3258}
3259
3260
3261IOReturn serializedCancelPowerChange ( OSObject *owner, void * refcon, void *, void *, void *)
3262{
3263 return ((IOService *)owner)->serializedCancelPowerChange2((unsigned long)refcon);
3264}
3265
3266IOReturn IOService::serializedCancelPowerChange2 ( unsigned long refcon )
3267{
3268 if ( ! responseValid(refcon) ) { // response valid?
3269 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr5,refcon,0);
3270 return kIOReturnSuccess; // no, just return
3271 }
3272 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogClientCancel,refcon,0);
3273
3274 pm_vars->doNotPowerDown = true;
3275
3276 return allowCancelCommon();
3277}
3278
3279
3280// **********************************************************************************
3281// allowCancelCommon
3282//
3283// **********************************************************************************
3284IOReturn IOService::allowCancelCommon ( void )
3285{
3286 if (! acquire_lock() ) {
3287 return kIOReturnSuccess;
3288 }
3289
3290 if ( checkForDone() ) { // is this the last response?
3291 stop_ack_timer(); // yes, stop the timer
3292 IOUnlock(priv->our_lock);
3293 IOLockLock(priv->flags_lock);
3294 if ( pm_vars->responseFlags ) {
3295 pm_vars->responseFlags->release();
3296 pm_vars->responseFlags = NULL;
3297 }
3298 IOLockUnlock(priv->flags_lock);
3299 switch (priv->machine_state) {
3300 case IOPMour_prechange_03: // our change, was it vetoed?
3301 if ( ! pm_vars->doNotPowerDown ) {
3302 our_prechange_03(); // no, we can continue
3303 }
3304 else {
3305 tellNoChangeDown(priv->head_note_state); // yes, rescind the warning
3306 priv->head_note_flags |= IOPMNotDone; // mark the change note un-actioned
3307 all_done(); // and we're done
3308 }
3309 break;
3310 case IOPMour_prechange_05:
3311 our_prechange_05(); // our change, continue
3312 break;
3313 case IOPMparent_down_0:
3314 parent_down_05(); // parent change, continueq8q
3315 break;
3316 }
3317 return kIOReturnSuccess;
3318 }
3319
3320 IOUnlock(priv->our_lock); // not done yet
3321 return kIOReturnSuccess;
3322}
3323
3324
3325//*********************************************************************************
3326// clampPowerOn
3327//
3328// Set to highest available power state for a minimum of duration milliseconds
3329//*********************************************************************************
3330
3331#define kFiveMinutesInNanoSeconds (300 * NSEC_PER_SEC)
3332
3333void IOService::clampPowerOn (unsigned long duration)
3334{
3335 changePowerStateToPriv (pm_vars->theNumberOfPowerStates-1);
3336
3337 if ( priv->clampTimerEventSrc == NULL ) {
3338 priv->clampTimerEventSrc = IOTimerEventSource::timerEventSource(this,
3339 c_PM_Clamp_Timer_Expired);
3340
3341 IOWorkLoop * workLoop = getPMworkloop ();
3342
3343 if ( !priv->clampTimerEventSrc || !workLoop ||
3344 ( workLoop->addEventSource( priv->clampTimerEventSrc) != kIOReturnSuccess) ) {
3345
3346 }
3347 }
3348
3349 priv->clampTimerEventSrc->setTimeout(kFiveMinutesInNanoSeconds, NSEC_PER_SEC);
3350}
3351
3352//*********************************************************************************
3353// PM_Clamp_Timer_Expired
3354//
3355// called when clamp timer expires...set power state to 0.
3356//*********************************************************************************
3357
3358void IOService::PM_Clamp_Timer_Expired (void)
3359{
3360 if ( ! initialized ) {
3361 return; // we're unloading
3362 }
3363
3364 changePowerStateToPriv (0);
3365}
3366
3367//*********************************************************************************
3368// c_PM_clamp_Timer_Expired (C Func)
3369//
3370// Called when our clamp timer expires...we will call the object method.
3371//*********************************************************************************
3372
3373void c_PM_Clamp_Timer_Expired (OSObject * client, IOTimerEventSource *)
3374{
3375 if (client)
3376 ((IOService *)client)->PM_Clamp_Timer_Expired ();
3377}
3378
3379
3380//*********************************************************************************
3381// setPowerState
3382//
3383// Does nothing here. This should be implemented in a subclass driver.
3384//*********************************************************************************
3385
3386IOReturn IOService::setPowerState ( unsigned long powerStateOrdinal, IOService* whatDevice )
3387{
3388 return IOPMNoErr;
3389}
3390
3391
3392//*********************************************************************************
3393// maxCapabilityForDomainState
3394//
3395// Finds the highest power state in the array whose input power
3396// requirement is equal to the input parameter. Where a more intelligent
3397// decision is possible, override this in the subclassed driver.
3398//*********************************************************************************
3399
3400unsigned long IOService::maxCapabilityForDomainState ( IOPMPowerFlags domainState )
3401{
3402 int i;
3403
3404 if (pm_vars->theNumberOfPowerStates == 0 ) {
3405 return 0;
3406 }
3407 for ( i = (pm_vars->theNumberOfPowerStates)-1; i >= 0; i-- ) {
3408 if ( pm_vars->thePowerStates[i].inputPowerRequirement == domainState ) {
3409 return i;
3410 }
3411 }
3412 return 0;
3413}
3414
3415
3416//*********************************************************************************
3417// initialPowerStateForDomainState
3418//
3419// Finds the highest power state in the array whose input power
3420// requirement is equal to the input parameter. Where a more intelligent
3421// decision is possible, override this in the subclassed driver.
3422//*********************************************************************************
3423
3424unsigned long IOService::initialPowerStateForDomainState ( IOPMPowerFlags domainState )
3425{
3426 int i;
3427
3428 if (pm_vars->theNumberOfPowerStates == 0 ) {
3429 return 0;
3430 }
3431 for ( i = (pm_vars->theNumberOfPowerStates)-1; i >= 0; i-- ) {
3432 if ( pm_vars->thePowerStates[i].inputPowerRequirement == domainState ) {
3433 return i;
3434 }
3435 }
3436 return 0;
3437}
3438
3439
3440//*********************************************************************************
3441// powerStateForDomainState
3442//
3443// Finds the highest power state in the array whose input power
3444// requirement is equal to the input parameter. Where a more intelligent
3445// decision is possible, override this in the subclassed driver.
3446//*********************************************************************************
3447
3448unsigned long IOService::powerStateForDomainState ( IOPMPowerFlags domainState )
3449{
3450 int i;
3451
3452 if (pm_vars->theNumberOfPowerStates == 0 ) {
3453 return 0;
3454 }
3455 for ( i = (pm_vars->theNumberOfPowerStates)-1; i >= 0; i-- ) {
3456 if ( pm_vars->thePowerStates[i].inputPowerRequirement == domainState ) {
3457 return i;
3458 }
3459 }
3460 return 0;
3461}
3462
3463
3464//*********************************************************************************
3465// didYouWakeSystem
3466//
3467// Does nothing here. This should be implemented in a subclass driver.
3468//*********************************************************************************
3469
3470bool IOService::didYouWakeSystem ( void )
3471{
3472 return false;
3473}
3474
3475
3476//*********************************************************************************
3477// powerStateWillChangeTo
3478//
3479// Does nothing here. This should be implemented in a subclass driver.
3480//*********************************************************************************
3481
3482IOReturn IOService::powerStateWillChangeTo ( IOPMPowerFlags, unsigned long, IOService*)
3483{
3484 return 0;
3485}
3486
3487
3488//*********************************************************************************
3489// powerStateDidChangeTo
3490//
3491// Does nothing here. This should be implemented in a subclass driver.
3492//*********************************************************************************
3493
3494IOReturn IOService::powerStateDidChangeTo ( IOPMPowerFlags, unsigned long, IOService*)
3495{
3496 return 0;
3497}
3498
3499
3500//*********************************************************************************
3501// powerChangeDone
3502//
3503// Does nothing here. This should be implemented in a subclass policy-maker.
3504//*********************************************************************************
3505
3506void IOService::powerChangeDone ( unsigned long )
3507{
3508}
3509
3510
3511//*********************************************************************************
3512// newTemperature
3513//
3514// Does nothing here. This should be implemented in a subclass driver.
3515//*********************************************************************************
3516
3517IOReturn IOService::newTemperature ( long currentTemp, IOService * whichZone )
3518
3519{
3520 return IOPMNoErr;
3521}
3522
3523
3524#undef super
3525#define super OSObject
3526
3527OSDefineMetaClassAndStructors(IOPMprot, OSObject)
3528//*********************************************************************************
3529// serialize
3530//
3531// Serialize protected instance variables for debug output.
3532//*********************************************************************************
3533bool IOPMprot::serialize(OSSerialize *s) const
3534{
3535 OSString * theOSString;
3536 char * buffer;
3537 char * ptr;
3538 int i;
3539 bool rtn_code;
3540
3541 buffer = ptr = IONew(char, 2000);
3542 if(!buffer)
3543 return false;
3544
3545 ptr += sprintf(ptr,"{ theNumberOfPowerStates = %d, ",(unsigned int)theNumberOfPowerStates);
3546
3547 if ( theNumberOfPowerStates != 0 ) {
3548 ptr += sprintf(ptr,"version %d, ",(unsigned int)thePowerStates[0].version);
3549 }
3550
3551 if ( theNumberOfPowerStates != 0 ) {
3552 for ( i = 0; i < (int)theNumberOfPowerStates; i++ ) {
3553 ptr += sprintf(ptr,"power state %d = { ",i);
3554 ptr += sprintf(ptr,"capabilityFlags %08x, ",(unsigned int)thePowerStates[i].capabilityFlags);
3555 ptr += sprintf(ptr,"outputPowerCharacter %08x, ",(unsigned int)thePowerStates[i].outputPowerCharacter);
3556 ptr += sprintf(ptr,"inputPowerRequirement %08x, ",(unsigned int)thePowerStates[i].inputPowerRequirement);
3557 ptr += sprintf(ptr,"staticPower %d, ",(unsigned int)thePowerStates[i].staticPower);
3558 ptr += sprintf(ptr,"unbudgetedPower %d, ",(unsigned int)thePowerStates[i].unbudgetedPower);
3559 ptr += sprintf(ptr,"powerToAttain %d, ",(unsigned int)thePowerStates[i].powerToAttain);
3560 ptr += sprintf(ptr,"timeToAttain %d, ",(unsigned int)thePowerStates[i].timeToAttain);
3561 ptr += sprintf(ptr,"settleUpTime %d, ",(unsigned int)thePowerStates[i].settleUpTime);
3562 ptr += sprintf(ptr,"timeToLower %d, ",(unsigned int)thePowerStates[i].timeToLower);
3563 ptr += sprintf(ptr,"settleDownTime %d, ",(unsigned int)thePowerStates[i].settleDownTime);
3564 ptr += sprintf(ptr,"powerDomainBudget %d }, ",(unsigned int)thePowerStates[i].powerDomainBudget);
3565 }
3566 }
3567
3568 ptr += sprintf(ptr,"aggressiveness = %d, ",(unsigned int)aggressiveness);
3569 ptr += sprintf(ptr,"myCurrentState = %d, ",(unsigned int)myCurrentState);
3570 ptr += sprintf(ptr,"parentsCurrentPowerFlags = %08x, ",(unsigned int)parentsCurrentPowerFlags);
3571 ptr += sprintf(ptr,"maxCapability = %d }",(unsigned int)maxCapability);
3572
3573 theOSString = OSString::withCString(buffer);
3574 rtn_code = theOSString->serialize(s);
3575 theOSString->release();
3576 IODelete(buffer, char, 2000);
3577
3578 return rtn_code;
3579}
3580
3581
3582#undef super
3583#define super OSObject
3584
3585OSDefineMetaClassAndStructors(IOPMpriv, OSObject)
3586//*********************************************************************************
3587// serialize
3588//
3589// Serialize private instance variables for debug output.
3590//*********************************************************************************
3591bool IOPMpriv::serialize(OSSerialize *s) const
3592{
3593 OSString * theOSString;
3594 bool rtn_code;
3595 char * buffer;
3596 char * ptr;
3597 IOPMinformee * nextObject;
3598
3599 buffer = ptr = IONew(char, 2000);
3600 if(!buffer)
3601 return false;
3602
3603 ptr += sprintf(ptr,"{ this object = %08x",(unsigned int)owner);
3604 if ( we_are_root ) {
3605 ptr += sprintf(ptr," (root)");
3606 }
3607 ptr += sprintf(ptr,", ");
3608
3609 nextObject = interestedDrivers->firstInList(); // display interested drivers
3610 while ( nextObject != NULL ) {
3611 ptr += sprintf(ptr,"interested driver = %08x, ",(unsigned int)nextObject->whatObject);
3612 nextObject = interestedDrivers->nextInList(nextObject);
3613 }
3614
3615 if ( machine_state != IOPMfinished ) {
3616 ptr += sprintf(ptr,"machine_state = %d, ",(unsigned int)machine_state);
3617 ptr += sprintf(ptr,"driver_timer = %d, ",(unsigned int)driver_timer);
3618 ptr += sprintf(ptr,"settle_time = %d, ",(unsigned int)settle_time);
3619 ptr += sprintf(ptr,"head_note_flags = %08x, ",(unsigned int)head_note_flags);
3620 ptr += sprintf(ptr,"head_note_state = %d, ",(unsigned int)head_note_state);
3621 ptr += sprintf(ptr,"head_note_outputFlags = %08x, ",(unsigned int)head_note_outputFlags);
3622 ptr += sprintf(ptr,"head_note_domainState = %08x, ",(unsigned int)head_note_domainState);
3623 ptr += sprintf(ptr,"head_note_capabilityFlags = %08x, ",(unsigned int)head_note_capabilityFlags);
3624 ptr += sprintf(ptr,"head_note_pendingAcks = %d, ",(unsigned int)head_note_pendingAcks);
3625 }
3626
3627 if ( device_overrides ) {
3628 ptr += sprintf(ptr,"device overrides, ");
3629 }
3630 ptr += sprintf(ptr,"driverDesire = %d, ",(unsigned int)driverDesire);
3631 ptr += sprintf(ptr,"deviceDesire = %d, ",(unsigned int)deviceDesire);
3632 ptr += sprintf(ptr,"ourDesiredPowerState = %d, ",(unsigned int)ourDesiredPowerState);
3633 ptr += sprintf(ptr,"previousRequest = %d }",(unsigned int)previousRequest);
3634
3635 theOSString = OSString::withCString(buffer);
3636 rtn_code = theOSString->serialize(s);
3637 theOSString->release();
3638 IODelete(buffer, char, 2000);
3639
3640 return rtn_code;
3641}
3642