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