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: