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