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