1: 
     2: #include "WiFiController.h" 
     3: 
     4: /**************************************************************************
     5: * POWER-MANAGEMENT CODE
     6: ***************************************************************************
     7: * These definitions and functions allow the driver to handle power state
     8: * changes to support sleep and wake.
     9: **************************************************************************/
    10: 
    11: // Two power states are supported by the driver, On and Off.
    12: 
    13: enum {
    14:     kWiFiControllerPowerStateOff = 0,
    15:     kWiFiControllerPowerStateOn,
    16:     kWiFiControllerPowerStateCount
    17: };
    18: 
    19: // An IOPMPowerState structure is added to the array for each supported
    20: // power state. This array is used by the power management policy-maker
    21: // to determine our capabilities and requirements for each power state.
    22: 
    23: static IOPMPowerState _wifiControllerPowerStateArray[ kWiFiControllerPowerStateCount ] =
    24: {
    25:     { 1,0,0,0,0,0,0,0,0,0,0,0 },
    26:     { 1,IOPMDeviceUsable,IOPMPowerOn,IOPMPowerOn,0,0,0,0,0,0,0,0 }
    27: };
    28: 
    29: enum {
    30:     kFiveSeconds = 5000000
    31: };
    32: 
    33: //---------------------------------------------------------------------------
    34: // handleSetPowerStateOff()
    35: //
    36: // The policy-maker has told the driver to turn off the device, and the
    37: // driver has started a new thread to do this. This C function is the start
    38: // of that thread. This function then calls itself through the command gate
    39: // to gain exclusive access to the device.
    40: //---------------------------------------------------------------------------
    41: 
    42: void handleSetPowerStateOff(thread_call_param_t param0, thread_call_param_t param1) {
    43:     WiFiController *self = (WiFiController *) param0;
    44: 
    45:     assert(self);
    46: 
    47:     if (param1 == 0) {
    48:         self->getCommandGate()->runAction( (IOCommandGate::Action)
    49:                                            handleSetPowerStateOff,
    50:                                            (void *) 1 /* param1 */ );
    51:     } else {
    52:         self->setPowerStateOff();
    53:         self->release();  // offset the retain in setPowerState()
    54:     }
    55: }
    56: 
    57: //---------------------------------------------------------------------------
    58: // handleSetPowerStateOn()
    59: //
    60: // The policy-maker has told the driver to turn on the device, and the
    61: // driver has started a new thread to do this. This C function is the start
    62: // of that thread. This function then calls itself through the command gate
    63: // to gain exclusive access to the device.
    64: //---------------------------------------------------------------------------
    65: 
    66: void handleSetPowerStateOn(thread_call_param_t param0, thread_call_param_t param1) {
    67:     WiFiController* self = ( WiFiController *) param0;
    68: 
    69:     assert(self);
    70: 
    71:     if (param1 == 0) {
    72:         self->getCommandGate()->runAction( (IOCommandGate::Action)
    73:                                            handleSetPowerStateOn,
    74:                                            (void *) 1 /* param1 */ );
    75:     } else {
    76:         self->setPowerStateOn();
    77:         self->release();  // offset the retain in setPowerState()
    78:     }
    79: }
    80: 
    81: //---------------------------------------------------------------------------
    82: // registerWithPolicyMaker()
    83: //
    84: // The superclass invokes this function when it is time for the driver to
    85: // register with the power management policy-maker of the device.
    86: //
    87: // The driver registers by passing to the policy-maker an array which
    88: // describes the power states supported by the hardware and the driver.
    89: //
    90: // Argument:
    91: //
    92: // policyMaker - A pointer to the power management policy-maker of the
    93: //               device.
    94: //---------------------------------------------------------------------------
    95: 
    96: IOReturn WiFiController::registerWithPolicyMaker(IOService * policyMaker) {
    97:     IOReturn ret;
    98: 
    99:     // Initialize power management support state.
   100: 
   101:     _pmPowerState  = kWiFiControllerPowerStateOn;
   102:     _pmPolicyMaker = policyMaker;
   103: 
   104:     // No cheating here. Decouple the driver's handling of power change
   105:     // requests from the power management work loop thread. Not strictly
   106:     // necessary for the work that this driver is doing currently, but
   107:     // useful as an example of how to do things in general.
   108:     //
   109:     // Allocate thread callouts for asynchronous power on and power off.
   110:     // Allocation failure is not detected here, but before each use in
   111:     // the setPowerState() method.
   112: 
   113:     _powerOffThreadCall = thread_call_allocate( 
   114:                            (thread_call_func_t)  handleSetPowerStateOff,
   115:                            (thread_call_param_t) this );
   116: 
   117:     _powerOnThreadCall  = thread_call_allocate(
   118:                            (thread_call_func_t)  handleSetPowerStateOn,
   119:                            (thread_call_param_t) this );
   120: 
   121:     ret = _pmPolicyMaker->registerPowerDriver(this,
   122:                                               _wifiControllerPowerStateArray,
   123:                                               kWiFiControllerPowerStateCount);
   124:     
   125:     return ret;
   126: }
   127: 
   128: //---------------------------------------------------------------------------
   129: // setPowerState()
   130: //
   131: // The power management policy-maker for this device invokes this function
   132: // to switch the power state of the device.
   133: //
   134: // Arguments:
   135: //
   136: // powerStateOrdinal - an index into the power state array for the state
   137: //                     to switch to.
   138: //
   139: // policyMaker       - a pointer to the policy-maker.
   140: //---------------------------------------------------------------------------
   141: 
   142: IOReturn WiFiController::setPowerState(unsigned long powerStateOrdinal, IOService *policyMaker) {
   143:     // The default return value is for an implied acknowledgement.
   144:     // If the appropriate thread wasn't allocated earlier in
   145:     // registerWithPolicyMaker(), then this is what will be returned.
   146: 
   147:     IOReturn result = IOPMAckImplied;
   148: 
   149:     // There's nothing to do if our current power state is the one
   150:     // we're being asked to change to.
   151:     if (_pmPowerState == powerStateOrdinal) {
   152:         return result;
   153:     }
   154: 
   155:     switch (powerStateOrdinal) {
   156:         case kWiFiControllerPowerStateOff:
   157: 
   158:             // The driver is being told to turn off the device for some reason.
   159:             // It saves whatever state and context it needs to and then shuts
   160:             // off the device.
   161:             //
   162:             // It may take some time to turn off the HW, so the driver spawns
   163:             // a thread to power down the device and returns immediately to
   164:             // the policy-maker giving an upper bound on the time it will need
   165:             // to complete the power state transition.
   166: 
   167:             if (_powerOffThreadCall) {
   168:                 // Prevent the object from being freed while a call is pending.
   169:                 // If thread_call_enter() returns TRUE, then a call is already
   170:                 // pending, and the extra retain is dropped.
   171:                 
   172:                 retain();
   173:                 if (thread_call_enter(_powerOffThreadCall) == TRUE) {
   174:                     release();
   175:                 }
   176:                 result = kFiveSeconds;
   177:             }
   178:             break;
   179: 
   180:         case kWiFiControllerPowerStateOn:
   181: 
   182:             // The driver is being told to turn on the device.  It does so
   183:             // and then restores any state or context which it has previously
   184:             // saved.
   185:             //
   186:             // It may take some time to turn on the HW, so the driver spawns
   187:             // a thread to power up the device and returns immediately to
   188:             // the policy-maker giving an upper bound on the time it will need
   189:             // to complete the power state transition.
   190: 
   191:             if (_powerOnThreadCall) {
   192:                 // Prevent the object from being freed while a call is pending.
   193:                 // If thread_call_enter() returns TRUE, then a call is already
   194:                 // pending, and the extra retain is dropped.
   195: 
   196:                 retain();
   197:                 if (thread_call_enter(_powerOnThreadCall) == TRUE) {
   198:                     release();
   199:                 }
   200:                 result = kFiveSeconds;
   201:             }
   202:             break;
   203:         
   204:         default:
   205:             WLLogEmerg("invalid power state (%ld)", powerStateOrdinal);
   206:             break;
   207:     }
   208: 
   209:     return result;
   210: }
   211: 
   212: //---------------------------------------------------------------------------
   213: // setPowerStateOff()
   214: //
   215: // The policy-maker has told the driver to turn off the device, and this
   216: // function is called by a new kernel thread, while holding the gate in
   217: // the driver's work loop. Exclusive hardware access is assured.
   218: //---------------------------------------------------------------------------
   219: 
   220: void WiFiController::setPowerStateOff() {
   221:     // At this point, all clients have been notified of the driver's
   222:     // imminent transition to a power state that renders it "unusable".
   223:     // And beacuse of the response to this notification by all clients,
   224:     // the controller driver is guaranteed to be disabled when this
   225:     // function is called.
   226: 
   227:     //freeHardware();
   228:     _cardGone = true;
   229:     getReadyForSleep();
   230:     
   231:     _pmPowerState = kWiFiControllerPowerStateOff;
   232: 
   233:     // Since the driver returned a non-acknowledgement when called at
   234:     // setPowerState(), it sends an ACK to the policy-maker here to
   235:     // indicate that our power state transition is complete.
   236: 
   237:     _pmPolicyMaker->acknowledgeSetPowerState();
   238: }
   239: 
   240: //---------------------------------------------------------------------------
   241: // setPowerStateOn()
   242: //
   243: // The policy-maker has told the driver to turn on the device, and this
   244: // function is called by a new kernel thread, while holding the gate in
   245: // the driver's work loop. Exclusive hardware access is assured.
   246: //---------------------------------------------------------------------------
   247: 
   248: void WiFiController::setPowerStateOn() {
   249:     _pmPowerState = kWiFiControllerPowerStateOn;
   250: 
   251:     IOSleep(2);
   252:     _cardGone = false;
   253:     initHardware();
   254:     
   255:     // Since the driver returned a non-acknowledgement when called at
   256:     // setPowerState(), it sends an ACK to the policy-maker here to
   257:     // indicate that our power state transition is complete.
   258: 
   259:     _pmPolicyMaker->acknowledgeSetPowerState();
   260: 
   261:     // With power restored, all clients will be notified that the driver
   262:     // has became "usable". If a client wishes to use the driver, then the
   263:     // driver can expect a call to its enable() method to start things off.
   264: }
   265: 
   266: