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