1 /******************************************************************************
3 * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 ******************************************************************************/
17 #include <drv_types.h>
22 /* Callback function of LED BlinkTimer, */
23 /* it just schedules to corresponding BlinkWorkItem/led_blink_hdl */
25 void BlinkTimerCallback(unsigned long data)
27 struct LED_871x *pLed = (struct LED_871x *)data;
28 struct adapter *padapter = pLed->padapter;
30 if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped))
33 schedule_work(&(pLed->BlinkWorkItem));
38 /* Callback function of LED BlinkWorkItem. */
40 void BlinkWorkItemCallback(struct work_struct *work)
42 struct LED_871x *pLed = container_of(work, struct LED_871x, BlinkWorkItem);
48 /* Reset status of LED_871x object. */
50 void ResetLedStatus(struct LED_871x *pLed)
52 pLed->CurrLedState = RTW_LED_OFF; /* Current LED state. */
53 pLed->bLedOn = false; /* true if LED is ON, false if LED is OFF. */
55 pLed->bLedBlinkInProgress = false; /* true if it is blinking, false o.w.. */
56 pLed->bLedWPSBlinkInProgress = false;
58 pLed->BlinkTimes = 0; /* Number of times to toggle led state for blinking. */
59 pLed->BlinkingLedState = LED_UNKNOWN; /* Next state for blinking, either RTW_LED_ON or RTW_LED_OFF are. */
61 pLed->bLedNoLinkBlinkInProgress = false;
62 pLed->bLedLinkBlinkInProgress = false;
63 pLed->bLedStartToLinkBlinkInProgress = false;
64 pLed->bLedScanBlinkInProgress = false;
68 /* Initialize an LED_871x object. */
69 void InitLed871x(struct adapter *padapter, struct LED_871x *pLed)
71 pLed->padapter = padapter;
75 setup_timer(&(pLed->BlinkTimer), BlinkTimerCallback,
78 INIT_WORK(&(pLed->BlinkWorkItem), BlinkWorkItemCallback);
84 /* DeInitialize an LED_871x object. */
86 void DeInitLed871x(struct LED_871x *pLed)
88 cancel_work_sync(&(pLed->BlinkWorkItem));
89 del_timer_sync(&(pLed->BlinkTimer));
95 /* Implementation of LED blinking behavior. */
96 /* It toggle off LED and schedule corresponding timer if necessary. */
99 static void SwLedBlink1(struct LED_871x *pLed)
101 struct adapter *padapter = pLed->padapter;
102 struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
103 u8 bStopBlinking = false;
105 /* Change LED according to BlinkingLedState specified. */
106 if (pLed->BlinkingLedState == RTW_LED_ON) {
107 SwLedOn(padapter, pLed);
108 RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes));
110 SwLedOff(padapter, pLed);
111 RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes));
114 if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
115 SwLedOff(padapter, pLed);
116 ResetLedStatus(pLed);
120 switch (pLed->CurrLedState) {
121 case LED_BLINK_SLOWLY:
123 pLed->BlinkingLedState = RTW_LED_OFF;
125 pLed->BlinkingLedState = RTW_LED_ON;
126 mod_timer(&pLed->BlinkTimer, jiffies +
127 msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA));
129 case LED_BLINK_NORMAL:
131 pLed->BlinkingLedState = RTW_LED_OFF;
133 pLed->BlinkingLedState = RTW_LED_ON;
134 mod_timer(&pLed->BlinkTimer, jiffies +
135 msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA));
139 if (pLed->BlinkTimes == 0)
140 bStopBlinking = true;
142 if (check_fwstate(pmlmepriv, _FW_LINKED)) {
143 pLed->bLedLinkBlinkInProgress = true;
144 pLed->CurrLedState = LED_BLINK_NORMAL;
146 pLed->BlinkingLedState = RTW_LED_OFF;
148 pLed->BlinkingLedState = RTW_LED_ON;
149 mod_timer(&pLed->BlinkTimer, jiffies +
150 msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA));
151 RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
152 } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) {
153 pLed->bLedNoLinkBlinkInProgress = true;
154 pLed->CurrLedState = LED_BLINK_SLOWLY;
156 pLed->BlinkingLedState = RTW_LED_OFF;
158 pLed->BlinkingLedState = RTW_LED_ON;
159 mod_timer(&pLed->BlinkTimer, jiffies +
160 msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA));
161 RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
163 pLed->bLedScanBlinkInProgress = false;
166 pLed->BlinkingLedState = RTW_LED_OFF;
168 pLed->BlinkingLedState = RTW_LED_ON;
169 mod_timer(&pLed->BlinkTimer, jiffies +
170 msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA));
175 if (pLed->BlinkTimes == 0)
176 bStopBlinking = true;
178 if (check_fwstate(pmlmepriv, _FW_LINKED)) {
179 pLed->bLedLinkBlinkInProgress = true;
180 pLed->CurrLedState = LED_BLINK_NORMAL;
182 pLed->BlinkingLedState = RTW_LED_OFF;
184 pLed->BlinkingLedState = RTW_LED_ON;
185 mod_timer(&pLed->BlinkTimer, jiffies +
186 msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA));
187 RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
188 } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) {
189 pLed->bLedNoLinkBlinkInProgress = true;
190 pLed->CurrLedState = LED_BLINK_SLOWLY;
192 pLed->BlinkingLedState = RTW_LED_OFF;
194 pLed->BlinkingLedState = RTW_LED_ON;
195 mod_timer(&pLed->BlinkTimer, jiffies +
196 msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA));
197 RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
199 pLed->BlinkTimes = 0;
200 pLed->bLedBlinkInProgress = false;
203 pLed->BlinkingLedState = RTW_LED_OFF;
205 pLed->BlinkingLedState = RTW_LED_ON;
206 mod_timer(&pLed->BlinkTimer, jiffies +
207 msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA));
212 pLed->BlinkingLedState = RTW_LED_OFF;
214 pLed->BlinkingLedState = RTW_LED_ON;
215 mod_timer(&pLed->BlinkTimer, jiffies +
216 msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA));
218 case LED_BLINK_WPS_STOP: /* WPS success */
219 if (pLed->BlinkingLedState == RTW_LED_ON)
220 bStopBlinking = false;
222 bStopBlinking = true;
225 pLed->bLedLinkBlinkInProgress = true;
226 pLed->CurrLedState = LED_BLINK_NORMAL;
228 pLed->BlinkingLedState = RTW_LED_OFF;
230 pLed->BlinkingLedState = RTW_LED_ON;
231 mod_timer(&pLed->BlinkTimer, jiffies +
232 msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA));
233 RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
235 pLed->bLedWPSBlinkInProgress = false;
237 pLed->BlinkingLedState = RTW_LED_OFF;
238 mod_timer(&pLed->BlinkTimer, jiffies +
239 msecs_to_jiffies(LED_BLINK_WPS_SUCCESS_INTERVAL_ALPHA));
247 /* ALPHA, added by chiyoko, 20090106 */
248 static void SwLedControlMode1(struct adapter *padapter, enum LED_CTL_MODE LedAction)
250 struct led_priv *ledpriv = &(padapter->ledpriv);
251 struct LED_871x *pLed = &(ledpriv->SwLed0);
252 struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
255 case LED_CTL_POWER_ON:
256 case LED_CTL_START_TO_LINK:
257 case LED_CTL_NO_LINK:
258 if (!pLed->bLedNoLinkBlinkInProgress) {
259 if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed))
261 if (pLed->bLedLinkBlinkInProgress) {
262 del_timer_sync(&(pLed->BlinkTimer));
263 pLed->bLedLinkBlinkInProgress = false;
265 if (pLed->bLedBlinkInProgress) {
266 del_timer_sync(&(pLed->BlinkTimer));
267 pLed->bLedBlinkInProgress = false;
270 pLed->bLedNoLinkBlinkInProgress = true;
271 pLed->CurrLedState = LED_BLINK_SLOWLY;
273 pLed->BlinkingLedState = RTW_LED_OFF;
275 pLed->BlinkingLedState = RTW_LED_ON;
276 mod_timer(&pLed->BlinkTimer, jiffies +
277 msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA));
281 if (!pLed->bLedLinkBlinkInProgress) {
282 if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed))
284 if (pLed->bLedNoLinkBlinkInProgress) {
285 del_timer_sync(&(pLed->BlinkTimer));
286 pLed->bLedNoLinkBlinkInProgress = false;
288 if (pLed->bLedBlinkInProgress) {
289 del_timer_sync(&(pLed->BlinkTimer));
290 pLed->bLedBlinkInProgress = false;
292 pLed->bLedLinkBlinkInProgress = true;
293 pLed->CurrLedState = LED_BLINK_NORMAL;
295 pLed->BlinkingLedState = RTW_LED_OFF;
297 pLed->BlinkingLedState = RTW_LED_ON;
298 mod_timer(&pLed->BlinkTimer, jiffies +
299 msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA));
302 case LED_CTL_SITE_SURVEY:
303 if ((pmlmepriv->LinkDetectInfo.bBusyTraffic) && (check_fwstate(pmlmepriv, _FW_LINKED))) {
305 } else if (!pLed->bLedScanBlinkInProgress) {
306 if (IS_LED_WPS_BLINKING(pLed))
308 if (pLed->bLedNoLinkBlinkInProgress) {
309 del_timer_sync(&(pLed->BlinkTimer));
310 pLed->bLedNoLinkBlinkInProgress = false;
312 if (pLed->bLedLinkBlinkInProgress) {
313 del_timer_sync(&(pLed->BlinkTimer));
314 pLed->bLedLinkBlinkInProgress = false;
316 if (pLed->bLedBlinkInProgress) {
317 del_timer_sync(&(pLed->BlinkTimer));
318 pLed->bLedBlinkInProgress = false;
320 pLed->bLedScanBlinkInProgress = true;
321 pLed->CurrLedState = LED_BLINK_SCAN;
322 pLed->BlinkTimes = 24;
324 pLed->BlinkingLedState = RTW_LED_OFF;
326 pLed->BlinkingLedState = RTW_LED_ON;
327 mod_timer(&pLed->BlinkTimer, jiffies +
328 msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA));
333 if (!pLed->bLedBlinkInProgress) {
334 if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed))
336 if (pLed->bLedNoLinkBlinkInProgress) {
337 del_timer_sync(&(pLed->BlinkTimer));
338 pLed->bLedNoLinkBlinkInProgress = false;
340 if (pLed->bLedLinkBlinkInProgress) {
341 del_timer_sync(&(pLed->BlinkTimer));
342 pLed->bLedLinkBlinkInProgress = false;
344 pLed->bLedBlinkInProgress = true;
345 pLed->CurrLedState = LED_BLINK_TXRX;
346 pLed->BlinkTimes = 2;
348 pLed->BlinkingLedState = RTW_LED_OFF;
350 pLed->BlinkingLedState = RTW_LED_ON;
351 mod_timer(&pLed->BlinkTimer, jiffies +
352 msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA));
355 case LED_CTL_START_WPS: /* wait until xinpin finish */
356 case LED_CTL_START_WPS_BOTTON:
357 if (!pLed->bLedWPSBlinkInProgress) {
358 if (pLed->bLedNoLinkBlinkInProgress) {
359 del_timer_sync(&(pLed->BlinkTimer));
360 pLed->bLedNoLinkBlinkInProgress = false;
362 if (pLed->bLedLinkBlinkInProgress) {
363 del_timer_sync(&(pLed->BlinkTimer));
364 pLed->bLedLinkBlinkInProgress = false;
366 if (pLed->bLedBlinkInProgress) {
367 del_timer_sync(&(pLed->BlinkTimer));
368 pLed->bLedBlinkInProgress = false;
370 if (pLed->bLedScanBlinkInProgress) {
371 del_timer_sync(&(pLed->BlinkTimer));
372 pLed->bLedScanBlinkInProgress = false;
374 pLed->bLedWPSBlinkInProgress = true;
375 pLed->CurrLedState = LED_BLINK_WPS;
377 pLed->BlinkingLedState = RTW_LED_OFF;
379 pLed->BlinkingLedState = RTW_LED_ON;
380 mod_timer(&pLed->BlinkTimer, jiffies +
381 msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA));
384 case LED_CTL_STOP_WPS:
385 if (pLed->bLedNoLinkBlinkInProgress) {
386 del_timer_sync(&(pLed->BlinkTimer));
387 pLed->bLedNoLinkBlinkInProgress = false;
389 if (pLed->bLedLinkBlinkInProgress) {
390 del_timer_sync(&(pLed->BlinkTimer));
391 pLed->bLedLinkBlinkInProgress = false;
393 if (pLed->bLedBlinkInProgress) {
394 del_timer_sync(&(pLed->BlinkTimer));
395 pLed->bLedBlinkInProgress = false;
397 if (pLed->bLedScanBlinkInProgress) {
398 del_timer_sync(&(pLed->BlinkTimer));
399 pLed->bLedScanBlinkInProgress = false;
401 if (pLed->bLedWPSBlinkInProgress)
402 del_timer_sync(&(pLed->BlinkTimer));
404 pLed->bLedWPSBlinkInProgress = true;
405 pLed->CurrLedState = LED_BLINK_WPS_STOP;
407 pLed->BlinkingLedState = RTW_LED_OFF;
408 mod_timer(&pLed->BlinkTimer, jiffies +
409 msecs_to_jiffies(LED_BLINK_WPS_SUCCESS_INTERVAL_ALPHA));
411 pLed->BlinkingLedState = RTW_LED_ON;
412 mod_timer(&pLed->BlinkTimer,
413 jiffies + msecs_to_jiffies(0));
416 case LED_CTL_STOP_WPS_FAIL:
417 if (pLed->bLedWPSBlinkInProgress) {
418 del_timer_sync(&(pLed->BlinkTimer));
419 pLed->bLedWPSBlinkInProgress = false;
421 pLed->bLedNoLinkBlinkInProgress = true;
422 pLed->CurrLedState = LED_BLINK_SLOWLY;
424 pLed->BlinkingLedState = RTW_LED_OFF;
426 pLed->BlinkingLedState = RTW_LED_ON;
427 mod_timer(&pLed->BlinkTimer, jiffies +
428 msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA));
430 case LED_CTL_POWER_OFF:
431 pLed->CurrLedState = RTW_LED_OFF;
432 pLed->BlinkingLedState = RTW_LED_OFF;
433 if (pLed->bLedNoLinkBlinkInProgress) {
434 del_timer_sync(&(pLed->BlinkTimer));
435 pLed->bLedNoLinkBlinkInProgress = false;
437 if (pLed->bLedLinkBlinkInProgress) {
438 del_timer_sync(&(pLed->BlinkTimer));
439 pLed->bLedLinkBlinkInProgress = false;
441 if (pLed->bLedBlinkInProgress) {
442 del_timer_sync(&(pLed->BlinkTimer));
443 pLed->bLedBlinkInProgress = false;
445 if (pLed->bLedWPSBlinkInProgress) {
446 del_timer_sync(&(pLed->BlinkTimer));
447 pLed->bLedWPSBlinkInProgress = false;
449 if (pLed->bLedScanBlinkInProgress) {
450 del_timer_sync(&(pLed->BlinkTimer));
451 pLed->bLedScanBlinkInProgress = false;
453 SwLedOff(padapter, pLed);
459 RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Led %d\n", pLed->CurrLedState));
464 /* Handler function of LED Blinking. */
466 void BlinkHandler(struct LED_871x *pLed)
468 struct adapter *padapter = pLed->padapter;
470 if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped))
476 void LedControl8188eu(struct adapter *padapter, enum LED_CTL_MODE LedAction)
478 struct led_priv *ledpriv = &(padapter->ledpriv);
480 if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped) ||
481 (!padapter->hw_init_completed))
484 if (!ledpriv->bRegUseLed)
487 if ((padapter->pwrctrlpriv.rf_pwrstate != rf_on &&
488 padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) &&
489 (LedAction == LED_CTL_TX || LedAction == LED_CTL_RX ||
490 LedAction == LED_CTL_SITE_SURVEY ||
491 LedAction == LED_CTL_LINK ||
492 LedAction == LED_CTL_NO_LINK ||
493 LedAction == LED_CTL_POWER_ON))
496 SwLedControlMode1(padapter, LedAction);