|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: #include <IOKit/IOService.h> ! 23: #include <IOKit/IOLib.h> ! 24: #include <IOKit/IOCommandQueue.h> ! 25: #include <IOKit/IOTimerEventSource.h> ! 26: #include <IOKit/IOWorkLoop.h> ! 27: #include <IOKit/IOPlatformExpert.h> ! 28: #include <IOKit/assert.h> ! 29: #include "IOKit/pwr_mgt/IOPMpmChild.h" ! 30: #include "IOKit/pwr_mgt/IOPMinformeeList.h" ! 31: #include "IOKit/pwr_mgt/IOPMchangeNoteList.h" ! 32: #include "IOKit/pwr_mgt/IOPMlog.h" ! 33: ! 34: static void ack_timer_expired(thread_call_param_t, thread_call_param_t); ! 35: static void settle_timer_expired(thread_call_param_t, thread_call_param_t); ! 36: void PMreceiveCmd ( OSObject *, void *, void *, void *, void * ); ! 37: static void PM_idle_timer_expired(OSObject *, IOTimerEventSource *); ! 38: ! 39: extern const IORegistryPlane * gIOPowerPlane; ! 40: ! 41: ! 42: // and there's 1000 nanosecons in a microsecond: ! 43: #define ns_per_us 1000 ! 44: ! 45: ! 46: // The current change note is processed by a state machine. ! 47: // Inputs are acks from interested parties, ack from the controlling driver, ! 48: // ack timeouts, settle timeout, and powerStateDidChange from the parent. ! 49: // These are the states: ! 50: ! 51: #define IOPMour_prechange_1 1 ! 52: #define IOPMour_prechange_2 2 ! 53: #define IOPMour_prechange_3 3 ! 54: #define IOPMour_prechange_4 4 ! 55: #define IOPMparent_prechange_down_3 5 ! 56: #define IOPMparent_prechange_down_4 6 ! 57: #define IOPMparent_prechange_down_5 7 ! 58: #define IOPMparent_postchange_down_1 8 ! 59: #define IOPMparent_postchange_down_2 9 ! 60: #define IOPMparent_prechange_up_1 10 ! 61: #define IOPMparent_postchange_up_1 11 ! 62: #define IOPMparent_postchange_up_4 12 ! 63: #define IOPMparent_postchange_up_5 13 ! 64: #define IOPMparent_postchange_up_6 14 ! 65: #define IOPMparent_postchange_null 15 ! 66: #define IOPMfinished 16 ! 67: ! 68: /* ! 69: There are two different kinds of power state changes. One is initiated by a subclassed device object which has either ! 70: decided to change power state, or its controlling driver has suggested it, or some other driver wants to use the ! 71: idle device and has asked it to become usable. The second kind of power state change is initiated by the power ! 72: domain parent. The two are handled slightly differently. ! 73: ! 74: There is a queue of so-called change notifications, or change notes for short. Usually the queue is empty, and when ! 75: it isn't, usually there is one change note in it, but since it's possible to have more than one power state change pending ! 76: at one time, a queue is implemented. Example: the subclass device decides it's idle and initiates a change to a lower ! 77: power state. This causes interested parties to be notified, but they don't all acknowledge right away. This causes the ! 78: change note to sit in the queue until all the acks are received. During this time, the device decides it isn't idle anymore and ! 79: wants to raise power back up again. This change can't be started, however, because the previous one isn't complete yet, ! 80: so the second one waits in the queue. During this time, the parent decides to lower or raise the power state of the entire ! 81: power domain and notifies the device, and that notification goes into the queue, too, and can't be actioned until the ! 82: others are. ! 83: ! 84: This is how a power change initiated by the subclass device is handled: ! 85: First, all interested parties are notified of the change via their powerStateWillChangeTo method. If they all don't ! 86: acknowledge via return code, then we have to wait. If they do, or when they finally all acknowledge via our ! 87: acknowledgePowerChange method, then we can continue. We call the controlling driver, instructing it to change to ! 88: the new state. Then we wait for power to settle. If there is no settling-time, or after it has passed, we notify ! 89: interested parties again, this time via their powerStateDidChangeTo methods. When they have all acked, we're done. ! 90: If we lowered power and don't need the power domain to be in its current power state, we suggest to the parent that ! 91: it lower the power domain state. ! 92: ! 93: This is how a change to a lower power domain state initiated by the parent is handled: ! 94: First, we figure out what power state we will be in when the new domain state is reached. Then all interested parties are ! 95: notified that we are moving to that new state. When they have acknowledged, we call the controlling driver to assume ! 96: that state and we wait for power to settle. Then we acknowledge our preparedness to our parent. When all its interested ! 97: parties have acknowledged, it lowers power and then notifies its interested parties again. When we get this call, we notify ! 98: our interested parties that the power state has changed, and when they have all acknowledged, we're done. ! 99: ! 100: This is how a change to a higher power domain state initiated by the parent is handled: ! 101: We figure out what power state we will be in when the new domain state is reached. If it is different from our current ! 102: state we notify all our interested parties. When they have all acknowledged, we acknowledge the parent. When all the ! 103: parent's interested parties have acknowledged, it raises power in the domain and waits for power to settle. Then it ! 104: notifies everyone that the new state has been reached. When we get this call, we call the controlling driver, instructing it ! 105: to assume the new state, and wait for power to settle. Then we notify our interested parties. When they all acknowledge ! 106: we are done. ! 107: ! 108: In either of the two cases above, it is possible that we will not be changing state even though the domain is. Examples: ! 109: A change to a lower domain state may not affect us because we are already in a low enough state, and ! 110: We will not take advantage of a change to a higher domain state, because we have no need of the higher power. ! 111: In such a case, there is nothing to do but acknowledge the parent. So when the parent calls our powerDomainWillChange ! 112: method, and we decide that we will not be changing state, we merely acknowledge the parent, via return code, and wait. ! 113: When the parent subsequently calls powerStateDidChange, we acknowledge again via return code, and the change is complete. ! 114: ! 115: Power state changes are processed in a state machine, and since there are four varieties of power state changes, there are ! 116: four major paths through the state machine: ! 117: ! 118: The fourth is nearly trivial. In this path, the parent is changing the domain state, but we are not changing the device state. ! 119: The change starts when the parent calls powerDomainWillChange. All we do is acknowledge the parent and enter the "IOPMparent_postchange" state. We wait there until the parent calls powerStateDidChange. Then we acknowledge the parent ! 120: again, and we're done. ! 121: ! 122: The first is fairly simple. It starts when a power domain child calls requestDomainState and we decide to change power states ! 123: to accomodate the child, or if our power-controlling driver calls changeStateTo, or if some other driver which is using our ! 124: device calls makeUsable, or if a subclassed object calls changeStateToPriv. These are all power changes initiated by us, not ! 125: forced upon us by the parent. We start by notifying interested parties. If they all acknowledge via return code, we can go ! 126: on to state "our_prechange_1". Otherwise, we start the ack timer and wait for the stragglers to acknowlege by calling ! 127: acknowledgePowerChange. We move on to state "our_prechange_1" when all the stragglers have acknowledged, ! 128: or when the ack timer expires on all those which didn't acknowledge. In "our_prechange_1" we call the power-controlling ! 129: driver to change the power state of the hardware. If it returns saying it has done so, we go on to state "our_prechange_2". ! 130: Otherwise, we have to wait for it, so we set the ack timer and wait. When it calls acknowledgeSetPowerState, or when the ! 131: ack timer expires, we go on. In "our_prechange_2", we look in the power state array to see if there is any settle time required ! 132: when changing from our current state to the new state. If not, we go right away to "our_prechange_3". Otherwise, we ! 133: set the settle timer and wait. When it expires, we move on. In "our_prechange_3" state, we notify all our interested parties ! 134: via their powerStateDidChange methods that we have finished changing power state. If they all acknowledge via return ! 135: code, we move on to "our_prechange_4". Otherwise we set the ack timer and wait. When they have all acknowledged, or ! 136: when the ack timer has expired for those that didn't, we move on to "our_prechange_4", where we remove the used ! 137: change note from the head of the queue and start the next one if one exists. ! 138: ! 139: Parent-initiated changes are more complex in the state machine. First, power going up and power going down are handled ! 140: differently, so they have different paths throught the state machine. Second, we can acknowledge the parent's notification ! 141: in two different ways, so each of the parent paths is really two. ! 142: ! 143: When the parent calls our powerDomainWillChange method, notifying us that it will lower power in the domain, we decide ! 144: what state that will put our device in. Then we embark on the state machine path "IOPMparent_prechange_down_1" ! 145: and "IOPMparent_prechange_down_2", in which we notify interested parties of the upcoming change, ! 146: instruct our driver to make the change, and check for settle time. If we get to the end of this path without ! 147: stalling due to an interested party which didn't acknowledge via return code, due to the controlling driver not able to change ! 148: state right away, or due to a non-zero settling time, then we return IOPMAckImplied to the parent and enter ! 149: "IOPMparent_postchange_down_1". If we do stall in any of those states, we return IOPMWillAckLater to the parent ! 150: and enter the parallel path "IOPMparent_prechange_down_4", "IOPMparent_prechange_down_5", and "IOPMparent_prechange_down_3", where we continue with the same processing, except that at the end we ! 151: acknowledge the parent explicitly via acknowledgePowerChange and enter "IOPMparent_postchange_down_1". ! 152: In "IOPMparent_postchange_down_1" we wait for the parent to lower power in the domain. When it calls us at ! 153: powerStateDidChange, we notify all our interested parties of the new power state. If they all acknowledge via return ! 154: code, we return to the parent, also acknowledging via return code. Otherwise we enter "parent_postchange_down_2", ! 155: waiting for acknowledgements. When they all arrive, or when the acknowledgement timer expires for all stragglers, we ! 156: explicitly acknowledge the parent via acknowledgePowerChange. In either case, we are done, and we remove the used ! 157: change note from the head of the queue and start on the next one. ! 158: ! 159: The case of the parent raising power in the domain is handled similarly in that there are parallel paths, one for no-stall ! 160: that ends in implicit acknowleging the parent, and one that has stalled at least once that ends in explicit acknowledging ! 161: the parent. This case is different, though in that our device changes state in the second half, after the parent calls ! 162: powerStateDidChange rather than before, as in the power-lowering case. ! 163: ! 164: As usual, we start by notifying our interested parties. If they all acknowledge via return code, we acknowledge the parent ! 165: via return code and enter "IOPMparent_postchange_up_1". If they don't, we wait in "parent_prechange_up_1" for them to ! 166: acknowledge or for the ack timer to expire on the stragglers. Then we acknowledge the parent via acknowledgePowerChange ! 167: and enter "IOPMparent_postchange_up_1", waiting for the parent to raise power and notify us. When the parent calls us ! 168: at powerStateDidChange, we instruct the power-controlling driver to change to the new higher state, we check for any ! 169: necessary settling time in "IOPMparent_postchange_up_2", and we notify all interested parties that power has changed ! 170: in "IOPMparent_postchange_up_3". If none of these operations stall, we acknowledge the parent via return code, release ! 171: the change note, and start the next, if there is one. If one of them does stall, we enter the parallel path ! 172: "IOPMparent_postchange_up_4", "IOPMparent_postchange_up_5", and "IOPMparent_postchange_up_6", which ends with ! 173: our explicit acknowledgement to the parent. ! 174: ! 175: */ ! 176: ! 177: ! 178: const char priv_key[ ] = "Power Management private data"; ! 179: const char prot_key[ ] = "Power Management protected data"; ! 180: ! 181: ! 182: void IOService::PMinit ( void ) ! 183: { ! 184: if ( ! initialized ) { ! 185: ! 186: pm_vars = new IOPMprot; // make space for our variables ! 187: priv = new IOPMpriv; ! 188: pm_vars->init(); ! 189: priv->init(); ! 190: ! 191: setProperty(prot_key, (OSObject *) pm_vars); // add these to the properties ! 192: setProperty(priv_key, (OSObject *) priv); ! 193: ! 194: initialized = true; ! 195: priv->owner = this; ! 196: pm_vars->theNumberOfPowerStates = 0; // then initialize them ! 197: pm_vars->myParent = NULL; ! 198: priv->we_are_root = false; ! 199: pm_vars->theControllingDriver = NULL; ! 200: priv->our_lock = IOLockAlloc(); ! 201: priv->interestedDrivers = new IOPMinformeeList; ! 202: priv->interestedDrivers->initialize(); ! 203: priv->children = new IOPMinformeeList; ! 204: priv->children->initialize(); ! 205: priv->numberOfInformees = 0; ! 206: priv->changeList = new IOPMchangeNoteList; ! 207: priv->changeList->initialize(); ! 208: pm_vars->aggressiveness = 0; ! 209: pm_vars->myCurrentState = 0; ! 210: priv->imminentState = 0; ! 211: priv->askingFor = 0; ! 212: priv->ourDesiredPowerState = 0; ! 213: pm_vars->parentCurrentPowerFlags = 0; ! 214: pm_vars->maxCapability = 0; ! 215: priv->driverDesire = 0; ! 216: priv->deviceDesire = 0; ! 217: priv->initial_change = true; ! 218: priv->need_to_become_usable = false; ! 219: priv->previousRequest = 0; ! 220: priv->device_overrides = false; ! 221: priv->machine_state = IOPMfinished; ! 222: pm_vars->commandQueue = NULL; ! 223: priv->timerEventSrc = NULL; ! 224: pm_vars->PMworkloop = NULL; ! 225: priv->activityLock = NULL; ! 226: pm_vars->ourName = getName(); ! 227: pm_vars->thePlatform = getPlatform(); ! 228: assert( pm_vars->thePlatform != 0 ); ! 229: } ! 230: } ! 231: ! 232: ! 233: //********************************************************************************* ! 234: // PMstop ! 235: // ! 236: // Free up the data created in PMinit. ! 237: //********************************************************************************* ! 238: void IOService::PMstop ( void ) ! 239: { ! 240: initialized = false; ! 241: ! 242: removeProperty(prot_key); // remove the properties ! 243: removeProperty(priv_key); ! 244: priv->interestedDrivers->release(); // remove lists ! 245: priv->children->release(); ! 246: priv->changeList->release(); ! 247: pm_vars->release(); // remove the instance variables ! 248: priv->release(); ! 249: pm_vars = NULL; ! 250: priv = NULL; ! 251: } ! 252: ! 253: ! 254: //********************************************************************************* ! 255: // joinPMtree ! 256: // ! 257: // A policy-maker calls its nub here when initializing, to be attached into ! 258: // the power management hierarchy. The default function is to call the ! 259: // platform expert, which knows how to do it. This method is overridden ! 260: // by a nub subclass which may either know how to do it, or may need ! 261: // to take other action. ! 262: // ! 263: // This may be the only "power management" method used in a nub, ! 264: // meaning it may not be initialized for power management. ! 265: //********************************************************************************* ! 266: void IOService::joinPMtree ( IOService * driver ) ! 267: { ! 268: IOPlatformExpert * thePlatform; ! 269: ! 270: thePlatform = getPlatform(); ! 271: assert(thePlatform != 0 ); ! 272: thePlatform->PMRegisterDevice(this,driver); ! 273: } ! 274: ! 275: ! 276: //********************************************************************************* ! 277: // youAreRoot ! 278: // ! 279: // Power Managment is informing us that we are the root power domain. ! 280: // The only difference between us and any other power domain is that ! 281: // we have no parent and therefore never call it. ! 282: //********************************************************************************* ! 283: IOReturn IOService::youAreRoot ( void ) ! 284: { ! 285: priv-> we_are_root = true; ! 286: pm_vars->myParent = (IOService *)1; // we won't use this, but keep it non-NULL ! 287: return IOPMNoErr; ! 288: } ! 289: ! 290: ! 291: //********************************************************************************* ! 292: // setParent ! 293: // ! 294: // Power Management is informing us who our parent is. ! 295: // If we have a controlling driver, find out, given our newly-informed ! 296: // power domain state, what state it would be in, and then tell it ! 297: // to assume that state. ! 298: //********************************************************************************* ! 299: IOReturn IOService::setParent ( IOService * theParent, IOPMPowerFlags currentState ) ! 300: { ! 301: unsigned long tempDesire; ! 302: ! 303: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogSetParent,(unsigned long)currentState,0); ! 304: ! 305: attachToParent( theParent, gIOPowerPlane); ! 306: pm_vars->myParent = theParent; ! 307: pm_vars->parentCurrentPowerFlags = currentState; ! 308: if ( pm_vars->theControllingDriver != NULL ) { ! 309: pm_vars->maxCapability = pm_vars->theControllingDriver->maxCapabilityForDomainState(pm_vars->parentCurrentPowerFlags); ! 310: tempDesire = priv->deviceDesire; // initially change into the state we are already in ! 311: priv->deviceDesire = pm_vars->theControllingDriver->initialPowerStateForDomainState(pm_vars->parentCurrentPowerFlags); ! 312: changeState(); ! 313: priv->deviceDesire = tempDesire; // put this back like before ! 314: } ! 315: return IOPMNoErr; ! 316: } ! 317: ! 318: ! 319: //********************************************************************************* ! 320: // addChild ! 321: // ! 322: // Power Management is informing us who our children are. ! 323: //********************************************************************************* ! 324: IOReturn IOService::addChild ( IOService * theChild ) ! 325: { ! 326: IOPMinformee * newChild; ! 327: IOPMPowerFlags capability; ! 328: ! 329: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAddChild,0,0); ! 330: ! 331: theChild->retain(); ! 332: ! 333: newChild = new IOPMpmChild; ! 334: newChild->initialize(theChild); // make a new child ! 335: priv->children->addToList(newChild); // add it to list of children ! 336: priv->numberOfInformees = priv->children->numberOfItems() + priv->interestedDrivers->numberOfItems(); ! 337: if ( pm_vars->theControllingDriver == NULL ) { // tell it the current state of the power domain ! 338: capability = 0; ! 339: } ! 340: else { ! 341: capability = pm_vars->thePowerStates[pm_vars->myCurrentState].outputPowerCharacter; ! 342: } ! 343: theChild->setParent(this,capability); ! 344: theChild->setAggressiveness (kPMGeneralAggressiveness,pm_vars->aggressiveness); // tell it the current aggressiveness ! 345: add_to_active_change(newChild, true); // catch it up if change is in progress ! 346: return IOPMNoErr; ! 347: } ! 348: ! 349: ! 350: //********************************************************************************* ! 351: // removeChild ! 352: // ! 353: //********************************************************************************* ! 354: IOReturn IOService::removeChild ( IOService * theChild ) ! 355: { ! 356: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogRemoveChild,0,0); ! 357: ! 358: priv->children->removeFromList(theChild); // remove the departing child ! 359: priv->numberOfInformees = priv->children->numberOfItems() + priv->interestedDrivers->numberOfItems(); ! 360: ! 361: if ( (pm_vars->theControllingDriver == NULL) || // if not fully initialized ! 362: (pm_vars->myParent == NULL) ) { ! 363: return IOPMNoErr; // we can do no more ! 364: } ! 365: ! 366: changeState(); // change state if we can now tolerate lower power ! 367: ! 368: return IOPMNoErr; ! 369: } ! 370: ! 371: ! 372: //********************************************************************************* ! 373: // registerControllingDriver ! 374: // ! 375: // A driver has called us volunteering to control power to our device. ! 376: // If the power state array it provides is richer than the one we already ! 377: // know about (supplied by an earlier volunteer), then accept the offer. ! 378: // Notify all interested parties of our power state, which we now know. ! 379: //********************************************************************************* ! 380: ! 381: IOReturn IOService::registerControllingDriver ( IOService * controllingDriver, IOPMPowerState* powerStates, unsigned long numberOfStates ) ! 382: { ! 383: unsigned long i; ! 384: unsigned long tempDesire; ! 385: ! 386: if ( (numberOfStates > pm_vars->theNumberOfPowerStates) && (numberOfStates > 1) ) { ! 387: if ( priv->changeList->currentChange() == -1 ) { ! 388: if ( controllingDriver != NULL ) { ! 389: if ( numberOfStates <= IOPMMaxPowerStates ) { ! 390: switch ( powerStates[0].version ) { ! 391: case 1: ! 392: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriver, ! 393: (unsigned long)numberOfStates, (unsigned long)powerStates[0].version); ! 394: for ( i = 0; i < numberOfStates; i++ ) { ! 395: pm_vars->thePowerStates[i] = powerStates[i]; ! 396: } ! 397: break; ! 398: case 2: ! 399: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriver, ! 400: (unsigned long) numberOfStates,(unsigned long) powerStates[0].version); ! 401: for ( i = 0; i < numberOfStates; i++ ) { ! 402: pm_vars->thePowerStates[i].version = powerStates[i].version; ! 403: pm_vars->thePowerStates[i].capabilityFlags = powerStates[i].capabilityFlags; ! 404: pm_vars->thePowerStates[i].outputPowerCharacter = powerStates[i].outputPowerCharacter; ! 405: pm_vars->thePowerStates[i].inputPowerRequirement = powerStates[i].inputPowerRequirement; ! 406: pm_vars->thePowerStates[i].staticPower = powerStates[i].staticPower; ! 407: pm_vars->thePowerStates[i].unbudgetedPower = powerStates[i].unbudgetedPower; ! 408: pm_vars->thePowerStates[i].powerToAttain = powerStates[i].powerToAttain; ! 409: pm_vars->thePowerStates[i].timeToAttain = powerStates[i].timeToAttain; ! 410: pm_vars->thePowerStates[i].settleUpTime = powerStates[i].settleUpTime; ! 411: pm_vars->thePowerStates[i].timeToLower = powerStates[i].timeToLower; ! 412: pm_vars->thePowerStates[i].settleDownTime = powerStates[i].settleDownTime; ! 413: pm_vars->thePowerStates[i].powerDomainBudget = powerStates[i].powerDomainBudget; ! 414: } ! 415: break; ! 416: default: ! 417: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriverErr1, ! 418: (unsigned long)powerStates[0].version,0); ! 419: return IOPMNoErr; ! 420: } ! 421: ! 422: pm_vars->theNumberOfPowerStates = numberOfStates; ! 423: pm_vars->theControllingDriver = controllingDriver; ! 424: if ( priv->interestedDrivers->findItem(controllingDriver) == NULL ) { // register it as interested ! 425: registerInterestedDriver (controllingDriver ); // unless already done ! 426: } ! 427: if ( priv->need_to_become_usable ) { ! 428: priv->need_to_become_usable = false; ! 429: priv->deviceDesire = pm_vars->theNumberOfPowerStates - 1; ! 430: } ! 431: if ( pm_vars->myParent != NULL ) { ! 432: pm_vars->maxCapability = pm_vars->theControllingDriver->maxCapabilityForDomainState(pm_vars->parentCurrentPowerFlags); ! 433: tempDesire = priv->deviceDesire; // initially change into the state we are already in ! 434: priv->deviceDesire = pm_vars->theControllingDriver->initialPowerStateForDomainState(pm_vars->parentCurrentPowerFlags); ! 435: changeState(); ! 436: priv->deviceDesire = tempDesire; // put this back like before ! 437: } ! 438: } ! 439: else { ! 440: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriverErr2,(unsigned long)numberOfStates,0); ! 441: } ! 442: } ! 443: else { ! 444: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriverErr4,0,0); ! 445: } ! 446: } ! 447: } ! 448: else { ! 449: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriverErr5,(unsigned long)numberOfStates,0); ! 450: } ! 451: return IOPMNoErr; ! 452: } ! 453: ! 454: //********************************************************************************* ! 455: // registerInterestedDriver ! 456: // ! 457: // Add the caller to our list of interested drivers and return our current ! 458: // power state. If we don't have a power-controlling driver yet, we will ! 459: // call this interested driver again later when we do get a driver and find ! 460: // out what the current power state of the device is. ! 461: //********************************************************************************* ! 462: ! 463: IOPMPowerFlags IOService::registerInterestedDriver ( IOService * theDriver ) ! 464: { ! 465: IOPMinformee * newInformee; ! 466: IOPMPowerFlags futureCapability; ! 467: ! 468: if (theDriver == NULL ) { ! 469: return 0; // can't tell it a state yet ! 470: } ! 471: ! 472: theDriver->retain(); ! 473: ! 474: newInformee = new IOPMinformee; // make new driver node ! 475: newInformee->initialize(theDriver); ! 476: priv->interestedDrivers->addToList(newInformee); // add it to list of drivers ! 477: priv->numberOfInformees = priv->children->numberOfItems() + priv->interestedDrivers->numberOfItems(); ! 478: ! 479: if ( (pm_vars->theControllingDriver == NULL) || (pm_vars->myParent == NULL) ) { ! 480: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogInterestedDriver,0,0); ! 481: return 0; // can't tell it a state yet ! 482: } ! 483: ! 484: switch (priv->machine_state) { // can we notify new driver of a change in progress? ! 485: case IOPMour_prechange_1: ! 486: case IOPMour_prechange_4: ! 487: case IOPMparent_prechange_down_4: ! 488: case IOPMparent_postchange_down_2: ! 489: case IOPMparent_prechange_up_1: ! 490: case IOPMparent_postchange_up_6: ! 491: futureCapability = priv->head_note_capabilityFlags; // yes, remember what we tell it ! 492: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogInterestedDriver,(unsigned long)futureCapability,0); ! 493: add_to_active_change(newInformee,false); // notify it ! 494: return futureCapability; // and return the same thing ! 495: } ! 496: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogInterestedDriver, ! 497: (unsigned long) pm_vars->thePowerStates[pm_vars->myCurrentState].capabilityFlags,0); ! 498: return pm_vars->thePowerStates[pm_vars->myCurrentState].capabilityFlags; // no, return current capability ! 499: } ! 500: ! 501: ! 502: //********************************************************************************* ! 503: // deRegisterInterestedDriver ! 504: // ! 505: //********************************************************************************* ! 506: IOReturn IOService::deRegisterInterestedDriver ( IOService * theDriver ) ! 507: { ! 508: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogRemoveDriver,0,0); ! 509: ! 510: priv->interestedDrivers->removeFromList(theDriver); // remove the departing driver ! 511: priv->numberOfInformees = priv->children->numberOfItems() + priv->interestedDrivers->numberOfItems(); ! 512: ! 513: theDriver->release(); ! 514: ! 515: return IOPMNoErr; ! 516: } ! 517: ! 518: ! 519: //********************************************************************************* ! 520: // acknowledgePowerChange ! 521: // ! 522: // After we notified one of the interested drivers or a power-domain child ! 523: // of an impending change in power, it has called to say it is now ! 524: // prepared for the change. If this object is the last to ! 525: // acknowledge this change, we take whatever action we have been waiting ! 526: // for. ! 527: // That may include acknowledging to our parent. In this case, we do it ! 528: // last of all to insure that this doesn't cause the parent to call us some- ! 529: // where else and alter data we are relying on here (like the very existance ! 530: // of a "current change note".) ! 531: //********************************************************************************* ! 532: ! 533: IOReturn IOService::acknowledgePowerChange ( IOService * whichObject ) ! 534: { ! 535: IOPMinformee * ackingObject; ! 536: ! 537: ackingObject = priv->interestedDrivers->findItem(whichObject); // one of our interested drivers? ! 538: if ( ackingObject == NULL ) { ! 539: ackingObject = priv->children->findItem(whichObject); // no, one of our children? ! 540: if ( ackingObject == NULL ) { ! 541: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr1,0,0); ! 542: return IOPMNoErr; // no, just return ! 543: } ! 544: else { ! 545: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChildAcknowledge,0,0); ! 546: } ! 547: } ! 548: else { ! 549: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogDriverAcknowledge,0,0); ! 550: } ! 551: ! 552: if (! acquire_lock() ) { ! 553: return IOPMNoErr; ! 554: } ! 555: ! 556: if (priv->head_note_pendingAcks != 0 ) { // yes, make sure we're expecting acks ! 557: if ( ackingObject->timer != 0 ) { // make sure we're expecting this ack ! 558: ackingObject->timer = 0; // mark it acked ! 559: priv->head_note_pendingAcks -= 1; // that's one fewer to worry about ! 560: if ( priv->head_note_pendingAcks == 0 ) { // is that the last? ! 561: stop_ack_timer(); // yes, stop the timer ! 562: IOUnlock(priv->our_lock); ! 563: all_acked(); // and now we can continue ! 564: return IOPMNoErr; ! 565: } ! 566: } ! 567: else { ! 568: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr2,0,0); // this object has already acked ! 569: } ! 570: } ! 571: else { ! 572: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr3,0,0); // not expecting anybody to ack ! 573: } ! 574: IOUnlock(priv->our_lock); ! 575: return IOPMNoErr; ! 576: } ! 577: ! 578: //********************************************************************************* ! 579: // acknowledgeSetPowerState ! 580: // ! 581: // After we instructed our controlling driver to change power states, ! 582: // it has called to say it has finished doing so. ! 583: // We continue to process the power state change. ! 584: //********************************************************************************* ! 585: ! 586: IOReturn IOService::acknowledgeSetPowerState ( void ) ! 587: { ! 588: if (! acquire_lock() ) { ! 589: return IOPMNoErr; ! 590: } ! 591: if ( priv->driver_timer == -1 ) { ! 592: priv->driver_timer = 0; // driver is acking instead of using return code ! 593: } ! 594: else { ! 595: if ( priv->driver_timer > 0 ) { // are we expecting this? ! 596: stop_ack_timer(); // yes, stop the timer ! 597: priv->driver_timer = 0; ! 598: IOUnlock(priv->our_lock); ! 599: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogDriverAcknowledgeSet,0,0); ! 600: driver_acked(); ! 601: return IOPMNoErr; ! 602: } ! 603: else { ! 604: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr4,0,0); // no ! 605: } ! 606: } ! 607: IOUnlock(priv->our_lock); ! 608: return IOPMNoErr; ! 609: } ! 610: ! 611: ! 612: //********************************************************************************* ! 613: // driver_acked ! 614: // ! 615: // Either the controlling driver has called acknowledgeSetPowerState ! 616: // or the acknowledgement timer has expired while waiting for that. ! 617: // We carry on processing the current change note. ! 618: //********************************************************************************* ! 619: ! 620: void IOService::driver_acked ( void ) ! 621: { ! 622: switch (priv->machine_state) { ! 623: case IOPMour_prechange_2: ! 624: our_prechange_2(); ! 625: break; ! 626: case IOPMparent_prechange_down_5: ! 627: parent_prechange_down_5(); ! 628: break; ! 629: case IOPMparent_postchange_up_4: ! 630: parent_postchange_up_4(); ! 631: break; ! 632: } ! 633: } ! 634: ! 635: ! 636: //********************************************************************************* ! 637: // powerDomainWillChangeTo ! 638: // ! 639: // Called by the power-hierarchy parent notifying of a new power state ! 640: // in the power domain. ! 641: // If power is going lower, we notify our interested parties that power ! 642: // will lower. When they have all acked, we lower the state of our device ! 643: // to the state appropriate for the coming domain level. Then we ack the parent. ! 644: // Later, when the domain has lowered, we notify everyone that power has dropped. ! 645: // ! 646: // If power is going higher and we will take advantage of this by raising our ! 647: // own power state, we notify our interested parties that power ! 648: // will raise. When they have all acked, we ack the parent. Later, when ! 649: // the domain has raised, we raise our power level. When power has ! 650: // settled, we inform our interested parties. When they have all acked, ! 651: // we ack the parent. ! 652: //********************************************************************************* ! 653: ! 654: IOReturn IOService::powerDomainWillChangeTo ( IOPMPowerFlags newPowerStateFlags ) ! 655: { ! 656: unsigned long newStateNumber; ! 657: ! 658: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogWillChange,(unsigned long)newPowerStateFlags,0); ! 659: ! 660: if ( pm_vars->myParent == NULL ) { ! 661: return IOPMAckImplied; // somebody goofed ! 662: } ! 663: ! 664: if ( pm_vars->theControllingDriver == NULL ) { ! 665: pm_vars->parentCurrentPowerFlags = newPowerStateFlags; // we can't take any action except note the change ! 666: return IOPMAckImplied; ! 667: } ! 668: newStateNumber = pm_vars->theControllingDriver->maxCapabilityForDomainState(newPowerStateFlags); ! 669: return enqueuePowerChange(IOPMParentInitiated, newStateNumber,newPowerStateFlags); // tell interested parties about it ! 670: } ! 671: ! 672: ! 673: //********************************************************************************* ! 674: // powerDomainDidChangeTo ! 675: // ! 676: // Called by the power-hierarchy parent after the power state of the power domain ! 677: // has settled at a new level. We must notify our interested drivers and children. ! 678: // If they all acknowledge immediately, so do we. Otherwise, we'll acknowledge ! 679: // when the last of them does. ! 680: //********************************************************************************* ! 681: ! 682: IOReturn IOService::powerDomainDidChangeTo ( IOPMPowerFlags newPowerStateFlags ) ! 683: { ! 684: ! 685: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogDidChange,(unsigned long)newPowerStateFlags,0); ! 686: ! 687: if ( (pm_vars->myParent == NULL) || (pm_vars->theControllingDriver == NULL) ) { ! 688: return IOPMAckImplied; // somebody goofed ! 689: } ! 690: ! 691: switch (priv->machine_state) { ! 692: case IOPMparent_postchange_down_1: ! 693: return parent_postchange_down_1(); // life-style 2 continues ! 694: case IOPMparent_postchange_up_1: ! 695: return parent_postchange_up_1(); // life-style 3 continues ! 696: case IOPMparent_postchange_null: ! 697: all_done(); ! 698: return IOPMAckImplied; // life-style 4 done ! 699: } ! 700: ! 701: return IOPMAckImplied; // something wrong ! 702: } ! 703: ! 704: ! 705: //********************************************************************************* ! 706: // requestDomainState ! 707: // ! 708: // ! 709: //********************************************************************************* ! 710: IOReturn IOService::requestDomainState ( IOPMPowerFlags desiredState, IOService* whichChild, unsigned long specification ) ! 711: { ! 712: unsigned long i; ! 713: IOPMinformee * nextChild; ! 714: ! 715: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogRequestDomain, ! 716: (unsigned long)desiredState,(unsigned long)specification); ! 717: ! 718: if ( pm_vars->theControllingDriver == NULL) { ! 719: return IOPMNotYetInitialized; ! 720: } ! 721: ! 722: switch (specification) { ! 723: case IOPMLowestState: ! 724: i = 0; ! 725: while ( i < pm_vars->theNumberOfPowerStates ) { ! 726: if ( ( pm_vars->thePowerStates[i].outputPowerCharacter & desiredState) == desiredState ) { ! 727: break; ! 728: } ! 729: i++; ! 730: } ! 731: if ( i >= pm_vars->theNumberOfPowerStates ) { ! 732: return IOPMNoSuchState; ! 733: } ! 734: break; ! 735: ! 736: case IOPMNextLowerState: ! 737: i = pm_vars->myCurrentState - 1; ! 738: while ( i >= 0 ) { ! 739: if ( ( pm_vars->thePowerStates[i].outputPowerCharacter & desiredState) == desiredState ) { ! 740: break; ! 741: } ! 742: i--; ! 743: } ! 744: if ( i < 0 ) { ! 745: return IOPMNoSuchState; ! 746: } ! 747: break; ! 748: ! 749: case IOPMHighestState: ! 750: i = pm_vars->theNumberOfPowerStates; ! 751: while ( i >= 0 ) { ! 752: i--; ! 753: if ( ( pm_vars->thePowerStates[i].outputPowerCharacter & desiredState) == desiredState ) { ! 754: break; ! 755: } ! 756: } ! 757: if ( i < 0 ) { ! 758: return IOPMNoSuchState; ! 759: } ! 760: break; ! 761: ! 762: case IOPMNextHigherState: ! 763: i = pm_vars->myCurrentState + 1; ! 764: while ( i < pm_vars->theNumberOfPowerStates ) { ! 765: if ( ( pm_vars->thePowerStates[i].outputPowerCharacter & desiredState) == desiredState ) { ! 766: break; ! 767: } ! 768: i++; ! 769: } ! 770: if ( i == pm_vars->theNumberOfPowerStates ) { ! 771: return IOPMNoSuchState; ! 772: } ! 773: break; ! 774: ! 775: default: ! 776: return IOPMBadSpecification; ! 777: } ! 778: ! 779: // Now loop through the children. When we encounter the calling child, save ! 780: // the new state as this child's desire. Then, compute a new maximum ! 781: // of everybody's desires. ! 782: ! 783: nextChild = priv->children->firstInList(); ! 784: ! 785: if ( nextChild == NULL ) { // we're not a power domain ! 786: return IOPMNoErr; ! 787: } ! 788: ! 789: while ( nextChild != NULL ) { ! 790: if ( whichChild == (IOService*)nextChild->whatObject ) { ! 791: ((IOPMpmChild *)nextChild)->desiredDomainState = i; ! 792: break; ! 793: } ! 794: nextChild = priv->children->nextInList(nextChild); ! 795: } ! 796: ! 797: if ( pm_vars->myParent != NULL ) { ! 798: changeState(); // change state if all children can now tolerate lower power ! 799: } ! 800: ! 801: return IOPMNoErr; ! 802: } ! 803: ! 804: ! 805: //********************************************************************************* ! 806: // makeUsable ! 807: // ! 808: // Some client of our device is asking that we become usable. Although ! 809: // this has not come from a subclassed device object, treat it exactly ! 810: // as if it had. In this way, subsequent requests for lower power from ! 811: // a subclassed device object will pre-empt this request. ! 812: // ! 813: // We treat this as a subclass object request to switch to the ! 814: // highest power state. ! 815: //********************************************************************************* ! 816: ! 817: IOReturn IOService::makeUsable ( void ) ! 818: { ! 819: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogMakeUsable,0,0); ! 820: ! 821: if ( pm_vars->theControllingDriver == NULL ) { ! 822: priv->need_to_become_usable = true; ! 823: return IOPMNoErr; ! 824: } ! 825: priv->deviceDesire = pm_vars->theNumberOfPowerStates - 1; ! 826: if ( pm_vars->myParent == NULL ) { ! 827: return IOPMNoErr; ! 828: } ! 829: return changeState(); ! 830: } ! 831: ! 832: ! 833: //********************************************************************************* ! 834: // currentCapability ! 835: // ! 836: //********************************************************************************* ! 837: ! 838: IOPMPowerFlags IOService::currentCapability ( void ) ! 839: { ! 840: if ( pm_vars->theControllingDriver == NULL ) { ! 841: return 0; ! 842: } ! 843: else { ! 844: return pm_vars->thePowerStates[pm_vars->myCurrentState].capabilityFlags; ! 845: } ! 846: } ! 847: ! 848: ! 849: //********************************************************************************* ! 850: // changeStateTo ! 851: // ! 852: // For some reason, our power-controlling driver has decided it needs to change ! 853: // power state. We enqueue the power change so that appropriate parties ! 854: // will be notified, and then we will instruct the driver to make the change. ! 855: //********************************************************************************* ! 856: ! 857: IOReturn IOService::changeStateTo ( unsigned long ordinal ) ! 858: { ! 859: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChangeStateTo,ordinal,0); ! 860: ! 861: if ( ordinal >= pm_vars->theNumberOfPowerStates ) { ! 862: return IOPMParameterError; ! 863: } ! 864: priv->driverDesire = ordinal; ! 865: if ( pm_vars->myParent == NULL ) { ! 866: return IOPMNoErr; ! 867: } ! 868: return changeState(); ! 869: } ! 870: ! 871: //********************************************************************************* ! 872: // changeStateToPriv ! 873: // ! 874: // For some reason, a subclassed device object has decided it needs to change ! 875: // power state. We enqueue the power change so that appropriate parties ! 876: // will be notified, and then we will instruct the driver to make the change. ! 877: //********************************************************************************* ! 878: ! 879: IOReturn IOService::changeStateToPriv ( unsigned long ordinal ) ! 880: { ! 881: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChangeStateToPriv,ordinal,0); ! 882: ! 883: if ( pm_vars->theControllingDriver == NULL) { ! 884: return IOPMNotYetInitialized; ! 885: } ! 886: if ( ordinal >= pm_vars->theNumberOfPowerStates ) { ! 887: return IOPMParameterError; ! 888: } ! 889: priv->deviceDesire = ordinal; ! 890: if ( pm_vars->myParent == NULL ) { ! 891: return IOPMNoErr; ! 892: } ! 893: return changeState(); ! 894: } ! 895: ! 896: ! 897: //********************************************************************************* ! 898: // changeState ! 899: // ! 900: // A subclass object, our controlling driver, or a power domain child ! 901: // has asked for a different power state. Here we compute what new ! 902: // state we should enter and enqueue the change (or start it). ! 903: //********************************************************************************* ! 904: ! 905: IOReturn IOService::changeState ( void ) ! 906: { ! 907: unsigned long newDesiredState = 0; ! 908: IOPMinformee * nextChild; ! 909: ! 910: // Compute the maximum of our children's desires, our controlling driver's desire, and the subclass device's desire. ! 911: ! 912: if ( ! priv->device_overrides ) { ! 913: nextChild = priv->children->firstInList(); ! 914: ! 915: while ( nextChild != NULL ) { ! 916: if ( (( IOPMpmChild *)nextChild)->desiredDomainState > newDesiredState ) { ! 917: newDesiredState =(( IOPMpmChild *)nextChild)->desiredDomainState; ! 918: } ! 919: nextChild = priv->children->nextInList(nextChild); ! 920: } ! 921: if ( priv->driverDesire > newDesiredState ) { ! 922: newDesiredState = priv->driverDesire; ! 923: } ! 924: } ! 925: ! 926: if ( priv->deviceDesire > newDesiredState ) { ! 927: newDesiredState = priv->deviceDesire; ! 928: } ! 929: ! 930: priv->ourDesiredPowerState = newDesiredState; ! 931: ! 932: return enqueuePowerChange(IOPMWeInitiated,newDesiredState,0); ! 933: } ! 934: ! 935: ! 936: //********************************************************************************* ! 937: // currentPowerConsumption ! 938: // ! 939: //********************************************************************************* ! 940: ! 941: unsigned long IOService::currentPowerConsumption ( void ) ! 942: { ! 943: if ( pm_vars->theControllingDriver == NULL ) { ! 944: return 0; ! 945: } ! 946: else { ! 947: return pm_vars->thePowerStates[pm_vars->myCurrentState].staticPower; ! 948: } ! 949: } ! 950: ! 951: //********************************************************************************* ! 952: // activityTickle ! 953: // ! 954: // The activity tickle with parameter kIOPMSubclassPolicyis not handled ! 955: // here and should have been intercepted by the subclass. ! 956: // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity ! 957: // flag to be set, and the device state checked. If the device has been ! 958: // powered down, it is powered up again. ! 959: //********************************************************************************* ! 960: ! 961: bool IOService::activityTickle ( unsigned long type, unsigned long stateNumber=0 ) ! 962: { ! 963: if ( type == kIOPMSuperclassPolicy1 ) { ! 964: if ( (priv->activityLock == NULL) || ! 965: (pm_vars->theControllingDriver == NULL) || ! 966: ( pm_vars->commandQueue == NULL) ) { ! 967: return true; ! 968: } ! 969: IOTakeLock(priv->activityLock); ! 970: priv->device_active = true; ! 971: if ( pm_vars->myCurrentState >= stateNumber) { ! 972: IOUnlock(priv->activityLock); ! 973: return true; ! 974: } ! 975: IOUnlock(priv->activityLock); // send a message on the command queue ! 976: pm_vars->commandQueue->enqueueCommand(true, (void *)kPMunIdleDevice, (void *)stateNumber); ! 977: return false; ! 978: } ! 979: return true; ! 980: } ! 981: ! 982: //********************************************************************************* ! 983: // getPMworkloop ! 984: // ! 985: // A child is calling to get a pointer to the Power Management workloop. ! 986: // We got it or get it from our parent. ! 987: //********************************************************************************* ! 988: ! 989: IOWorkLoop * IOService::getPMworkloop ( void ) ! 990: { ! 991: if ( pm_vars->myParent == NULL ) { ! 992: return NULL; ! 993: } ! 994: if ( pm_vars->PMworkloop == NULL ) { ! 995: pm_vars->PMworkloop = pm_vars->myParent->getPMworkloop(); ! 996: } ! 997: return pm_vars->PMworkloop; ! 998: } ! 999: ! 1000: ! 1001: //********************************************************************************* ! 1002: // setIdleTimerPeriod ! 1003: // ! 1004: // A subclass policy-maker is going to use our standard idleness ! 1005: // detection service. Make a command queue and an idle timer and ! 1006: // connect them to the power management workloop. Finally, ! 1007: // start the timer. ! 1008: //********************************************************************************* ! 1009: ! 1010: IOReturn IOService::setIdleTimerPeriod ( unsigned long period ) ! 1011: { ! 1012: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMsetIdleTimerPeriod,period, 0); ! 1013: ! 1014: priv->idle_timer_period = period; ! 1015: ! 1016: if ( period > 0 ) { ! 1017: if ( getPMworkloop() == NULL ) { ! 1018: return kIOReturnError; ! 1019: } ! 1020: ! 1021: if (pm_vars->commandQueue == NULL ) { // make the command queue ! 1022: pm_vars->commandQueue = IOCommandQueue::commandQueue(this, PMreceiveCmd); ! 1023: if (! pm_vars->commandQueue || ! 1024: ( pm_vars->PMworkloop->addEventSource( pm_vars->commandQueue) != kIOReturnSuccess) ) { ! 1025: return kIOReturnError; ! 1026: } ! 1027: } ! 1028: // make the timer event ! 1029: if ( priv->timerEventSrc == NULL ) { ! 1030: priv->timerEventSrc = IOTimerEventSource::timerEventSource(this, ! 1031: PM_idle_timer_expired); ! 1032: if ( ! priv->timerEventSrc || ! 1033: ( pm_vars->PMworkloop->addEventSource( priv->timerEventSrc) != kIOReturnSuccess) ) { ! 1034: return kIOReturnError; ! 1035: } ! 1036: } ! 1037: ! 1038: if ( priv->activityLock == NULL ) { ! 1039: priv->activityLock = IOLockAlloc(); ! 1040: } ! 1041: ! 1042: start_PM_idle_timer(); ! 1043: } ! 1044: return IOPMNoErr; ! 1045: } ! 1046: ! 1047: ! 1048: //********************************************************************************* ! 1049: // start_PM_idle_timer ! 1050: // ! 1051: // The parameter is a pointer to us. Use it to call our timeout method. ! 1052: //********************************************************************************* ! 1053: void IOService::start_PM_idle_timer ( void ) ! 1054: { ! 1055: priv->timerEventSrc->setTimeout(priv->idle_timer_period, NSEC_PER_SEC); ! 1056: } ! 1057: ! 1058: ! 1059: //********************************************************************************* ! 1060: // PM_idle_timer_expired ! 1061: // ! 1062: // The parameter is a pointer to us. Use it to call our timeout method. ! 1063: //********************************************************************************* ! 1064: ! 1065: void PM_idle_timer_expired(OSObject * ourSelves, IOTimerEventSource *) ! 1066: { ! 1067: ((IOService *)ourSelves)->PM_idle_timer_expiration(); ! 1068: } ! 1069: ! 1070: ! 1071: //********************************************************************************* ! 1072: // PM_idle_timer_expiration ! 1073: // ! 1074: // The idle timer has expired. If there has been activity since the last ! 1075: // expiration, just restart the timer and return. If there has not been ! 1076: // activity, switch to the next lower power state and restart the timer. ! 1077: //********************************************************************************* ! 1078: ! 1079: void IOService::PM_idle_timer_expiration ( void ) ! 1080: { ! 1081: if ( priv->idle_timer_period > 0 ) { ! 1082: IOTakeLock(priv->activityLock); ! 1083: if ( priv->device_active ) { ! 1084: priv->device_active = false; ! 1085: IOUnlock(priv->activityLock); ! 1086: start_PM_idle_timer(); ! 1087: return; ! 1088: } ! 1089: if (pm_vars->myCurrentState > 0 ) { ! 1090: IOUnlock(priv->activityLock); ! 1091: priv->askingFor = pm_vars->myCurrentState - 1; ! 1092: changeStateToPriv(pm_vars->myCurrentState - 1); ! 1093: start_PM_idle_timer(); ! 1094: return; ! 1095: } ! 1096: IOUnlock(priv->activityLock); ! 1097: start_PM_idle_timer(); ! 1098: } ! 1099: } ! 1100: ! 1101: ! 1102: ! 1103: // ********************************************************************************** ! 1104: // PMreceiveCmd ! 1105: // ! 1106: // ! 1107: // ! 1108: // ********************************************************************************** ! 1109: void PMreceiveCmd ( OSObject * theDriver, void * command, void * param1, void * param2, void *param3 ) ! 1110: { ! 1111: ((IOService *)theDriver)->command_received(command,param1,param2,param3); ! 1112: } ! 1113: ! 1114: ! 1115: // ********************************************************************************** ! 1116: // command_received ! 1117: // ! 1118: // We have received a command from ourselves on the command queue. ! 1119: // This is to prevent races with timer-expiration code. ! 1120: // ********************************************************************************** ! 1121: void IOService::command_received ( void * command, void *stateNumber , void * , void *) ! 1122: { ! 1123: if ( command == (void *)kPMunIdleDevice ) { ! 1124: if ((pm_vars->myCurrentState < (unsigned long)stateNumber) && ! 1125: (priv->imminentState < (unsigned long)stateNumber ) && ! 1126: ((unsigned long)stateNumber > priv->askingFor) ) { ! 1127: priv->askingFor = (unsigned long)stateNumber; ! 1128: changeStateToPriv((unsigned long)stateNumber); ! 1129: } ! 1130: } ! 1131: } ! 1132: ! 1133: ! 1134: //********************************************************************************* ! 1135: // setAggressiveness ! 1136: // ! 1137: // Pass on the input parameters to all power domain children. All those which are ! 1138: // power domains will pass it on to their children, etc. ! 1139: //********************************************************************************* ! 1140: ! 1141: IOReturn IOService::setAggressiveness ( unsigned long type, unsigned long newLevel ) ! 1142: { ! 1143: IOPMinformee * nextChild; ! 1144: ! 1145: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogSetAggressiveness,type, newLevel); ! 1146: ! 1147: if ( type == kPMGeneralAggressiveness ) { ! 1148: pm_vars->aggressiveness = newLevel; ! 1149: } ! 1150: ! 1151: nextChild = priv->children->firstInList(); ! 1152: ! 1153: while ( nextChild != NULL ) { ! 1154: nextChild->whatObject->setAggressiveness(type, newLevel); ! 1155: nextChild = priv->children->nextInList(nextChild); ! 1156: } ! 1157: ! 1158: return IOPMNoErr; ! 1159: } ! 1160: ! 1161: ! 1162: //********************************************************************************* ! 1163: // systemWake ! 1164: // ! 1165: // Pass this to all power domain children. All those which are ! 1166: // power domains will pass it on to their children, etc. ! 1167: //********************************************************************************* ! 1168: ! 1169: IOReturn IOService::systemWake ( void ) ! 1170: { ! 1171: IOPMinformee * nextChild; ! 1172: ! 1173: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogSystemWake,0, 0); ! 1174: ! 1175: nextChild = priv->children->firstInList(); ! 1176: ! 1177: while ( nextChild != NULL ) { ! 1178: nextChild->whatObject->systemWake(); ! 1179: nextChild = priv->children->nextInList(nextChild); ! 1180: } ! 1181: ! 1182: return IOPMNoErr; ! 1183: } ! 1184: ! 1185: ! 1186: //********************************************************************************* ! 1187: // temperatureCriticalForZone ! 1188: // ! 1189: //********************************************************************************* ! 1190: ! 1191: IOReturn IOService::temperatureCriticalForZone ( IOService * whichZone ) ! 1192: { ! 1193: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogCriticalTemp,0,0); ! 1194: ! 1195: if ( (pm_vars->myParent != NULL) && ! 1196: ( ! priv->we_are_root) ) { ! 1197: pm_vars->myParent->temperatureCriticalForZone(whichZone); ! 1198: } ! 1199: return IOPMNoErr; ! 1200: } ! 1201: ! 1202: ! 1203: //********************************************************************************* ! 1204: // overrideOnPriv ! 1205: // ! 1206: //********************************************************************************* ! 1207: ! 1208: ! 1209: IOReturn IOService::overrideOnPriv ( void ) ! 1210: { ! 1211: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogOverrideOn,0,0); ! 1212: ! 1213: priv->device_overrides = true; // turn on the override ! 1214: return changeState(); // change state if that changed something ! 1215: } ! 1216: ! 1217: ! 1218: //********************************************************************************* ! 1219: // overrideOffPriv ! 1220: // ! 1221: //********************************************************************************* ! 1222: IOReturn IOService::overrideOffPriv ( void ) ! 1223: { ! 1224: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogOverrideOff,0,0); ! 1225: ! 1226: priv->device_overrides = false; // turn off the override ! 1227: return changeState(); // change state if that changed something ! 1228: } ! 1229: ! 1230: ! 1231: //********************************************************************************* ! 1232: // enqueuePowerChange ! 1233: // ! 1234: // Allocate a new state change notification, initialize it with fields from the ! 1235: // caller, and add it to the tail of the list of pending power changes. ! 1236: // ! 1237: // If it is early enough in the list, and almost all the time it is the only one in ! 1238: // the list, start the power change. ! 1239: // ! 1240: // In rare instances, this change will preempt the previous change in the list. ! 1241: // If the previous change is un-actioned in any way (because we are still ! 1242: // processing an even earlier power change), and if both the previous change ! 1243: // in the list and this change are initiated by us (not the parent), then we ! 1244: // needn't perform the previous change, so we collapse the list a little. ! 1245: //********************************************************************************* ! 1246: ! 1247: IOReturn IOService::enqueuePowerChange ( unsigned long flags, unsigned long whatStateOrdinal, unsigned long domainState ) ! 1248: { ! 1249: long newNote; ! 1250: long previousNote; ! 1251: ! 1252: // Create and initialize the new change note ! 1253: ! 1254: newNote = priv->changeList->createChangeNote(); ! 1255: if ( newNote == -1 ) { ! 1256: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogEnqueueErr,0,0); ! 1257: return IOPMAckImplied; // uh-oh, our list is full ! 1258: } ! 1259: ! 1260: priv->changeList->changeNote[newNote].newStateNumber = whatStateOrdinal; ! 1261: priv->changeList->changeNote[newNote].outputPowerCharacter = pm_vars->thePowerStates[whatStateOrdinal].outputPowerCharacter; ! 1262: priv->changeList->changeNote[newNote].inputPowerRequirement = pm_vars->thePowerStates[whatStateOrdinal].inputPowerRequirement; ! 1263: priv->changeList->changeNote[newNote].capabilityFlags = pm_vars->thePowerStates[whatStateOrdinal].capabilityFlags; ! 1264: priv->changeList->changeNote[newNote].flags = flags; ! 1265: if (flags & IOPMParentInitiated ) { ! 1266: priv->changeList->changeNote[newNote].domainState = domainState; ! 1267: } ! 1268: ! 1269: previousNote = priv->changeList->previousChangeNote(newNote); ! 1270: ! 1271: if ( previousNote == -1 ) { ! 1272: ! 1273: // Queue is empty, we can start this change. ! 1274: ! 1275: if (flags & IOPMWeInitiated ) { ! 1276: start_our_change(newNote); ! 1277: return 0; ! 1278: } ! 1279: else { ! 1280: return start_parent_change(newNote); ! 1281: } ! 1282: } ! 1283: ! 1284: // The queue is not empty. Try to collapse this new change and the previous one in queue into one change. ! 1285: // This is possible only if both changes are initiated by us, and neither has been started yet. ! 1286: // Do this more than once if possible. ! 1287: ! 1288: // (A change is started iff it is at the head of the queue) ! 1289: ! 1290: while ( (previousNote != priv->head_note) && (previousNote != -1) && ! 1291: (priv->changeList->changeNote[newNote].flags & priv->changeList->changeNote[previousNote].flags & IOPMWeInitiated) ) { ! 1292: priv->changeList->changeNote[previousNote].outputPowerCharacter = priv->changeList->changeNote[newNote].outputPowerCharacter; ! 1293: priv->changeList->changeNote[previousNote].inputPowerRequirement = priv->changeList->changeNote[newNote].inputPowerRequirement; ! 1294: priv->changeList->changeNote[previousNote].capabilityFlags =priv-> changeList->changeNote[newNote].capabilityFlags; ! 1295: priv->changeList->changeNote[previousNote].newStateNumber = priv->changeList->changeNote[newNote].newStateNumber; ! 1296: priv->changeList->releaseTailChangeNote(); ! 1297: newNote = previousNote; ! 1298: previousNote = priv->changeList->previousChangeNote(newNote); ! 1299: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogCollapseQueue,0,0); ! 1300: } ! 1301: return IOPMWillAckLater; // in any case, we can't start yet ! 1302: } ! 1303: ! 1304: ! 1305: //********************************************************************************* ! 1306: // notifyAll ! 1307: // ! 1308: // Notify all interested parties either that a change is impending or that the ! 1309: // previously-notified change is done and power has settled. ! 1310: // The parameter identifies whether this is the ! 1311: // pre-change notification or the post-change notification. ! 1312: // ! 1313: //********************************************************************************* ! 1314: ! 1315: IOReturn IOService::notifyAll ( bool is_prechange ) ! 1316: { ! 1317: IOPMinformee * nextObject; ! 1318: bool start_timer = false; ! 1319: ! 1320: // To prevent acknowledgePowerChange from finishing the change note and removing it from the queue if ! 1321: // some driver calls it, we inflate the number of pending acks so it cannot become zero. We'll fix it later. ! 1322: ! 1323: priv->head_note_pendingAcks = priv->numberOfInformees + 1; ! 1324: ! 1325: // OK, we will go through the lists of interested drivers and power domain children ! 1326: // and notify each one of this change. ! 1327: ! 1328: nextObject = priv->interestedDrivers->firstInList(); // notify interested drivers ! 1329: while ( nextObject != NULL ) { ! 1330: if (! notifyObject( nextObject, is_prechange, false) ) { ! 1331: start_timer = true; ! 1332: } ! 1333: nextObject = priv->interestedDrivers->nextInList(nextObject); ! 1334: } ! 1335: if ( start_timer ) { // start ack timer if any drivers didn't ack ! 1336: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0); ! 1337: start_ack_timer(); ! 1338: } ! 1339: ! 1340: nextObject = priv->children->firstInList(); // notify power domain children ! 1341: while ( nextObject != NULL ) { ! 1342: notifyObject(nextObject, is_prechange, true); ! 1343: nextObject = priv->children->nextInList(nextObject); ! 1344: } ! 1345: ! 1346: priv->head_note_pendingAcks -= 1; // fix this ! 1347: if (priv->head_note_pendingAcks == 0 ) { // is it all acked? ! 1348: return IOPMAckImplied; // return ack to parent ! 1349: } ! 1350: return IOPMWillAckLater; ! 1351: } ! 1352: ! 1353: ! 1354: //********************************************************************************* ! 1355: // notifyObject ! 1356: // ! 1357: // Notify an interested driver or a power domain child of an upcoming ! 1358: // power change. ! 1359: // ! 1360: // If the object acknowledges the current change, we return TRUE. ! 1361: //********************************************************************************* ! 1362: ! 1363: bool IOService::notifyObject ( IOPMinformee * nextObject, bool is_prechange, bool is_child ) ! 1364: { ! 1365: IOReturn k = IOPMAckImplied; ! 1366: ! 1367: nextObject->timer = -1; // initialize this ! 1368: ! 1369: if ( is_prechange ) { ! 1370: if ( is_child ) { ! 1371: k =nextObject->whatObject->powerDomainWillChangeTo( priv->head_note_outputFlags); ! 1372: } ! 1373: else { ! 1374: pm_vars->thePlatform->PMLog (pm_vars->ourName,PMlogInformDriverPreChange, ! 1375: (unsigned long)priv->head_note_capabilityFlags,(unsigned long)priv->head_note_state); ! 1376: k = nextObject->whatObject->powerStateWillChangeTo( priv->head_note_capabilityFlags,priv->head_note_state,this); ! 1377: } ! 1378: } ! 1379: else { ! 1380: if ( is_child ) { ! 1381: k = nextObject->whatObject->powerDomainDidChangeTo(priv->head_note_outputFlags); ! 1382: } ! 1383: else { ! 1384: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogInformDriverPostChange, ! 1385: (unsigned long)priv->head_note_capabilityFlags,(unsigned long)priv->head_note_state); ! 1386: k = nextObject->whatObject->powerStateDidChangeTo(priv->head_note_capabilityFlags,priv->head_note_state,this); ! 1387: } ! 1388: } ! 1389: ! 1390: if ( nextObject->timer == 0 ) { // did it ack behind our back? ! 1391: return true; // yes ! 1392: } ! 1393: if ( k ==IOPMAckImplied ) { // no, did the return code ack? ! 1394: nextObject->timer = 0; // yes ! 1395: priv->head_note_pendingAcks -= 1; ! 1396: return true; ! 1397: } ! 1398: if ( k < 0 ) { ! 1399: nextObject->timer = 0; // somebody goofed ! 1400: priv-> head_note_pendingAcks -= 1; ! 1401: return true; ! 1402: } ! 1403: nextObject->timer = (k * ns_per_us / ACK_TIMER_PERIOD) + 1; // no, it's a timer ! 1404: return false; ! 1405: } ! 1406: ! 1407: ! 1408: //********************************************************************************* ! 1409: // our_prechange_1 ! 1410: // ! 1411: // All parties have acknowledged our pre-change notification of a power ! 1412: // change we initiated. Here we instruct our controlling driver to make ! 1413: // the change to the hardware. If it does so, we continue processing ! 1414: // (waiting for settle and notifying interested parties post-change.) ! 1415: // If it doesn't, we have to wait for it to acknowledge and then continue. ! 1416: //********************************************************************************* ! 1417: ! 1418: void IOService::our_prechange_1 ( void ) ! 1419: { ! 1420: if ( instruct_driver(priv->head_note_state) == IOPMAckImplied ) { ! 1421: our_prechange_2(); // it's done, carry on ! 1422: } ! 1423: else { ! 1424: priv->machine_state = IOPMour_prechange_2; // it's not, wait for it ! 1425: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0); ! 1426: start_ack_timer(); ! 1427: } ! 1428: } ! 1429: ! 1430: ! 1431: //********************************************************************************* ! 1432: // our_prechange_2 ! 1433: // ! 1434: // Our controlling driver has changed power state on the hardware ! 1435: // during a power change we initiated. Here we see if we need to wait ! 1436: // for power to settle before continuing. If not, we continue processing ! 1437: // (notifying interested parties post-change). If so, we wait and ! 1438: // continue later. ! 1439: //********************************************************************************* ! 1440: ! 1441: void IOService::our_prechange_2 ( void ) ! 1442: { ! 1443: priv->settle_time = compute_settle_time(); ! 1444: if ( priv->settle_time == 0 ) { ! 1445: our_prechange_3(); ! 1446: } ! 1447: else { ! 1448: priv->machine_state = IOPMour_prechange_3; ! 1449: startSettleTimer(priv->settle_time); ! 1450: } ! 1451: } ! 1452: ! 1453: ! 1454: //********************************************************************************* ! 1455: // our_prechange_3 ! 1456: // ! 1457: // Power has settled on a power change we initiated. Here we notify ! 1458: // all our interested parties post-change. If they all acknowledge, we're ! 1459: // done with this change note, and we can start on the next one. ! 1460: // Otherwise we have to wait for acknowledgements and finish up later. ! 1461: //********************************************************************************* ! 1462: ! 1463: void IOService::our_prechange_3 ( void ) ! 1464: { ! 1465: priv->machine_state = IOPMour_prechange_4; // in case they don't all ack ! 1466: if ( notifyAll(false) == IOPMAckImplied ) { ! 1467: our_prechange_4(); ! 1468: } ! 1469: } ! 1470: ! 1471: ! 1472: //********************************************************************************* ! 1473: // our_prechange_4 ! 1474: // ! 1475: // Power has settled on a power change we initiated, and ! 1476: // all our interested parties have acknowledged. We're ! 1477: // done with this change note, and we can start on the next one. ! 1478: //********************************************************************************* ! 1479: ! 1480: void IOService::our_prechange_4 ( void ) ! 1481: { ! 1482: all_done(); ! 1483: } ! 1484: ! 1485: ! 1486: //********************************************************************************* ! 1487: // parent_prechange_down_1 ! 1488: // ! 1489: // All parties have acknowledged our pre-change notification of a power ! 1490: // lowering initiated by the parent. Here we instruct our controlling driver ! 1491: // to put the hardware in the state it needs to be in when the domain is ! 1492: // lowered. If it does so, we continue processing ! 1493: // (waiting for settle and acknowledging the parent.) ! 1494: // If it doesn't, we have to wait for it to acknowledge and then continue. ! 1495: //********************************************************************************* ! 1496: ! 1497: IOReturn IOService::parent_prechange_down_1 ( void ) ! 1498: { ! 1499: if ( instruct_driver(priv->head_note_state) == IOPMAckImplied ) { ! 1500: return parent_prechange_down_2(); // it's done, carry on ! 1501: } ! 1502: priv->machine_state = IOPMparent_prechange_down_5; // it's not, wait for it ! 1503: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0); ! 1504: start_ack_timer(); ! 1505: return IOPMWillAckLater; ! 1506: } ! 1507: ! 1508: ! 1509: //********************************************************************************* ! 1510: // parent_prechange_down_4 ! 1511: // ! 1512: // We had to wait for it, but all parties have acknowledged our pre-change ! 1513: // notification of a power lowering initiated by the parent. ! 1514: // Here we instruct our controlling driver ! 1515: // to put the hardware in the state it needs to be in when the domain is ! 1516: // lowered. If it does so, we continue processing ! 1517: // (waiting for settle and acknowledging the parent.) ! 1518: // If it doesn't, we have to wait for it to acknowledge and then continue. ! 1519: //********************************************************************************* ! 1520: ! 1521: void IOService::parent_prechange_down_4 ( void ) ! 1522: { ! 1523: if ( instruct_driver(priv->head_note_state) == IOPMAckImplied ) { ! 1524: parent_prechange_down_5(); // it's done, carry on ! 1525: } ! 1526: else { ! 1527: priv-> machine_state = IOPMparent_prechange_down_5; // it's not, wait for it ! 1528: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0); ! 1529: start_ack_timer(); ! 1530: } ! 1531: } ! 1532: ! 1533: ! 1534: //********************************************************************************* ! 1535: // parent_prechange_down_2 ! 1536: // ! 1537: // Our controlling driver has changed power state on the hardware ! 1538: // during a power change initiated by our parent. Here we see if we need ! 1539: // to wait for power to settle before continuing. If not, we continue ! 1540: // processing (acknowledging our preparedness to the parent). ! 1541: // If so, we wait and continue later. ! 1542: //********************************************************************************* ! 1543: ! 1544: IOReturn IOService::parent_prechange_down_2 ( void ) ! 1545: { ! 1546: priv->settle_time = compute_settle_time(); ! 1547: if ( priv->settle_time == 0 ) { ! 1548: priv->machine_state = IOPMparent_postchange_down_1; ! 1549: return IOPMAckImplied; ! 1550: } ! 1551: else { ! 1552: priv->machine_state = IOPMparent_prechange_down_3; ! 1553: startSettleTimer(priv->settle_time); ! 1554: return IOPMWillAckLater; ! 1555: } ! 1556: } ! 1557: ! 1558: ! 1559: //********************************************************************************* ! 1560: // parent_prechange_down_5 ! 1561: // ! 1562: // Our controlling driver has changed power state on the hardware ! 1563: // during a power change initiated by our parent. We have had to wait ! 1564: // for acknowledgement from interested parties, or we have had to wait ! 1565: // for the controlling driver to change the state. Here we see if we need ! 1566: // to wait for power to settle before continuing. If not, we continue ! 1567: // processing (acknowledging our preparedness to the parent). ! 1568: // If so, we wait and continue later. ! 1569: //********************************************************************************* ! 1570: ! 1571: void IOService::parent_prechange_down_5 ( void ) ! 1572: { ! 1573: priv->settle_time = compute_settle_time(); ! 1574: if ( priv->settle_time == 0 ) { ! 1575: parent_prechange_down_3(); ! 1576: } ! 1577: else { ! 1578: priv->machine_state = IOPMparent_prechange_down_3; ! 1579: startSettleTimer(priv->settle_time); ! 1580: } ! 1581: } ! 1582: ! 1583: ! 1584: //********************************************************************************* ! 1585: // parent_prechange_down_3 ! 1586: // ! 1587: // Power has settled on a power change initiated by our parent. Here we ! 1588: // acknowledge the parent. There is nothing more to do until the ! 1589: // parent lowers power in the domain and calls us at powerStateDidChange. ! 1590: //********************************************************************************* ! 1591: ! 1592: void IOService::parent_prechange_down_3 ( void ) ! 1593: { ! 1594: priv->machine_state = IOPMparent_postchange_down_1; ! 1595: pm_vars->myParent->acknowledgePowerChange(this); ! 1596: } ! 1597: ! 1598: ! 1599: //********************************************************************************* ! 1600: // parent_prechange_up_1 ! 1601: // ! 1602: // All parties have acknowledged our pre-change notification of a power ! 1603: // raising initiated by the parent. Here we acknowledge the parent. ! 1604: // There is nothing more to do until the parent raises power in the domain ! 1605: // and calls us at powerStateDidChange. ! 1606: //********************************************************************************* ! 1607: ! 1608: void IOService::parent_prechange_up_1 ( void ) ! 1609: { ! 1610: priv->machine_state = IOPMparent_postchange_up_1; ! 1611: pm_vars->myParent->acknowledgePowerChange(this); ! 1612: } ! 1613: ! 1614: ! 1615: //********************************************************************************* ! 1616: // parent_postchange_down_1 ! 1617: // ! 1618: // Our parent is lowering power, and has called us at powerStateDidChange ! 1619: // to tell us the domain power has now settled in the new lower state. ! 1620: // We notify our interested parties. When they have all acked, we're done ! 1621: //********************************************************************************* ! 1622: ! 1623: IOReturn IOService::parent_postchange_down_1 ( void ) ! 1624: { ! 1625: priv->machine_state = IOPMparent_postchange_down_2; // in case they don't all ack ! 1626: if ( notifyAll(false) == IOPMAckImplied ) { ! 1627: all_done(); ! 1628: return IOPMAckImplied; ! 1629: } ! 1630: return IOPMWillAckLater; // they didn't ! 1631: } ! 1632: ! 1633: ! 1634: //********************************************************************************* ! 1635: // parent_postchange_down_2 ! 1636: // ! 1637: // We had to wait for it, but all parties have acknowledged our post-change ! 1638: // notification of a power lowering initiated by the parent. ! 1639: // Here we acknowledge the parent. ! 1640: // We are done with this change note, and we can start on the next one. ! 1641: //********************************************************************************* ! 1642: ! 1643: void IOService::parent_postchange_down_2 ( void ) ! 1644: { ! 1645: all_done(); ! 1646: pm_vars->myParent->acknowledgePowerChange(this); ! 1647: } ! 1648: ! 1649: ! 1650: //********************************************************************************* ! 1651: // parent_postchange_up_1 ! 1652: // ! 1653: // Our parent has informed us via powerStateDidChange that it has ! 1654: // raised the power in our power domain. Here we instruct our controlling ! 1655: // driver to program the hardware to take advantage of the higher domain ! 1656: // power. If it does so, we continue processing ! 1657: // (waiting for settle and notifying interested parties post-change.) ! 1658: // If it doesn't, we have to wait for it to acknowledge and then continue. ! 1659: //********************************************************************************* ! 1660: ! 1661: IOReturn IOService::parent_postchange_up_1 ( void ) ! 1662: { ! 1663: if ( instruct_driver(priv->head_note_state) == IOPMAckImplied ) { ! 1664: return parent_postchange_up_2(); // it did it, carry on ! 1665: } ! 1666: else { ! 1667: priv->machine_state = IOPMparent_postchange_up_4; // it didn't, wait for it ! 1668: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0); ! 1669: start_ack_timer(); ! 1670: return IOPMWillAckLater; ! 1671: } ! 1672: } ! 1673: ! 1674: ! 1675: //********************************************************************************* ! 1676: // parent_postchange_up_2 ! 1677: // ! 1678: // Our controlling driver has changed power state on the hardware ! 1679: // during a power raise initiated by the parent. Here we see if we need to wait ! 1680: // for power to settle before continuing. If not, we continue processing ! 1681: // (notifying interested parties post-change). If so, we wait and ! 1682: // continue later. ! 1683: //********************************************************************************* ! 1684: ! 1685: IOReturn IOService::parent_postchange_up_2 ( void ) ! 1686: { ! 1687: priv->settle_time = compute_settle_time(); ! 1688: if ( priv->settle_time == 0 ) { ! 1689: return parent_postchange_up_3(); ! 1690: } ! 1691: else { ! 1692: priv->machine_state = IOPMparent_postchange_up_5; ! 1693: startSettleTimer(priv->settle_time); ! 1694: return IOPMWillAckLater; ! 1695: } ! 1696: } ! 1697: ! 1698: ! 1699: //********************************************************************************* ! 1700: // parent_postchange_up_4 ! 1701: // ! 1702: // Our controlling driver has changed power state on the hardware ! 1703: // during a power raise initiated by the parent, but we had to wait for it. ! 1704: // Here we see if we need to wait for power to settle before continuing. ! 1705: // If not, we continue processing (notifying interested parties post-change). ! 1706: // If so, we wait and continue later. ! 1707: //********************************************************************************* ! 1708: ! 1709: void IOService::parent_postchange_up_4 ( void ) ! 1710: { ! 1711: priv->settle_time = compute_settle_time(); ! 1712: if ( priv->settle_time == 0 ) { ! 1713: parent_postchange_up_5(); ! 1714: } ! 1715: else { ! 1716: priv->machine_state = IOPMparent_postchange_up_5; ! 1717: startSettleTimer(priv->settle_time); ! 1718: } ! 1719: } ! 1720: ! 1721: ! 1722: //********************************************************************************* ! 1723: // parent_postchange_up_3 ! 1724: // ! 1725: // No power settling was required on a power raise initiated by the parent. ! 1726: // Here we notify all our interested parties post-change. If they all acknowledge, ! 1727: // we're done with this change note, and we can start on the next one. ! 1728: // Otherwise we have to wait for acknowledgements and finish up later. ! 1729: //********************************************************************************* ! 1730: ! 1731: IOReturn IOService::parent_postchange_up_3 ( void ) ! 1732: { ! 1733: priv->machine_state = IOPMparent_postchange_up_6; // in case they don't all ack ! 1734: if ( notifyAll(false) == IOPMAckImplied ) { ! 1735: all_done(); ! 1736: return IOPMAckImplied; ! 1737: } ! 1738: return IOPMWillAckLater; // they didn't ! 1739: } ! 1740: ! 1741: ! 1742: //********************************************************************************* ! 1743: // parent_postchange_up_5 ! 1744: // ! 1745: // Power has settled on a power raise initiated by the parent. ! 1746: // Here we notify all our interested parties post-change. If they all acknowledge, ! 1747: // we're done with this change note, and we can start on the next one. ! 1748: // Otherwise we have to wait for acknowledgements and finish up later. ! 1749: //********************************************************************************* ! 1750: ! 1751: void IOService::parent_postchange_up_5 ( void ) ! 1752: { ! 1753: priv->machine_state = IOPMparent_postchange_up_6; // in case they don't all ack ! 1754: if ( notifyAll(false) == IOPMAckImplied ) { ! 1755: parent_postchange_up_6(); ! 1756: } ! 1757: } ! 1758: ! 1759: ! 1760: //********************************************************************************* ! 1761: // parent_postchange_up_6 ! 1762: // ! 1763: // All parties have acknowledged our post-change notification of a power ! 1764: // raising initiated by the parent. Here we acknowledge the parent. ! 1765: // We are done with this change note, and we can start on the next one. ! 1766: //********************************************************************************* ! 1767: ! 1768: void IOService::parent_postchange_up_6 ( void ) ! 1769: { ! 1770: all_done(); ! 1771: pm_vars->myParent->acknowledgePowerChange(this); ! 1772: } ! 1773: ! 1774: ! 1775: //********************************************************************************* ! 1776: // all_done ! 1777: // ! 1778: // A power change is complete, and the used post-change note is at ! 1779: // the head of the queue. Remove it and set myCurrentState to the result ! 1780: // of the change. Start up the next change in queue. ! 1781: //********************************************************************************* ! 1782: ! 1783: void IOService::all_done ( void ) ! 1784: { ! 1785: priv->machine_state = IOPMfinished; ! 1786: ! 1787: if ( priv->head_note_flags & IOPMWeInitiated ) { ! 1788: if ( !( priv->head_note_flags & IOPMNotDone) ) { // could our driver switch to the new state? ! 1789: pm_vars->myCurrentState = priv-> head_note_state; // yes ! 1790: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChangeDone,(unsigned long)pm_vars->myCurrentState,0); ! 1791: } ! 1792: else { // no ! 1793: pm_vars->myCurrentState = pm_vars->theControllingDriver->powerStateForDomainState(pm_vars->parentCurrentPowerFlags); ! 1794: } ! 1795: } ! 1796: if ( priv->head_note_flags & IOPMParentInitiated ) { ! 1797: pm_vars->myCurrentState = priv->head_note_state; ! 1798: pm_vars->maxCapability = pm_vars->theControllingDriver->maxCapabilityForDomainState(priv->head_note_domainState); ! 1799: pm_vars->parentCurrentPowerFlags = priv->head_note_domainState; ! 1800: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChangeDone,(unsigned long)pm_vars->myCurrentState,0); ! 1801: } ! 1802: ! 1803: priv->changeList->releaseHeadChangeNote(); // either way, we're done with this ! 1804: ! 1805: priv->head_note = priv->changeList->currentChange(); // start next one in queue ! 1806: if ( priv->head_note != -1 ) { ! 1807: ! 1808: if (priv->changeList->changeNote[priv->head_note].flags & IOPMWeInitiated ) { ! 1809: start_our_change(priv->head_note); ! 1810: } ! 1811: else { ! 1812: if ( start_parent_change(priv->head_note) == IOPMAckImplied ) { ! 1813: pm_vars->myParent->acknowledgePowerChange(this); ! 1814: } ! 1815: } ! 1816: } ! 1817: } ! 1818: ! 1819: ! 1820: ! 1821: //********************************************************************************* ! 1822: // all_acked ! 1823: // ! 1824: // A driver or child has acknowledged our notification of an upcoming power ! 1825: // change, and this acknowledgement is the last one pending ! 1826: // before we change power or after changing power. ! 1827: // ! 1828: //********************************************************************************* ! 1829: ! 1830: void IOService::all_acked ( void ) ! 1831: { ! 1832: switch (priv->machine_state) { ! 1833: case IOPMour_prechange_1: ! 1834: our_prechange_1(); ! 1835: break; ! 1836: case IOPMour_prechange_4: ! 1837: our_prechange_4(); ! 1838: break; ! 1839: case IOPMparent_prechange_down_4: ! 1840: parent_prechange_down_4(); ! 1841: break; ! 1842: case IOPMparent_postchange_down_2: ! 1843: parent_postchange_down_2(); ! 1844: break; ! 1845: case IOPMparent_prechange_up_1: ! 1846: parent_prechange_up_1(); ! 1847: break; ! 1848: case IOPMparent_postchange_up_6: ! 1849: parent_postchange_up_6(); ! 1850: break; ! 1851: } ! 1852: } ! 1853: ! 1854: ! 1855: //********************************************************************************* ! 1856: // settleTimerExpired ! 1857: // ! 1858: // Power has settled after our last change. Notify interested parties that ! 1859: // there is a new power state. ! 1860: //********************************************************************************* ! 1861: ! 1862: void IOService::settleTimerExpired ( void ) ! 1863: { ! 1864: switch (priv->machine_state) { ! 1865: case IOPMour_prechange_3: ! 1866: our_prechange_3(); ! 1867: break; ! 1868: case IOPMparent_prechange_down_3: ! 1869: parent_prechange_down_3(); ! 1870: break; ! 1871: case IOPMparent_postchange_up_5: ! 1872: parent_postchange_up_5(); ! 1873: break; ! 1874: } ! 1875: } ! 1876: ! 1877: ! 1878: //********************************************************************************* ! 1879: // compute_settle_time ! 1880: // ! 1881: // Compute the power-settling delay in microseconds for the ! 1882: // change from myCurrentState to head_note_state. ! 1883: //********************************************************************************* ! 1884: ! 1885: unsigned long IOService::compute_settle_time ( void ) ! 1886: { ! 1887: unsigned long totalTime; ! 1888: unsigned long i; ! 1889: ! 1890: totalTime = 0; // compute total time to attain the new state ! 1891: i = pm_vars->myCurrentState; ! 1892: if ( priv->head_note_state < pm_vars->myCurrentState ) { // we're lowering power ! 1893: while ( i > priv->head_note_state ) { ! 1894: totalTime += pm_vars->thePowerStates[i].settleDownTime; ! 1895: i--; ! 1896: } ! 1897: } ! 1898: ! 1899: if ( priv->head_note_state > pm_vars->myCurrentState ) { // we're raising power ! 1900: while ( i < priv->head_note_state ) { ! 1901: totalTime += pm_vars->thePowerStates[i+1].settleUpTime; ! 1902: i++; ! 1903: } ! 1904: } ! 1905: ! 1906: return totalTime; ! 1907: } ! 1908: ! 1909: ! 1910: //********************************************************************************* ! 1911: // startSettleTimer ! 1912: // ! 1913: // Enter with a power-settling delay in microseconds and start a nano-second ! 1914: // timer for that delay. ! 1915: //********************************************************************************* ! 1916: ! 1917: IOReturn IOService::startSettleTimer ( unsigned long delay ) ! 1918: { ! 1919: AbsoluteTime deadline; ! 1920: ! 1921: clock_interval_to_deadline(delay, kMicrosecondScale, &deadline); ! 1922: thread_call_func_delayed(settle_timer_expired, (void *)this, deadline); ! 1923: return IOPMNoErr; ! 1924: } ! 1925: ! 1926: //********************************************************************************* ! 1927: // ack_timer_ticked ! 1928: // ! 1929: // The acknowledgement timeout periodic timer has ticked. ! 1930: // If we are awaiting acks for a power change notification, ! 1931: // we decrement the timer word of each interested driver which hasn't acked. ! 1932: // If a timer word becomes zero, we pretend the driver aknowledged. ! 1933: // If we are waiting for the controlling driver to change the power ! 1934: // state of the hardware, we decrement its timer word, and if it becomes ! 1935: // zero, we pretend the driver acknowledged. ! 1936: //********************************************************************************* ! 1937: ! 1938: void IOService::ack_timer_ticked ( void ) ! 1939: { ! 1940: IOPMinformee * nextObject; ! 1941: ! 1942: if (! acquire_lock() ) { ! 1943: return; ! 1944: } ! 1945: ! 1946: if ( priv->driver_timer != 0 ) { // are we waiting for our driver to make its change? ! 1947: priv->driver_timer -= 1; // yes, tick once ! 1948: if ( priv->driver_timer == 0 ) { // it's tardy, we'll go on without it ! 1949: IOUnlock(priv->our_lock); ! 1950: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogCtrlDriverTardy,0,0); ! 1951: driver_acked(); ! 1952: } ! 1953: else { // still waiting, set timer again ! 1954: start_ack_timer(); ! 1955: IOUnlock(priv->our_lock); ! 1956: } ! 1957: return; ! 1958: } ! 1959: ! 1960: if (priv->head_note_pendingAcks != 0 ) { // are we waiting for interested parties to acknowledge? ! 1961: nextObject = priv->interestedDrivers->firstInList(); // yes, go through the list of interested drivers ! 1962: while ( nextObject != NULL ) { // and check each one ! 1963: if ( nextObject->timer > 0 ) { ! 1964: nextObject->timer -= 1; ! 1965: if ( nextObject->timer == 0 ) { // this one should have acked by now ! 1966: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogIntDriverTardy,0,0); ! 1967: priv->head_note_pendingAcks -= 1; ! 1968: } ! 1969: } ! 1970: nextObject = priv->interestedDrivers->nextInList(nextObject); ! 1971: } ! 1972: if ( priv->head_note_pendingAcks == 0 ) { // is that the last? ! 1973: IOUnlock(priv->our_lock); ! 1974: all_acked(); // yes, we can continue ! 1975: } ! 1976: else { // no, set timer again ! 1977: start_ack_timer(); ! 1978: IOUnlock(priv->our_lock); ! 1979: } ! 1980: return; ! 1981: } ! 1982: IOUnlock(priv->our_lock); // not waiting for acks ! 1983: } ! 1984: ! 1985: ! 1986: //********************************************************************************* ! 1987: // start_ack_timer ! 1988: // ! 1989: //********************************************************************************* ! 1990: ! 1991: void IOService::start_ack_timer ( void ) ! 1992: { ! 1993: AbsoluteTime deadline; ! 1994: ! 1995: clock_interval_to_deadline(ACK_TIMER_PERIOD, kNanosecondScale, &deadline); ! 1996: thread_call_func_delayed(ack_timer_expired, (void *)this, deadline); ! 1997: } ! 1998: ! 1999: ! 2000: //********************************************************************************* ! 2001: // stop_ack_timer ! 2002: // ! 2003: //********************************************************************************* ! 2004: ! 2005: void IOService::stop_ack_timer ( void ) ! 2006: { ! 2007: thread_call_func_cancel(ack_timer_expired, (void *)this, true); ! 2008: } ! 2009: ! 2010: ! 2011: //********************************************************************************* ! 2012: // c-language timer expiration functions ! 2013: // ! 2014: //********************************************************************************* ! 2015: ! 2016: static void ack_timer_expired ( thread_call_param_t us, thread_call_param_t ) ! 2017: { ! 2018: ((IOService *)us)->ack_timer_ticked(); ! 2019: } ! 2020: ! 2021: ! 2022: static void settle_timer_expired ( thread_call_param_t us, thread_call_param_t ) ! 2023: { ! 2024: ((IOService *)us)->settleTimerExpired(); ! 2025: } ! 2026: ! 2027: ! 2028: //********************************************************************************* ! 2029: // add_to_active_change ! 2030: // ! 2031: // A child or interested driver has just registered with us. If there is ! 2032: // currently a change in progress, get the new party involved: if we ! 2033: // have notified all parties and are waiting for acks, notify the new ! 2034: // party. ! 2035: //********************************************************************************* ! 2036: ! 2037: IOReturn IOService::add_to_active_change ( IOPMinformee * newObject, bool is_child ) ! 2038: { ! 2039: if (! acquire_lock() ) { ! 2040: return IOPMNoErr; ! 2041: } ! 2042: ! 2043: switch (priv->machine_state) { ! 2044: case IOPMour_prechange_1: ! 2045: priv->head_note_pendingAcks += 1; ! 2046: IOUnlock(priv->our_lock); ! 2047: notifyObject(newObject, true, is_child); ! 2048: return IOPMNoErr; ! 2049: case IOPMour_prechange_4: ! 2050: priv->head_note_pendingAcks += 1; ! 2051: IOUnlock(priv->our_lock); ! 2052: notifyObject(newObject, false, is_child); ! 2053: return IOPMNoErr; ! 2054: case IOPMparent_prechange_down_4: ! 2055: priv->head_note_pendingAcks += 1; ! 2056: IOUnlock(priv->our_lock); ! 2057: notifyObject(newObject, true, is_child); ! 2058: return IOPMNoErr; ! 2059: case IOPMparent_postchange_down_2: ! 2060: priv->head_note_pendingAcks += 1; ! 2061: IOUnlock(priv->our_lock); ! 2062: notifyObject(newObject, false, is_child); ! 2063: return IOPMNoErr; ! 2064: case IOPMparent_prechange_up_1: ! 2065: priv->head_note_pendingAcks += 1; ! 2066: IOUnlock(priv->our_lock); ! 2067: notifyObject(newObject, true, is_child); ! 2068: return IOPMNoErr; ! 2069: case IOPMparent_postchange_up_6: ! 2070: priv-> head_note_pendingAcks += 1; ! 2071: IOUnlock(priv->our_lock); ! 2072: notifyObject(newObject, false, is_child); ! 2073: return IOPMNoErr; ! 2074: } ! 2075: IOUnlock(priv->our_lock); ! 2076: return IOPMNoErr; ! 2077: } ! 2078: ! 2079: ! 2080: //********************************************************************************* ! 2081: // start_parent_change ! 2082: // ! 2083: // Here we begin the processing of a change note initiated by our parent ! 2084: // which is at the head of the queue. ! 2085: // ! 2086: // It is possible for the change to be processed to completion and removed from the queue. ! 2087: // There are several possible interruptions to the processing, though, and they are: ! 2088: // we may have to wait for interested parties to acknowledge our pre-change notification, ! 2089: // changes initiated by the parent will wait in the middle for powerStateDidChange, ! 2090: // we may have to wait for our controlling driver to change the hardware power state, ! 2091: // there may be a settling time after changing the hardware power state, ! 2092: // we may have to wait for interested parties to acknowledge our post-change notification, ! 2093: // we may have to wait for the acknowledgement timer expiration to substitute for the ! 2094: // acknowledgement from a failing driver. ! 2095: // We identify which of the following three possible lives the note ! 2096: // will have and then start the life: ! 2097: // 2. The parent initiated the change, and it is lowering power, ! 2098: // 3. The parent initiated the change, and it is raising power, ! 2099: // 4. The parent initiated the change, and the power state is not changing. ! 2100: // ! 2101: // In life-style 2, if all interested parties acknowledge our pre-change notification, ! 2102: // our controlling driver changes power states immediately without having to call us back later, ! 2103: // and there is no settling time required, we return IOPMAckImplied. ! 2104: // In life-style 3, if all interested parties acknowledge our pre-change notification, we return IOPMAckImplied. ! 2105: // In life-style 4, we always return IOPMAckImplied. ! 2106: // In any other case, we return IOPMWillAckLater. ! 2107: // If our caller is ultimately our powerDomainWillChange method, it will return our return code to the parent. ! 2108: // Otherwise, this new notification was dequeued from the queue after we finished a previous one. ! 2109: // In this case, an IOPMAckImplied return from here will cause the caller to explicitly acknowledge ! 2110: // the parent by calling its acknowledgePowerChange method. ! 2111: //********************************************************************************* ! 2112: ! 2113: IOReturn IOService::start_parent_change ( unsigned long queue_head ) ! 2114: { ! 2115: priv->head_note = queue_head; ! 2116: priv-> head_note_flags = priv-> changeList->changeNote[priv->head_note].flags; ! 2117: priv-> head_note_state = priv->changeList->changeNote[priv->head_note].newStateNumber; ! 2118: priv-> head_note_outputFlags = priv->changeList->changeNote[priv->head_note].outputPowerCharacter; ! 2119: priv->head_note_domainState = priv->changeList->changeNote[priv->head_note].domainState; ! 2120: priv->head_note_capabilityFlags = priv->changeList->changeNote[priv->head_note].capabilityFlags; ! 2121: ! 2122: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartParentChange,(unsigned long)priv->head_note_state,0); ! 2123: ! 2124: ask_parent( priv->ourDesiredPowerState); // if we need something and haven't told the parent, do so ! 2125: ! 2126: if ( priv->head_note_state < pm_vars->myCurrentState ) { ! 2127: priv->initial_change = false; // life-style 2 ! 2128: priv->machine_state = IOPMparent_prechange_down_4; // in case they don't all ack ! 2129: if ( notifyAll(true) == IOPMAckImplied ) { ! 2130: return parent_prechange_down_1(); ! 2131: } ! 2132: return IOPMWillAckLater; // they didn't ! 2133: } ! 2134: ! 2135: if ( priv->head_note_state > pm_vars->myCurrentState ) { // if the parent is raising power, we may or may not ! 2136: if ( priv->ourDesiredPowerState > pm_vars->myCurrentState ) { ! 2137: if ( priv->ourDesiredPowerState < priv->head_note_state ) { ! 2138: priv->head_note_state = priv->ourDesiredPowerState; // we do, but not all the way ! 2139: priv->head_note_outputFlags = pm_vars->thePowerStates[priv->head_note_state].outputPowerCharacter; ! 2140: priv->head_note_capabilityFlags = pm_vars->thePowerStates[priv->head_note_state].capabilityFlags; ! 2141: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAmendParentChange,(unsigned long)priv->head_note_state,0); ! 2142: } ! 2143: } ! 2144: else { ! 2145: priv-> head_note_state = pm_vars->myCurrentState; // we don't ! 2146: priv->head_note_outputFlags = pm_vars->thePowerStates[priv->head_note_state].outputPowerCharacter; ! 2147: priv->head_note_capabilityFlags = pm_vars->thePowerStates[priv->head_note_state].capabilityFlags; ! 2148: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAmendParentChange,(unsigned long)priv->head_note_state,0); ! 2149: } ! 2150: } ! 2151: ! 2152: if ( priv->head_note_state > pm_vars->myCurrentState ) { ! 2153: priv->initial_change = false; // life-style 3 ! 2154: priv->machine_state = IOPMparent_prechange_up_1; // in case they don't all ack ! 2155: if ( notifyAll(true) == IOPMAckImplied ) { ! 2156: priv->machine_state = IOPMparent_postchange_up_1; ! 2157: return IOPMAckImplied; ! 2158: } ! 2159: return IOPMWillAckLater; // they didn't ! 2160: } ! 2161: ! 2162: if ( priv->head_note_state == pm_vars->myCurrentState ) { ! 2163: priv->machine_state = IOPMparent_postchange_null; // life-style 4 ! 2164: return IOPMAckImplied; ! 2165: } ! 2166: return IOPMAckImplied; // something wrong ! 2167: } ! 2168: ! 2169: ! 2170: //********************************************************************************* ! 2171: // start_our_change ! 2172: // ! 2173: // Here we begin the processing of a change note initiated by us ! 2174: // which is at the head of the queue. ! 2175: // ! 2176: // It is possible for the change to be processed to completion and removed from the queue. ! 2177: // There are several possible interruptions to the processing, though, and they are: ! 2178: // we may have to wait for interested parties to acknowledge our pre-change notification, ! 2179: // changes initiated by the parent will wait in the middle for powerStateDidChange, ! 2180: // we may have to wait for our controlling driver to change the hardware power state, ! 2181: // there may be a settling time after changing the hardware power state, ! 2182: // we may have to wait for interested parties to acknowledge our post-change notification, ! 2183: // we may have to wait for the acknowledgement timer expiration to substitute for the ! 2184: // acknowledgement from a failing driver. ! 2185: //********************************************************************************* ! 2186: ! 2187: void IOService::start_our_change ( unsigned long queue_head ) ! 2188: { ! 2189: priv->head_note = queue_head; ! 2190: priv->head_note_flags = priv->changeList->changeNote[priv->head_note].flags; ! 2191: priv->head_note_state = priv->changeList->changeNote[priv->head_note].newStateNumber; ! 2192: priv->head_note_outputFlags = priv->changeList->changeNote[priv->head_note].outputPowerCharacter; ! 2193: priv->head_note_capabilityFlags = priv->changeList->changeNote[priv->head_note].capabilityFlags; ! 2194: ! 2195: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartDeviceChange,(unsigned long)priv->head_note_state,0); ! 2196: ! 2197: if ( ! priv->we_are_root ) { ! 2198: ask_parent(priv->head_note_state); // if this changes our power requirement, tell the parent ! 2199: } ! 2200: ! 2201: if ( priv->head_note_capabilityFlags & IOPMNotAttainable ) { // can our driver switch to the new state? ! 2202: priv-> head_note_flags |= IOPMNotDone; // no, mark the change note un-actioned ! 2203: all_done(); // and we're done ! 2204: return; // let the parent make the change for us ! 2205: } ! 2206: if ( (pm_vars->maxCapability < priv->head_note_state) && (! priv->we_are_root) ) { // is there enough power in the domain? ! 2207: priv->head_note_flags |= IOPMNotDone; // no, mark the change note un-actioned ! 2208: all_done(); // and we're done ! 2209: return; // till the parent raises power ! 2210: } ! 2211: ! 2212: if ( ! priv->initial_change ) { ! 2213: if ( priv->head_note_state == pm_vars->myCurrentState ) { ! 2214: all_done(); // we initiated a null change; forget it ! 2215: return; ! 2216: } ! 2217: } ! 2218: priv->initial_change = false; ! 2219: ! 2220: priv->machine_state = IOPMour_prechange_1; // in case they don't all ack ! 2221: if ( notifyAll(true) == IOPMAckImplied ) { // in life-style 1 ! 2222: our_prechange_1(); ! 2223: } ! 2224: } ! 2225: ! 2226: ! 2227: //********************************************************************************* ! 2228: // ask_parent ! 2229: // ! 2230: // Call the power domain parent to ask for a higher power state in the domain ! 2231: // or to suggest a lower power state. ! 2232: //********************************************************************************* ! 2233: ! 2234: IOReturn IOService::ask_parent ( unsigned long requestedState ) ! 2235: { ! 2236: unsigned long savedPreviousRequest; ! 2237: IOReturn return_code; ! 2238: ! 2239: if ( priv->previousRequest == pm_vars->thePowerStates[requestedState].inputPowerRequirement ) { // is this a new desire? ! 2240: return IOPMNoErr; // no, the parent knows already, just return ! 2241: } ! 2242: ! 2243: if ( priv->we_are_root ) { ! 2244: return IOPMNoErr; ! 2245: } ! 2246: savedPreviousRequest = priv->previousRequest; // yes, remember our previous request for a second ! 2247: priv->previousRequest = pm_vars->thePowerStates[requestedState].inputPowerRequirement; ! 2248: return_code = pm_vars->myParent->requestDomainState( priv->previousRequest,this,IOPMLowestState); ! 2249: ! 2250: if ( return_code != IOPMNoErr ) { // if that was not ok with the parent, ! 2251: ! 2252: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogRequestDenied,(unsigned long)priv->previousRequest,0); ! 2253: priv->previousRequest = savedPreviousRequest; // remember our previous desire ! 2254: } ! 2255: return return_code; ! 2256: } ! 2257: ! 2258: ! 2259: //********************************************************************************* ! 2260: // instruct_driver ! 2261: // ! 2262: // Call the controlling driver and have it change the power state of the ! 2263: // hardware. If it returns IOPMAckImplied, the change is complete, and ! 2264: // we return IOPMAckImplied. Otherwise, it will ack when the change ! 2265: // is done; we return IOPMWillAckLater. ! 2266: //********************************************************************************* ! 2267: ! 2268: IOReturn IOService::instruct_driver ( unsigned long newState ) ! 2269: { ! 2270: IOReturn return_code; ! 2271: ! 2272: if ( pm_vars->thePowerStates[newState].capabilityFlags & IOPMNotAttainable ) { // can our driver switch to the desired state? ! 2273: return IOPMAckImplied; // no, so don't try ! 2274: } ! 2275: priv->driver_timer = -1; ! 2276: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogProgramHardware,newState,0); ! 2277: return_code = pm_vars->theControllingDriver->setPowerState( newState,this ); // yes, instruct it ! 2278: if ( return_code == IOPMAckImplied ) { // it finished ! 2279: priv->driver_timer = 0; ! 2280: return IOPMAckImplied; ! 2281: } ! 2282: ! 2283: if ( priv->driver_timer == 0 ) { // it acked behind our back ! 2284: return IOPMAckImplied; ! 2285: } ! 2286: ! 2287: if ( return_code < 0 ) { // somebody goofed ! 2288: return IOPMAckImplied; ! 2289: } ! 2290: ! 2291: priv->driver_timer = (return_code / 1000) + 1; // it didn't finish ! 2292: return IOPMWillAckLater; ! 2293: } ! 2294: ! 2295: ! 2296: //********************************************************************************* ! 2297: // acquire_lock ! 2298: // ! 2299: // We are acquiring the lock we use to protect our queue head from ! 2300: // simutaneous access by a thread which calls acknowledgePowerStateChange ! 2301: // or acknowledgeSetPowerState and the ack timer expiration thread. ! 2302: // Return TRUE if we acquire the lock, and the queue head didn't change ! 2303: // while we were acquiring the lock (and maybe blocked). ! 2304: // If there is no queue head, or it changes while we are blocked, ! 2305: // return FALSE with the lock unlocked. ! 2306: //********************************************************************************* ! 2307: ! 2308: bool IOService::acquire_lock ( void ) ! 2309: { ! 2310: long current_change_note; ! 2311: ! 2312: current_change_note = priv->head_note; ! 2313: if ( current_change_note == -1 ) { ! 2314: return FALSE; ! 2315: } ! 2316: ! 2317: IOTakeLock(priv->our_lock); ! 2318: if ( current_change_note == priv->head_note ) { ! 2319: return TRUE; ! 2320: } ! 2321: else { // we blocked and something changed radically ! 2322: IOUnlock(priv->our_lock); // so there's nothing to do any more ! 2323: return FALSE; ! 2324: } ! 2325: } ! 2326: ! 2327: ! 2328: //********************************************************************************* ! 2329: // foundDevice ! 2330: // ! 2331: // Does nothing here. This should be implemented in a subclass driver. ! 2332: //********************************************************************************* ! 2333: #if BREAK ! 2334: IOReturn IOService::foundDevice ( IOService * yourDevice ) ! 2335: { ! 2336: return IOPMNoErr; ! 2337: } ! 2338: #endif ! 2339: ! 2340: //********************************************************************************* ! 2341: // setPowerState ! 2342: // ! 2343: // Does nothing here. This should be implemented in a subclass driver. ! 2344: //********************************************************************************* ! 2345: ! 2346: IOReturn IOService::setPowerState ( unsigned long powerStateOrdinal, IOService* whatDevice ) ! 2347: { ! 2348: return IOPMNoErr; ! 2349: } ! 2350: ! 2351: ! 2352: //********************************************************************************* ! 2353: // maxCapabilityForDomainState ! 2354: // ! 2355: // Finds the highest power state in the array whose input power ! 2356: // requirement is equal to the input parameter. Where a more intelligent ! 2357: // decision is possible, override this in the subclassed driver. ! 2358: //********************************************************************************* ! 2359: ! 2360: unsigned long IOService::maxCapabilityForDomainState ( IOPMPowerFlags domainState ) ! 2361: { ! 2362: int i; ! 2363: ! 2364: if (pm_vars->theNumberOfPowerStates == 0 ) { ! 2365: return 0; ! 2366: } ! 2367: for ( i = (pm_vars->theNumberOfPowerStates)-1; i >= 0; i-- ) { ! 2368: if ( pm_vars->thePowerStates[i].inputPowerRequirement == domainState ) { ! 2369: return i; ! 2370: } ! 2371: } ! 2372: return 0; ! 2373: } ! 2374: ! 2375: ! 2376: //********************************************************************************* ! 2377: // initialPowerStateForDomainState ! 2378: // ! 2379: // Finds the highest power state in the array whose input power ! 2380: // requirement is equal to the input parameter. Where a more intelligent ! 2381: // decision is possible, override this in the subclassed driver. ! 2382: //********************************************************************************* ! 2383: ! 2384: unsigned long IOService::initialPowerStateForDomainState ( IOPMPowerFlags domainState ) ! 2385: { ! 2386: int i; ! 2387: ! 2388: if (pm_vars->theNumberOfPowerStates == 0 ) { ! 2389: return 0; ! 2390: } ! 2391: for ( i = (pm_vars->theNumberOfPowerStates)-1; i >= 0; i-- ) { ! 2392: if ( pm_vars->thePowerStates[i].inputPowerRequirement == domainState ) { ! 2393: return i; ! 2394: } ! 2395: } ! 2396: return 0; ! 2397: } ! 2398: ! 2399: ! 2400: //********************************************************************************* ! 2401: // powerStateForDomainState ! 2402: // ! 2403: // Finds the highest power state in the array whose input power ! 2404: // requirement is equal to the input parameter. Where a more intelligent ! 2405: // decision is possible, override this in the subclassed driver. ! 2406: //********************************************************************************* ! 2407: ! 2408: unsigned long IOService::powerStateForDomainState ( IOPMPowerFlags domainState ) ! 2409: { ! 2410: int i; ! 2411: ! 2412: if (pm_vars->theNumberOfPowerStates == 0 ) { ! 2413: return 0; ! 2414: } ! 2415: for ( i = (pm_vars->theNumberOfPowerStates)-1; i >= 0; i-- ) { ! 2416: if ( pm_vars->thePowerStates[i].inputPowerRequirement == domainState ) { ! 2417: return i; ! 2418: } ! 2419: } ! 2420: return 0; ! 2421: } ! 2422: ! 2423: ! 2424: //********************************************************************************* ! 2425: // powerStateWillChangeTo ! 2426: // ! 2427: // Does nothing here. This should be implemented in a subclass driver. ! 2428: //********************************************************************************* ! 2429: ! 2430: IOReturn IOService::powerStateWillChangeTo ( IOPMPowerFlags, unsigned long, IOService*) ! 2431: { ! 2432: return 0; ! 2433: } ! 2434: ! 2435: ! 2436: //********************************************************************************* ! 2437: // powerStateDidChangeTo ! 2438: // ! 2439: // Does nothing here. This should be implemented in a subclass driver. ! 2440: //********************************************************************************* ! 2441: ! 2442: IOReturn IOService::powerStateDidChangeTo ( IOPMPowerFlags, unsigned long, IOService*) ! 2443: { ! 2444: return 0; ! 2445: } ! 2446: ! 2447: ! 2448: //********************************************************************************* ! 2449: // newTemperature ! 2450: // ! 2451: // Does nothing here. This should be implemented in a subclass driver. ! 2452: //********************************************************************************* ! 2453: ! 2454: IOReturn IOService::newTemperature ( long currentTemp, IOService * whichZone ) ! 2455: ! 2456: { ! 2457: return IOPMNoErr; ! 2458: } ! 2459: ! 2460: ! 2461: #undef super ! 2462: #define super OSObject ! 2463: ! 2464: OSDefineMetaClassAndStructors(IOPMprot, OSObject) ! 2465: //********************************************************************************* ! 2466: // serialize ! 2467: // ! 2468: // Serialize protected instance variables for debug output. ! 2469: //********************************************************************************* ! 2470: bool IOPMprot::serialize(OSSerialize *s) const ! 2471: { ! 2472: OSString * theOSString; ! 2473: char * buffer; ! 2474: char * ptr; ! 2475: int i; ! 2476: bool rtn_code; ! 2477: ! 2478: buffer = ptr = IONew(char, 2000); ! 2479: if(!buffer) ! 2480: return false; ! 2481: ! 2482: ptr += sprintf(ptr,"{ theNumberOfPowerStates = %d, ",(unsigned int)theNumberOfPowerStates); ! 2483: ! 2484: if ( theNumberOfPowerStates != 0 ) { ! 2485: ptr += sprintf(ptr,"version %d, ",(unsigned int)thePowerStates[0].version); ! 2486: } ! 2487: ! 2488: if ( theNumberOfPowerStates != 0 ) { ! 2489: for ( i = 0; i < (int)theNumberOfPowerStates; i++ ) { ! 2490: ptr += sprintf(ptr,"power state %d = { ",i); ! 2491: ptr += sprintf(ptr,"capabilityFlags %08x, ",(unsigned int)thePowerStates[i].capabilityFlags); ! 2492: ptr += sprintf(ptr,"outputPowerCharacter %08x, ",(unsigned int)thePowerStates[i].outputPowerCharacter); ! 2493: ptr += sprintf(ptr,"inputPowerRequirement %08x, ",(unsigned int)thePowerStates[i].inputPowerRequirement); ! 2494: ptr += sprintf(ptr,"staticPower %d, ",(unsigned int)thePowerStates[i].staticPower); ! 2495: ptr += sprintf(ptr,"unbudgetedPower %d, ",(unsigned int)thePowerStates[i].unbudgetedPower); ! 2496: ptr += sprintf(ptr,"powerToAttain %d, ",(unsigned int)thePowerStates[i].powerToAttain); ! 2497: ptr += sprintf(ptr,"timeToAttain %d, ",(unsigned int)thePowerStates[i].timeToAttain); ! 2498: ptr += sprintf(ptr,"settleUpTime %d, ",(unsigned int)thePowerStates[i].settleUpTime); ! 2499: ptr += sprintf(ptr,"timeToLower %d, ",(unsigned int)thePowerStates[i].timeToLower); ! 2500: ptr += sprintf(ptr,"settleDownTime %d, ",(unsigned int)thePowerStates[i].settleDownTime); ! 2501: ptr += sprintf(ptr,"powerDomainBudget %d }, ",(unsigned int)thePowerStates[i].powerDomainBudget); ! 2502: } ! 2503: } ! 2504: ! 2505: ptr += sprintf(ptr,"aggressiveness = %d, ",(unsigned int)aggressiveness); ! 2506: ptr += sprintf(ptr,"myCurrentState = %d, ",(unsigned int)myCurrentState); ! 2507: ptr += sprintf(ptr,"parentCurrentPowerFlags = %08x, ",(unsigned int)parentCurrentPowerFlags); ! 2508: ptr += sprintf(ptr,"maxCapability = %d }",(unsigned int)maxCapability); ! 2509: ! 2510: theOSString = OSString::withCString(buffer); ! 2511: rtn_code = theOSString->serialize(s); ! 2512: theOSString->release(); ! 2513: IODelete(buffer, char, 2000); ! 2514: ! 2515: return rtn_code; ! 2516: } ! 2517: ! 2518: ! 2519: #undef super ! 2520: #define super OSObject ! 2521: ! 2522: OSDefineMetaClassAndStructors(IOPMpriv, OSObject) ! 2523: //********************************************************************************* ! 2524: // serialize ! 2525: // ! 2526: // Serialize private instance variables for debug output. ! 2527: //********************************************************************************* ! 2528: bool IOPMpriv::serialize(OSSerialize *s) const ! 2529: { ! 2530: OSString * theOSString; ! 2531: char * buffer; ! 2532: char * ptr; ! 2533: IOPMinformee * nextObject; ! 2534: bool rtn_code; ! 2535: ! 2536: buffer = ptr = IONew(char, 2000); ! 2537: if(!buffer) ! 2538: return false; ! 2539: ! 2540: ptr += sprintf(ptr,"{ this object = %08x",(unsigned int)owner); ! 2541: if ( we_are_root ) { ! 2542: ptr += sprintf(ptr," (root)"); ! 2543: } ! 2544: ptr += sprintf(ptr,", "); ! 2545: ! 2546: nextObject = interestedDrivers->firstInList(); // display interested drivers ! 2547: while ( nextObject != NULL ) { ! 2548: ptr += sprintf(ptr,"interested driver = %08x, ",(unsigned int)nextObject->whatObject); ! 2549: nextObject = interestedDrivers->nextInList(nextObject); ! 2550: } ! 2551: ! 2552: nextObject =children->firstInList(); // display power domain children ! 2553: while ( nextObject != NULL ) { ! 2554: ptr += sprintf(ptr,"child = %08x, ",(unsigned int)nextObject->whatObject); ! 2555: nextObject = children->nextInList(nextObject); ! 2556: } ! 2557: ! 2558: ptr += sprintf(ptr,"numberOfInformees = %d, ",(unsigned int)numberOfInformees); ! 2559: ! 2560: if ( machine_state != IOPMfinished ) { ! 2561: ptr += sprintf(ptr,"machine_state = %d, ",(unsigned int)machine_state); ! 2562: ptr += sprintf(ptr,"driver_timer = %d, ",(unsigned int)driver_timer); ! 2563: ptr += sprintf(ptr,"settle_time = %d, ",(unsigned int)settle_time); ! 2564: ptr += sprintf(ptr,"head_note_flags = %08x, ",(unsigned int)head_note_flags); ! 2565: ptr += sprintf(ptr,"head_note_state = %d, ",(unsigned int)head_note_state); ! 2566: ptr += sprintf(ptr,"head_note_outputFlags = %08x, ",(unsigned int)head_note_outputFlags); ! 2567: ptr += sprintf(ptr,"head_note_domainState = %08x, ",(unsigned int)head_note_domainState); ! 2568: ptr += sprintf(ptr,"head_note_capabilityFlags = %08x, ",(unsigned int)head_note_capabilityFlags); ! 2569: ptr += sprintf(ptr,"head_note_pendingAcks = %d, ",(unsigned int)head_note_pendingAcks); ! 2570: } ! 2571: ! 2572: if ( device_overrides ) { ! 2573: ptr += sprintf(ptr,"device overrides, "); ! 2574: } ! 2575: ptr += sprintf(ptr,"driverDesire = %d, ",(unsigned int)driverDesire); ! 2576: ptr += sprintf(ptr,"deviceDesire = %d, ",(unsigned int)deviceDesire); ! 2577: ptr += sprintf(ptr,"ourDesiredPowerState = %d, ",(unsigned int)ourDesiredPowerState); ! 2578: ptr += sprintf(ptr,"previousRequest = %d }",(unsigned int)previousRequest); ! 2579: ! 2580: theOSString = OSString::withCString(buffer); ! 2581: rtn_code = theOSString->serialize(s); ! 2582: theOSString->release(); ! 2583: IODelete(buffer, char, 2000); ! 2584: ! 2585: return rtn_code; ! 2586: } ! 2587:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.