1 /*
2 * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include <IOKit/assert.h>
30 #include <IOKit/IOKitDebug.h>
31 #include <IOKit/IOLib.h>
32 #include <IOKit/IOMessage.h>
33 #include <IOKit/IOPlatformExpert.h>
34 #include <IOKit/IOService.h>
35 #include <IOKit/IOTimerEventSource.h>
36 #include <IOKit/IOWorkLoop.h>
37 #include <IOKit/IOCommand.h>
38
39 #include <IOKit/pwr_mgt/IOPMlog.h>
40 #include <IOKit/pwr_mgt/IOPMinformee.h>
41 #include <IOKit/pwr_mgt/IOPMinformeeList.h>
42 #include <IOKit/pwr_mgt/IOPowerConnection.h>
43 #include <IOKit/pwr_mgt/RootDomain.h>
44
45 #include <sys/proc.h>
46
47 // Required for notification instrumentation
48 #include "IOServicePrivate.h"
49 #include "IOServicePMPrivate.h"
50 #include "IOKitKernelInternal.h"
51
52 static void settle_timer_expired(thread_call_param_t, thread_call_param_t);
53 static void PM_idle_timer_expired(OSObject *, IOTimerEventSource *);
54 void tellAppWithResponse(OSObject * object, void * context) { /*empty*/ }
55 void tellClientWithResponse(OSObject * object, void * context) { /*empty*/ }
56 void tellClient(OSObject * object, void * context);
57 IOReturn serializedAllowPowerChange(OSObject *, void *, void *, void *, void *);
58
59 static uint64_t computeTimeDeltaNS( const AbsoluteTime * start )
60 {
61 AbsoluteTime now;
62 uint64_t nsec;
63
64 clock_get_uptime(&now);
65 SUB_ABSOLUTETIME(&now, start);
66 absolutetime_to_nanoseconds(now, &nsec);
67 return nsec;
68 }
69
70 OSDefineMetaClassAndStructors(IOPMprot, OSObject)
71
72 // log setPowerStates longer than (ns):
73 #define LOG_SETPOWER_TIMES (50ULL * 1000ULL * 1000ULL)
74 // log app responses longer than (ns):
75 #define LOG_APP_RESPONSE_TIMES (100ULL * 1000ULL * 1000ULL)
76
77 //*********************************************************************************
78 // Globals
79 //*********************************************************************************
80
81 static bool gIOPMInitialized = false;
82 static IOItemCount gIOPMBusyCount = 0;
83 static IOWorkLoop * gIOPMWorkLoop = 0;
84 static IOPMRequestQueue * gIOPMRequestQueue = 0;
85 static IOPMRequestQueue * gIOPMReplyQueue = 0;
86 static IOPMRequestQueue * gIOPMFreeQueue = 0;
87
88 //*********************************************************************************
89 // Macros
90 //*********************************************************************************
91
92 #define PM_ERROR(x...) do { kprintf(x); IOLog(x); } while (false)
93 #define PM_DEBUG(x...) do { kprintf(x); } while (false)
94
95 #define PM_TRACE(x...) do { \
96 if (kIOLogDebugPower & gIOKitDebug) kprintf(x); } while (false)
97
98 #define PM_CONNECT(x...)
99
100 #define PM_ASSERT_IN_GATE(x) \
101 do { \
102 assert(gIOPMWorkLoop->inGate()); \
103 } while(false)
104
105 #define PM_LOCK() IOLockLock(fPMLock)
106 #define PM_UNLOCK() IOLockUnlock(fPMLock)
107
108 #define ns_per_us 1000
109 #define k30seconds (30*1000000)
110 #define kMinAckTimeoutTicks (10*1000000)
111 #define kIOPMTardyAckSPSKey "IOPMTardyAckSetPowerState"
112 #define kIOPMTardyAckPSCKey "IOPMTardyAckPowerStateChange"
113 #define kPwrMgtKey "IOPowerManagement"
114
115 #define OUR_PMLog(t, a, b) \
116 do { fPlatform->PMLog( fName, t, a, b); } while(0)
117
118 #define NS_TO_MS(nsec) ((int)((nsec) / 1000000ULL))
119
120 //*********************************************************************************
121 // PM machine states
122 //*********************************************************************************
123
124 enum {
125 kIOPM_OurChangeTellClientsPowerDown = 1,
126 kIOPM_OurChangeTellPriorityClientsPowerDown = 2,
127 kIOPM_OurChangeNotifyInterestedDriversWillChange = 3,
128 kIOPM_OurChangeSetPowerState = 4,
129 kIOPM_OurChangeWaitForPowerSettle = 5,
130 kIOPM_OurChangeNotifyInterestedDriversDidChange = 6,
131 kIOPM_OurChangeFinish = 7,
132 kIOPM_ParentDownTellPriorityClientsPowerDown = 8,
133 kIOPM_ParentDownNotifyInterestedDriversWillChange = 9,
134 /* 10 not used */
135 kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange = 11,
136 kIOPM_ParentDownSetPowerState = 12,
137 kIOPM_ParentDownWaitForPowerSettle = 13,
138 kIOPM_ParentDownAcknowledgeChange = 14,
139 kIOPM_ParentUpSetPowerState = 15,
140 /* 16 not used */
141 kIOPM_ParentUpWaitForSettleTime = 17,
142 kIOPM_ParentUpNotifyInterestedDriversDidChange = 18,
143 kIOPM_ParentUpAcknowledgePowerChange = 19,
144 kIOPM_Finished = 20,
145 kIOPM_DriverThreadCallDone = 21,
146 kIOPM_NotifyChildrenDone = 22
147 };
148
149
150 /*
151 Power Management defines a few roles that drivers can play in their own,
152 and other drivers', power management. We briefly define those here.
153
154 Many drivers implement their policy maker and power controller within the same
155 IOService object, but that is not required.
156
157 == Policy Maker ==
158 * Virtual IOService PM methods a "policy maker" may implement
159 * maxCapabilityForDomainState()
160 * initialPowerStateForDomainState()
161 * powerStateForDomainState()
162
163 * Virtual IOService PM methods a "policy maker" may CALL
164 * PMinit()
165
166 == Power Controller ==
167 * Virtual IOService PM methods a "power controller" may implement
168 * setPowerState()
169
170 * Virtual IOService PM methods a "power controller" may CALL
171 * joinPMtree()
172 * registerPowerDriver()
173
174 =======================
175 There are two different kinds of power state changes.
176 * One is initiated by a subclassed device object which has either decided
177 to change power state, or its controlling driver has suggested it, or
178 some other driver wants to use the idle device and has asked it to become
179 usable.
180 * The second kind of power state change is initiated by the power domain
181 parent.
182 The two are handled through different code paths.
183
184 We maintain a queue of "change notifications," or change notes.
185 * Usually the queue is empty.
186 * When it isn't, usually there is one change note in it
187 * It's possible to have more than one power state change pending at one
188 time, so a queue is implemented.
189 Example:
190 * The subclass device decides it's idle and initiates a change to a lower
191 power state. This causes interested parties to be notified, but they
192 don't all acknowledge right away. This causes the change note to sit
193 in the queue until all the acks are received. During this time, the
194 device decides it isn't idle anymore and wants to raise power back up
195 again. This change can't be started, however, because the previous one
196 isn't complete yet, so the second one waits in the queue. During this
197 time, the parent decides to lower or raise the power state of the entire
198 power domain and notifies the device, and that notification goes into
199 the queue, too, and can't be actioned until the others are.
200
201 == SelfInitiated ==
202 This is how a power change initiated by the subclass device is handled:
203 -> First, all interested parties are notified of the change via their
204 powerStateWillChangeTo method. If they all don't acknowledge via return
205 code, then we have to wait. If they do, or when they finally all
206 acknowledge via our acknowledgePowerChange method, then we can continue.
207 -> We call the controlling driver, instructing it to change to the new state
208 -> Then we wait for power to settle. If there is no settling-time, or after
209 it has passed,
210 -> we notify interested parties again, this time via their
211 powerStateDidChangeTo methods.
212 -> When they have all acked, we're done.
213 If we lowered power and don't need the power domain to be in its current power
214 state, we suggest to the parent that it lower the power domain state.
215
216 == PowerDomainDownInitiated ==
217 How a change to a lower power domain state initiated by the parent is handled:
218 -> First, we figure out what power state we will be in when the new domain
219 state is reached.
220 -> Then all interested parties are notified that we are moving to that new
221 state.
222 -> When they have acknowledged, we call the controlling driver to assume
223 that state and we wait for power to settle.
224 -> Then we acknowledge our preparedness to our parent. When all its
225 interested parties have acknowledged,
226 -> it lowers power and then notifies its interested parties again.
227 -> When we get this call, we notify our interested parties that the power
228 state has changed, and when they have all acknowledged, we're done.
229
230 == PowerDomainUpInitiated ==
231 How a change to a higher power domain state initiated by the parent is handled:
232 -> We figure out what power state we will be in when the new domain state is
233 reached.
234 -> If it is different from our current state we acknowledge the parent.
235 -> When all the parent's interested parties have acknowledged, it raises
236 power in the domain and waits for power to settle.
237 -> Then it notifies everyone that the new state has been reached.
238 -> When we get this call, we call the controlling driver, instructing it to
239 assume the new state, and wait for power to settle.
240 -> Then we notify our interested parties. When they all acknowledge we are
241 done.
242
243 In either of the two power domain state cases above, it is possible that we
244 will not be changing state even though the domain is.
245 Examples:
246 * A change to a lower domain state may not affect us because we are already
247 in a low enough state,
248 * We will not take advantage of a change to a higher domain state, because
249 we have no need of the higher power. In such cases, there is nothing to
250 do but acknowledge the parent. So when the parent calls our
251 powerDomainWillChange method, and we decide that we will not be changing
252 state, we merely acknowledge the parent, via return code, and wait.
253 When the parent subsequently calls powerStateDidChange, we acknowledge again
254 via return code, and the change is complete.
255
256 == 4 Paths Through State Machine ==
257 Power state changes are processed in a state machine, and since there are four
258 varieties of power state changes, there are four major paths through the state
259 machine.
260
261 == 5. No Need To change ==
262 The fourth is nearly trivial. In this path, the parent is changing the domain
263 state, but we are not changing the device state. The change starts when the
264 parent calls powerDomainWillChange. All we do is acknowledge the parent. When
265 the parent calls powerStateDidChange, we acknowledge the parent again, and
266 we're done.
267
268 == 1. OurChange Down == XXX gvdl
269 The first is fairly simple. It starts:
270 * when a power domain child calls requestPowerDomainState and we decide to
271 change power states to accomodate the child,
272 * or if our power-controlling driver calls changePowerStateTo,
273 * or if some other driver which is using our device calls makeUsable,
274 * or if a subclassed object calls changePowerStateToPriv.
275 These are all power changes initiated by us, not forced upon us by the parent.
276
277 -> We start by notifying interested parties.
278 -> If they all acknowledge via return code, we can go on to state
279 "msSetPowerState".
280 -> Otherwise, we start the ack timer and wait for the stragglers to
281 acknowlege by calling acknowledgePowerChange.
282 -> We move on to state "msSetPowerState" when all the
283 stragglers have acknowledged, or when the ack timer expires on
284 all those which didn't acknowledge.
285 In "msSetPowerState" we call the power-controlling driver to change the
286 power state of the hardware.
287 -> If it returns saying it has done so, we go on to state
288 "msWaitForPowerSettle".
289 -> Otherwise, we have to wait for it, so we set the ack timer and wait.
290 -> When it calls acknowledgeSetPowerState, or when the ack timer
291 expires, we go on.
292 In "msWaitForPowerSettle", we look in the power state array to see if
293 there is any settle time required when changing from our current state to the
294 new state.
295 -> If not, we go right away to "msNotifyInterestedDriversDidChange".
296 -> Otherwise, we set the settle timer and wait. When it expires, we move on.
297 In "msNotifyInterestedDriversDidChange" state, we notify all our
298 interested parties via their powerStateDidChange methods that we have finished
299 changing power state.
300 -> If they all acknowledge via return code, we move on to "msFinish".
301 -> Otherwise we set the ack timer and wait. When they have all
302 acknowledged, or when the ack timer has expired for those that didn't,
303 we move on to "msFinish".
304 In "msFinish" we remove the used change note from the head of the queue
305 and start the next one if one exists.
306
307 == 2. Parent Change Down ==
308 Start at Stage 2 of OurChange Down XXX gvdl
309
310 == 3. Change Up ==
311 Start at Stage 4 of OurChange Down XXX gvdl
312
313 Note all parent requested changes need to acknowledge the power has changed to the parent when done.
314 */
315
316 //*********************************************************************************
317 // [public virtual] PMinit
318 //
319 // Initialize power management.
320 //*********************************************************************************
321
322 void IOService::PMinit ( void )
323 {
324 if ( !initialized )
325 {
326 if ( !gIOPMInitialized )
327 {
328 gIOPMWorkLoop = IOWorkLoop::workLoop();
329 if (gIOPMWorkLoop)
330 {
331 gIOPMRequestQueue = IOPMRequestQueue::create(
332 this, OSMemberFunctionCast(IOPMRequestQueue::Action,
333 this, &IOService::servicePMRequestQueue));
334
335 gIOPMReplyQueue = IOPMRequestQueue::create(
336 this, OSMemberFunctionCast(IOPMRequestQueue::Action,
337 this, &IOService::servicePMReplyQueue));
338
339 gIOPMFreeQueue = IOPMRequestQueue::create(
340 this, OSMemberFunctionCast(IOPMRequestQueue::Action,
341 this, &IOService::servicePMFreeQueue));
342
343 if (gIOPMWorkLoop->addEventSource(gIOPMRequestQueue) !=
344 kIOReturnSuccess)
345 {
346 gIOPMRequestQueue->release();
347 gIOPMRequestQueue = 0;
348 }
349
350 if (gIOPMWorkLoop->addEventSource(gIOPMReplyQueue) !=
351 kIOReturnSuccess)
352 {
353 gIOPMReplyQueue->release();
354 gIOPMReplyQueue = 0;
355 }
356
357 if (gIOPMWorkLoop->addEventSource(gIOPMFreeQueue) !=
358 kIOReturnSuccess)
359 {
360 gIOPMFreeQueue->release();
361 gIOPMFreeQueue = 0;
362 }
363 }
364
365 if (gIOPMRequestQueue && gIOPMReplyQueue && gIOPMFreeQueue)
366 gIOPMInitialized = true;
367 }
368 if (!gIOPMInitialized)
369 return;
370
371 pwrMgt = new IOServicePM;
372 pwrMgt->init();
373 setProperty(kPwrMgtKey, pwrMgt);
374
375 fOwner = this;
376 fWeAreRoot = false;
377 fPMLock = IOLockAlloc();
378 fInterestedDrivers = new IOPMinformeeList;
379 fInterestedDrivers->initialize();
380 fDesiredPowerState = 0;
381 fDriverDesire = 0;
382 fDeviceDesire = 0;
383 fInitialChange = true;
384 fNeedToBecomeUsable = false;
385 fPreviousRequest = 0;
386 fDeviceOverrides = false;
387 fMachineState = kIOPM_Finished;
388 fIdleTimerEventSource = NULL;
389 fActivityLock = IOLockAlloc();
390 fClampOn = false;
391 fStrictTreeOrder = false;
392 fActivityTicklePowerState = -1;
393 fControllingDriver = NULL;
394 fPowerStates = NULL;
395 fNumberOfPowerStates = 0;
396 fCurrentPowerState = 0;
397 fParentsCurrentPowerFlags = 0;
398 fMaxCapability = 0;
399 fName = getName();
400 fPlatform = getPlatform();
401 fParentsKnowState = false;
402 fSerialNumber = 0;
403 fResponseArray = NULL;
404 fDoNotPowerDown = true;
405 fCurrentPowerConsumption = kIOPMUnknown;
406
407 for (unsigned int i = 0; i <= kMaxType; i++)
408 {
409 fAggressivenessValue[i] = 0;
410 fAggressivenessValid[i] = false;
411 }
412
413 fAckTimer = thread_call_allocate(
414 &IOService::ack_timer_expired, (thread_call_param_t)this);
415 fSettleTimer = thread_call_allocate(
416 &settle_timer_expired, (thread_call_param_t)this);
417 fDriverCallEntry = thread_call_allocate(
418 (thread_call_func_t) &IOService::pmDriverCallout, this);
419 assert(fDriverCallEntry);
420
421 #if PM_VARS_SUPPORT
422 IOPMprot * prot = new IOPMprot;
423 if (prot)
424 {
425 prot->init();
426 prot->ourName = fName;
427 prot->thePlatform = fPlatform;
428 fPMVars = prot;
429 pm_vars = prot;
430 }
431 #else
432 pm_vars = (IOPMprot *) true;
433 #endif
434
435 initialized = true;
436 }
437 }
438
439 //*********************************************************************************
440 // [public] PMfree
441 //
442 // Free up the data created in PMinit, if it exists.
443 //*********************************************************************************
444
445 void IOService::PMfree ( void )
446 {
447 initialized = false;
448 pm_vars = 0;
449
450 if ( pwrMgt )
451 {
452 assert(fMachineState == kIOPM_Finished);
453 assert(fInsertInterestSet == NULL);
454 assert(fRemoveInterestSet == NULL);
455 assert(fNotifyChildArray == NULL);
456
457 if ( fIdleTimerEventSource != NULL ) {
458 getPMworkloop()->removeEventSource(fIdleTimerEventSource);
459 fIdleTimerEventSource->release();
460 fIdleTimerEventSource = NULL;
461 }
462 if ( fSettleTimer ) {
463 thread_call_cancel(fSettleTimer);
464 thread_call_free(fSettleTimer);
465 fSettleTimer = NULL;
466 }
467 if ( fAckTimer ) {
468 thread_call_cancel(fAckTimer);
469 thread_call_free(fAckTimer);
470 fAckTimer = NULL;
471 }
472 if ( fDriverCallEntry ) {
473 thread_call_free(fDriverCallEntry);
474 fDriverCallEntry = NULL;
475 }
476 if ( fPMLock ) {
477 IOLockFree(fPMLock);
478 fPMLock = NULL;
479 }
480 if ( fActivityLock ) {
481 IOLockFree(fActivityLock);
482 fActivityLock = NULL;
483 }
484 if ( fInterestedDrivers ) {
485 fInterestedDrivers->release();
486 fInterestedDrivers = NULL;
487 }
488 if ( fPMWorkQueue ) {
489 getPMworkloop()->removeEventSource(fPMWorkQueue);
490 fPMWorkQueue->release();
491 fPMWorkQueue = 0;
492 }
493 if (fDriverCallParamSlots && fDriverCallParamPtr) {
494 IODelete(fDriverCallParamPtr, DriverCallParam, fDriverCallParamSlots);
495 fDriverCallParamPtr = 0;
496 fDriverCallParamSlots = 0;
497 }
498 if ( fResponseArray ) {
499 fResponseArray->release();
500 fResponseArray = NULL;
501 }
502 if (fPowerStates && fNumberOfPowerStates) {
503 IODelete(fPowerStates, IOPMPowerState, fNumberOfPowerStates);
504 fNumberOfPowerStates = 0;
505 fPowerStates = NULL;
506 }
507
508 #if PM_VARS_SUPPORT
509 if (fPMVars)
510 {
511 fPMVars->release();
512 fPMVars = 0;
513 }
514 #endif
515
516 pwrMgt->release();
517 pwrMgt = 0;
518 }
519 }
520
521 //*********************************************************************************
522 // [public virtual] joinPMtree
523 //
524 // A policy-maker calls its nub here when initializing, to be attached into
525 // the power management hierarchy. The default function is to call the
526 // platform expert, which knows how to do it. This method is overridden
527 // by a nub subclass which may either know how to do it, or may need to
528 // take other action.
529 //
530 // This may be the only "power management" method used in a nub,
531 // meaning it may not be initialized for power management.
532 //*********************************************************************************
533
534 void IOService::joinPMtree ( IOService * driver )
535 {
536 IOPlatformExpert * platform;
537
538 platform = getPlatform();
539 assert(platform != 0);
540 platform->PMRegisterDevice(this, driver);
541 }
542
543 //*********************************************************************************
544 // [public virtual] youAreRoot
545 //
546 // Power Managment is informing us that we are the root power domain.
547 // The only difference between us and any other power domain is that
548 // we have no parent and therefore never call it.
549 //*********************************************************************************
550
551 IOReturn IOService::youAreRoot ( void )
552 {
553 fWeAreRoot = true;
554 fParentsKnowState = true;
555 attachToParent( getRegistryRoot(), gIOPowerPlane );
556 return IOPMNoErr;
557 }
558
559 //*********************************************************************************
560 // [public virtual] PMstop
561 //
562 // Immediately stop driver callouts. Schedule an async stop request to detach
563 // from power plane.
564 //*********************************************************************************
565
566 void IOService::PMstop ( void )
567 {
568 IOPMRequest * request;
569
570 if (!initialized)
571 return;
572
573 // Schedule an async PMstop request, but immediately stop any further
574 // calls to the controlling or interested drivers. This device will
575 // continue to exist in the power plane and participate in power state
576 // changes until the PMstop async request is processed.
577
578 PM_LOCK();
579 fWillPMStop = true;
580 if (fDriverCallBusy)
581 PM_DEBUG("%s::PMstop() driver call busy\n", getName());
582 PM_UNLOCK();
583
584 request = acquirePMRequest( this, kIOPMRequestTypePMStop );
585 if (request)
586 {
587 PM_TRACE("[%s] %p PMstop\n", getName(), this);
588 submitPMRequest( request );
589 }
590 }
591
592 //*********************************************************************************
593 // handlePMstop
594 //
595 // Disconnect the node from its parents and children in the Power Plane.
596 //*********************************************************************************
597
598 void IOService::handlePMstop ( IOPMRequest * request )
599 {
600 OSIterator * iter;
601 OSObject * next;
602 IOPowerConnection * connection;
603 IOService * theChild;
604 IOService * theParent;
605
606 PM_ASSERT_IN_GATE();
607 PM_TRACE("[%s] %p %s start\n", getName(), this, __FUNCTION__);
608
609 // remove the property
610 removeProperty(kPwrMgtKey);
611
612 // detach parents
613 iter = getParentIterator(gIOPowerPlane);
614 if ( iter )
615 {
616 while ( (next = iter->getNextObject()) )
617 {
618 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
619 {
620 theParent = (IOService *)connection->copyParentEntry(gIOPowerPlane);
621 if ( theParent )
622 {
623 theParent->removePowerChild(connection);
624 theParent->release();
625 }
626 }
627 }
628 iter->release();
629 }
630
631 // detach IOConnections
632 detachAbove( gIOPowerPlane );
633
634 // no more power state changes
635 fParentsKnowState = false;
636
637 // detach children
638 iter = getChildIterator(gIOPowerPlane);
639 if ( iter )
640 {
641 while ( (next = iter->getNextObject()) )
642 {
643 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
644 {
645 theChild = ((IOService *)(connection->copyChildEntry(gIOPowerPlane)));
646 if ( theChild )
647 {
648 // detach nub from child
649 connection->detachFromChild(theChild, gIOPowerPlane);
650 theChild->release();
651 }
652 // detach us from nub
653 detachFromChild(connection, gIOPowerPlane);
654 }
655 }
656 iter->release();
657 }
658
659 // Remove all interested drivers from the list, including the power
660 // controlling driver.
661 //
662 // Usually, the controlling driver and the policy-maker functionality
663 // are implemented by the same object, and without the deregistration,
664 // the object will be holding an extra retain on itself, and cannot
665 // be freed.
666
667 if ( fInterestedDrivers )
668 {
669 IOPMinformeeList * list = fInterestedDrivers;
670 IOPMinformee * item;
671
672 PM_LOCK();
673 while ((item = list->firstInList()))
674 {
675 list->removeFromList(item->whatObject);
676 }
677 PM_UNLOCK();
678 }
679
680 // Tell PM_idle_timer_expiration() to ignore idle timer.
681 fIdleTimerPeriod = 0;
682
683 fWillPMStop = false;
684 PM_TRACE("[%s] %p %s done\n", getName(), this, __FUNCTION__);
685 }
686
687 //*********************************************************************************
688 // [public virtual] addPowerChild
689 //
690 // Power Management is informing us who our children are.
691 //*********************************************************************************
692
693 IOReturn IOService::addPowerChild ( IOService * child )
694 {
695 IOPowerConnection * connection = 0;
696 IOPMRequest * requests[3] = {0, 0, 0};
697 OSIterator * iter;
698 bool ok = true;
699
700 if (!child)
701 return kIOReturnBadArgument;
702
703 if (!initialized || !child->initialized)
704 return IOPMNotYetInitialized;
705
706 OUR_PMLog( kPMLogAddChild, 0, 0 );
707
708 do {
709 // Is this child already one of our children?
710
711 iter = child->getParentIterator( gIOPowerPlane );
712 if ( iter )
713 {
714 IORegistryEntry * entry;
715 OSObject * next;
716
717 while ((next = iter->getNextObject()))
718 {
719 if ((entry = OSDynamicCast(IORegistryEntry, next)) &&
720 isChild(entry, gIOPowerPlane))
721 {
722 ok = false;
723 break;
724 }
725 }
726 iter->release();
727 }
728 if (!ok)
729 {
730 PM_DEBUG("[%s] %s (%p) is already a child\n",
731 getName(), child->getName(), child);
732 break;
733 }
734
735 // Add the child to the power plane immediately, but the
736 // joining connection is marked as not ready.
737 // We want the child to appear in the power plane before
738 // returning to the caller, but don't want the caller to
739 // block on the PM work loop.
740
741 connection = new IOPowerConnection;
742 if (!connection)
743 break;
744
745 // Create a chain of PM requests to perform the bottom-half
746 // work from the PM work loop.
747
748 requests[0] = acquirePMRequest(
749 /* target */ this,
750 /* type */ kIOPMRequestTypeAddPowerChild1 );
751
752 requests[1] = acquirePMRequest(
753 /* target */ child,
754 /* type */ kIOPMRequestTypeAddPowerChild2 );
755
756 requests[2] = acquirePMRequest(
757 /* target */ this,
758 /* type */ kIOPMRequestTypeAddPowerChild3 );
759
760 if (!requests[0] || !requests[1] || !requests[2])
761 break;
762
763 requests[0]->setParentRequest( requests[1] );
764 requests[1]->setParentRequest( requests[2] );
765
766 connection->init();
767 connection->start(this);
768 connection->setAwaitingAck(false);
769 connection->setReadyFlag(false);
770
771 attachToChild( connection, gIOPowerPlane );
772 connection->attachToChild( child, gIOPowerPlane );
773
774 // connection needs to be released
775 requests[0]->fArg0 = connection;
776 requests[1]->fArg0 = connection;
777 requests[2]->fArg0 = connection;
778
779 submitPMRequest( requests, 3 );
780 return kIOReturnSuccess;
781 }
782 while (false);
783
784 if (connection) connection->release();
785 if (requests[0]) releasePMRequest(requests[0]);
786 if (requests[1]) releasePMRequest(requests[1]);
787 if (requests[2]) releasePMRequest(requests[2]);
788
789 // silent failure, to prevent platform drivers from adding the child
790 // to the root domain.
791 return IOPMNoErr;
792 }
793
794 //*********************************************************************************
795 // [private] addPowerChild1
796 //
797 // Called on the power parent.
798 //*********************************************************************************
799
800 void IOService::addPowerChild1 ( IOPMRequest * request )
801 {
802 unsigned long tempDesire = 0;
803
804 // Make us temporary usable before adding the child.
805
806 PM_ASSERT_IN_GATE();
807 OUR_PMLog( kPMLogMakeUsable, kPMLogMakeUsable, fDeviceDesire );
808
809 if (fControllingDriver && inPlane(gIOPowerPlane) && fParentsKnowState)
810 {
811 tempDesire = fNumberOfPowerStates - 1;
812 }
813
814 if (tempDesire && (fWeAreRoot || (fMaxCapability >= tempDesire)))
815 {
816 computeDesiredState( tempDesire );
817 changeState();
818 }
819 }
820
821 //*********************************************************************************
822 // [private] addPowerChild2
823 //
824 // Called on the joining child. Blocked behind addPowerChild1.
825 //*********************************************************************************
826
827 void IOService::addPowerChild2 ( IOPMRequest * request )
828 {
829 IOPowerConnection * connection = (IOPowerConnection *) request->fArg0;
830 IOService * parent;
831 IOPMPowerFlags powerFlags;
832 bool knowsState;
833 unsigned long powerState;
834 unsigned long tempDesire;
835
836 PM_ASSERT_IN_GATE();
837 parent = (IOService *) connection->getParentEntry(gIOPowerPlane);
838
839 if (!parent || !inPlane(gIOPowerPlane))
840 {
841 PM_DEBUG("[%s] addPowerChild2 not in power plane\n", getName());
842 return;
843 }
844
845 // Parent will be waiting for us to complete this stage, safe to
846 // directly access parent's vars.
847
848 knowsState = (parent->fPowerStates) && (parent->fParentsKnowState);
849 powerState = parent->fCurrentPowerState;
850
851 if (knowsState)
852 powerFlags = parent->fPowerStates[powerState].outputPowerCharacter;
853 else
854 powerFlags = 0;
855
856 // Set our power parent.
857
858 OUR_PMLog(kPMLogSetParent, knowsState, powerFlags);
859
860 setParentInfo( powerFlags, connection, knowsState );
861
862 connection->setReadyFlag(true);
863
864 if ( fControllingDriver && fParentsKnowState )
865 {
866 fMaxCapability = fControllingDriver->maxCapabilityForDomainState(fParentsCurrentPowerFlags);
867 // initially change into the state we are already in
868 tempDesire = fControllingDriver->initialPowerStateForDomainState(fParentsCurrentPowerFlags);
869 computeDesiredState(tempDesire);
870 fPreviousRequest = 0xffffffff;
871 changeState();
872 }
873 }
874
875 //*********************************************************************************
876 // [private] addPowerChild3
877 //
878 // Called on the parent. Blocked behind addPowerChild2.
879 //*********************************************************************************
880
881 void IOService::addPowerChild3 ( IOPMRequest * request )
882 {
883 IOPowerConnection * connection = (IOPowerConnection *) request->fArg0;
884 IOService * child;
885 unsigned int i;
886
887 PM_ASSERT_IN_GATE();
888 child = (IOService *) connection->getChildEntry(gIOPowerPlane);
889
890 if (child && inPlane(gIOPowerPlane))
891 {
892 if (child->getProperty("IOPMStrictTreeOrder"))
893 {
894 PM_DEBUG("[%s] strict ordering enforced\n", getName());
895 fStrictTreeOrder = true;
896 }
897
898 for (i = 0; i <= kMaxType; i++)
899 {
900 if ( fAggressivenessValid[i] )
901 {
902 child->setAggressiveness(i, fAggressivenessValue[i]);
903 }
904 }
905 }
906 else
907 {
908 PM_DEBUG("[%s] addPowerChild3 not in power plane\n", getName());
909 }
910
911 connection->release();
912 }
913
914 //*********************************************************************************
915 // [public virtual deprecated] setPowerParent
916 //
917 // Power Management is informing us who our parent is.
918 // If we have a controlling driver, find out, given our newly-informed
919 // power domain state, what state it would be in, and then tell it
920 // to assume that state.
921 //*********************************************************************************
922
923 IOReturn IOService::setPowerParent (
924 IOPowerConnection * theParent, bool stateKnown, IOPMPowerFlags powerFlags )
925 {
926 return kIOReturnUnsupported;
927 }
928
929 //*********************************************************************************
930 // [public virtual] removePowerChild
931 //
932 // Called on a parent whose child is being removed by PMstop().
933 //*********************************************************************************
934
935 IOReturn IOService::removePowerChild ( IOPowerConnection * theNub )
936 {
937 IORegistryEntry * theChild;
938
939 PM_ASSERT_IN_GATE();
940 OUR_PMLog( kPMLogRemoveChild, 0, 0 );
941
942 theNub->retain();
943
944 // detach nub from child
945 theChild = theNub->copyChildEntry(gIOPowerPlane);
946 if ( theChild )
947 {
948 theNub->detachFromChild(theChild, gIOPowerPlane);
949 theChild->release();
950 }
951 // detach from the nub
952 detachFromChild(theNub, gIOPowerPlane);
953
954 // Are we awaiting an ack from this child?
955 if ( theNub->getAwaitingAck() )
956 {
957 // yes, pretend we got one
958 theNub->setAwaitingAck(false);
959 if (fHeadNotePendingAcks != 0 )
960 {
961 // that's one fewer ack to worry about
962 fHeadNotePendingAcks--;
963
964 // is that the last?
965 if ( fHeadNotePendingAcks == 0 )
966 {
967 stop_ack_timer();
968 }
969 }
970 }
971
972 theNub->release();
973
974 // Schedule a request to re-scan child desires and clamp bits.
975 if (!fWillAdjustPowerState)
976 {
977 IOPMRequest * request;
978
979 request = acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState );
980 if (request)
981 {
982 submitPMRequest( request );
983 fWillAdjustPowerState = true;
984 }
985 }
986
987 return IOPMNoErr;
988 }
989
990 //*********************************************************************************
991 // [public virtual] registerPowerDriver
992 //
993 // A driver has called us volunteering to control power to our device.
994 //*********************************************************************************
995
996 IOReturn IOService::registerPowerDriver (
997 IOService * powerDriver,
998 IOPMPowerState * powerStates,
999 unsigned long numberOfStates )
1000 {
1001 IOPMRequest * request;
1002 IOPMPowerState * powerStatesCopy = 0;
1003
1004 if (!initialized)
1005 return IOPMNotYetInitialized;
1006
1007 // Validate arguments.
1008 if (!powerStates || (numberOfStates < 2))
1009 {
1010 OUR_PMLog(kPMLogControllingDriverErr5, numberOfStates, 0);
1011 return kIOReturnBadArgument;
1012 }
1013
1014 if (!powerDriver)
1015 {
1016 OUR_PMLog(kPMLogControllingDriverErr4, 0, 0);
1017 return kIOReturnBadArgument;
1018 }
1019
1020 if (powerStates[0].version != kIOPMPowerStateVersion1)
1021 {
1022 OUR_PMLog(kPMLogControllingDriverErr1, powerStates[0].version, 0);
1023 return kIOReturnBadArgument;
1024 }
1025
1026 do {
1027 // Make a copy of the supplied power state array.
1028 powerStatesCopy = IONew(IOPMPowerState, numberOfStates);
1029 if (!powerStatesCopy)
1030 break;
1031
1032 bcopy( powerStates, powerStatesCopy,
1033 sizeof(IOPMPowerState) * numberOfStates );
1034
1035 request = acquirePMRequest( this, kIOPMRequestTypeRegisterPowerDriver );
1036 if (!request)
1037 break;
1038
1039 powerDriver->retain();
1040 request->fArg0 = (void *) powerDriver;
1041 request->fArg1 = (void *) powerStatesCopy;
1042 request->fArg2 = (void *) numberOfStates;
1043
1044 submitPMRequest( request );
1045 return kIOReturnSuccess;
1046 }
1047 while (false);
1048
1049 if (powerStatesCopy)
1050 IODelete(powerStatesCopy, IOPMPowerState, numberOfStates);
1051 return kIOReturnNoMemory;
1052 }
1053
1054 //*********************************************************************************
1055 // [private] handleRegisterPowerDriver
1056 //*********************************************************************************
1057
1058 void IOService::handleRegisterPowerDriver ( IOPMRequest * request )
1059 {
1060 IOService * powerDriver = (IOService *) request->fArg0;
1061 IOPMPowerState * powerStates = (IOPMPowerState *) request->fArg1;
1062 unsigned long numberOfStates = (unsigned long) request->fArg2;
1063 unsigned long i;
1064 IOService * root;
1065
1066 PM_ASSERT_IN_GATE();
1067 assert(powerStates);
1068 assert(powerDriver);
1069 assert(numberOfStates > 1);
1070
1071 if ( !fNumberOfPowerStates )
1072 {
1073 OUR_PMLog(kPMLogControllingDriver,
1074 (unsigned long) numberOfStates,
1075 (unsigned long) powerStates[0].version);
1076
1077 fPowerStates = powerStates;
1078 fNumberOfPowerStates = numberOfStates;
1079 fControllingDriver = powerDriver;
1080 fCurrentCapabilityFlags = fPowerStates[0].capabilityFlags;
1081
1082 // make a mask of all the character bits we know about
1083 fOutputPowerCharacterFlags = 0;
1084 for ( i = 0; i < numberOfStates; i++ ) {
1085 fOutputPowerCharacterFlags |= fPowerStates[i].outputPowerCharacter;
1086 }
1087
1088 // Register powerDriver as interested, unless already done.
1089 // We don't want to register the default implementation since
1090 // it does nothing. One ramification of not always registering
1091 // is the one fewer retain count held.
1092
1093 root = getPlatform()->getProvider();
1094 assert(root);
1095 if (!root ||
1096 ((OSMemberFunctionCast(void (*)(void),
1097 root, &IOService::powerStateDidChangeTo)) !=
1098 ((OSMemberFunctionCast(void (*)(void),
1099 this, &IOService::powerStateDidChangeTo)))) ||
1100 ((OSMemberFunctionCast(void (*)(void),
1101 root, &IOService::powerStateWillChangeTo)) !=
1102 ((OSMemberFunctionCast(void (*)(void),
1103 this, &IOService::powerStateWillChangeTo)))))
1104 {
1105 if (fInterestedDrivers->findItem(powerDriver) == NULL)
1106 {
1107 PM_LOCK();
1108 fInterestedDrivers->appendNewInformee(powerDriver);
1109 PM_UNLOCK();
1110 }
1111 }
1112
1113 if ( fNeedToBecomeUsable ) {
1114 fNeedToBecomeUsable = false;
1115 fDeviceDesire = fNumberOfPowerStates - 1;
1116 }
1117
1118 if ( inPlane(gIOPowerPlane) && fParentsKnowState )
1119 {
1120 unsigned long tempDesire;
1121 fMaxCapability = fControllingDriver->maxCapabilityForDomainState(fParentsCurrentPowerFlags);
1122 // initially change into the state we are already in
1123 tempDesire = fControllingDriver->initialPowerStateForDomainState(fParentsCurrentPowerFlags);
1124 computeDesiredState(tempDesire);
1125 changeState();
1126 }
1127 }
1128 else
1129 {
1130 OUR_PMLog(kPMLogControllingDriverErr2, numberOfStates, 0);
1131 IODelete(powerStates, IOPMPowerState, numberOfStates);
1132 }
1133
1134 powerDriver->release();
1135 }
1136
1137 //*********************************************************************************
1138 // [public virtual] registerInterestedDriver
1139 //
1140 // Add the caller to our list of interested drivers and return our current
1141 // power state. If we don't have a power-controlling driver yet, we will
1142 // call this interested driver again later when we do get a driver and find
1143 // out what the current power state of the device is.
1144 //*********************************************************************************
1145
1146 IOPMPowerFlags IOService::registerInterestedDriver ( IOService * driver )
1147 {
1148 IOPMRequest * request;
1149 bool signal;
1150
1151 if (!initialized || !fInterestedDrivers)
1152 return IOPMNotPowerManaged;
1153
1154 PM_LOCK();
1155 signal = (!fInsertInterestSet && !fRemoveInterestSet);
1156 if (fInsertInterestSet == NULL)
1157 fInsertInterestSet = OSSet::withCapacity(4);
1158 if (fInsertInterestSet)
1159 fInsertInterestSet->setObject(driver);
1160 PM_UNLOCK();
1161
1162 if (signal)
1163 {
1164 request = acquirePMRequest( this, kIOPMRequestTypeInterestChanged );
1165 if (request)
1166 submitPMRequest( request );
1167 }
1168
1169 // This return value cannot be trusted, but return a value
1170 // for those clients that care.
1171
1172 OUR_PMLog(kPMLogInterestedDriver, kIOPMDeviceUsable, 2);
1173 return kIOPMDeviceUsable;
1174 }
1175
1176 //*********************************************************************************
1177 // [public virtual] deRegisterInterestedDriver
1178 //*********************************************************************************
1179
1180 IOReturn IOService::deRegisterInterestedDriver ( IOService * driver )
1181 {
1182 IOPMinformeeList * list;
1183 IOPMinformee * item;
1184 IOPMRequest * request;
1185 bool signal;
1186
1187 if (!initialized || !fInterestedDrivers)
1188 return IOPMNotPowerManaged;
1189
1190 PM_LOCK();
1191 signal = (!fRemoveInterestSet && !fInsertInterestSet);
1192 if (fRemoveInterestSet == NULL)
1193 fRemoveInterestSet = OSSet::withCapacity(4);
1194 if (fRemoveInterestSet)
1195 {
1196 fRemoveInterestSet->setObject(driver);
1197
1198 list = fInterestedDrivers;
1199 item = list->findItem(driver);
1200 if (item && item->active)
1201 {
1202 item->active = false;
1203 }
1204 if (fDriverCallBusy)
1205 PM_DEBUG("%s::deRegisterInterestedDriver() driver call busy\n", getName());
1206 }
1207 PM_UNLOCK();
1208
1209 if (signal)
1210 {
1211 request = acquirePMRequest( this, kIOPMRequestTypeInterestChanged );
1212 if (request)
1213 submitPMRequest( request );
1214 }
1215
1216 return IOPMNoErr;
1217 }
1218
1219 //*********************************************************************************
1220 // [private] handleInterestChanged
1221 //
1222 // Handle interest added or removed.
1223 //*********************************************************************************
1224
1225 void IOService::handleInterestChanged( IOPMRequest * request )
1226 {
1227 IOService * driver;
1228 IOPMinformee * informee;
1229 IOPMinformeeList * list = fInterestedDrivers;
1230
1231 PM_LOCK();
1232
1233 if (fInsertInterestSet)
1234 {
1235 while ((driver = (IOService *) fInsertInterestSet->getAnyObject()))
1236 {
1237 if ((list->findItem(driver) == NULL) &&
1238 (!fRemoveInterestSet ||
1239 !fRemoveInterestSet->containsObject(driver)))
1240 {
1241 informee = list->appendNewInformee(driver);
1242 }
1243 fInsertInterestSet->removeObject(driver);
1244 }
1245 fInsertInterestSet->release();
1246 fInsertInterestSet = 0;
1247 }
1248
1249 if (fRemoveInterestSet)
1250 {
1251 while ((driver = (IOService *) fRemoveInterestSet->getAnyObject()))
1252 {
1253 informee = list->findItem(driver);
1254 if (informee)
1255 {
1256 if (fHeadNotePendingAcks && informee->timer)
1257 {
1258 informee->timer = 0;
1259 fHeadNotePendingAcks--;
1260 }
1261 list->removeFromList(driver);
1262 }
1263 fRemoveInterestSet->removeObject(driver);
1264 }
1265 fRemoveInterestSet->release();
1266 fRemoveInterestSet = 0;
1267 }
1268
1269 PM_UNLOCK();
1270 }
1271
1272 //*********************************************************************************
1273 // [public virtual] acknowledgePowerChange
1274 //
1275 // After we notified one of the interested drivers or a power-domain child
1276 // of an impending change in power, it has called to say it is now
1277 // prepared for the change. If this object is the last to
1278 // acknowledge this change, we take whatever action we have been waiting
1279 // for.
1280 // That may include acknowledging to our parent. In this case, we do it
1281 // last of all to insure that this doesn't cause the parent to call us some-
1282 // where else and alter data we are relying on here (like the very existance
1283 // of a "current change note".)
1284 //*********************************************************************************
1285
1286 IOReturn IOService::acknowledgePowerChange ( IOService * whichObject )
1287 {
1288 IOPMRequest * request;
1289
1290 if (!initialized)
1291 return IOPMNotYetInitialized;
1292 if (!whichObject)
1293 return kIOReturnBadArgument;
1294
1295 request = acquirePMRequest( this, kIOPMRequestTypeAckPowerChange );
1296 if (!request)
1297 {
1298 PM_ERROR("%s::%s no memory\n", getName(), __FUNCTION__);
1299 return kIOReturnNoMemory;
1300 }
1301
1302 whichObject->retain();
1303 request->fArg0 = whichObject;
1304
1305 submitPMRequest( request );
1306 return IOPMNoErr;
1307 }
1308
1309 //*********************************************************************************
1310 // [private] handleAcknowledgePowerChange
1311 //*********************************************************************************
1312
1313 bool IOService::handleAcknowledgePowerChange ( IOPMRequest * request )
1314 {
1315 IOPMinformee * informee;
1316 unsigned long childPower = kIOPMUnknown;
1317 IOService * theChild;
1318 IOService * whichObject;
1319 bool all_acked = false;
1320
1321 PM_ASSERT_IN_GATE();
1322 whichObject = (IOService *) request->fArg0;
1323 assert(whichObject);
1324
1325 // one of our interested drivers?
1326 informee = fInterestedDrivers->findItem( whichObject );
1327 if ( informee == NULL )
1328 {
1329 if ( !isChild(whichObject, gIOPowerPlane) )
1330 {
1331 OUR_PMLog(kPMLogAcknowledgeErr1, 0, 0);
1332 goto no_err;
1333 } else {
1334 OUR_PMLog(kPMLogChildAcknowledge, fHeadNotePendingAcks, 0);
1335 }
1336 } else {
1337 OUR_PMLog(kPMLogDriverAcknowledge, fHeadNotePendingAcks, 0);
1338 }
1339
1340 if ( fHeadNotePendingAcks != 0 )
1341 {
1342 assert(fPowerStates != NULL);
1343
1344 // yes, make sure we're expecting acks
1345 if ( informee != NULL )
1346 {
1347 // it's an interested driver
1348 // make sure we're expecting this ack
1349 if ( informee->timer != 0 )
1350 {
1351 #if LOG_SETPOWER_TIMES
1352 if (informee->timer > 0)
1353 {
1354 uint64_t nsec = computeTimeDeltaNS(&informee->startTime);
1355 if (nsec > LOG_SETPOWER_TIMES)
1356 PM_DEBUG("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) async took %d ms\n",
1357 informee->whatObject->getName(),
1358 (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
1359 informee->whatObject,
1360 fName, fCurrentPowerState, fHeadNoteState, NS_TO_MS(nsec));
1361 }
1362 #endif
1363 // mark it acked
1364 informee->timer = 0;
1365 // that's one fewer to worry about
1366 fHeadNotePendingAcks--;
1367 } else {
1368 // this driver has already acked
1369 OUR_PMLog(kPMLogAcknowledgeErr2, 0, 0);
1370 }
1371 } else {
1372 // it's a child
1373 // make sure we're expecting this ack
1374 if ( ((IOPowerConnection *)whichObject)->getAwaitingAck() )
1375 {
1376 // that's one fewer to worry about
1377 fHeadNotePendingAcks--;
1378 ((IOPowerConnection *)whichObject)->setAwaitingAck(false);
1379 theChild = (IOService *)whichObject->copyChildEntry(gIOPowerPlane);
1380 if ( theChild )
1381 {
1382 childPower = theChild->currentPowerConsumption();
1383 theChild->release();
1384 }
1385 if ( childPower == kIOPMUnknown )
1386 {
1387 fPowerStates[fHeadNoteState].staticPower = kIOPMUnknown;
1388 } else {
1389 if ( fPowerStates[fHeadNoteState].staticPower != kIOPMUnknown )
1390 {
1391 fPowerStates[fHeadNoteState].staticPower += childPower;
1392 }
1393 }
1394 }
1395 }
1396
1397 if ( fHeadNotePendingAcks == 0 ) {
1398 // yes, stop the timer
1399 stop_ack_timer();
1400 // and now we can continue
1401 all_acked = true;
1402 }
1403 } else {
1404 OUR_PMLog(kPMLogAcknowledgeErr3, 0, 0); // not expecting anybody to ack
1405 }
1406
1407 no_err:
1408 if (whichObject)
1409 whichObject->release();
1410
1411 return all_acked;
1412 }
1413
1414 //*********************************************************************************
1415 // [public virtual] acknowledgeSetPowerState
1416 //
1417 // After we instructed our controlling driver to change power states,
1418 // it has called to say it has finished doing so.
1419 // We continue to process the power state change.
1420 //*********************************************************************************
1421
1422 IOReturn IOService::acknowledgeSetPowerState ( void )
1423 {
1424 IOPMRequest * request;
1425
1426 if (!initialized)
1427 return IOPMNotYetInitialized;
1428
1429 request = acquirePMRequest( this, kIOPMRequestTypeAckSetPowerState );
1430 if (!request)
1431 {
1432 PM_ERROR("%s::%s no memory\n", getName(), __FUNCTION__);
1433 return kIOReturnNoMemory;
1434 }
1435
1436 submitPMRequest( request );
1437 return kIOReturnSuccess;
1438 }
1439
1440 //*********************************************************************************
1441 // [private] adjustPowerState
1442 //
1443 // Child has signaled a change - child changed it's desire, new child added,
1444 // existing child removed. Adjust our power state accordingly.
1445 //*********************************************************************************
1446
1447 void IOService::adjustPowerState( void )
1448 {
1449 PM_ASSERT_IN_GATE();
1450 if (inPlane(gIOPowerPlane))
1451 {
1452 rebuildChildClampBits();
1453 computeDesiredState();
1454 if ( fControllingDriver && fParentsKnowState )
1455 changeState();
1456 }
1457 else
1458 {
1459 PM_DEBUG("[%s] %s: not in power tree\n", getName(), __FUNCTION__);
1460 return;
1461 }
1462 fWillAdjustPowerState = false;
1463 }
1464
1465 //*********************************************************************************
1466 // [public deprecated] powerDomainWillChangeTo
1467 //
1468 // Called by the power-hierarchy parent notifying of a new power state
1469 // in the power domain.
1470 // We enqueue a parent power-change to our queue of power changes.
1471 // This may or may not cause us to change power, depending on what
1472 // kind of change is occuring in the domain.
1473 //*********************************************************************************
1474
1475 IOReturn IOService::powerDomainWillChangeTo (
1476 IOPMPowerFlags newPowerFlags,
1477 IOPowerConnection * whichParent )
1478 {
1479 assert(false);
1480 return kIOReturnUnsupported;
1481 }
1482
1483 //*********************************************************************************
1484 // [private] handlePowerDomainWillChangeTo
1485 //*********************************************************************************
1486
1487 void IOService::handlePowerDomainWillChangeTo ( IOPMRequest * request )
1488 {
1489 IOPMPowerFlags newPowerFlags = (IOPMPowerFlags) request->fArg0;
1490 IOPowerConnection * whichParent = (IOPowerConnection *) request->fArg1;
1491 bool powerWillDrop = (bool) request->fArg2;
1492 OSIterator * iter;
1493 OSObject * next;
1494 IOPowerConnection * connection;
1495 unsigned long newPowerState;
1496 IOPMPowerFlags combinedPowerFlags;
1497 bool savedParentsKnowState;
1498 IOReturn result = IOPMAckImplied;
1499
1500 PM_ASSERT_IN_GATE();
1501 OUR_PMLog(kPMLogWillChange, newPowerFlags, 0);
1502
1503 if (!inPlane(gIOPowerPlane))
1504 {
1505 PM_DEBUG("[%s] %s: not in power tree\n", getName(), __FUNCTION__);
1506 return;
1507 }
1508
1509 savedParentsKnowState = fParentsKnowState;
1510
1511 // Combine parents' power flags to determine our maximum state
1512 // within the new power domain
1513 combinedPowerFlags = 0;
1514
1515 iter = getParentIterator(gIOPowerPlane);
1516 if ( iter )
1517 {
1518 while ( (next = iter->getNextObject()) )
1519 {
1520 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
1521 {
1522 if ( connection == whichParent )
1523 combinedPowerFlags |= newPowerFlags;
1524 else
1525 combinedPowerFlags |= connection->parentCurrentPowerFlags();
1526 }
1527 }
1528 iter->release();
1529 }
1530
1531 if ( fControllingDriver )
1532 {
1533 newPowerState = fControllingDriver->maxCapabilityForDomainState(
1534 combinedPowerFlags);
1535
1536 result = enqueuePowerChange(
1537 /* flags */ IOPMParentInitiated | IOPMDomainWillChange,
1538 /* power state */ newPowerState,
1539 /* domain state */ combinedPowerFlags,
1540 /* connection */ whichParent,
1541 /* parent state */ newPowerFlags);
1542 }
1543
1544 // If parent is dropping power, immediately update the parent's
1545 // capability flags. Any future merging of parent(s) combined
1546 // power flags should account for this power drop.
1547
1548 if (powerWillDrop)
1549 {
1550 setParentInfo(newPowerFlags, whichParent, true);
1551 }
1552
1553 // Parent is expecting an ACK from us. If we did not embark on a state
1554 // transition, when enqueuePowerChang() returns IOPMAckImplied. We are
1555 // still required to issue an ACK to our parent.
1556
1557 if (IOPMAckImplied == result)
1558 {
1559 IOService * parent;
1560 parent = (IOService *) whichParent->copyParentEntry(gIOPowerPlane);
1561 assert(parent);
1562 if ( parent )
1563 {
1564 parent->acknowledgePowerChange( whichParent );
1565 parent->release();
1566 }
1567 }
1568
1569 // If the parent registers it's power driver late, then this is the
1570 // first opportunity to tell our parent about our desire.
1571
1572 if (!savedParentsKnowState && fParentsKnowState)
1573 {
1574 PM_TRACE("[%s] powerDomainWillChangeTo: parentsKnowState = true\n",
1575 getName());
1576 ask_parent( fDesiredPowerState );
1577 }
1578 }
1579
1580 //*********************************************************************************
1581 // [public deprecated] powerDomainDidChangeTo
1582 //
1583 // Called by the power-hierarchy parent after the power state of the power domain
1584 // has settled at a new level.
1585 // We enqueue a parent power-change to our queue of power changes.
1586 // This may or may not cause us to change power, depending on what
1587 // kind of change is occuring in the domain.
1588 //*********************************************************************************
1589
1590 IOReturn IOService::powerDomainDidChangeTo (
1591 IOPMPowerFlags newPowerFlags,
1592 IOPowerConnection * whichParent )
1593 {
1594 assert(false);
1595 return kIOReturnUnsupported;
1596 }
1597
1598 //*********************************************************************************
1599 // [private] handlePowerDomainDidChangeTo
1600 //*********************************************************************************
1601
1602 void IOService::handlePowerDomainDidChangeTo ( IOPMRequest * request )
1603 {
1604 IOPMPowerFlags newPowerFlags = (IOPMPowerFlags) request->fArg0;
1605 IOPowerConnection * whichParent = (IOPowerConnection *) request->fArg1;
1606 unsigned long newPowerState;
1607 bool savedParentsKnowState;
1608 IOReturn result = IOPMAckImplied;
1609
1610 PM_ASSERT_IN_GATE();
1611 OUR_PMLog(kPMLogDidChange, newPowerFlags, 0);
1612
1613 if (!inPlane(gIOPowerPlane))
1614 {
1615 PM_DEBUG("[%s] %s: not in power tree\n", getName(), __FUNCTION__);
1616 return;
1617 }
1618
1619 savedParentsKnowState = fParentsKnowState;
1620
1621 setParentInfo(newPowerFlags, whichParent, true);
1622
1623 if ( fControllingDriver )
1624 {
1625 newPowerState = fControllingDriver->maxCapabilityForDomainState(
1626 fParentsCurrentPowerFlags);
1627
1628 result = enqueuePowerChange(
1629 /* flags */ IOPMParentInitiated | IOPMDomainDidChange,
1630 /* power state */ newPowerState,
1631 /* domain state */ fParentsCurrentPowerFlags,
1632 /* connection */ whichParent,
1633 /* parent state */ 0);
1634 }
1635
1636 // Parent is expecting an ACK from us. If we did not embark on a state
1637 // transition, when enqueuePowerChang() returns IOPMAckImplied. We are
1638 // still required to issue an ACK to our parent.
1639
1640 if (IOPMAckImplied == result)
1641 {
1642 IOService * parent;
1643 parent = (IOService *) whichParent->copyParentEntry(gIOPowerPlane);
1644 assert(parent);
1645 if ( parent )
1646 {
1647 parent->acknowledgePowerChange( whichParent );
1648 parent->release();
1649 }
1650 }
1651
1652 // If the parent registers it's power driver late, then this is the
1653 // first opportunity to tell our parent about our desire.
1654
1655 if (!savedParentsKnowState && fParentsKnowState)
1656 {
1657 PM_TRACE("[%s] powerDomainDidChangeTo: parentsKnowState = true\n",
1658 getName());
1659 ask_parent( fDesiredPowerState );
1660 }
1661 }
1662
1663 //*********************************************************************************
1664 // [private] setParentInfo
1665 //
1666 // Set our connection data for one specific parent, and then combine all the parent
1667 // data together.
1668 //*********************************************************************************
1669
1670 void IOService::setParentInfo (
1671 IOPMPowerFlags newPowerFlags,
1672 IOPowerConnection * whichParent,
1673 bool knowsState )
1674 {
1675 OSIterator * iter;
1676 OSObject * next;
1677 IOPowerConnection * conn;
1678
1679 PM_ASSERT_IN_GATE();
1680
1681 // set our connection data
1682 whichParent->setParentCurrentPowerFlags(newPowerFlags);
1683 whichParent->setParentKnowsState(knowsState);
1684
1685 // recompute our parent info
1686 fParentsCurrentPowerFlags = 0;
1687 fParentsKnowState = true;
1688
1689 iter = getParentIterator(gIOPowerPlane);
1690 if ( iter )
1691 {
1692 while ( (next = iter->getNextObject()) )
1693 {
1694 if ( (conn = OSDynamicCast(IOPowerConnection, next)) )
1695 {
1696 fParentsKnowState &= conn->parentKnowsState();
1697 fParentsCurrentPowerFlags |= conn->parentCurrentPowerFlags();
1698 }
1699 }
1700 iter->release();
1701 }
1702 }
1703
1704 //*********************************************************************************
1705 // [private] rebuildChildClampBits
1706 //
1707 // The ChildClamp bits (kIOPMChildClamp & kIOPMChildClamp2) in our capabilityFlags
1708 // indicate that one of our children (or grandchildren or great-grandchildren ...)
1709 // doesn't support idle or system sleep in its current state. Since we don't track
1710 // the origin of each bit, every time any child changes state we have to clear
1711 // these bits and rebuild them.
1712 //*********************************************************************************
1713
1714 void IOService::rebuildChildClampBits ( void )
1715 {
1716 unsigned long i;
1717 OSIterator * iter;
1718 OSObject * next;
1719 IOPowerConnection * connection;
1720 unsigned long powerState;
1721
1722 // A child's desires has changed. We need to rebuild the child-clamp bits in
1723 // our power state array. Start by clearing the bits in each power state.
1724
1725 for ( i = 0; i < fNumberOfPowerStates; i++ )
1726 {
1727 fPowerStates[i].capabilityFlags &= ~(kIOPMChildClamp | kIOPMChildClamp2);
1728 }
1729
1730 // Loop through the children. When we encounter the calling child, save the
1731 // computed state as this child's desire. And set the ChildClamp bits in any
1732 // of our states that some child has clamp on.
1733
1734 iter = getChildIterator(gIOPowerPlane);
1735 if ( iter )
1736 {
1737 while ( (next = iter->getNextObject()) )
1738 {
1739 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
1740 {
1741 if (connection->getReadyFlag() == false)
1742 {
1743 PM_CONNECT("[%s] %s: connection not ready\n",
1744 getName(), __FUNCTION__);
1745 continue;
1746 }
1747
1748 powerState = connection->getDesiredDomainState();
1749 if (powerState < fNumberOfPowerStates)
1750 {
1751 if ( connection->getPreventIdleSleepFlag() )
1752 fPowerStates[powerState].capabilityFlags |= kIOPMChildClamp;
1753 if ( connection->getPreventSystemSleepFlag() )
1754 fPowerStates[powerState].capabilityFlags |= kIOPMChildClamp2;
1755 }
1756 }
1757 }
1758 iter->release();
1759 }
1760 }
1761
1762 //*********************************************************************************
1763 // [public virtual] requestPowerDomainState
1764 //
1765 // The child of a power domain calls it parent here to request power of a certain
1766 // character.
1767 //*********************************************************************************
1768
1769 IOReturn IOService::requestPowerDomainState (
1770 IOPMPowerFlags desiredState,
1771 IOPowerConnection * whichChild,
1772 unsigned long specification )
1773 {
1774 unsigned long i;
1775 unsigned long computedState;
1776 unsigned long theDesiredState;
1777 IOService * child;
1778
1779 if (!initialized)
1780 return IOPMNotYetInitialized;
1781
1782 if (gIOPMWorkLoop->onThread() == false)
1783 {
1784 PM_DEBUG("[%s] called requestPowerDomainState\n", getName());
1785 return kIOReturnSuccess;
1786 }
1787
1788 theDesiredState = desiredState & ~(kIOPMPreventIdleSleep | kIOPMPreventSystemSleep);
1789
1790 OUR_PMLog(kPMLogRequestDomain, desiredState, specification);
1791
1792 if (!isChild(whichChild, gIOPowerPlane))
1793 return kIOReturnNotAttached;
1794
1795 if (fControllingDriver == NULL || !fPowerStates)
1796 return IOPMNotYetInitialized;
1797
1798 child = (IOService *) whichChild->getChildEntry(gIOPowerPlane);
1799 assert(child);
1800
1801 switch (specification) {
1802 case IOPMLowestState:
1803 i = 0;
1804 while ( i < fNumberOfPowerStates )
1805 {
1806 if ( ( fPowerStates[i].outputPowerCharacter & theDesiredState) ==
1807 (theDesiredState & fOutputPowerCharacterFlags) )
1808 {
1809 break;
1810 }
1811 i++;
1812 }
1813 if ( i >= fNumberOfPowerStates )
1814 {
1815 return IOPMNoSuchState;
1816 }
1817 break;
1818
1819 case IOPMNextLowerState:
1820 i = fCurrentPowerState - 1;
1821 while ( (int) i >= 0 )
1822 {
1823 if ( ( fPowerStates[i].outputPowerCharacter & theDesiredState) ==
1824 (theDesiredState & fOutputPowerCharacterFlags) )
1825 {
1826 break;
1827 }
1828 i--;
1829 }
1830 if ( (int) i < 0 )
1831 {
1832 return IOPMNoSuchState;
1833 }
1834 break;
1835
1836 case IOPMHighestState:
1837 i = fNumberOfPowerStates;
1838 while ( (int) i >= 0 )
1839 {
1840 i--;
1841 if ( ( fPowerStates[i].outputPowerCharacter & theDesiredState) ==
1842 (theDesiredState & fOutputPowerCharacterFlags) )
1843 {
1844 break;
1845 }
1846 }
1847 if ( (int) i < 0 )
1848 {
1849 return IOPMNoSuchState;
1850 }
1851 break;
1852
1853 case IOPMNextHigherState:
1854 i = fCurrentPowerState + 1;
1855 while ( i < fNumberOfPowerStates )
1856 {
1857 if ( ( fPowerStates[i].outputPowerCharacter & theDesiredState) ==
1858 (theDesiredState & fOutputPowerCharacterFlags) )
1859 {
1860 break;
1861 }
1862 i++;
1863 }
1864 if ( i == fNumberOfPowerStates )
1865 {
1866 return IOPMNoSuchState;
1867 }
1868 break;
1869
1870 default:
1871 return IOPMBadSpecification;
1872 }
1873
1874 computedState = i;
1875
1876 // Clamp removed on the initial power request from a new child.
1877
1878 if (fClampOn && !whichChild->childHasRequestedPower())
1879 {
1880 PM_TRACE("[%s] %p power clamp removed (child = %p)\n",
1881 getName(), this, whichChild);
1882 fClampOn = false;
1883 fDeviceDesire = 0;
1884 }
1885
1886 // Record the child's desires on the connection.
1887
1888 whichChild->setDesiredDomainState( computedState );
1889 whichChild->setPreventIdleSleepFlag( desiredState & kIOPMPreventIdleSleep );
1890 whichChild->setPreventSystemSleepFlag( desiredState & kIOPMPreventSystemSleep );
1891 whichChild->setChildHasRequestedPower();
1892
1893 if (whichChild->getReadyFlag() == false)
1894 return IOPMNoErr;
1895
1896 // Issue a ping for us to re-evaluate all children desires and
1897 // possibly change power state.
1898
1899 if (!fWillAdjustPowerState && !fDeviceOverrides)
1900 {
1901 IOPMRequest * childRequest;
1902
1903 childRequest = acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState );
1904 if (childRequest)
1905 {
1906 submitPMRequest( childRequest );
1907 fWillAdjustPowerState = true;
1908 }
1909 }
1910
1911 return IOPMNoErr;
1912 }
1913
1914 //*********************************************************************************
1915 // [public virtual] temporaryPowerClampOn
1916 //
1917 // A power domain wants to clamp its power on till it has children which
1918 // will thendetermine the power domain state.
1919 //
1920 // We enter the highest state until addPowerChild is called.
1921 //*********************************************************************************
1922
1923 IOReturn IOService::temporaryPowerClampOn ( void )
1924 {
1925 IOPMRequest * request;
1926
1927 if (!initialized)
1928 return IOPMNotYetInitialized;
1929
1930 request = acquirePMRequest( this, kIOPMRequestTypeTemporaryPowerClamp );
1931 if (!request)
1932 return kIOReturnNoMemory;
1933
1934 submitPMRequest( request );
1935 return IOPMNoErr;
1936 }
1937
1938 //*********************************************************************************
1939 // [public virtual] makeUsable
1940 //
1941 // Some client of our device is asking that we become usable. Although
1942 // this has not come from a subclassed device object, treat it exactly
1943 // as if it had. In this way, subsequent requests for lower power from
1944 // a subclassed device object will pre-empt this request.
1945 //
1946 // We treat this as a subclass object request to switch to the
1947 // highest power state.
1948 //*********************************************************************************
1949
1950 IOReturn IOService::makeUsable ( void )
1951 {
1952 IOPMRequest * request;
1953
1954 if (!initialized)
1955 return IOPMNotYetInitialized;
1956
1957 OUR_PMLog(kPMLogMakeUsable, 0, 0);
1958
1959 request = acquirePMRequest( this, kIOPMRequestTypeMakeUsable );
1960 if (!request)
1961 return kIOReturnNoMemory;
1962
1963 submitPMRequest( request );
1964 return IOPMNoErr;
1965 }
1966
1967 //*********************************************************************************
1968 // [private] handleMakeUsable
1969 //
1970 // Handle a request to become usable.
1971 //*********************************************************************************
1972
1973 void IOService::handleMakeUsable ( IOPMRequest * request )
1974 {
1975 PM_ASSERT_IN_GATE();
1976 if ( fControllingDriver )
1977 {
1978 fDeviceDesire = fNumberOfPowerStates - 1;
1979 computeDesiredState();
1980 if ( inPlane(gIOPowerPlane) && fParentsKnowState )
1981 {
1982 changeState();
1983 }
1984 }
1985 else
1986 {
1987 fNeedToBecomeUsable = true;
1988 }
1989 }
1990
1991 //*********************************************************************************
1992 // [public virtual] currentCapability
1993 //*********************************************************************************
1994
1995 IOPMPowerFlags IOService::currentCapability ( void )
1996 {
1997 if (!initialized)
1998 return IOPMNotPowerManaged;
1999
2000 return fCurrentCapabilityFlags;
2001 }
2002
2003 //*********************************************************************************
2004 // [public virtual] changePowerStateTo
2005 //
2006 // For some reason, our power-controlling driver has decided it needs to change
2007 // power state. We enqueue the power change so that appropriate parties
2008 // will be notified, and then we will instruct the driver to make the change.
2009 //*********************************************************************************
2010
2011 IOReturn IOService::changePowerStateTo ( unsigned long ordinal )
2012 {
2013 IOPMRequest * request;
2014
2015 if (!initialized)
2016 return IOPMNotYetInitialized;
2017
2018 OUR_PMLog(kPMLogChangeStateTo, ordinal, 0);
2019
2020 request = acquirePMRequest( this, kIOPMRequestTypeChangePowerStateTo );
2021 if (!request)
2022 return kIOReturnNoMemory;
2023
2024 request->fArg0 = (void *) ordinal;
2025 request->fArg1 = (void *) false;
2026
2027 // Avoid needless downwards power transitions by clamping power in
2028 // computeDesiredState() until the delayed request is processed.
2029
2030 if (gIOPMWorkLoop->inGate())
2031 {
2032 fTempClampPowerState = max(fTempClampPowerState, ordinal);
2033 fTempClampCount++;
2034 request->fArg1 = (void *) true;
2035 }
2036
2037 submitPMRequest( request );
2038 return IOPMNoErr;
2039 }
2040
2041 //*********************************************************************************
2042 // [private] handleChangePowerStateTo
2043 //*********************************************************************************
2044
2045 void IOService::handleChangePowerStateTo ( IOPMRequest * request )
2046 {
2047 unsigned long ordinal = (unsigned long) request->fArg0;
2048
2049 PM_ASSERT_IN_GATE();
2050 if (request->fArg1)
2051 {
2052 assert(fTempClampCount != 0);
2053 if (fTempClampCount)
2054 fTempClampCount--;
2055 if (!fTempClampCount)
2056 fTempClampPowerState = 0;
2057 }
2058
2059 if ( fControllingDriver && (ordinal < fNumberOfPowerStates))
2060 {
2061 fDriverDesire = ordinal;
2062 computeDesiredState();
2063 if ( inPlane(gIOPowerPlane) && fParentsKnowState )
2064 {
2065 changeState();
2066 }
2067 }
2068 }
2069
2070 //*********************************************************************************
2071 // [public virtual] changePowerStateToPriv
2072 //
2073 // For some reason, a subclassed device object has decided it needs to change
2074 // power state. We enqueue the power change so that appropriate parties
2075 // will be notified, and then we will instruct the driver to make the change.
2076 //*********************************************************************************
2077
2078 IOReturn IOService::changePowerStateToPriv ( unsigned long ordinal )
2079 {
2080 IOPMRequest * request;
2081
2082 if (!initialized)
2083 return IOPMNotYetInitialized;
2084
2085 request = acquirePMRequest( this, kIOPMRequestTypeChangePowerStateToPriv );
2086 if (!request)
2087 return kIOReturnNoMemory;
2088
2089 request->fArg0 = (void *) ordinal;
2090 request->fArg1 = (void *) false;
2091
2092 // Avoid needless downwards power transitions by clamping power in
2093 // computeDesiredState() until the delayed request is processed.
2094
2095 if (gIOPMWorkLoop->inGate())
2096 {
2097 fTempClampPowerState = max(fTempClampPowerState, ordinal);
2098 fTempClampCount++;
2099 request->fArg1 = (void *) true;
2100 }
2101
2102 submitPMRequest( request );
2103 return IOPMNoErr;
2104 }
2105
2106 //*********************************************************************************
2107 // [private] handleChangePowerStateToPriv
2108 //*********************************************************************************
2109
2110 void IOService::handleChangePowerStateToPriv ( IOPMRequest * request )
2111 {
2112 unsigned long ordinal = (unsigned long) request->fArg0;
2113
2114 PM_ASSERT_IN_GATE();
2115 OUR_PMLog(kPMLogChangeStateToPriv, ordinal, 0);
2116 if (request->fArg1)
2117 {
2118 assert(fTempClampCount != 0);
2119 if (fTempClampCount)
2120 fTempClampCount--;
2121 if (!fTempClampCount)
2122 fTempClampPowerState = 0;
2123 }
2124
2125 if ( fControllingDriver && (ordinal < fNumberOfPowerStates))
2126 {
2127 fDeviceDesire = ordinal;
2128 computeDesiredState();
2129 if ( inPlane(gIOPowerPlane) && fParentsKnowState )
2130 {
2131 changeState();
2132 }
2133 }
2134 }
2135
2136 //*********************************************************************************
2137 // [private] computeDesiredState
2138 //*********************************************************************************
2139
2140 void IOService::computeDesiredState ( unsigned long tempDesire )
2141 {
2142 OSIterator * iter;
2143 OSObject * next;
2144 IOPowerConnection * connection;
2145 unsigned long newDesiredState = 0;
2146 unsigned long childDesire = 0;
2147 unsigned long deviceDesire;
2148
2149 if (tempDesire)
2150 deviceDesire = tempDesire;
2151 else
2152 deviceDesire = fDeviceDesire;
2153
2154 // If clamp is on, always override deviceDesire to max.
2155
2156 if (fClampOn && fNumberOfPowerStates)
2157 deviceDesire = fNumberOfPowerStates - 1;
2158
2159 // Compute the maximum of our children's desires,
2160 // our controlling driver's desire, and the subclass device's desire.
2161
2162 if ( !fDeviceOverrides )
2163 {
2164 iter = getChildIterator(gIOPowerPlane);
2165 if ( iter )
2166 {
2167 while ( (next = iter->getNextObject()) )
2168 {
2169 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
2170 {
2171 if (connection->getReadyFlag() == false)
2172 {
2173 PM_CONNECT("[%s] %s: connection not ready\n",
2174 getName(), __FUNCTION__);
2175 continue;
2176 }
2177
2178 if (connection->getDesiredDomainState() > childDesire)
2179 childDesire = connection->getDesiredDomainState();
2180 }
2181 }
2182 iter->release();
2183 }
2184
2185 fChildrenDesire = childDesire;
2186 newDesiredState = max(childDesire, fDriverDesire);
2187 }
2188
2189 newDesiredState = max(deviceDesire, newDesiredState);
2190 if (fTempClampCount && (fTempClampPowerState < fNumberOfPowerStates))
2191 newDesiredState = max(fTempClampPowerState, newDesiredState);
2192
2193 fDesiredPowerState = newDesiredState;
2194
2195 // Limit check against number of power states.
2196
2197 if (fNumberOfPowerStates == 0)
2198 fDesiredPowerState = 0;
2199 else if (fDesiredPowerState >= fNumberOfPowerStates)
2200 fDesiredPowerState = fNumberOfPowerStates - 1;
2201
2202 // Restart idle timer if stopped and deviceDesire has increased.
2203
2204 if (fDeviceDesire && fActivityTimerStopped)
2205 {
2206 fActivityTimerStopped = false;
2207 start_PM_idle_timer();
2208 }
2209
2210 // Invalidate cached tickle power state when desires change, and not
2211 // due to a tickle request. This invalidation must occur before the
2212 // power state change to minimize races. We want to err on the side
2213 // of servicing more activity tickles rather than dropping one when
2214 // the device is in a low power state.
2215
2216 if (fPMRequest && (fPMRequest->getType() != kIOPMRequestTypeActivityTickle) &&
2217 (fActivityTicklePowerState != -1))
2218 {
2219 IOLockLock(fActivityLock);
2220 fActivityTicklePowerState = -1;
2221 IOLockUnlock(fActivityLock);
2222 }
2223
2224 PM_TRACE(" NewState %ld, Child %ld, Driver %ld, Device %ld, Clamp %d (%ld)\n",
2225 fDesiredPowerState, childDesire, fDriverDesire, deviceDesire,
2226 fClampOn, fTempClampCount ? fTempClampPowerState : 0);
2227 }
2228
2229 //*********************************************************************************
2230 // [private] changeState
2231 //
2232 // A subclass object, our controlling driver, or a power domain child
2233 // has asked for a different power state. Here we compute what new
2234 // state we should enter and enqueue the change (or start it).
2235 //*********************************************************************************
2236
2237 IOReturn IOService::changeState ( void )
2238 {
2239 IOReturn result;
2240
2241 PM_ASSERT_IN_GATE();
2242 assert(inPlane(gIOPowerPlane));
2243 assert(fParentsKnowState);
2244 assert(fControllingDriver);
2245
2246 result = enqueuePowerChange(
2247 /* flags */ IOPMWeInitiated,
2248 /* power state */ fDesiredPowerState,
2249 /* domain state */ 0,
2250 /* connection */ 0,
2251 /* parent state */ 0);
2252
2253 return result;
2254 }
2255
2256 //*********************************************************************************
2257 // [public virtual] currentPowerConsumption
2258 //
2259 //*********************************************************************************
2260
2261 unsigned long IOService::currentPowerConsumption ( void )
2262 {
2263 if (!initialized)
2264 return kIOPMUnknown;
2265
2266 return fCurrentPowerConsumption;
2267 }
2268
2269 //*********************************************************************************
2270 // [public virtual] getPMworkloop
2271 //*********************************************************************************
2272
2273 IOWorkLoop * IOService::getPMworkloop ( void )
2274 {
2275 return gIOPMWorkLoop;
2276 }
2277
2278 //*********************************************************************************
2279 // [public virtual] activityTickle
2280 //
2281 // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
2282 // flag to be set, and the device state checked. If the device has been
2283 // powered down, it is powered up again.
2284 // The tickle with parameter kIOPMSubclassPolicy is ignored here and
2285 // should be intercepted by a subclass.
2286 //*********************************************************************************
2287
2288 bool IOService::activityTickle ( unsigned long type, unsigned long stateNumber )
2289 {
2290 IOPMRequest * request;
2291 bool noPowerChange = true;
2292
2293 if ( initialized && stateNumber && (type == kIOPMSuperclassPolicy1) )
2294 {
2295 IOLockLock(fActivityLock);
2296
2297 // Record device activity for the idle timer handler.
2298
2299 fDeviceActive = true;
2300 clock_get_uptime(&fDeviceActiveTimestamp);
2301
2302 // Record the last tickle power state.
2303 // This helps to filter out redundant tickles as
2304 // this function may be called from the data path.
2305
2306 if (fActivityTicklePowerState < (long)stateNumber)
2307 {
2308 fActivityTicklePowerState = stateNumber;
2309 noPowerChange = false;
2310
2311 request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
2312 if (request)
2313 {
2314 request->fArg0 = (void *) stateNumber; // power state
2315 request->fArg1 = (void *) true; // power rise
2316 submitPMRequest(request);
2317 }
2318 }
2319
2320 IOLockUnlock(fActivityLock);
2321 }
2322
2323 // Returns false if the activityTickle might cause a transition to a
2324 // higher powered state, true otherwise.
2325
2326 return noPowerChange;
2327 }
2328
2329 //*********************************************************************************
2330 // [public virtual] setIdleTimerPeriod
2331 //
2332 // A subclass policy-maker is going to use our standard idleness
2333 // detection service. Make a command queue and an idle timer and
2334 // connect them to the power management workloop. Finally,
2335 // start the timer.
2336 //*********************************************************************************
2337
2338 IOReturn IOService::setIdleTimerPeriod ( unsigned long period )
2339 {
2340 IOWorkLoop * wl = getPMworkloop();
2341
2342 if (!initialized || !wl)
2343 return IOPMNotYetInitialized;
2344
2345 OUR_PMLog(PMsetIdleTimerPeriod, period, 0);
2346
2347 fIdleTimerPeriod = period;
2348
2349 if ( period > 0 )
2350 {
2351 // make the timer event
2352 if ( fIdleTimerEventSource == NULL )
2353 {
2354 IOTimerEventSource * timerSrc;
2355
2356 timerSrc = IOTimerEventSource::timerEventSource(
2357 this, PM_idle_timer_expired);
2358
2359 if (timerSrc && (wl->addEventSource(timerSrc) != kIOReturnSuccess))
2360 {
2361 timerSrc->release();
2362 timerSrc = 0;
2363 }
2364
2365 fIdleTimerEventSource = timerSrc;
2366 }
2367
2368 start_PM_idle_timer();
2369 }
2370 return IOPMNoErr;
2371 }
2372
2373 //******************************************************************************
2374 // [public virtual] nextIdleTimeout
2375 //
2376 // Returns how many "seconds from now" the device should idle into its
2377 // next lowest power state.
2378 //******************************************************************************
2379
2380 SInt32 IOService::nextIdleTimeout(
2381 AbsoluteTime currentTime,
2382 AbsoluteTime lastActivity,
2383 unsigned int powerState)
2384 {
2385 AbsoluteTime delta;
2386 UInt64 delta_ns;
2387 SInt32 delta_secs;
2388 SInt32 delay_secs;
2389
2390 // Calculate time difference using funky macro from clock.h.
2391 delta = currentTime;
2392 SUB_ABSOLUTETIME(&delta, &lastActivity);
2393
2394 // Figure it in seconds.
2395 absolutetime_to_nanoseconds(delta, &delta_ns);
2396 delta_secs = (SInt32)(delta_ns / NSEC_PER_SEC);
2397
2398 // Be paranoid about delta somehow exceeding timer period.
2399 if (delta_secs < (int) fIdleTimerPeriod )
2400 delay_secs = (int) fIdleTimerPeriod - delta_secs;
2401 else
2402 delay_secs = (int) fIdleTimerPeriod;
2403
2404 return (SInt32)delay_secs;
2405 }
2406
2407 //******************************************************************************
2408 // [public virtual] start_PM_idle_timer
2409 //
2410 // The parameter is a pointer to us. Use it to call our timeout method.
2411 //******************************************************************************
2412
2413 void IOService::start_PM_idle_timer ( void )
2414 {
2415 static const int maxTimeout = 100000;
2416 static const int minTimeout = 1;
2417 AbsoluteTime uptime;
2418 SInt32 idle_in = 0;
2419
2420 if (!initialized || !fIdleTimerEventSource)
2421 return;
2422
2423 IOLockLock(fActivityLock);
2424
2425 clock_get_uptime(&uptime);
2426
2427 // Subclasses may modify idle sleep algorithm
2428 idle_in = nextIdleTimeout(uptime, fDeviceActiveTimestamp, fCurrentPowerState);
2429
2430 // Check for out-of range responses
2431 if (idle_in > maxTimeout)
2432 {
2433 // use standard implementation
2434 idle_in = IOService::nextIdleTimeout(uptime,
2435 fDeviceActiveTimestamp,
2436 fCurrentPowerState);
2437 } else if (idle_in < minTimeout) {
2438 idle_in = fIdleTimerPeriod;
2439 }
2440
2441 IOLockUnlock(fActivityLock);
2442
2443 fIdleTimerEventSource->setTimeout(idle_in, NSEC_PER_SEC);
2444 }
2445
2446 //*********************************************************************************
2447 // [private] PM_idle_timer_expired
2448 //
2449 // The parameter is a pointer to us. Use it to call our timeout method.
2450 //*********************************************************************************
2451
2452 void PM_idle_timer_expired ( OSObject * ourSelves, IOTimerEventSource * )
2453 {
2454 ((IOService *)ourSelves)->PM_idle_timer_expiration();
2455 }
2456
2457 //*********************************************************************************
2458 // [public virtual] PM_idle_timer_expiration
2459 //
2460 // The idle timer has expired. If there has been activity since the last
2461 // expiration, just restart the timer and return. If there has not been
2462 // activity, switch to the next lower power state and restart the timer.
2463 //*********************************************************************************
2464
2465 void IOService::PM_idle_timer_expiration ( void )
2466 {
2467 IOPMRequest * request;
2468 bool restartTimer = true;
2469
2470 if ( !initialized || !fIdleTimerPeriod )
2471 return;
2472
2473 IOLockLock(fActivityLock);
2474
2475 // Check for device activity (tickles) over last timer period.
2476
2477 if (fDeviceActive)
2478 {
2479 // Device was active - do not drop power, restart timer.
2480 fDeviceActive = false;
2481 }
2482 else
2483 {
2484 // No device activity - drop power state by one level.
2485 // Decrement the cached tickle power state when possible.
2486 // This value may be (-1) before activityTickle() is called,
2487 // but the power drop request must be issued regardless.
2488
2489 if (fActivityTicklePowerState > 0)
2490 {
2491 fActivityTicklePowerState--;
2492 }
2493
2494 request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
2495 if (request)
2496 {
2497 request->fArg0 = (void *) 0; // power state (irrelevant)
2498 request->fArg1 = (void *) false; // power drop
2499 submitPMRequest( request );
2500
2501 // Do not restart timer until after the tickle request has been
2502 // processed.
2503
2504 restartTimer = false;
2505 }
2506 }
2507
2508 IOLockUnlock(fActivityLock);
2509
2510 if (restartTimer)
2511 start_PM_idle_timer();
2512 }
2513
2514 //*********************************************************************************
2515 // [public virtual] command_received
2516 //
2517 //*********************************************************************************
2518
2519 void IOService::command_received ( void *statePtr , void *, void * , void * )
2520 {
2521 }
2522
2523 //*********************************************************************************
2524 // [public virtual] setAggressiveness
2525 //
2526 // Pass on the input parameters to all power domain children. All those which are
2527 // power domains will pass it on to their children, etc.
2528 //*********************************************************************************
2529
2530 IOReturn IOService::setAggressiveness ( unsigned long type, unsigned long newLevel )
2531 {
2532 OSIterator * iter;
2533 OSObject * next;
2534 IOPowerConnection * connection;
2535 IOService * child;
2536
2537 if (!initialized)
2538 return IOPMNotYetInitialized;
2539
2540 if (getPMRootDomain() == this)
2541 OUR_PMLog(kPMLogSetAggressiveness, type, newLevel);
2542
2543 if ( type <= kMaxType )
2544 {
2545 fAggressivenessValue[type] = newLevel;
2546 fAggressivenessValid[type] = true;
2547 }
2548
2549 iter = getChildIterator(gIOPowerPlane);
2550 if ( iter )
2551 {
2552 while ( (next = iter->getNextObject()) )
2553 {
2554 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
2555 {
2556 if (connection->getReadyFlag() == false)
2557 {
2558 PM_CONNECT("[%s] %s: connection not ready\n",
2559 getName(), __FUNCTION__);
2560 continue;
2561 }
2562
2563 child = ((IOService *)(connection->copyChildEntry(gIOPowerPlane)));
2564 if ( child )
2565 {
2566 child->setAggressiveness(type, newLevel);
2567 child->release();
2568 }
2569 }
2570 }
2571 iter->release();
2572 }
2573
2574 return IOPMNoErr;
2575 }
2576
2577 //*********************************************************************************
2578 // [public virtual] getAggressiveness
2579 //
2580 // Called by the user client.
2581 //*********************************************************************************
2582
2583 IOReturn IOService::getAggressiveness ( unsigned long type, unsigned long * currentLevel )
2584 {
2585 if ( !initialized || (type > kMaxType) )
2586 return kIOReturnBadArgument;
2587
2588 if ( !fAggressivenessValid[type] )
2589 return kIOReturnInvalid;
2590
2591 *currentLevel = fAggressivenessValue[type];
2592
2593 return kIOReturnSuccess;
2594 }
2595
2596 //*********************************************************************************
2597 // [public] getPowerState
2598 //
2599 //*********************************************************************************
2600
2601 UInt32 IOService::getPowerState ( void )
2602 {
2603 if (!initialized)
2604 return 0;
2605
2606 return fCurrentPowerState;
2607 }
2608
2609 //*********************************************************************************
2610 // [public virtual] systemWake
2611 //
2612 // Pass this to all power domain children. All those which are
2613 // power domains will pass it on to their children, etc.
2614 //*********************************************************************************
2615
2616 IOReturn IOService::systemWake ( void )
2617 {
2618 OSIterator * iter;
2619 OSObject * next;
2620 IOPowerConnection * connection;
2621 IOService * theChild;
2622
2623 OUR_PMLog(kPMLogSystemWake, 0, 0);
2624
2625 iter = getChildIterator(gIOPowerPlane);
2626 if ( iter )
2627 {
2628 while ( (next = iter->getNextObject()) )
2629 {
2630 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
2631 {
2632 if (connection->getReadyFlag() == false)
2633 {
2634 PM_CONNECT("[%s] %s: connection not ready\n",
2635 getName(), __FUNCTION__);
2636 continue;
2637 }
2638
2639 theChild = (IOService *)connection->copyChildEntry(gIOPowerPlane);
2640 if ( theChild )
2641 {
2642 theChild->systemWake();
2643 theChild->release();
2644 }
2645 }
2646 }
2647 iter->release();
2648 }
2649
2650 if ( fControllingDriver != NULL )
2651 {
2652 if ( fControllingDriver->didYouWakeSystem() )
2653 {
2654 makeUsable();
2655 }
2656 }
2657
2658 return IOPMNoErr;
2659 }
2660
2661 //*********************************************************************************
2662 // [public virtual] temperatureCriticalForZone
2663 //*********************************************************************************
2664
2665 IOReturn IOService::temperatureCriticalForZone ( IOService * whichZone )
2666 {
2667 IOService * theParent;
2668 IOService * theNub;
2669
2670 OUR_PMLog(kPMLogCriticalTemp, 0, 0);
2671
2672 if ( inPlane(gIOPowerPlane) && !fWeAreRoot )
2673 {
2674 theNub = (IOService *)copyParentEntry(gIOPowerPlane);
2675 if ( theNub )
2676 {
2677 theParent = (IOService *)theNub->copyParentEntry(gIOPowerPlane);
2678 theNub->release();
2679 if ( theParent )
2680 {
2681 theParent->temperatureCriticalForZone(whichZone);
2682 theParent->release();
2683 }
2684 }
2685 }
2686 return IOPMNoErr;
2687 }
2688
2689 //*********************************************************************************
2690 // [public] powerOverrideOnPriv
2691 //*********************************************************************************
2692
2693 IOReturn IOService::powerOverrideOnPriv ( void )
2694 {
2695 IOPMRequest * request;
2696
2697 if (!initialized)
2698 return IOPMNotYetInitialized;
2699
2700 if (gIOPMWorkLoop->inGate())
2701 {
2702 fDeviceOverrides = true;
2703 return IOPMNoErr;
2704 }
2705
2706 request = acquirePMRequest( this, kIOPMRequestTypePowerOverrideOnPriv );
2707 if (!request)
2708 return kIOReturnNoMemory;
2709
2710 submitPMRequest( request );
2711 return IOPMNoErr;
2712 }
2713
2714 //*********************************************************************************
2715 // [public] powerOverrideOffPriv
2716 //*********************************************************************************
2717
2718 IOReturn IOService::powerOverrideOffPriv ( void )
2719 {
2720 IOPMRequest * request;
2721
2722 if (!initialized)
2723 return IOPMNotYetInitialized;
2724
2725 if (gIOPMWorkLoop->inGate())
2726 {
2727 fDeviceOverrides = false;
2728 return IOPMNoErr;
2729 }
2730
2731 request = acquirePMRequest( this, kIOPMRequestTypePowerOverrideOffPriv );
2732 if (!request)
2733 return kIOReturnNoMemory;
2734
2735 submitPMRequest( request );
2736 return IOPMNoErr;
2737 }
2738
2739 //*********************************************************************************
2740 // [private] handlePowerOverrideChanged
2741 //*********************************************************************************
2742
2743 void IOService::handlePowerOverrideChanged ( IOPMRequest * request )
2744 {
2745 PM_ASSERT_IN_GATE();
2746 if (request->getType() == kIOPMRequestTypePowerOverrideOnPriv)
2747 {
2748 OUR_PMLog(kPMLogOverrideOn, 0, 0);
2749 fDeviceOverrides = true;
2750 }
2751 else
2752 {
2753 OUR_PMLog(kPMLogOverrideOff, 0, 0);
2754 fDeviceOverrides = false;
2755 }
2756
2757 if (fControllingDriver && inPlane(gIOPowerPlane) && fParentsKnowState)
2758 {
2759 computeDesiredState();
2760 changeState();
2761 }
2762 }
2763
2764 //*********************************************************************************
2765 // [private] enqueuePowerChange
2766 //*********************************************************************************
2767
2768 IOReturn IOService::enqueuePowerChange (
2769 unsigned long flags,
2770 unsigned long whatStateOrdinal,
2771 unsigned long domainState,
2772 IOPowerConnection * whichParent,
2773 unsigned long singleParentState )
2774 {
2775 changeNoteItem changeNote;
2776 IOPMPowerState * powerStatePtr;
2777
2778 PM_ASSERT_IN_GATE();
2779 assert( fMachineState == kIOPM_Finished );
2780 assert( whatStateOrdinal < fNumberOfPowerStates );
2781
2782 if (whatStateOrdinal >= fNumberOfPowerStates)
2783 return IOPMAckImplied;
2784
2785 powerStatePtr = &fPowerStates[whatStateOrdinal];
2786
2787 // Initialize the change note
2788 changeNote.flags = flags;
2789 changeNote.newStateNumber = whatStateOrdinal;
2790 changeNote.outputPowerCharacter = powerStatePtr->outputPowerCharacter;
2791 changeNote.inputPowerRequirement = powerStatePtr->inputPowerRequirement;
2792 changeNote.capabilityFlags = powerStatePtr->capabilityFlags;
2793 changeNote.parent = NULL;
2794
2795 if (flags & IOPMParentInitiated )
2796 {
2797 changeNote.domainState = domainState;
2798 changeNote.parent = whichParent;
2799 changeNote.singleParentState = singleParentState;
2800 }
2801
2802 if (flags & IOPMWeInitiated )
2803 {
2804 start_our_change(&changeNote);
2805 return 0;
2806 }
2807 else
2808 {
2809 return start_parent_change(&changeNote);
2810 }
2811 }
2812
2813 //*********************************************************************************
2814 // [private] notifyInterestedDrivers
2815 //*********************************************************************************
2816
2817 bool IOService::notifyInterestedDrivers ( void )
2818 {
2819 IOPMinformee * informee;
2820 IOPMinformeeList * list = fInterestedDrivers;
2821 DriverCallParam * param;
2822 IOItemCount count;
2823
2824 PM_ASSERT_IN_GATE();
2825 assert( fDriverCallBusy == false );
2826 assert( fDriverCallParamCount == 0 );
2827 assert( fHeadNotePendingAcks == 0 );
2828
2829 count = list->numberOfItems();
2830 if (!count)
2831 goto done; // no interested drivers
2832
2833 // Allocate an array of interested drivers and their return values
2834 // for the callout thread. Everything else is still "owned" by the
2835 // PM work loop, which can run to process acknowledgePowerChange()
2836 // responses.
2837
2838 param = (DriverCallParam *) fDriverCallParamPtr;
2839 if (count > fDriverCallParamSlots)
2840 {
2841 if (fDriverCallParamSlots)
2842 {
2843 assert(fDriverCallParamPtr);
2844 IODelete(fDriverCallParamPtr, DriverCallParam, fDriverCallParamSlots);
2845 fDriverCallParamPtr = 0;
2846 fDriverCallParamSlots = 0;
2847 }
2848
2849 param = IONew(DriverCallParam, count);
2850 if (!param)
2851 goto done; // no memory
2852
2853 fDriverCallParamPtr = (void *) param;
2854 fDriverCallParamSlots = count;
2855 }
2856
2857 informee = list->firstInList();
2858 assert(informee);
2859 for (IOItemCount i = 0; i < count; i++)
2860 {
2861 informee->timer = -1;
2862 param[i].Target = informee;
2863 informee->retain();
2864 informee = list->nextInList( informee );
2865 }
2866
2867 fDriverCallParamCount = count;
2868 fHeadNotePendingAcks = count;
2869
2870 // Machine state will be blocked pending callout thread completion.
2871
2872 PM_LOCK();
2873 fDriverCallBusy = true;
2874 PM_UNLOCK();
2875 thread_call_enter( fDriverCallEntry );
2876 return true;
2877
2878 done:
2879 // no interested drivers or did not schedule callout thread due to error.
2880 return false;
2881 }
2882
2883 //*********************************************************************************
2884 // [private] notifyInterestedDriversDone
2885 //*********************************************************************************
2886
2887 void IOService::notifyInterestedDriversDone ( void )
2888 {
2889 IOPMinformee * informee;
2890 IOItemCount count;
2891 DriverCallParam * param;
2892 IOReturn result;
2893
2894 PM_ASSERT_IN_GATE();
2895 param = (DriverCallParam *) fDriverCallParamPtr;
2896 count = fDriverCallParamCount;
2897
2898 assert( fDriverCallBusy == false );
2899 assert( fMachineState == kIOPM_DriverThreadCallDone );
2900
2901 if (param && count)
2902 {
2903 for (IOItemCount i = 0; i < count; i++, param++)
2904 {
2905 informee = (IOPMinformee *) param->Target;
2906 result = param->Result;
2907
2908 if ((result == IOPMAckImplied) || (result < 0))
2909 {
2910 // child return IOPMAckImplied
2911 informee->timer = 0;
2912 fHeadNotePendingAcks--;
2913 }
2914 else if (informee->timer)
2915 {
2916 assert(informee->timer == -1);
2917
2918 // Driver has not acked, and has returned a positive result.
2919 // Enforce a minimum permissible timeout value.
2920 // Make the min value large enough so timeout is less likely
2921 // to occur if a driver misinterpreted that the return value
2922 // should be in microsecond units. And make it large enough
2923 // to be noticeable if a driver neglects to ack.
2924
2925 if (result < kMinAckTimeoutTicks)
2926 result = kMinAckTimeoutTicks;
2927
2928 informee->timer = (result / (ACK_TIMER_PERIOD / ns_per_us)) + 1;
2929 }
2930 // else, child has already acked or driver has removed interest,
2931 // and head_note_pendingAcks decremented.
2932 // informee may have been removed from the interested drivers list,
2933 // thus the informee must be retained across the callout.
2934
2935 informee->release();
2936 }
2937
2938 fDriverCallParamCount = 0;
2939
2940 if ( fHeadNotePendingAcks )
2941 {
2942 OUR_PMLog(kPMLogStartAckTimer, 0, 0);
2943 start_ack_timer();
2944 }
2945 }
2946
2947 // Hop back to original machine state path (from notifyAll)
2948 fMachineState = fNextMachineState;
2949
2950 notifyChildren();
2951 }
2952
2953 //*********************************************************************************
2954 // [private] notifyChildren
2955 //*********************************************************************************
2956
2957 void IOService::notifyChildren ( void )
2958 {
2959 OSIterator * iter;
2960 OSObject * next;
2961 IOPowerConnection * connection;
2962 OSArray * children = 0;
2963
2964 if (fStrictTreeOrder)
2965 children = OSArray::withCapacity(8);
2966
2967 // Sum child power consumption in notifyChild()
2968 fPowerStates[fHeadNoteState].staticPower = 0;
2969
2970 iter = getChildIterator(gIOPowerPlane);
2971 if ( iter )
2972 {
2973 while ((next = iter->getNextObject()))
2974 {
2975 if ((connection = OSDynamicCast(IOPowerConnection, next)))
2976 {
2977 if (connection->getReadyFlag() == false)
2978 {
2979 PM_CONNECT("[%s] %s: connection not ready\n",
2980 getName(), __FUNCTION__);
2981 continue;
2982 }
2983
2984 if (children)
2985 children->setObject( connection );
2986 else
2987 notifyChild( connection,
2988 fDriverCallReason == kDriverCallInformPreChange );
2989 }
2990 }
2991 iter->release();
2992 }
2993
2994 if (children)
2995 {
2996 if (children->getCount() == 0)
2997 {
2998 children->release();
2999 children = 0;
3000 }
3001 else
3002 {
3003 assert(fNotifyChildArray == 0);
3004 fNotifyChildArray = children;
3005 fNextMachineState = fMachineState;
3006 fMachineState = kIOPM_NotifyChildrenDone;
3007 }
3008 }
3009 }
3010
3011 //*********************************************************************************
3012 // [private] notifyChildrenDone
3013 //*********************************************************************************
3014
3015 void IOService::notifyChildrenDone ( void )
3016 {
3017 PM_ASSERT_IN_GATE();
3018 assert(fNotifyChildArray);
3019 assert(fMachineState == kIOPM_NotifyChildrenDone);
3020
3021 // Interested drivers have all acked (if any), ack timer stopped.
3022 // Notify one child, wait for it's ack, then repeat for next child.
3023 // This is a workaround for some drivers with multiple instances at
3024 // the same branch in the power tree, but the driver is slow to power
3025 // up unless the tree ordering is observed. Problem observed only on
3026 // system wake, not on system sleep.
3027 //
3028 // We have the ability to power off in reverse child index order.
3029 // That works nicely on some machines, but not on all HW configs.
3030
3031 if (fNotifyChildArray->getCount())
3032 {
3033 IOPowerConnection * connection;
3034 connection = (IOPowerConnection *) fNotifyChildArray->getObject(0);
3035 fNotifyChildArray->removeObject(0);
3036 notifyChild( connection, fDriverCallReason == kDriverCallInformPreChange );
3037 }
3038 else
3039 {
3040 fNotifyChildArray->release();
3041 fNotifyChildArray = 0;
3042 fMachineState = fNextMachineState;
3043 }
3044 }
3045
3046 //*********************************************************************************
3047 // [private] notifyAll
3048 //*********************************************************************************
3049
3050 IOReturn IOService::notifyAll ( bool is_prechange )
3051 {
3052 // Save the next machine_state to be restored by notifyInterestedDriversDone()
3053
3054 PM_ASSERT_IN_GATE();
3055 fNextMachineState = fMachineState;
3056 fMachineState = kIOPM_DriverThreadCallDone;
3057 fDriverCallReason = is_prechange ?
3058 kDriverCallInformPreChange : kDriverCallInformPostChange;
3059
3060 if (!notifyInterestedDrivers())
3061 notifyInterestedDriversDone();
3062
3063 return IOPMWillAckLater;
3064 }
3065
3066 //*********************************************************************************
3067 // [private, static] pmDriverCallout
3068 //
3069 // Thread call context
3070 //*********************************************************************************
3071
3072 IOReturn IOService::actionDriverCalloutDone (
3073 OSObject * target,
3074 void * arg0, void * arg1,
3075 void * arg2, void * arg3 )
3076 {
3077 IOServicePM * pwrMgt = (IOServicePM *) arg0;
3078
3079 PM_LOCK();
3080 fDriverCallBusy = false;
3081 PM_UNLOCK();
3082
3083 if (gIOPMReplyQueue)
3084 gIOPMReplyQueue->signalWorkAvailable();
3085
3086 return kIOReturnSuccess;
3087 }
3088
3089 void IOService::pmDriverCallout ( IOService * from )
3090 {
3091 assert(from);
3092 switch (from->fDriverCallReason)
3093 {
3094 case kDriverCallSetPowerState:
3095 from->driverSetPowerState();
3096 break;
3097
3098 case kDriverCallInformPreChange:
3099 case kDriverCallInformPostChange:
3100 from->driverInformPowerChange();
3101 break;
3102
3103 default:
3104 IOPanic("IOService::pmDriverCallout bad machine state");
3105 }
3106
3107 gIOPMWorkLoop->runAction(actionDriverCalloutDone,
3108 /* target */ from,
3109 /* arg0 */ (void *) from->pwrMgt );
3110 }
3111
3112 //*********************************************************************************
3113 // [private] driverSetPowerState
3114 //
3115 // Thread call context
3116 //*********************************************************************************
3117
3118 void IOService::driverSetPowerState ( void )
3119 {
3120 IOService * driver;
3121 unsigned long powerState;
3122 DriverCallParam * param;
3123 IOReturn result;
3124 AbsoluteTime end;
3125
3126 assert( fDriverCallBusy );
3127 param = (DriverCallParam *) fDriverCallParamPtr;
3128 assert( param );
3129 assert( fDriverCallParamCount == 1 );
3130
3131 driver = fControllingDriver;
3132 powerState = fHeadNoteState;
3133
3134 if (!fWillPMStop)
3135 {
3136 OUR_PMLog( kPMLogProgramHardware, (UInt32) this, powerState);
3137 clock_get_uptime(&fDriverCallStartTime);
3138 result = driver->setPowerState( powerState, this );
3139 clock_get_uptime(&end);
3140 OUR_PMLog((UInt32) -kPMLogProgramHardware, (UInt32) this, (UInt32) result);
3141
3142 #if LOG_SETPOWER_TIMES
3143 if ((result == IOPMAckImplied) || (result < 0))
3144 {
3145 uint64_t nsec;
3146
3147 SUB_ABSOLUTETIME(&end, &fDriverCallStartTime);
3148 absolutetime_to_nanoseconds(end, &nsec);
3149 if (nsec > LOG_SETPOWER_TIMES)
3150 PM_DEBUG("%s::setPowerState(%p, %lu -> %lu) took %d ms\n",
3151 fName, this, fCurrentPowerState, powerState, NS_TO_MS(nsec));
3152 }
3153 #endif
3154 }
3155 else
3156 result = kIOPMAckImplied;
3157
3158 param->Result = result;
3159 }
3160
3161 //*********************************************************************************
3162 // [private] driverInformPowerChange
3163 //
3164 // Thread call context
3165 //*********************************************************************************
3166
3167 void IOService::driverInformPowerChange ( void )
3168 {
3169 IOItemCount count;
3170 IOPMinformee * informee;
3171 IOService * driver;
3172 IOReturn result;
3173 IOPMPowerFlags powerFlags;
3174 unsigned long powerState;
3175 DriverCallParam * param;
3176 AbsoluteTime end;
3177
3178 assert( fDriverCallBusy );
3179 param = (DriverCallParam *) fDriverCallParamPtr;
3180 count = fDriverCallParamCount;
3181 assert( count && param );
3182
3183 powerFlags = fHeadNoteCapabilityFlags;
3184 powerState = fHeadNoteState;
3185
3186 for (IOItemCount i = 0; i < count; i++)
3187 {
3188 informee = (IOPMinformee *) param->Target;
3189 driver = informee->whatObject;
3190
3191 if (!fWillPMStop && informee->active)
3192 {
3193 if (fDriverCallReason == kDriverCallInformPreChange)
3194 {
3195 OUR_PMLog(kPMLogInformDriverPreChange, (UInt32) this, powerState);
3196 clock_get_uptime(&informee->startTime);
3197 result = driver->powerStateWillChangeTo(powerFlags, powerState, this);
3198 clock_get_uptime(&end);
3199 OUR_PMLog((UInt32)-kPMLogInformDriverPreChange, (UInt32) this, result);
3200 }
3201 else
3202 {
3203 OUR_PMLog(kPMLogInformDriverPostChange, (UInt32) this, powerState);
3204 clock_get_uptime(&informee->startTime);
3205 result = driver->powerStateDidChangeTo(powerFlags, powerState, this);
3206 clock_get_uptime(&end);
3207 OUR_PMLog((UInt32)-kPMLogInformDriverPostChange, (UInt32) this, result);
3208 }
3209
3210 #if LOG_SETPOWER_TIMES
3211 if ((result == IOPMAckImplied) || (result < 0))
3212 {
3213 uint64_t nsec;
3214
3215 SUB_ABSOLUTETIME(&end, &informee->startTime);
3216 absolutetime_to_nanoseconds(end, &nsec);
3217 if (nsec > LOG_SETPOWER_TIMES)
3218 PM_DEBUG("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) took %d ms\n",
3219 driver->getName(),
3220 (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
3221 driver, fName, fCurrentPowerState, powerState, NS_TO_MS(nsec));
3222 }
3223 #endif
3224 }
3225 else
3226 result = kIOPMAckImplied;
3227
3228 param->Result = result;
3229 param++;
3230 }
3231 }
3232
3233 //*********************************************************************************
3234 // [private] notifyChild
3235 //
3236 // Notify a power domain child of an upcoming power change.
3237 // If the object acknowledges the current change, we return TRUE.
3238 //*********************************************************************************
3239
3240 bool IOService::notifyChild ( IOPowerConnection * theNub, bool is_prechange )
3241 {
3242 IOReturn k = IOPMAckImplied;
3243 unsigned long childPower;
3244 IOService * theChild;
3245 IOPMRequest * childRequest;
3246 int requestType;
3247
3248 PM_ASSERT_IN_GATE();
3249 theChild = (IOService *)(theNub->copyChildEntry(gIOPowerPlane));
3250 if (!theChild)
3251 {
3252 assert(false);
3253 return true;
3254 }
3255
3256 // Unless the child handles the notification immediately and returns
3257 // kIOPMAckImplied, we'll be awaiting their acknowledgement later.
3258 fHeadNotePendingAcks++;
3259 theNub->setAwaitingAck(true);
3260
3261 requestType = is_prechange ?
3262 kIOPMRequestTypePowerDomainWillChange :
3263 kIOPMRequestTypePowerDomainDidChange;
3264
3265 childRequest = acquirePMRequest( theChild, requestType );
3266 if (childRequest)
3267 {
3268 childRequest->fArg0 = (void *) fHeadNoteOutputFlags;
3269 childRequest->fArg1 = (void *) theNub;
3270 childRequest->fArg2 = (void *) (fHeadNoteState < fCurrentPowerState);
3271 theChild->submitPMRequest( childRequest );
3272 k = IOPMWillAckLater;
3273 }
3274 else
3275 {
3276 k = IOPMAckImplied;
3277 fHeadNotePendingAcks--;
3278 theNub->setAwaitingAck(false);
3279 childPower = theChild->currentPowerConsumption();
3280 if ( childPower == kIOPMUnknown )
3281 {
3282 fPowerStates[fHeadNoteState].staticPower = kIOPMUnknown;
3283 } else {
3284 if ( fPowerStates[fHeadNoteState].staticPower != kIOPMUnknown )
3285 {
3286 fPowerStates[fHeadNoteState].staticPower += childPower;
3287 }
3288 }
3289 }
3290
3291 theChild->release();
3292 return (k == IOPMAckImplied);
3293 }
3294
3295 //*********************************************************************************
3296 // [private] OurChangeTellClientsPowerDown
3297 //
3298 // All registered applications and kernel clients have positively acknowledged our
3299 // intention of lowering power. Here we notify them all that we will definitely
3300 // lower the power. If we don't have to wait for any of them to acknowledge, we
3301 // carry on by notifying interested drivers. Otherwise, we do wait.
3302 //*********************************************************************************
3303
3304 void IOService::OurChangeTellClientsPowerDown ( void )
3305 {
3306 fMachineState = kIOPM_OurChangeTellPriorityClientsPowerDown;
3307 tellChangeDown1(fHeadNoteState);
3308 }
3309
3310 //*********************************************************************************
3311 // [private] OurChangeTellPriorityClientsPowerDown
3312 //
3313 // All registered applications and kernel clients have positively acknowledged our
3314 // intention of lowering power. Here we notify "priority" clients that we are
3315 // lowering power. If we don't have to wait for any of them to acknowledge, we
3316 // carry on by notifying interested drivers. Otherwise, we do wait.
3317 //*********************************************************************************
3318
3319 void IOService::OurChangeTellPriorityClientsPowerDown ( void )
3320 {
3321 fMachineState = kIOPM_OurChangeNotifyInterestedDriversWillChange;
3322 tellChangeDown2(fHeadNoteState);
3323 }
3324
3325 //*********************************************************************************
3326 // [private] OurChangeNotifyInterestedDriversWillChange
3327 //
3328 // All registered applications and kernel clients have acknowledged our notification
3329 // that we are lowering power. Here we notify interested drivers. If we don't have
3330 // to wait for any of them to acknowledge, we instruct our power driver to make the
3331 // change. Otherwise, we do wait.
3332 //*********************************************************************************
3333
3334 void IOService::OurChangeNotifyInterestedDriversWillChange ( void )
3335 {
3336 fMachineState = kIOPM_OurChangeSetPowerState;
3337 notifyAll( true );
3338 }
3339
3340 //*********************************************************************************
3341 // [private] OurChangeSetPowerState
3342 //
3343 // All interested drivers have acknowledged our pre-change notification of a power
3344 // change we initiated. Here we instruct our controlling driver to make
3345 // the change to the hardware. If it does so, we continue processing
3346 // (waiting for settle and notifying interested parties post-change.)
3347 // If it doesn't, we have to wait for it to acknowledge and then continue.
3348 //*********************************************************************************
3349
3350 void IOService::OurChangeSetPowerState ( void )
3351 {
3352 fNextMachineState = kIOPM_OurChangeWaitForPowerSettle;
3353 fMachineState = kIOPM_DriverThreadCallDone;
3354 fDriverCallReason = kDriverCallSetPowerState;
3355
3356 if (notifyControllingDriver() == false)
3357 notifyControllingDriverDone();
3358 }
3359
3360 //*********************************************************************************
3361 // [private] OurChangeWaitForPowerSettle
3362 //
3363 // Our controlling driver has changed power state on the hardware
3364 // during a power change we initiated. Here we see if we need to wait
3365 // for power to settle before continuing. If not, we continue processing
3366 // (notifying interested parties post-change). If so, we wait and
3367 // continue later.
3368 //*********************************************************************************
3369
3370 void IOService::OurChangeWaitForPowerSettle ( void )
3371 {
3372 fMachineState = kIOPM_OurChangeNotifyInterestedDriversDidChange;
3373 fSettleTimeUS = compute_settle_time();
3374 if ( fSettleTimeUS )
3375 {
3376 startSettleTimer(fSettleTimeUS);
3377 }
3378 }
3379
3380 //*********************************************************************************
3381 // [private] OurChangeNotifyInterestedDriversDidChange
3382 //
3383 // Power has settled on a power change we initiated. Here we notify
3384 // all our interested parties post-change. If they all acknowledge, we're
3385 // done with this change note, and we can start on the next one.
3386 // Otherwise we have to wait for acknowledgements and finish up later.
3387 //*********************************************************************************
3388
3389 void IOService::OurChangeNotifyInterestedDriversDidChange ( void )
3390 {
3391 fMachineState = kIOPM_OurChangeFinish;
3392 notifyAll(false);
3393 }
3394
3395 //*********************************************************************************
3396 // [private] OurChangeFinish
3397 //
3398 // Power has settled on a power change we initiated, and
3399 // all our interested parties have acknowledged. We're
3400 // done with this change note, and we can start on the next one.
3401 //*********************************************************************************
3402
3403 void IOService::OurChangeFinish ( void )
3404 {
3405 all_done();
3406 }
3407
3408 //*********************************************************************************
3409 // [private] ParentDownTellPriorityClientsPowerDown
3410 //
3411 // All applications and kernel clients have been notified of a power lowering
3412 // initiated by the parent and we had to wait for responses. Here
3413 // we notify any priority clients. If they all ack, we continue with the power change.
3414 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
3415 //*********************************************************************************
3416
3417 void IOService::ParentDownTellPriorityClientsPowerDown ( void )
3418 {
3419 fMachineState = kIOPM_ParentDownNotifyInterestedDriversWillChange;
3420 tellChangeDown2(fHeadNoteState);
3421 }
3422
3423 //*********************************************************************************
3424 // [private] ParentDownNotifyInterestedDriversWillChange
3425 //
3426 // All applications and kernel clients have been notified of a power lowering
3427 // initiated by the parent and we had to wait for their responses. Here we notify
3428 // any interested drivers and power domain children. If they all ack, we continue
3429 // with the power change.
3430 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
3431 //*********************************************************************************
3432
3433 void IOService::ParentDownNotifyInterestedDriversWillChange ( void )
3434 {
3435 fMachineState = kIOPM_ParentDownSetPowerState;
3436 notifyAll( true );
3437 }
3438
3439 //*********************************************************************************
3440 // [private] ParentDownSetPowerState
3441 //
3442 // We had to wait for it, but all parties have acknowledged our pre-change
3443 // notification of a power lowering initiated by the parent.
3444 // Here we instruct our controlling driver
3445 // to put the hardware in the state it needs to be in when the domain is
3446 // lowered. If it does so, we continue processing
3447 // (waiting for settle and acknowledging the parent.)
3448 // If it doesn't, we have to wait for it to acknowledge and then continue.
3449 //*********************************************************************************
3450
3451 void IOService::ParentDownSetPowerState ( void )
3452 {
3453 fNextMachineState = kIOPM_ParentDownWaitForPowerSettle;
3454 fMachineState = kIOPM_DriverThreadCallDone;
3455 fDriverCallReason = kDriverCallSetPowerState;
3456
3457 if (notifyControllingDriver() == false)
3458 notifyControllingDriverDone();
3459 }
3460
3461 //*********************************************************************************
3462 // [private] ParentDownWaitForPowerSettle
3463 //
3464 // Our controlling driver has changed power state on the hardware
3465 // during a power change initiated by our parent. We have had to wait
3466 // for acknowledgement from interested parties, or we have had to wait
3467 // for the controlling driver to change the state. Here we see if we need
3468 // to wait for power to settle before continuing. If not, we continue
3469 // processing (acknowledging our preparedness to the parent).
3470 // If so, we wait and continue later.
3471 //*********************************************************************************
3472
3473 void IOService::ParentDownWaitForPowerSettle ( void )
3474 {
3475 fMachineState = kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange;
3476 fSettleTimeUS = compute_settle_time();
3477 if ( fSettleTimeUS )
3478 {
3479 startSettleTimer(fSettleTimeUS);
3480 }
3481 }
3482
3483 //*********************************************************************************
3484 // [private] ParentDownNotifyDidChangeAndAcknowledgeChange
3485 //
3486 // Power has settled on a power change initiated by our parent. Here we
3487 // notify interested parties.
3488 //*********************************************************************************
3489
3490 void IOService::ParentDownNotifyDidChangeAndAcknowledgeChange ( void )
3491 {
3492 fMachineState = kIOPM_ParentDownAcknowledgeChange;
3493 notifyAll(false);
3494 }
3495
3496 //*********************************************************************************
3497 // [private] ParentDownAcknowledgeChange
3498 //
3499 // We had to wait for it, but all parties have acknowledged our post-change
3500 // notification of a power lowering initiated by the parent.
3501 // Here we acknowledge the parent.
3502 // We are done with this change note, and we can start on the next one.
3503 //*********************************************************************************
3504
3505 void IOService::ParentDownAcknowledgeChange ( void )
3506 {
3507 IORegistryEntry * nub;
3508 IOService * parent;
3509
3510 nub = fHeadNoteParent;
3511 nub->retain();
3512 all_done();
3513 parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
3514 if ( parent )
3515 {
3516 parent->acknowledgePowerChange((IOService *)nub);
3517 parent->release();
3518 }
3519 nub->release();
3520 }
3521
3522 //*********************************************************************************
3523 // [private] ParentUpSetPowerState
3524 //
3525 // Our parent has informed us via powerStateDidChange that it has
3526 // raised the power in our power domain, and we have had to wait
3527 // for some interested party to acknowledge our notification.
3528 // Here we instruct our controlling
3529 // driver to program the hardware to take advantage of the higher domain
3530 // power. If it does so, we continue processing
3531 // (waiting for settle and notifying interested parties post-change.)
3532 // If it doesn't, we have to wait for it to acknowledge and then continue.
3533 //*********************************************************************************
3534
3535 void IOService::ParentUpSetPowerState ( void )
3536 {
3537 fNextMachineState = kIOPM_ParentUpWaitForSettleTime;
3538 fMachineState = kIOPM_DriverThreadCallDone;
3539 fDriverCallReason = kDriverCallSetPowerState;
3540
3541 if (notifyControllingDriver() == false)
3542 notifyControllingDriverDone();
3543 }
3544
3545 //*********************************************************************************
3546 // [private] ParentUpWaitForSettleTime
3547 //
3548 // Our controlling driver has changed power state on the hardware
3549 // during a power raise initiated by the parent, but we had to wait for it.
3550 // Here we see if we need to wait for power to settle before continuing.
3551 // If not, we continue processing (notifying interested parties post-change).
3552 // If so, we wait and continue later.
3553 //*********************************************************************************
3554
3555 void IOService::ParentUpWaitForSettleTime ( void )
3556 {
3557 fMachineState = kIOPM_ParentUpNotifyInterestedDriversDidChange;
3558 fSettleTimeUS = compute_settle_time();
3559 if ( fSettleTimeUS )
3560 {
3561 startSettleTimer(fSettleTimeUS);
3562 }
3563 }
3564
3565 //*********************************************************************************
3566 // [private] ParentUpNotifyInterestedDriversDidChange
3567 //
3568 // Power has settled on a power raise initiated by the parent.
3569 // Here we notify all our interested parties post-change. If they all acknowledge,
3570 // we're done with this change note, and we can start on the next one.
3571 // Otherwise we have to wait for acknowledgements and finish up later.
3572 //*********************************************************************************
3573
3574 void IOService::ParentUpNotifyInterestedDriversDidChange ( void )
3575 {
3576 fMachineState = kIOPM_ParentUpAcknowledgePowerChange;
3577 notifyAll(false);
3578 }
3579
3580 //*********************************************************************************
3581 // [private] ParentUpAcknowledgePowerChange
3582 //
3583 // All parties have acknowledged our post-change notification of a power
3584 // raising initiated by the parent. Here we acknowledge the parent.
3585 // We are done with this change note, and we can start on the next one.
3586 //*********************************************************************************
3587
3588 void IOService::ParentUpAcknowledgePowerChange ( void )
3589 {
3590 IORegistryEntry * nub;
3591 IOService * parent;
3592
3593 nub = fHeadNoteParent;
3594 nub->retain();
3595 all_done();
3596 parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
3597 if ( parent )
3598 {
3599 parent->acknowledgePowerChange((IOService *)nub);
3600 parent->release();
3601 }
3602 nub->release();
3603 }
3604
3605 //*********************************************************************************
3606 // [private] all_done
3607 //
3608 // A power change is complete, and the used post-change note is at
3609 // the head of the queue. Remove it and set myCurrentState to the result
3610 // of the change. Start up the next change in queue.
3611 //*********************************************************************************
3612
3613 void IOService::all_done ( void )
3614 {
3615 unsigned long previous_state;
3616
3617 fMachineState = kIOPM_Finished;
3618
3619 // our power change
3620 if ( fHeadNoteFlags & IOPMWeInitiated )
3621 {
3622 // could our driver switch to the new state?
3623 if ( !( fHeadNoteFlags & IOPMNotDone) )
3624 {
3625 // we changed, tell our parent
3626 if ( !fWeAreRoot )
3627 {
3628 ask_parent(fHeadNoteState);
3629 }
3630
3631 // yes, did power raise?
3632 if ( fCurrentPowerState < fHeadNoteState )
3633 {
3634 // yes, inform clients and apps
3635 tellChangeUp (fHeadNoteState);
3636 }
3637 previous_state = fCurrentPowerState;
3638 // either way
3639 fCurrentPowerState = fHeadNoteState;
3640 #if PM_VARS_SUPPORT
3641 fPMVars->myCurrentState = fCurrentPowerState;
3642 #endif
3643 OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, 0);
3644
3645 // inform subclass policy-maker
3646 if (!fWillPMStop && fParentsKnowState)
3647 powerChangeDone(previous_state);
3648 else
3649 PM_DEBUG("%s::powerChangeDone() skipped\n", getName());
3650 }
3651 }
3652
3653 // parent's power change
3654 if ( fHeadNoteFlags & IOPMParentInitiated)
3655 {
3656 if (((fHeadNoteFlags & IOPMDomainWillChange) && (fCurrentPowerState >= fHeadNoteState)) ||
3657 ((fHeadNoteFlags & IOPMDomainDidChange) && (fCurrentPowerState < fHeadNoteState)))
3658 {
3659 // did power raise?
3660 if ( fCurrentPowerState < fHeadNoteState )
3661 {
3662 // yes, inform clients and apps
3663 tellChangeUp (fHeadNoteState);
3664 }
3665 // either way
3666 previous_state = fCurrentPowerState;
3667 fCurrentPowerState = fHeadNoteState;
3668 #if PM_VARS_SUPPORT
3669 fPMVars->myCurrentState = fCurrentPowerState;
3670 #endif
3671 fMaxCapability = fControllingDriver->maxCapabilityForDomainState(fHeadNoteDomainState);
3672
3673 OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, 0);
3674
3675 // inform subclass policy-maker
3676 if (!fWillPMStop && fParentsKnowState)
3677 powerChangeDone(previous_state);
3678 else
3679 PM_DEBUG("%s::powerChangeDone() skipped\n", getName());
3680 }
3681 }
3682
3683 if (fCurrentPowerState < fNumberOfPowerStates)
3684 {
3685 const IOPMPowerState * powerStatePtr = &fPowerStates[fCurrentPowerState];
3686
3687 fCurrentCapabilityFlags = powerStatePtr->capabilityFlags;
3688 if (fCurrentCapabilityFlags & kIOPMStaticPowerValid)
3689 fCurrentPowerConsumption = powerStatePtr->staticPower;
3690 }
3691 }
3692
3693 //*********************************************************************************
3694 // [public] settleTimerExpired
3695 //
3696 // Power has settled after our last change. Notify interested parties that
3697 // there is a new power state.
3698 //*********************************************************************************
3699
3700 void IOService::settleTimerExpired ( void )
3701 {
3702 fSettleTimeUS = 0;
3703 }
3704
3705 //*********************************************************************************
3706 // [private] compute_settle_time
3707 //
3708 // Compute the power-settling delay in microseconds for the
3709 // change from myCurrentState to head_note_state.
3710 //*********************************************************************************
3711
3712 unsigned long IOService::compute_settle_time ( void )
3713 {
3714 unsigned long totalTime;
3715 unsigned long i;
3716
3717 PM_ASSERT_IN_GATE();
3718
3719 // compute total time to attain the new state
3720 totalTime = 0;
3721 i = fCurrentPowerState;
3722
3723 // we're lowering power
3724 if ( fHeadNoteState < fCurrentPowerState )
3725 {
3726 while ( i > fHeadNoteState )
3727 {
3728 totalTime += fPowerStates[i].settleDownTime;
3729 i--;
3730 }
3731 }
3732
3733 // we're raising power
3734 if ( fHeadNoteState > fCurrentPowerState )
3735 {
3736 while ( i < fHeadNoteState )
3737 {
3738 totalTime += fPowerStates[i+1].settleUpTime;
3739 i++;
3740 }
3741 }
3742
3743 return totalTime;
3744 }
3745
3746 //*********************************************************************************
3747 // [private] startSettleTimer
3748 //
3749 // Enter a power-settling delay in microseconds and start a timer for that delay.
3750 //*********************************************************************************
3751
3752 IOReturn IOService::startSettleTimer ( unsigned long delay )
3753 {
3754 AbsoluteTime deadline;
3755 boolean_t pending;
3756
3757 retain();
3758 clock_interval_to_deadline(delay, kMicrosecondScale, &deadline);
3759 pending = thread_call_enter_delayed(fSettleTimer, deadline);
3760 if (pending) release();
3761
3762 return IOPMNoErr;
3763 }
3764
3765 //*********************************************************************************
3766 // [public] ackTimerTick
3767 //
3768 // The acknowledgement timeout periodic timer has ticked.
3769 // If we are awaiting acks for a power change notification,
3770 // we decrement the timer word of each interested driver which hasn't acked.
3771 // If a timer word becomes zero, we pretend the driver aknowledged.
3772 // If we are waiting for the controlling driver to change the power
3773 // state of the hardware, we decrement its timer word, and if it becomes
3774 // zero, we pretend the driver acknowledged.
3775 //
3776 // Returns true if the timer tick made it possible to advance to the next
3777 // machine state, false otherwise.
3778 //*********************************************************************************
3779
3780 void IOService::ack_timer_ticked ( void )
3781 {
3782 assert(false);
3783 }
3784
3785 bool IOService::ackTimerTick( void )
3786 {
3787 IOPMinformee * nextObject;
3788 bool done = false;
3789
3790 PM_ASSERT_IN_GATE();
3791 switch (fMachineState) {
3792 case kIOPM_OurChangeWaitForPowerSettle:
3793 case kIOPM_ParentDownWaitForPowerSettle:
3794 case kIOPM_ParentUpWaitForSettleTime:
3795 // are we waiting for controlling driver to acknowledge?
3796 if ( fDriverTimer > 0 )
3797 {
3798 // yes, decrement timer tick
3799 fDriverTimer--;
3800 if ( fDriverTimer == 0 )
3801 {
3802 // controlling driver is tardy
3803 uint64_t nsec = computeTimeDeltaNS(&fDriverCallStartTime);
3804 OUR_PMLog(kPMLogCtrlDriverTardy, 0, 0);
3805 setProperty(kIOPMTardyAckSPSKey, kOSBooleanTrue);
3806 PM_ERROR("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms\n",
3807 fName, this, fCurrentPowerState, fHeadNoteState, NS_TO_MS(nsec));
3808
3809 if (gIOKitDebug & kIOLogDebugPower)
3810 {
3811 panic("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms",
3812 fName, this, fCurrentPowerState, fHeadNoteState, NS_TO_MS(nsec));
3813 }
3814 else
3815 {
3816 // Unblock state machine and pretend driver has acked.
3817 done = true;
3818 }
3819 } else {
3820 // still waiting, set timer again
3821 start_ack_timer();
3822 }
3823 }
3824 break;
3825
3826 case kIOPM_OurChangeSetPowerState:
3827 case kIOPM_OurChangeFinish:
3828 case kIOPM_ParentDownSetPowerState:
3829 case kIOPM_ParentDownAcknowledgeChange:
3830 case kIOPM_ParentUpSetPowerState:
3831 case kIOPM_ParentUpAcknowledgePowerChange:
3832 case kIOPM_NotifyChildrenDone:
3833 // are we waiting for interested parties to acknowledge?
3834 if ( fHeadNotePendingAcks != 0 )
3835 {
3836 // yes, go through the list of interested drivers
3837 nextObject = fInterestedDrivers->firstInList();
3838 // and check each one
3839 while ( nextObject != NULL )
3840 {
3841 if ( nextObject->timer > 0 )
3842 {
3843 nextObject->timer--;
3844 // this one should have acked by now
3845 if ( nextObject->timer == 0 )
3846 {
3847 uint64_t nsec = computeTimeDeltaNS(&nextObject->startTime);
3848 OUR_PMLog(kPMLogIntDriverTardy, 0, 0);
3849 nextObject->whatObject->setProperty(kIOPMTardyAckPSCKey, kOSBooleanTrue);
3850 PM_ERROR("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) timed out after %d ms\n",
3851 nextObject->whatObject->getName(),
3852 (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
3853 nextObject->whatObject, fName, fCurrentPowerState, fHeadNoteState,
3854 NS_TO_MS(nsec));
3855
3856 // Pretend driver has acked.
3857 fHeadNotePendingAcks--;
3858 }
3859 }
3860 nextObject = fInterestedDrivers->nextInList(nextObject);
3861 }
3862
3863 // is that the last?
3864 if ( fHeadNotePendingAcks == 0 )
3865 {
3866 // yes, we can continue
3867 done = true;
3868 } else {
3869 // no, set timer again
3870 start_ack_timer();
3871 }
3872 }
3873 break;
3874
3875 case kIOPM_ParentDownTellPriorityClientsPowerDown:
3876 case kIOPM_ParentDownNotifyInterestedDriversWillChange:
3877 case kIOPM_OurChangeTellClientsPowerDown:
3878 case kIOPM_OurChangeTellPriorityClientsPowerDown:
3879 case kIOPM_OurChangeNotifyInterestedDriversWillChange:
3880 // apps didn't respond in time
3881 cleanClientResponses(true);
3882 OUR_PMLog(kPMLogClientTardy, 0, 1);
3883 if (fMachineState == kIOPM_OurChangeTellClientsPowerDown)
3884 {
3885 // tardy equates to veto
3886 fDoNotPowerDown = true;
3887 }
3888 done = true;
3889 break;
3890
3891 default:
3892 PM_TRACE("[%s] unexpected ack timer tick (state = %ld)\n",
3893 getName(), fMachineState);
3894 break;
3895 }
3896 return done;
3897 }
3898
3899 //*********************************************************************************
3900 // [private] start_ack_timer
3901 //*********************************************************************************
3902
3903 void IOService::start_ack_timer ( void )
3904 {
3905 start_ack_timer( ACK_TIMER_PERIOD, kNanosecondScale );
3906 }
3907
3908 void IOService::start_ack_timer ( UInt32 interval, UInt32 scale )
3909 {
3910 AbsoluteTime deadline;
3911 boolean_t pending;
3912
3913 clock_interval_to_deadline(interval, scale, &deadline);
3914
3915 retain();
3916 pending = thread_call_enter_delayed(fAckTimer, deadline);
3917 if (pending) release();
3918 }
3919
3920 //*********************************************************************************
3921 // [private] stop_ack_timer
3922 //*********************************************************************************
3923
3924 void IOService::stop_ack_timer ( void )
3925 {
3926 boolean_t pending;
3927
3928 pending = thread_call_cancel(fAckTimer);
3929 if (pending) release();
3930 }
3931
3932 //*********************************************************************************
3933 // [static] settleTimerExpired
3934 //
3935 // Inside PM work loop's gate.
3936 //*********************************************************************************
3937
3938 IOReturn
3939 IOService::actionAckTimerExpired (
3940 OSObject * target,
3941 void * arg0, void * arg1,
3942 void * arg2, void * arg3 )
3943 {
3944 IOService * me = (IOService *) target;
3945 bool done;
3946
3947 // done will be true if the timer tick unblocks the machine state,
3948 // otherwise no need to signal the work loop.
3949
3950 done = me->ackTimerTick();
3951 if (done && gIOPMReplyQueue)
3952 gIOPMReplyQueue->signalWorkAvailable();
3953
3954 return kIOReturnSuccess;
3955 }
3956
3957 //*********************************************************************************
3958 // ack_timer_expired
3959 //
3960 // Thread call function. Holds a retain while the callout is in flight.
3961 //*********************************************************************************
3962
3963 void
3964 IOService::ack_timer_expired ( thread_call_param_t arg0, thread_call_param_t arg1 )
3965 {
3966 IOService * me = (IOService *) arg0;
3967
3968 if (gIOPMWorkLoop)
3969 {
3970 gIOPMWorkLoop->runAction(&actionAckTimerExpired, me);
3971 }
3972 me->release();
3973 }
3974
3975 //*********************************************************************************
3976 // settleTimerExpired
3977 //
3978 // Inside PM work loop's gate.
3979 //*********************************************************************************
3980
3981 static IOReturn
3982 settleTimerExpired (
3983 OSObject * target,
3984 void * arg0, void * arg1,
3985 void * arg2, void * arg3 )
3986 {
3987 IOService * me = (IOService *) target;
3988 me->settleTimerExpired();
3989 return kIOReturnSuccess;
3990 }
3991
3992 //*********************************************************************************
3993 // settle_timer_expired
3994 //
3995 // Thread call function. Holds a retain while the callout is in flight.
3996 //*********************************************************************************
3997
3998 static void
3999 settle_timer_expired ( thread_call_param_t arg0, thread_call_param_t arg1 )
4000 {
4001 IOService * me = (IOService *) arg0;
4002
4003 if (gIOPMWorkLoop && gIOPMReplyQueue)
4004 {
4005 gIOPMWorkLoop->runAction(settleTimerExpired, me);
4006 gIOPMReplyQueue->signalWorkAvailable();
4007 }
4008 me->release();
4009 }
4010
4011 //*********************************************************************************
4012 // [private] start_parent_change
4013 //
4014 // Here we begin the processing of a power change initiated by our parent.
4015 //*********************************************************************************
4016
4017 IOReturn IOService::start_parent_change ( const changeNoteItem * changeNote )
4018 {
4019 fHeadNoteFlags = changeNote->flags;
4020 fHeadNoteState = changeNote->newStateNumber;
4021 fHeadNoteOutputFlags = changeNote->outputPowerCharacter;
4022 fHeadNoteDomainState = changeNote->domainState;
4023 fHeadNoteParent = changeNote->parent;
4024 fHeadNoteCapabilityFlags = changeNote->capabilityFlags;
4025
4026 PM_ASSERT_IN_GATE();
4027 OUR_PMLog( kPMLogStartParentChange, fHeadNoteState, fCurrentPowerState );
4028
4029 // Power domain is lowering power
4030 if ( fHeadNoteState < fCurrentPowerState )
4031 {
4032 setParentInfo(
4033 changeNote->singleParentState,
4034 fHeadNoteParent, true );
4035
4036 // tell apps and kernel clients
4037 fInitialChange = false;
4038 fMachineState = kIOPM_ParentDownTellPriorityClientsPowerDown;
4039 tellChangeDown1(fHeadNoteState);
4040 return IOPMWillAckLater;
4041 }
4042
4043 // Power domain is raising power
4044 if ( fHeadNoteState > fCurrentPowerState )
4045 {
4046 IOPMPowerState * powerStatePtr;
4047
4048 if ( fDesiredPowerState > fCurrentPowerState )
4049 {
4050 if ( fDesiredPowerState < fHeadNoteState )
4051 {
4052 // We power up, but not all the way
4053 fHeadNoteState = fDesiredPowerState;
4054 powerStatePtr = &fPowerStates[fHeadNoteState];
4055 fHeadNoteOutputFlags = powerStatePtr->outputPowerCharacter;
4056 fHeadNoteCapabilityFlags = powerStatePtr->capabilityFlags;
4057 OUR_PMLog(kPMLogAmendParentChange, fHeadNoteState, 0);
4058 }
4059 } else {
4060 // We don't need to change
4061 fHeadNoteState = fCurrentPowerState;
4062 powerStatePtr = &fPowerStates[fHeadNoteState];
4063 fHeadNoteOutputFlags = powerStatePtr->outputPowerCharacter;
4064 fHeadNoteCapabilityFlags = powerStatePtr->capabilityFlags;
4065 OUR_PMLog(kPMLogAmendParentChange, fHeadNoteState, 0);
4066 }
4067 }
4068
4069 if ((fHeadNoteState > fCurrentPowerState) &&
4070 (fHeadNoteFlags & IOPMDomainDidChange))
4071 {
4072 // Parent did change up - start our change up
4073 fInitialChange = false;
4074 fMachineState = kIOPM_ParentUpSetPowerState;
4075 notifyAll( true );
4076 return IOPMWillAckLater;
4077 }
4078
4079 all_done();
4080 return IOPMAckImplied;
4081 }
4082
4083 //*********************************************************************************
4084 // [private] start_our_change
4085 //
4086 // Here we begin the processing of a power change initiated by us.
4087 //*********************************************************************************
4088
4089 void IOService::start_our_change ( const changeNoteItem * changeNote )
4090 {
4091 fHeadNoteFlags = changeNote->flags;
4092 fHeadNoteState = changeNote->newStateNumber;
4093 fHeadNoteOutputFlags = changeNote->outputPowerCharacter;
4094 fHeadNoteCapabilityFlags = changeNote->capabilityFlags;
4095
4096 PM_ASSERT_IN_GATE();
4097
4098 OUR_PMLog( kPMLogStartDeviceChange, fHeadNoteState, fCurrentPowerState );
4099
4100 // can our driver switch to the new state?
4101 if (( fHeadNoteCapabilityFlags & IOPMNotAttainable ) ||
4102 ((fMaxCapability < fHeadNoteState) && (!fWeAreRoot)))
4103 {
4104 // mark the change note un-actioned
4105 fHeadNoteFlags |= IOPMNotDone;
4106
4107 // no, ask the parent to do it then
4108 if ( !fWeAreRoot )
4109 {
4110 ask_parent(fHeadNoteState);
4111 }
4112 all_done();
4113 return;
4114 }
4115
4116 if ( !fInitialChange )
4117 {
4118 if ( fHeadNoteState == fCurrentPowerState )
4119 {
4120 // we initiated a null change; forget it
4121 all_done();
4122 return;
4123 }
4124 }
4125 fInitialChange = false;
4126
4127 // dropping power?
4128 if ( fHeadNoteState < fCurrentPowerState )
4129 {
4130 // yes, in case we have to wait for acks
4131 fMachineState = kIOPM_OurChangeTellClientsPowerDown;
4132 fDoNotPowerDown = false;
4133
4134 // ask apps and kernel clients if we can drop power
4135 fOutOfBandParameter = kNotifyApps;
4136 askChangeDown(fHeadNoteState);
4137 } else {
4138 // in case they don't all ack
4139 fMachineState = kIOPM_OurChangeSetPowerState;
4140 // notify interested drivers and children
4141 notifyAll(true);
4142 }
4143 }
4144
4145 //*********************************************************************************
4146 // [private] ask_parent
4147 //
4148 // Call the power domain parent to ask for a higher power state in the domain
4149 // or to suggest a lower power state.
4150 //*********************************************************************************
4151
4152 IOReturn IOService::ask_parent ( unsigned long requestedState )
4153 {
4154 OSIterator * iter;
4155 OSObject * next;
4156 IOPowerConnection * connection;
4157 IOService * parent;
4158 const IOPMPowerState * powerStatePtr;
4159 unsigned long ourRequest;
4160
4161 PM_ASSERT_IN_GATE();
4162 if (requestedState >= fNumberOfPowerStates)
4163 return IOPMNoErr;
4164
4165 powerStatePtr = &fPowerStates[requestedState];
4166 ourRequest = powerStatePtr->inputPowerRequirement;
4167
4168 if ( powerStatePtr->capabilityFlags & (kIOPMChildClamp | kIOPMPreventIdleSleep) )
4169 {
4170 ourRequest |= kIOPMPreventIdleSleep;
4171 }
4172 if ( powerStatePtr->capabilityFlags & (kIOPMChildClamp2 | kIOPMPreventSystemSleep) )
4173 {
4174 ourRequest |= kIOPMPreventSystemSleep;
4175 }
4176
4177 // is this a new desire?
4178 if ( fPreviousRequest == ourRequest )
4179 {
4180 // no, the parent knows already, just return
4181 return IOPMNoErr;
4182 }
4183
4184 if ( fWeAreRoot )
4185 {
4186 return IOPMNoErr;
4187 }
4188 fPreviousRequest = ourRequest;
4189
4190 iter = getParentIterator(gIOPowerPlane);
4191 if ( iter )
4192 {
4193 while ( (next = iter->getNextObject()) )
4194 {
4195 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
4196 {
4197 parent = (IOService *)connection->copyParentEntry(gIOPowerPlane);
4198 if ( parent ) {
4199 if ( parent->requestPowerDomainState(
4200 ourRequest, connection, IOPMLowestState) != IOPMNoErr )
4201 {
4202 OUR_PMLog(kPMLogRequestDenied, fPreviousRequest, 0);
4203 }
4204 parent->release();
4205 }
4206 }
4207 }
4208 iter->release();
4209 }
4210
4211 return IOPMNoErr;
4212 }
4213
4214 //*********************************************************************************
4215 // [private] notifyControllingDriver
4216 //*********************************************************************************
4217
4218 bool IOService::notifyControllingDriver ( void )
4219 {
4220 DriverCallParam * param;
4221 unsigned long powerState;
4222
4223 PM_ASSERT_IN_GATE();
4224 assert( fDriverCallBusy == false );
4225 assert( fDriverCallParamCount == 0 );
4226 assert( fControllingDriver );
4227
4228 powerState = fHeadNoteState;
4229 if (fPowerStates[powerState].capabilityFlags & IOPMNotAttainable )
4230 return false; // state not attainable
4231
4232 param = (DriverCallParam *) fDriverCallParamPtr;
4233 if (!param)
4234 {
4235 param = IONew(DriverCallParam, 1);
4236 if (!param)
4237 return false; // no memory
4238
4239 fDriverCallParamPtr = (void *) param;
4240 fDriverCallParamSlots = 1;
4241 }
4242
4243 param->Target = fControllingDriver;
4244 fDriverCallParamCount = 1;
4245
4246 fDriverTimer = -1;
4247
4248 // Machine state for this object will stall waiting for a reply
4249 // from the callout thread.
4250
4251 PM_LOCK();
4252 fDriverCallBusy = true;
4253 PM_UNLOCK();
4254 thread_call_enter( fDriverCallEntry );
4255 return true;
4256 }
4257
4258 //*********************************************************************************
4259 // [private] notifyControllingDriverDone
4260 //*********************************************************************************
4261
4262 void IOService::notifyControllingDriverDone( void )
4263 {
4264 DriverCallParam * param;
4265 IOReturn result;
4266
4267 PM_ASSERT_IN_GATE();
4268 param = (DriverCallParam *) fDriverCallParamPtr;
4269
4270 assert( fDriverCallBusy == false );
4271 assert( fMachineState == kIOPM_DriverThreadCallDone );
4272
4273 if (param)
4274 {
4275 assert(fDriverCallParamCount == 1);
4276
4277 // the return value from setPowerState()
4278 result = param->Result;
4279
4280 if ((result == IOPMAckImplied) || (result < 0))
4281 {
4282 // child return IOPMAckImplied
4283 fDriverTimer = 0;
4284 }
4285 else if (fDriverTimer)
4286 {
4287 assert(fDriverTimer == -1);
4288
4289 // Driver has not acked, and has returned a positive result.
4290 // Enforce a minimum permissible timeout value.
4291 // Make the min value large enough so timeout is less likely
4292 // to occur if a driver misinterpreted that the return value
4293 // should be in microsecond units. And make it large enough
4294 // to be noticeable if a driver neglects to ack.
4295
4296 if (result < kMinAckTimeoutTicks)
4297 result = kMinAckTimeoutTicks;
4298
4299 fDriverTimer = (result / (ACK_TIMER_PERIOD / ns_per_us)) + 1;
4300 }
4301 // else, child has already acked and driver_timer reset to 0.
4302
4303 fDriverCallParamCount = 0;
4304
4305 if ( fDriverTimer )
4306 {
4307 OUR_PMLog(kPMLogStartAckTimer, 0, 0);
4308 start_ack_timer();
4309 }
4310 }
4311
4312 // Hop back to original machine state path.
4313 fMachineState = fNextMachineState;
4314 }
4315
4316 //*********************************************************************************
4317 // [public virtual] askChangeDown
4318 //
4319 // Ask registered applications and kernel clients if we can change to a lower
4320 // power state.
4321 //
4322 // Subclass can override this to send a different message type. Parameter is
4323 // the destination state number.
4324 //
4325 // Return true if we don't have to wait for acknowledgements
4326 //*********************************************************************************
4327
4328 bool IOService::askChangeDown ( unsigned long stateNum )
4329 {
4330 return tellClientsWithResponse( kIOMessageCanDevicePowerOff );
4331 }
4332
4333 //*********************************************************************************
4334 // [public] tellChangeDown1
4335 //
4336 // Notify registered applications and kernel clients that we are definitely
4337 // dropping power.
4338 //
4339 // Return true if we don't have to wait for acknowledgements
4340 //*********************************************************************************
4341
4342 bool IOService::tellChangeDown1 ( unsigned long stateNum )
4343 {
4344 fOutOfBandParameter = kNotifyApps;
4345 return tellChangeDown(stateNum);
4346 }
4347
4348 //*********************************************************************************
4349 // [public] tellChangeDown2
4350 //
4351 // Notify priority clients that we are definitely dropping power.
4352 //
4353 // Return true if we don't have to wait for acknowledgements
4354 //*********************************************************************************
4355
4356 bool IOService::tellChangeDown2 ( unsigned long stateNum )
4357 {
4358 fOutOfBandParameter = kNotifyPriority;
4359 return tellChangeDown(stateNum);
4360 }
4361
4362 //*********************************************************************************
4363 // [public virtual] tellChangeDown
4364 //
4365 // Notify registered applications and kernel clients that we are definitely
4366 // dropping power.
4367 //
4368 // Subclass can override this to send a different message type. Parameter is
4369 // the destination state number.
4370 //
4371 // Return true if we don't have to wait for acknowledgements
4372 //*********************************************************************************
4373
4374 bool IOService::tellChangeDown ( unsigned long stateNum )
4375 {
4376 return tellClientsWithResponse( kIOMessageDeviceWillPowerOff );
4377 }
4378
4379 //*********************************************************************************
4380 // cleanClientResponses
4381 //
4382 //*********************************************************************************
4383
4384 static void logAppTimeouts ( OSObject * object, void * context)
4385 {
4386 struct context *theContext = (struct context *)context;
4387 OSObject *flag;
4388
4389 if( !OSDynamicCast( IOService, object) ) {
4390 flag = theContext->responseFlags->getObject(theContext->counter);
4391 if (kOSBooleanTrue != flag)
4392 {
4393 OSString * clientID = 0;
4394 theContext->us->messageClient(theContext->msgType, object, &clientID);
4395 PM_ERROR(theContext->errorLog, clientID ? clientID->getCStringNoCopy() : "");
4396 if (clientID)
4397 clientID->release();
4398 }
4399 theContext->counter += 1;
4400 }
4401 }
4402
4403 void IOService::cleanClientResponses ( bool logErrors )
4404 {
4405 struct context theContext;
4406
4407 if (logErrors && fResponseArray) {
4408 theContext.responseFlags = fResponseArray;
4409 theContext.serialNumber = fSerialNumber;
4410 theContext.counter = 0;
4411 theContext.msgType = kIOMessageCopyClientID;
4412 theContext.us = this;
4413 theContext.maxTimeRequested = 0;
4414 theContext.stateNumber = fHeadNoteState;
4415 theContext.stateFlags = fHeadNoteCapabilityFlags;
4416 theContext.errorLog = "PM notification timeout (%s)\n";
4417
4418 switch ( fOutOfBandParameter ) {
4419 case kNotifyApps:
4420 applyToInterested(gIOAppPowerStateInterest, logAppTimeouts, (void *) &theContext);
4421 case kNotifyPriority:
4422 default:
4423 break;
4424 }
4425 }
4426
4427 if (fResponseArray)
4428 {
4429 // get rid of this stuff
4430 fResponseArray->release();
4431 fResponseArray = NULL;
4432 }
4433
4434 return;
4435 }
4436
4437 //*********************************************************************************
4438 // [public] tellClientsWithResponse
4439 //
4440 // Notify registered applications and kernel clients that we are definitely
4441 // dropping power.
4442 //
4443 // Return true if we don't have to wait for acknowledgements
4444 //*********************************************************************************
4445
4446 bool IOService::tellClientsWithResponse ( int messageType )
4447 {
4448 struct context theContext;
4449
4450 PM_ASSERT_IN_GATE();
4451
4452 fResponseArray = OSArray::withCapacity( 1 );
4453 fSerialNumber += 1;
4454
4455 theContext.responseFlags = fResponseArray;
4456 theContext.serialNumber = fSerialNumber;
4457 theContext.counter = 0;
4458 theContext.msgType = messageType;
4459 theContext.us = this;
4460 theContext.maxTimeRequested = 0;
4461 theContext.stateNumber = fHeadNoteState;
4462 theContext.stateFlags = fHeadNoteCapabilityFlags;
4463
4464 switch ( fOutOfBandParameter ) {
4465 case kNotifyApps:
4466 applyToInterested(gIOAppPowerStateInterest,
4467 pmTellAppWithResponse, (void *)&theContext);
4468 applyToInterested(gIOGeneralInterest,
4469 pmTellClientWithResponse, (void *)&theContext);
4470 break;
4471 case kNotifyPriority:
4472 applyToInterested(gIOPriorityPowerStateInterest,
4473 pmTellClientWithResponse, (void *)&theContext);
4474 break;
4475 }
4476
4477 // do we have to wait for somebody?
4478 if ( !checkForDone() )
4479 {
4480 OUR_PMLog(kPMLogStartAckTimer,theContext.maxTimeRequested, 0);
4481 start_ack_timer( theContext.maxTimeRequested / 1000, kMillisecondScale );
4482 return false;
4483 }
4484
4485 // everybody responded
4486 fResponseArray->release();
4487 fResponseArray = NULL;
4488 // cleanClientResponses(false);
4489
4490 return true;
4491 }
4492
4493 //*********************************************************************************
4494 // [static private] pmTellAppWithResponse
4495 //
4496 // We send a message to an application, and we expect a response, so we compute a
4497 // cookie we can identify the response with.
4498 //*********************************************************************************
4499
4500 void IOService::pmTellAppWithResponse ( OSObject * object, void * context )
4501 {
4502 struct context * theContext = (struct context *) context;
4503 IOServicePM * pwrMgt = theContext->us->pwrMgt;
4504 AbsoluteTime now;
4505
4506 if( OSDynamicCast( IOService, object) )
4507 {
4508 // Automatically 'ack' in kernel clients
4509 theContext->responseFlags->setObject(theContext->counter, kOSBooleanTrue);
4510
4511 const char *who = ((IOService *) object)->getName();
4512 fPlatform->PMLog(who,
4513 kPMLogClientAcknowledge, theContext->msgType, * (UInt32 *) object);
4514 } else {
4515 UInt32 refcon = ((theContext->serialNumber & 0xFFFF)<<16)
4516 + (theContext->counter & 0xFFFF);
4517 OUR_PMLog(kPMLogAppNotify, theContext->msgType, refcon);
4518
4519 #if LOG_APP_RESPONSE_TIMES
4520 OSNumber * num;
4521 clock_get_uptime(&now);
4522 num = OSNumber::withNumber(AbsoluteTime_to_scalar(&now), sizeof(uint64_t) * 8);
4523 if (num)
4524 {
4525 theContext->responseFlags->setObject(theContext->counter, num);
4526 num->release();
4527 }
4528 else
4529 #endif
4530 theContext->responseFlags->setObject(theContext->counter, kOSBooleanFalse);
4531
4532 theContext->us->messageClient(theContext->msgType, object, (void *)refcon);
4533 if ( theContext->maxTimeRequested < k30seconds )
4534 {
4535 theContext->maxTimeRequested = k30seconds;
4536 }
4537
4538 theContext->counter += 1;
4539 }
4540 }
4541
4542 //*********************************************************************************
4543 // [static private] pmTellClientWithResponse
4544 //
4545 // We send a message to an in-kernel client, and we expect a response, so we compute a
4546 // cookie we can identify the response with.
4547 // If it doesn't understand the notification (it is not power-management savvy)
4548 // we won't wait for it to prepare for sleep. If it tells us via a return code
4549 // in the passed struct that it is currently ready, we won't wait for it to prepare.
4550 // If it tells us via the return code in the struct that it does need time, we will chill.
4551 //*********************************************************************************
4552
4553 void IOService::pmTellClientWithResponse ( OSObject * object, void * context )
4554 {
4555 struct context *theContext = (struct context *)context;
4556 IOPowerStateChangeNotification notify;
4557 UInt32 refcon;
4558 IOReturn retCode;
4559 OSObject *theFlag;
4560
4561 refcon = ((theContext->serialNumber & 0xFFFF)<<16) + (theContext->counter & 0xFFFF);
4562 theContext->responseFlags->setObject(theContext->counter, kOSBooleanFalse);
4563
4564 IOServicePM * pwrMgt = theContext->us->pwrMgt;
4565 if (gIOKitDebug & kIOLogPower) {
4566 OUR_PMLog(kPMLogClientNotify, refcon, (UInt32) theContext->msgType);
4567 if (OSDynamicCast(IOService, object)) {
4568 const char *who = ((IOService *) object)->getName();
4569 fPlatform->PMLog(who,
4570 kPMLogClientNotify, * (UInt32 *) object, (UInt32) object);
4571 } else if (OSDynamicCast(_IOServiceInterestNotifier, object)) {
4572 _IOServiceInterestNotifier *n = (_IOServiceInterestNotifier *) object;
4573 OUR_PMLog(kPMLogClientNotify, (UInt32) n->handler, 0);
4574 }
4575 }
4576
4577 notify.powerRef = (void *)refcon;
4578 notify.returnValue = 0;
4579 notify.stateNumber = theContext->stateNumber;
4580 notify.stateFlags = theContext->stateFlags;
4581 retCode = theContext->us->messageClient(theContext->msgType,object,(void *)¬ify);
4582 if ( retCode == kIOReturnSuccess )
4583 {
4584 if ( notify.returnValue == 0 )
4585 {
4586 // client doesn't want time to respond
4587 theContext->responseFlags->replaceObject(theContext->counter, kOSBooleanTrue);
4588 OUR_PMLog(kPMLogClientAcknowledge, refcon, (UInt32) object);
4589 } else {
4590 // it does want time, and it hasn't responded yet
4591 theFlag = theContext->responseFlags->getObject(theContext->counter);
4592 if ( kOSBooleanTrue != theFlag )
4593 {
4594 // so note its time requirement
4595 if ( theContext->maxTimeRequested < notify.returnValue )
4596 {
4597 theContext->maxTimeRequested = notify.returnValue;
4598 }
4599 }
4600 }
4601 } else {
4602 OUR_PMLog(kPMLogClientAcknowledge, refcon, 0);
4603 // not a client of ours
4604 // so we won't be waiting for response
4605 theContext->responseFlags->replaceObject(theContext->counter, kOSBooleanTrue);
4606 }
4607 theContext->counter += 1;
4608 }
4609
4610 //*********************************************************************************
4611 // [public virtual] tellNoChangeDown
4612 //
4613 // Notify registered applications and kernel clients that we are not
4614 // dropping power.
4615 //
4616 // Subclass can override this to send a different message type. Parameter is
4617 // the aborted destination state number.
4618 //*********************************************************************************
4619
4620 void IOService::tellNoChangeDown ( unsigned long )
4621 {
4622 return tellClients( kIOMessageDeviceWillNotPowerOff );
4623 }
4624
4625 //*********************************************************************************
4626 // [public virtual] tellChangeUp
4627 //
4628 // Notify registered applications and kernel clients that we are raising power.
4629 //
4630 // Subclass can override this to send a different message type. Parameter is
4631 // the aborted destination state number.
4632 //*********************************************************************************
4633
4634 void IOService::tellChangeUp ( unsigned long )
4635 {
4636 return tellClients( kIOMessageDeviceHasPoweredOn );
4637 }
4638
4639 //*********************************************************************************
4640 // [public] tellClients
4641 //
4642 // Notify registered applications and kernel clients of something.
4643 //*********************************************************************************
4644
4645 void IOService::tellClients ( int messageType )
4646 {
4647 struct context theContext;
4648
4649 theContext.msgType = messageType;
4650 theContext.us = this;
4651 theContext.stateNumber = fHeadNoteState;
4652 theContext.stateFlags = fHeadNoteCapabilityFlags;
4653
4654 applyToInterested(gIOPriorityPowerStateInterest,tellClient,(void *)&theContext);
4655 applyToInterested(gIOAppPowerStateInterest,tellClient, (void *)&theContext);
4656 applyToInterested(gIOGeneralInterest,tellClient, (void *)&theContext);
4657 }
4658
4659 //*********************************************************************************
4660 // [global] tellClient
4661 //
4662 // Notify a registered application or kernel client of something.
4663 //*********************************************************************************
4664
4665 void tellClient ( OSObject * object, void * context )
4666 {
4667 struct context * theContext = (struct context *) context;
4668 IOPowerStateChangeNotification notify;
4669
4670 notify.powerRef = (void *) 0;
4671 notify.returnValue = 0;
4672 notify.stateNumber = theContext->stateNumber;
4673 notify.stateFlags = theContext->stateFlags;
4674
4675 theContext->us->messageClient(theContext->msgType, object, ¬ify);
4676 }
4677
4678 //*********************************************************************************
4679 // [private] checkForDone
4680 //*********************************************************************************
4681
4682 bool IOService::checkForDone ( void )
4683 {
4684 int i = 0;
4685 OSObject * theFlag;
4686
4687 if ( fResponseArray == NULL )
4688 {
4689 return true;
4690 }
4691
4692 for ( i = 0; ; i++ )
4693 {
4694 theFlag = fResponseArray->getObject(i);
4695 if ( theFlag == NULL )
4696 {
4697 break;
4698 }
4699 if ( kOSBooleanTrue != theFlag )
4700 {
4701 return false;
4702 }
4703 }
4704 return true;
4705 }
4706
4707 //*********************************************************************************
4708 // [public] responseValid
4709 //*********************************************************************************
4710
4711 bool IOService::responseValid ( unsigned long x, int pid )
4712 {
4713 UInt16 serialComponent;
4714 UInt16 ordinalComponent;
4715 OSObject * theFlag;
4716 unsigned long refcon = (unsigned long) x;
4717
4718 serialComponent = (refcon >> 16) & 0xFFFF;
4719 ordinalComponent = (refcon & 0xFFFF);
4720
4721 if ( serialComponent != fSerialNumber )
4722 {
4723 return false;
4724 }
4725
4726 if ( fResponseArray == NULL )
4727 {
4728 return false;
4729 }
4730
4731 theFlag = fResponseArray->getObject(ordinalComponent);
4732
4733 if ( theFlag == 0 )
4734 {
4735 return false;
4736 }
4737
4738 OSNumber * num;
4739 if ((num = OSDynamicCast(OSNumber, theFlag)))
4740 {
4741 #if LOG_APP_RESPONSE_TIMES
4742 AbsoluteTime now;
4743 AbsoluteTime start;
4744 uint64_t nsec;
4745
4746 clock_get_uptime(&now);
4747 AbsoluteTime_to_scalar(&start) = num->unsigned64BitValue();
4748 SUB_ABSOLUTETIME(&now, &start);
4749 absolutetime_to_nanoseconds(now, &nsec);
4750
4751 // > 100 ms
4752 if (nsec > LOG_APP_RESPONSE_TIMES)
4753 {
4754 OSString * name = IOCopyLogNameForPID(pid);
4755 PM_DEBUG("PM response took %d ms (%s)\n", NS_TO_MS(nsec),
4756 name ? name->getCStringNoCopy() : "");
4757 if (name)
4758 name->release();
4759 }
4760 #endif
4761 theFlag = kOSBooleanFalse;
4762 }
4763
4764 if ( kOSBooleanFalse == theFlag )
4765 {
4766 fResponseArray->replaceObject(ordinalComponent, kOSBooleanTrue);
4767 }
4768
4769 return true;
4770 }
4771
4772 //*********************************************************************************
4773 // [public virtual] allowPowerChange
4774 //
4775 // Our power state is about to lower, and we have notified applications
4776 // and kernel clients, and one of them has acknowledged. If this is the last to do
4777 // so, and all acknowledgements are positive, we continue with the power change.
4778 //
4779 // We serialize this processing with timer expiration with a command gate on the
4780 // power management workloop, which the timer expiration is command gated to as well.
4781 //*********************************************************************************
4782
4783 IOReturn IOService::allowPowerChange ( unsigned long refcon )
4784 {
4785 IOPMRequest * request;
4786
4787 if ( !initialized )
4788 {
4789 // we're unloading
4790 return kIOReturnSuccess;
4791 }
4792
4793 request = acquirePMRequest( this, kIOPMRequestTypeAllowPowerChange );
4794 if (!request)
4795 {
4796 PM_ERROR("%s::%s no memory\n", getName(), __FUNCTION__);
4797 return kIOReturnNoMemory;
4798 }
4799
4800 request->fArg0 = (void *) refcon;
4801 request->fArg1 = (void *) proc_selfpid();
4802 submitPMRequest( request );
4803
4804 return kIOReturnSuccess;
4805 }
4806
4807 IOReturn serializedAllowPowerChange ( OSObject *owner, void * refcon, void *, void *, void *)
4808 {
4809 // [deprecated] public
4810 return kIOReturnUnsupported;
4811 }
4812
4813 IOReturn IOService::serializedAllowPowerChange2 ( unsigned long refcon )
4814 {
4815 // [deprecated] public
4816 return kIOReturnUnsupported;
4817 }
4818
4819 //*********************************************************************************
4820 // [public virtual] cancelPowerChange
4821 //
4822 // Our power state is about to lower, and we have notified applications
4823 // and kernel clients, and one of them has vetoed the change. If this is the last
4824 // client to respond, we abandon the power change.
4825 //
4826 // We serialize this processing with timer expiration with a command gate on the
4827 // power management workloop, which the timer expiration is command gated to as well.
4828 //*********************************************************************************
4829
4830 IOReturn IOService::cancelPowerChange ( unsigned long refcon )
4831 {
4832 IOPMRequest * request;
4833
4834 if ( !initialized )
4835 {
4836 // we're unloading
4837 return kIOReturnSuccess;
4838 }
4839
4840 request = acquirePMRequest( this, kIOPMRequestTypeCancelPowerChange );
4841 if (!request)
4842 {
4843 PM_ERROR("%s::%s no memory\n", getName(), __FUNCTION__);
4844 return kIOReturnNoMemory;
4845 }
4846
4847 request->fArg0 = (void *) refcon;
4848 request->fArg1 = (void *) proc_selfpid();
4849 submitPMRequest( request );
4850
4851 return kIOReturnSuccess;
4852 }
4853
4854 IOReturn serializedCancelPowerChange ( OSObject *owner, void * refcon, void *, void *, void *)
4855 {
4856 // [deprecated] public
4857 return kIOReturnUnsupported;
4858 }
4859
4860 IOReturn IOService::serializedCancelPowerChange2 ( unsigned long refcon )
4861 {
4862 // [deprecated] public
4863 return kIOReturnUnsupported;
4864 }
4865
4866 #if 0
4867 //*********************************************************************************
4868 // c_PM_clamp_Timer_Expired (C Func)
4869 //
4870 // Called when our clamp timer expires...we will call the object method.
4871 //*********************************************************************************
4872
4873 static void c_PM_Clamp_Timer_Expired ( OSObject * client, IOTimerEventSource * )
4874 {
4875 if (client)
4876 ((IOService *)client)->PM_Clamp_Timer_Expired ();
4877 }
4878 #endif
4879
4880 //*********************************************************************************
4881 // PM_Clamp_Timer_Expired
4882 //
4883 // called when clamp timer expires...set power state to 0.
4884 //*********************************************************************************
4885
4886 void IOService::PM_Clamp_Timer_Expired ( void )
4887 {
4888 #if 0
4889 if ( ! initialized )
4890 {
4891 // we're unloading
4892 return;
4893 }
4894
4895 changePowerStateToPriv (0);
4896 #endif
4897 }
4898
4899 //*********************************************************************************
4900 // clampPowerOn
4901 //
4902 // Set to highest available power state for a minimum of duration milliseconds
4903 //*********************************************************************************
4904
4905 #define kFiveMinutesInNanoSeconds (300 * NSEC_PER_SEC)
4906
4907 void IOService::clampPowerOn ( unsigned long duration )
4908 {
4909 #if 0
4910 changePowerStateToPriv (fNumberOfPowerStates-1);
4911
4912 if ( pwrMgt->clampTimerEventSrc == NULL ) {
4913 pwrMgt->clampTimerEventSrc = IOTimerEventSource::timerEventSource(this,
4914 c_PM_Clamp_Timer_Expired);
4915
4916 IOWorkLoop * workLoop = getPMworkloop ();
4917
4918 if ( !pwrMgt->clampTimerEventSrc || !workLoop ||
4919 ( workLoop->addEventSource( pwrMgt->clampTimerEventSrc) != kIOReturnSuccess) ) {
4920
4921 }
4922 }
4923
4924 pwrMgt->clampTimerEventSrc->setTimeout(300*USEC_PER_SEC, USEC_PER_SEC);
4925 #endif
4926 }
4927
4928 //*********************************************************************************
4929 // [public virtual] setPowerState
4930 //
4931 // Does nothing here. This should be implemented in a subclass driver.
4932 //*********************************************************************************
4933
4934 IOReturn IOService::setPowerState (
4935 unsigned long powerStateOrdinal, IOService * whatDevice )
4936 {
4937 return IOPMNoErr;
4938 }
4939
4940 //*********************************************************************************
4941 // [public virtual] maxCapabilityForDomainState
4942 //
4943 // Finds the highest power state in the array whose input power
4944 // requirement is equal to the input parameter. Where a more intelligent
4945 // decision is possible, override this in the subclassed driver.
4946 //*********************************************************************************
4947
4948 unsigned long IOService::maxCapabilityForDomainState ( IOPMPowerFlags domainState )
4949 {
4950 int i;
4951
4952 if (fNumberOfPowerStates == 0 )
4953 {
4954 return 0;
4955 }
4956 for ( i = fNumberOfPowerStates - 1; i >= 0; i-- )
4957 {
4958 if ( (domainState & fPowerStates[i].inputPowerRequirement) ==
4959 fPowerStates[i].inputPowerRequirement )
4960 {
4961 return i;
4962 }
4963 }
4964 return 0;
4965 }
4966
4967 //*********************************************************************************
4968 // [public virtual] initialPowerStateForDomainState
4969 //
4970 // Finds the highest power state in the array whose input power
4971 // requirement is equal to the input parameter. Where a more intelligent
4972 // decision is possible, override this in the subclassed driver.
4973 //*********************************************************************************
4974
4975 unsigned long IOService::initialPowerStateForDomainState ( IOPMPowerFlags domainState )
4976 {
4977 int i;
4978
4979 if (fNumberOfPowerStates == 0 )
4980 {
4981 return 0;
4982 }
4983 for ( i = fNumberOfPowerStates - 1; i >= 0; i-- )
4984 {
4985 if ( (domainState & fPowerStates[i].inputPowerRequirement) ==
4986 fPowerStates[i].inputPowerRequirement )
4987 {
4988 return i;
4989 }
4990 }
4991 return 0;
4992 }
4993
4994 //*********************************************************************************
4995 // [public virtual] powerStateForDomainState
4996 //
4997 // Finds the highest power state in the array whose input power
4998 // requirement is equal to the input parameter. Where a more intelligent
4999 // decision is possible, override this in the subclassed driver.
5000 //*********************************************************************************
5001
5002 unsigned long IOService::powerStateForDomainState ( IOPMPowerFlags domainState )
5003 {
5004 int i;
5005
5006 if (fNumberOfPowerStates == 0 )
5007 {
5008 return 0;
5009 }
5010 for ( i = fNumberOfPowerStates - 1; i >= 0; i-- )
5011 {
5012 if ( (domainState & fPowerStates[i].inputPowerRequirement) ==
5013 fPowerStates[i].inputPowerRequirement )
5014 {
5015 return i;
5016 }
5017 }
5018 return 0;
5019 }
5020
5021 //*********************************************************************************
5022 // [public virtual] didYouWakeSystem
5023 //
5024 // Does nothing here. This should be implemented in a subclass driver.
5025 //*********************************************************************************
5026
5027 bool IOService::didYouWakeSystem ( void )
5028 {
5029 return false;
5030 }
5031
5032 //*********************************************************************************
5033 // [public virtual] powerStateWillChangeTo
5034 //
5035 // Does nothing here. This should be implemented in a subclass driver.
5036 //*********************************************************************************
5037
5038 IOReturn IOService::powerStateWillChangeTo ( IOPMPowerFlags, unsigned long, IOService * )
5039 {
5040 return kIOPMAckImplied;
5041 }
5042
5043 //*********************************************************************************
5044 // [public virtual] powerStateDidChangeTo
5045 //
5046 // Does nothing here. This should be implemented in a subclass driver.
5047 //*********************************************************************************
5048
5049 IOReturn IOService::powerStateDidChangeTo ( IOPMPowerFlags, unsigned long, IOService * )
5050 {
5051 return kIOPMAckImplied;
5052 }
5053
5054 //*********************************************************************************
5055 // [public virtual] powerChangeDone
5056 //
5057 // Called from PM work loop thread.
5058 // Does nothing here. This should be implemented in a subclass policy-maker.
5059 //*********************************************************************************
5060
5061 void IOService::powerChangeDone ( unsigned long )
5062 {
5063 }
5064
5065 //*********************************************************************************
5066 // [public virtual] newTemperature
5067 //
5068 // Does nothing here. This should be implemented in a subclass driver.
5069 //*********************************************************************************
5070
5071 IOReturn IOService::newTemperature ( long currentTemp, IOService * whichZone )
5072 {
5073 return IOPMNoErr;
5074 }
5075
5076 //*********************************************************************************
5077 // [public virtual] systemWillShutdown
5078 //
5079 // System shutdown and restart notification.
5080 //*********************************************************************************
5081
5082 void IOService::systemWillShutdown( IOOptionBits specifier )
5083 {
5084 IOPMrootDomain * rootDomain = IOService::getPMRootDomain();
5085 if (rootDomain)
5086 rootDomain->acknowledgeSystemWillShutdown( this );
5087 }
5088
5089 //*********************************************************************************
5090 // [private static] acquirePMRequest
5091 //*********************************************************************************
5092
5093 IOPMRequest *
5094 IOService::acquirePMRequest( IOService * target, IOOptionBits requestType )
5095 {
5096 IOPMRequest * request;
5097
5098 assert(target);
5099
5100 request = IOPMRequest::create();
5101 if (request)
5102 {
5103 request->init( target, requestType );
5104 }
5105 return request;
5106 }
5107
5108 //*********************************************************************************
5109 // [private static] releasePMRequest
5110 //*********************************************************************************
5111
5112 void IOService::releasePMRequest( IOPMRequest * request )
5113 {
5114 if (request)
5115 {
5116 request->reset();
5117 request->release();
5118 }
5119 }
5120
5121 //*********************************************************************************
5122 // [private] submitPMRequest
5123 //*********************************************************************************
5124
5125 void IOService::submitPMRequest( IOPMRequest * request )
5126 {
5127 assert( request );
5128 assert( gIOPMReplyQueue );
5129 assert( gIOPMRequestQueue );
5130
5131 PM_TRACE("[+ %02lx] %p [%p %s] %p %p %p\n",
5132 request->getType(), request,
5133 request->getTarget(), request->getTarget()->getName(),
5134 request->fArg0, request->fArg1, request->fArg2);
5135
5136 if (request->isReply())
5137 gIOPMReplyQueue->queuePMRequest( request );
5138 else
5139 gIOPMRequestQueue->queuePMRequest( request );
5140 }
5141
5142 void IOService::submitPMRequest( IOPMRequest ** requests, IOItemCount count )
5143 {
5144 assert( requests );
5145 assert( count > 0 );
5146 assert( gIOPMRequestQueue );
5147
5148 for (IOItemCount i = 0; i < count; i++)
5149 {
5150 IOPMRequest * req = requests[i];
5151 PM_TRACE("[+ %02lx] %p [%p %s] %p %p %p\n",
5152 req->getType(), req,
5153 req->getTarget(), req->getTarget()->getName(),
5154 req->fArg0, req->fArg1, req->fArg2);
5155 }
5156
5157 gIOPMRequestQueue->queuePMRequestChain( requests, count );
5158 }
5159
5160 //*********************************************************************************
5161 // [private] servicePMRequestQueue
5162 //*********************************************************************************
5163
5164 bool IOService::servicePMRequestQueue(
5165 IOPMRequest * request,
5166 IOPMRequestQueue * queue )
5167 {
5168 // Calling PM methods without PMinit() is not allowed, fail the requests.
5169
5170 if (!initialized)
5171 {
5172 PM_DEBUG("[%s] %s: PM not initialized\n", getName(), __FUNCTION__);
5173 goto done;
5174 }
5175
5176 // Create an IOPMWorkQueue on demand, when the initial PM request is
5177 // received.
5178
5179 if (!fPMWorkQueue)
5180 {
5181 // Allocate and attach an IOPMWorkQueue on demand to avoid taking
5182 // the work loop lock in PMinit(), which may deadlock with certain
5183 // drivers / families.
5184
5185 fPMWorkQueue = IOPMWorkQueue::create(
5186 /* target */ this,
5187 /* Work */ OSMemberFunctionCast(IOPMWorkQueue::Action, this,
5188 &IOService::servicePMRequest),
5189 /* Done */ OSMemberFunctionCast(IOPMWorkQueue::Action, this,
5190 &IOService::retirePMRequest)
5191 );
5192
5193 if (fPMWorkQueue &&
5194 (gIOPMWorkLoop->addEventSource(fPMWorkQueue) != kIOReturnSuccess))
5195 {
5196 PM_ERROR("[%s] %s: addEventSource failed\n",
5197 getName(), __FUNCTION__);
5198 fPMWorkQueue->release();
5199 fPMWorkQueue = 0;
5200 }
5201
5202 if (!fPMWorkQueue)
5203 {
5204 PM_ERROR("[%s] %s: not ready (type %02lx)\n",
5205 getName(), __FUNCTION__, request->getType());
5206 goto done;
5207 }
5208 }
5209
5210 fPMWorkQueue->queuePMRequest(request);
5211 return false; // do not signal more
5212
5213 done:
5214 gIOPMFreeQueue->queuePMRequest( request );
5215 return false; // do not signal more
5216 }
5217
5218 //*********************************************************************************
5219 // [private] servicePMFreeQueue
5220 //
5221 // Called by IOPMFreeQueue to recycle a completed request.
5222 //*********************************************************************************
5223
5224 bool IOService::servicePMFreeQueue(
5225 IOPMRequest * request,
5226 IOPMRequestQueue * queue )
5227 {
5228 bool more = request->hasParentRequest();
5229 releasePMRequest( request );
5230 return more;
5231 }
5232
5233 //*********************************************************************************
5234 // [private] retirePMRequest
5235 //
5236 // Called by IOPMWorkQueue to retire a completed request.
5237 //*********************************************************************************
5238
5239 bool IOService::retirePMRequest( IOPMRequest * request, IOPMWorkQueue * queue )
5240 {
5241 assert(request && queue);
5242
5243 PM_TRACE("[- %02lx] %p [%p %s] State %ld, Busy %ld\n",
5244 request->getType(), request, this, getName(),
5245 fMachineState, gIOPMBusyCount);
5246
5247 // Catch requests created by PM_idle_timer_expiration().
5248
5249 if ((request->getType() == kIOPMRequestTypeActivityTickle) &&
5250 (request->fArg1 == (void *) false))
5251 {
5252 // Idle timer power drop request completed.
5253 // Restart the idle timer if deviceDesire can go lower, otherwise set
5254 // a flag so we know to restart idle timer when deviceDesire goes up.
5255
5256 if (fDeviceDesire > 0)
5257 start_PM_idle_timer();
5258 else
5259 fActivityTimerStopped = true;
5260 }
5261
5262 gIOPMFreeQueue->queuePMRequest( request );
5263 return true;
5264 }
5265
5266 //*********************************************************************************
5267 // [private] isPMBlocked
5268 //
5269 // Check if machine state transition is blocked.
5270 //*********************************************************************************
5271
5272 bool IOService::isPMBlocked ( IOPMRequest * request, int count )
5273 {
5274 int reason = 0;
5275
5276 do {
5277 if (kIOPM_Finished == fMachineState)
5278 break;
5279
5280 if (kIOPM_DriverThreadCallDone == fMachineState)
5281 {
5282 // 5 = kDriverCallInformPreChange
5283 // 6 = kDriverCallInformPostChange
5284 // 7 = kDriverCallSetPowerState
5285 if (fDriverCallBusy) reason = 5 + fDriverCallReason;
5286 break;
5287 }
5288
5289 // Waiting on driver's setPowerState() timeout.
5290 if (fDriverTimer)
5291 {
5292 reason = 1; break;
5293 }
5294
5295 // Child or interested driver acks pending.
5296 if (fHeadNotePendingAcks)
5297 {
5298 reason = 2; break;
5299 }
5300
5301 // Waiting on apps or priority power interest clients.
5302 if (fResponseArray)
5303 {
5304 reason = 3; break;
5305 }
5306
5307 // Waiting on settle timer expiration.
5308 if (fSettleTimeUS)
5309 {
5310 reason = 4; break;
5311 }
5312 } while (false);
5313
5314 fWaitReason = reason;
5315
5316 if (reason)
5317 {
5318 if (count)
5319 {
5320 PM_TRACE("[B %02lx] %p [%p %s] State %ld, Reason %d\n",
5321 request->getType(), request, this, getName(),
5322 fMachineState, reason);
5323 }
5324
5325 return true;
5326 }
5327
5328 return false;
5329 }
5330
5331 //*********************************************************************************
5332 // [private] servicePMRequest
5333 //
5334 // Service a request from our work queue.
5335 //*********************************************************************************
5336
5337 bool IOService::servicePMRequest( IOPMRequest * request, IOPMWorkQueue * queue )
5338 {
5339 bool done = false;
5340 int loop = 0;
5341
5342 assert(request && queue);
5343
5344 while (isPMBlocked(request, loop++) == false)
5345 {
5346 PM_TRACE("[W %02lx] %p [%p %s] State %ld\n",
5347 request->getType(), request, this, getName(), fMachineState);
5348
5349 fPMRequest = request;
5350
5351 // Every PM machine states must be handled in one of the cases below.
5352
5353 switch ( fMachineState )
5354 {
5355 case kIOPM_Finished:
5356 executePMRequest( request );
5357 break;
5358
5359 case kIOPM_OurChangeTellClientsPowerDown:
5360 // our change, was it vetoed?
5361 if (fDesiredPowerState > fHeadNoteState)
5362 {
5363 PM_DEBUG("%s: idle cancel\n", fName);
5364 fDoNotPowerDown = true;
5365 }
5366 if (!fDoNotPowerDown)
5367 {
5368 // no, we can continue
5369 OurChangeTellClientsPowerDown();
5370 }
5371 else
5372 {
5373 // yes, rescind the warning
5374 tellNoChangeDown(fHeadNoteState);
5375 // mark the change note un-actioned
5376 fHeadNoteFlags |= IOPMNotDone;
5377 // and we're done
5378 all_done();
5379 }
5380 break;
5381
5382 case kIOPM_OurChangeTellPriorityClientsPowerDown:
5383 OurChangeTellPriorityClientsPowerDown();
5384 break;
5385
5386 case kIOPM_OurChangeNotifyInterestedDriversWillChange:
5387 OurChangeNotifyInterestedDriversWillChange();
5388 break;
5389
5390 case kIOPM_OurChangeSetPowerState:
5391 OurChangeSetPowerState();
5392 break;
5393
5394 case kIOPM_OurChangeWaitForPowerSettle:
5395 OurChangeWaitForPowerSettle();
5396 break;
5397
5398 case kIOPM_OurChangeNotifyInterestedDriversDidChange:
5399 OurChangeNotifyInterestedDriversDidChange();
5400 break;
5401
5402 case kIOPM_OurChangeFinish:
5403 OurChangeFinish();
5404 break;
5405
5406 case kIOPM_ParentDownTellPriorityClientsPowerDown:
5407 ParentDownTellPriorityClientsPowerDown();
5408 break;
5409
5410 case kIOPM_ParentDownNotifyInterestedDriversWillChange:
5411 ParentDownNotifyInterestedDriversWillChange();
5412 break;
5413
5414 case kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange:
5415 ParentDownNotifyDidChangeAndAcknowledgeChange();
5416 break;
5417
5418 case kIOPM_ParentDownSetPowerState:
5419 ParentDownSetPowerState();
5420 break;
5421
5422 case kIOPM_ParentDownWaitForPowerSettle:
5423 ParentDownWaitForPowerSettle();
5424 break;
5425
5426 case kIOPM_ParentDownAcknowledgeChange:
5427 ParentDownAcknowledgeChange();
5428 break;
5429
5430 case kIOPM_ParentUpSetPowerState:
5431 ParentUpSetPowerState();
5432 break;
5433
5434 case kIOPM_ParentUpWaitForSettleTime:
5435 ParentUpWaitForSettleTime();
5436 break;
5437
5438 case kIOPM_ParentUpNotifyInterestedDriversDidChange:
5439 ParentUpNotifyInterestedDriversDidChange();
5440 break;
5441
5442 case kIOPM_ParentUpAcknowledgePowerChange:
5443 ParentUpAcknowledgePowerChange();
5444 break;
5445
5446 case kIOPM_DriverThreadCallDone:
5447 if (fDriverCallReason == kDriverCallSetPowerState)
5448 notifyControllingDriverDone();
5449 else
5450 notifyInterestedDriversDone();
5451 break;
5452
5453 case kIOPM_NotifyChildrenDone:
5454 notifyChildrenDone();
5455 break;
5456
5457 default:
5458 IOPanic("servicePMWorkQueue: unknown machine state");
5459 }
5460
5461 fPMRequest = 0;
5462
5463 if (fMachineState == kIOPM_Finished)
5464 {
5465 //PM_TRACE("[%s] PM End: Request %p (type %02lx)\n",
5466 // getName(), request, request->getType());
5467 done = true;
5468 break;
5469 }
5470 }
5471
5472 return done;
5473 }
5474
5475 //*********************************************************************************
5476 // [private] executePMRequest
5477 //*********************************************************************************
5478
5479 void IOService::executePMRequest( IOPMRequest * request )
5480 {
5481 assert( kIOPM_Finished == fMachineState );
5482
5483 switch (request->getType())
5484 {
5485 case kIOPMRequestTypePMStop:
5486 handlePMstop( request );
5487 break;
5488
5489 case kIOPMRequestTypeAddPowerChild1:
5490 addPowerChild1( request );
5491 break;
5492
5493 case kIOPMRequestTypeAddPowerChild2:
5494 addPowerChild2( request );
5495 break;
5496
5497 case kIOPMRequestTypeAddPowerChild3:
5498 addPowerChild3( request );
5499 break;
5500
5501 case kIOPMRequestTypeRegisterPowerDriver:
5502 handleRegisterPowerDriver( request );
5503 break;
5504
5505 case kIOPMRequestTypeAdjustPowerState:
5506 adjustPowerState();
5507 break;
5508
5509 case kIOPMRequestTypeMakeUsable:
5510 handleMakeUsable( request );
5511 break;
5512
5513 case kIOPMRequestTypeTemporaryPowerClamp:
5514 fClampOn = true;
5515 handleMakeUsable( request );
5516 break;
5517
5518 case kIOPMRequestTypePowerDomainWillChange:
5519 handlePowerDomainWillChangeTo( request );
5520 break;
5521
5522 case kIOPMRequestTypePowerDomainDidChange:
5523 handlePowerDomainDidChangeTo( request );
5524 break;
5525
5526 case kIOPMRequestTypeChangePowerStateTo:
5527 handleChangePowerStateTo( request );
5528 break;
5529
5530 case kIOPMRequestTypeChangePowerStateToPriv:
5531 handleChangePowerStateToPriv( request );
5532 break;
5533
5534 case kIOPMRequestTypePowerOverrideOnPriv:
5535 case kIOPMRequestTypePowerOverrideOffPriv:
5536 handlePowerOverrideChanged( request );
5537 break;
5538
5539 case kIOPMRequestTypeActivityTickle:
5540 if (request)
5541 {
5542 bool setDeviceDesire = false;
5543
5544 if (request->fArg1)
5545 {
5546 // power rise
5547 if (fDeviceDesire < (unsigned long) request->fArg0)
5548 setDeviceDesire = true;
5549 }
5550 else if (fDeviceDesire)
5551 {
5552 // power drop and deviceDesire is not zero
5553 request->fArg0 = (void *) (fDeviceDesire - 1);
5554 setDeviceDesire = true;
5555 }
5556
5557 if (setDeviceDesire)
5558 {
5559 // handleChangePowerStateToPriv() does not check the
5560 // request type, as long as the args are appropriate
5561 // for kIOPMRequestTypeChangePowerStateToPriv.
5562
5563 request->fArg1 = (void *) false;
5564 handleChangePowerStateToPriv( request );
5565 }
5566 }
5567 break;
5568
5569 default:
5570 IOPanic("executePMRequest: unknown request type");
5571 }
5572 }
5573
5574 //*********************************************************************************
5575 // [private] servicePMReplyQueue
5576 //*********************************************************************************
5577
5578 bool IOService::servicePMReplyQueue( IOPMRequest * request, IOPMRequestQueue * queue )
5579 {
5580 bool more = false;
5581
5582 assert( request && queue );
5583 assert( request->isReply() );
5584
5585 PM_TRACE("[A %02lx] %p [%p %s] State %ld\n",
5586 request->getType(), request, this, getName(), fMachineState);
5587
5588 switch ( request->getType() )
5589 {
5590 case kIOPMRequestTypeAllowPowerChange:
5591 case kIOPMRequestTypeCancelPowerChange:
5592 // Check if we are expecting this response.
5593 if (responseValid((unsigned long) request->fArg0, (int) request->fArg1))
5594 {
5595 if (kIOPMRequestTypeCancelPowerChange == request->getType())
5596 fDoNotPowerDown = true;
5597
5598 if (checkForDone())
5599 {
5600 stop_ack_timer();
5601 if ( fResponseArray )
5602 {
5603 fResponseArray->release();
5604 fResponseArray = NULL;
5605 }
5606 more = true;
5607 }
5608 }
5609 break;
5610
5611 case kIOPMRequestTypeAckPowerChange:
5612 more = handleAcknowledgePowerChange( request );
5613 break;
5614
5615 case kIOPMRequestTypeAckSetPowerState:
5616 if (fDriverTimer == -1)
5617 {
5618 // driver acked while setPowerState() call is in-flight.
5619 // take this ack, return value from setPowerState() is irrelevant.
5620 OUR_PMLog(kPMLogDriverAcknowledgeSet,
5621 (UInt32) this, fDriverTimer);
5622 fDriverTimer = 0;
5623 }
5624 else if (fDriverTimer > 0)
5625 {
5626 // expected ack, stop the timer
5627 stop_ack_timer();
5628
5629 #if LOG_SETPOWER_TIMES
5630 uint64_t nsec = computeTimeDeltaNS(&fDriverCallStartTime);
5631 if (nsec > LOG_SETPOWER_TIMES)
5632 PM_DEBUG("%s::setPowerState(%p, %lu -> %lu) async took %d ms\n",
5633 fName, this, fCurrentPowerState, fHeadNoteState, NS_TO_MS(nsec));
5634 #endif
5635 OUR_PMLog(kPMLogDriverAcknowledgeSet, (UInt32) this, fDriverTimer);
5636 fDriverTimer = 0;
5637 more = true;
5638 }
5639 else
5640 {
5641 // unexpected ack
5642 OUR_PMLog(kPMLogAcknowledgeErr4, (UInt32) this, 0);
5643 }
5644 break;
5645
5646 case kIOPMRequestTypeInterestChanged:
5647 handleInterestChanged( request );
5648 more = true;
5649 break;
5650
5651 default:
5652 IOPanic("servicePMReplyQueue: unknown reply type");
5653 }
5654
5655 releasePMRequest( request );
5656 return more;
5657 }
5658
5659 //*********************************************************************************
5660 // IOPMRequest Class
5661 //
5662 // Requests from PM clients, and also used for inter-object messaging within PM.
5663 //*********************************************************************************
5664
5665 OSDefineMetaClassAndStructors( IOPMRequest, IOCommand );
5666
5667 IOPMRequest * IOPMRequest::create( void )
5668 {
5669 IOPMRequest * me = OSTypeAlloc(IOPMRequest);
5670 if (me && !me->init(0, kIOPMRequestTypeInvalid))
5671 {
5672 me->release();
5673 me = 0;
5674 }
5675 return me;
5676 }
5677
5678 bool IOPMRequest::init( IOService * target, IOOptionBits type )
5679 {
5680 if (!IOCommand::init())
5681 return false;
5682
5683 fType = type;
5684 fTarget = target;
5685 fParent = 0;
5686 fChildCount = 0;
5687 fArg0 = fArg1 = fArg2 = 0;
5688
5689 if (fTarget)
5690 fTarget->retain();
5691
5692 return true;
5693 }
5694
5695 void IOPMRequest::reset( void )
5696 {
5697 assert( fChildCount == 0 );
5698
5699 fType = kIOPMRequestTypeInvalid;
5700
5701 if (fParent)
5702 {
5703 fParent->fChildCount--;
5704 fParent = 0;
5705 }
5706
5707 if (fTarget)
5708 {
5709 fTarget->release();
5710 fTarget = 0;
5711 }
5712 }
5713
5714 //*********************************************************************************
5715 // IOPMRequestQueue Class
5716 //
5717 // Global queues. As PM-aware drivers load and unload, their IOPMWorkQueue's are
5718 // created and deallocated. IOPMRequestQueue are created once and never released.
5719 //*********************************************************************************
5720
5721 OSDefineMetaClassAndStructors( IOPMRequestQueue, IOEventSource );
5722
5723 IOPMRequestQueue * IOPMRequestQueue::create( IOService * inOwner, Action inAction )
5724 {
5725 IOPMRequestQueue * me = OSTypeAlloc(IOPMRequestQueue);
5726 if (me && !me->init(inOwner, inAction))
5727 {
5728 me->release();
5729 me = 0;
5730 }
5731 return me;
5732 }
5733
5734 bool IOPMRequestQueue::init( IOService * inOwner, Action inAction )
5735 {
5736 if (!inAction || !IOEventSource::init(inOwner, (IOEventSourceAction)inAction))
5737 return false;
5738
5739 queue_init(&fQueue);
5740 fLock = IOLockAlloc();
5741 return (fLock != 0);
5742 }
5743
5744 void IOPMRequestQueue::free( void )
5745 {
5746 if (fLock)
5747 {
5748 IOLockFree(fLock);
5749 fLock = 0;
5750 }
5751 return IOEventSource::free();
5752 }
5753
5754 void IOPMRequestQueue::queuePMRequest( IOPMRequest * request )
5755 {
5756 assert(request);
5757 IOLockLock(fLock);
5758 queue_enter(&fQueue, request, IOPMRequest *, fCommandChain);
5759 IOLockUnlock(fLock);
5760 if (workLoop) signalWorkAvailable();
5761 }
5762
5763 void
5764 IOPMRequestQueue::queuePMRequestChain( IOPMRequest ** requests, IOItemCount count )
5765 {
5766 IOPMRequest * next;
5767
5768 assert(requests && count);
5769 IOLockLock(fLock);
5770 while (count--)
5771 {
5772 next = *requests;
5773 requests++;
5774 queue_enter(&fQueue, next, IOPMRequest *, fCommandChain);
5775 }
5776 IOLockUnlock(fLock);
5777 if (workLoop) signalWorkAvailable();
5778 }
5779
5780 bool IOPMRequestQueue::checkForWork( void )
5781 {
5782 Action dqAction = (Action) action;
5783 IOPMRequest * request;
5784 IOService * target;
5785 bool more = false;
5786
5787 IOLockLock( fLock );
5788
5789 while (!queue_empty(&fQueue))
5790 {
5791 queue_remove_first( &fQueue, request, IOPMRequest *, fCommandChain );
5792 IOLockUnlock( fLock );
5793 target = request->getTarget();
5794 assert(target);
5795 more |= (*dqAction)( target, request, this );
5796 IOLockLock( fLock );
5797 }
5798
5799 IOLockUnlock( fLock );
5800 return more;
5801 }
5802
5803 void IOPMRequestQueue::signalWorkAvailable( void )
5804 {
5805 IOEventSource::signalWorkAvailable();
5806 }
5807
5808 //*********************************************************************************
5809 // IOPMWorkQueue Class
5810 //
5811 // Every object in the power plane that has handled a PM request, will have an
5812 // instance of IOPMWorkQueue allocated for it.
5813 //*********************************************************************************
5814
5815 OSDefineMetaClassAndStructors( IOPMWorkQueue, IOEventSource );
5816
5817 IOPMWorkQueue *
5818 IOPMWorkQueue::create( IOService * inOwner, Action work, Action retire )
5819 {
5820 IOPMWorkQueue * me = OSTypeAlloc(IOPMWorkQueue);
5821 if (me && !me->init(inOwner, work, retire))
5822 {
5823 me->release();
5824 me = 0;
5825 }
5826 return me;
5827 }
5828
5829 bool IOPMWorkQueue::init( IOService * inOwner, Action work, Action retire )
5830 {
5831 if (!work || !retire ||
5832 !IOEventSource::init(inOwner, (IOEventSourceAction)0))
5833 return false;
5834
5835 queue_init(&fWorkQueue);
5836
5837 fWorkAction = work;
5838 fRetireAction = retire;
5839
5840 return true;
5841 }
5842
5843 void IOPMWorkQueue::queuePMRequest( IOPMRequest * request )
5844 {
5845 assert( request );
5846 assert( onThread() );
5847
5848 gIOPMBusyCount++;
5849 queue_enter(&fWorkQueue, request, IOPMRequest *, fCommandChain);
5850 checkForWork();
5851 }
5852
5853 bool IOPMWorkQueue::checkForWork( void )
5854 {
5855 IOPMRequest * request;
5856 IOService * target = (IOService *) owner;
5857 bool done;
5858
5859 while (!queue_empty(&fWorkQueue))
5860 {
5861 request = (IOPMRequest *) queue_first(&fWorkQueue);
5862 assert(request->getTarget() == target);
5863 if (request->hasChildRequest()) break;
5864 done = (*fWorkAction)( target, request, this );
5865 if (!done) break;
5866
5867 assert(gIOPMBusyCount > 0);
5868 if (gIOPMBusyCount) gIOPMBusyCount--;
5869 queue_remove_first(&fWorkQueue, request, IOPMRequest *, fCommandChain);
5870 (*fRetireAction)( target, request, this );
5871 }
5872
5873 return false;
5874 }
5875
5876 OSDefineMetaClassAndStructors(IOServicePM, OSObject)
5877
5878 //*********************************************************************************
5879 // serialize
5880 //
5881 // Serialize IOServicePM for debugging.
5882 //*********************************************************************************
5883
5884 static void
5885 setPMProperty( OSDictionary * dict, const char * key, unsigned long value )
5886 {
5887 OSNumber * num = OSNumber::withNumber(value, sizeof(value) * 8);
5888 if (num)
5889 {
5890 dict->setObject(key, num);
5891 num->release();
5892 }
5893 }
5894
5895 bool IOServicePM::serialize( OSSerialize * s ) const
5896 {
5897 OSDictionary * dict;
5898 bool ok = false;
5899
5900 dict = OSDictionary::withCapacity(8);
5901 if (dict)
5902 {
5903 setPMProperty( dict, "CurrentPowerState", CurrentPowerState );
5904 if (DesiredPowerState != CurrentPowerState)
5905 setPMProperty( dict, "DesiredPowerState", DesiredPowerState );
5906 if (kIOPM_Finished != MachineState)
5907 setPMProperty( dict, "MachineState", MachineState );
5908 if (ChildrenDesire)
5909 setPMProperty( dict, "ChildrenPowerState", ChildrenDesire );
5910 if (DeviceDesire)
5911 setPMProperty( dict, "DeviceChangePowerState", DeviceDesire );
5912 if (DriverDesire)
5913 setPMProperty( dict, "DriverChangePowerState", DriverDesire );
5914 if (DeviceOverrides)
5915 dict->setObject( "PowerOverrideOn", kOSBooleanTrue );
5916
5917 ok = dict->serialize(s);
5918 dict->release();
5919 }
5920
5921 return ok;
5922 }
Cache object: fff00687e6b563d6f4e0de87fae943ab
|