Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / staging / rtl8188eu / core / rtw_led.c
1 /******************************************************************************
2  *
3  * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
4  *
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.
8  *
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
12  * more details.
13  *
14  *
15  ******************************************************************************/
16
17 #include <drv_types.h>
18 #include "rtw_led.h"
19
20 /*  */
21 /*      Description: */
22 /*              Callback function of LED BlinkTimer, */
23 /*              it just schedules to corresponding BlinkWorkItem/led_blink_hdl */
24 /*  */
25 void BlinkTimerCallback(unsigned long data)
26 {
27         struct LED_871x *pLed = (struct LED_871x *)data;
28         struct adapter *padapter = pLed->padapter;
29
30         if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped))
31                 return;
32
33         schedule_work(&(pLed->BlinkWorkItem));
34 }
35
36 /*  */
37 /*      Description: */
38 /*              Callback function of LED BlinkWorkItem. */
39 /*  */
40 void BlinkWorkItemCallback(struct work_struct *work)
41 {
42         struct LED_871x *pLed = container_of(work, struct LED_871x, BlinkWorkItem);
43         BlinkHandler(pLed);
44 }
45
46 /*  */
47 /*      Description: */
48 /*              Reset status of LED_871x object. */
49 /*  */
50 void ResetLedStatus(struct LED_871x *pLed)
51 {
52         pLed->CurrLedState = RTW_LED_OFF; /*  Current LED state. */
53         pLed->bLedOn = false; /*  true if LED is ON, false if LED is OFF. */
54
55         pLed->bLedBlinkInProgress = false; /*  true if it is blinking, false o.w.. */
56         pLed->bLedWPSBlinkInProgress = false;
57
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. */
60
61         pLed->bLedNoLinkBlinkInProgress = false;
62         pLed->bLedLinkBlinkInProgress = false;
63         pLed->bLedStartToLinkBlinkInProgress = false;
64         pLed->bLedScanBlinkInProgress = false;
65 }
66
67 /*Description: */
68 /*              Initialize an LED_871x object. */
69 void InitLed871x(struct adapter *padapter, struct LED_871x *pLed)
70 {
71         pLed->padapter = padapter;
72
73         ResetLedStatus(pLed);
74
75         setup_timer(&(pLed->BlinkTimer), BlinkTimerCallback,
76                     (unsigned long)pLed);
77
78         INIT_WORK(&(pLed->BlinkWorkItem), BlinkWorkItemCallback);
79 }
80
81
82 /*  */
83 /*      Description: */
84 /*              DeInitialize an LED_871x object. */
85 /*  */
86 void DeInitLed871x(struct LED_871x *pLed)
87 {
88         cancel_work_sync(&(pLed->BlinkWorkItem));
89         del_timer_sync(&(pLed->BlinkTimer));
90         ResetLedStatus(pLed);
91 }
92
93 /*  */
94 /*      Description: */
95 /*              Implementation of LED blinking behavior. */
96 /*              It toggle off LED and schedule corresponding timer if necessary. */
97 /*  */
98
99 static void SwLedBlink1(struct LED_871x *pLed)
100 {
101         struct adapter *padapter = pLed->padapter;
102         struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
103         u8 bStopBlinking = false;
104
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));
109         } else {
110                 SwLedOff(padapter, pLed);
111                 RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes));
112         }
113
114         if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
115                 SwLedOff(padapter, pLed);
116                 ResetLedStatus(pLed);
117                 return;
118         }
119
120         switch (pLed->CurrLedState) {
121         case LED_BLINK_SLOWLY:
122                 if (pLed->bLedOn)
123                         pLed->BlinkingLedState = RTW_LED_OFF;
124                 else
125                         pLed->BlinkingLedState = RTW_LED_ON;
126                 mod_timer(&pLed->BlinkTimer, jiffies +
127                           msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA));
128                 break;
129         case LED_BLINK_NORMAL:
130                 if (pLed->bLedOn)
131                         pLed->BlinkingLedState = RTW_LED_OFF;
132                 else
133                         pLed->BlinkingLedState = RTW_LED_ON;
134                 mod_timer(&pLed->BlinkTimer, jiffies +
135                           msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA));
136                 break;
137         case LED_BLINK_SCAN:
138                 pLed->BlinkTimes--;
139                 if (pLed->BlinkTimes == 0)
140                         bStopBlinking = true;
141                 if (bStopBlinking) {
142                         if (check_fwstate(pmlmepriv, _FW_LINKED)) {
143                                 pLed->bLedLinkBlinkInProgress = true;
144                                 pLed->CurrLedState = LED_BLINK_NORMAL;
145                                 if (pLed->bLedOn)
146                                         pLed->BlinkingLedState = RTW_LED_OFF;
147                                 else
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;
155                                 if (pLed->bLedOn)
156                                         pLed->BlinkingLedState = RTW_LED_OFF;
157                                 else
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));
162                         }
163                         pLed->bLedScanBlinkInProgress = false;
164                 } else {
165                         if (pLed->bLedOn)
166                                 pLed->BlinkingLedState = RTW_LED_OFF;
167                         else
168                                 pLed->BlinkingLedState = RTW_LED_ON;
169                         mod_timer(&pLed->BlinkTimer, jiffies +
170                                   msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA));
171                 }
172                 break;
173         case LED_BLINK_TXRX:
174                 pLed->BlinkTimes--;
175                 if (pLed->BlinkTimes == 0)
176                         bStopBlinking = true;
177                 if (bStopBlinking) {
178                         if (check_fwstate(pmlmepriv, _FW_LINKED)) {
179                                 pLed->bLedLinkBlinkInProgress = true;
180                                 pLed->CurrLedState = LED_BLINK_NORMAL;
181                                 if (pLed->bLedOn)
182                                         pLed->BlinkingLedState = RTW_LED_OFF;
183                                 else
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;
191                                 if (pLed->bLedOn)
192                                         pLed->BlinkingLedState = RTW_LED_OFF;
193                                 else
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));
198                         }
199                         pLed->BlinkTimes = 0;
200                         pLed->bLedBlinkInProgress = false;
201                 } else {
202                         if (pLed->bLedOn)
203                                 pLed->BlinkingLedState = RTW_LED_OFF;
204                         else
205                                 pLed->BlinkingLedState = RTW_LED_ON;
206                         mod_timer(&pLed->BlinkTimer, jiffies +
207                                   msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA));
208                 }
209                 break;
210         case LED_BLINK_WPS:
211                 if (pLed->bLedOn)
212                         pLed->BlinkingLedState = RTW_LED_OFF;
213                 else
214                         pLed->BlinkingLedState = RTW_LED_ON;
215                 mod_timer(&pLed->BlinkTimer, jiffies +
216                           msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA));
217                 break;
218         case LED_BLINK_WPS_STOP:        /* WPS success */
219                 if (pLed->BlinkingLedState == RTW_LED_ON)
220                         bStopBlinking = false;
221                 else
222                         bStopBlinking = true;
223
224                 if (bStopBlinking) {
225                         pLed->bLedLinkBlinkInProgress = true;
226                         pLed->CurrLedState = LED_BLINK_NORMAL;
227                         if (pLed->bLedOn)
228                                 pLed->BlinkingLedState = RTW_LED_OFF;
229                         else
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));
234
235                         pLed->bLedWPSBlinkInProgress = false;
236                 } else {
237                         pLed->BlinkingLedState = RTW_LED_OFF;
238                         mod_timer(&pLed->BlinkTimer, jiffies +
239                                   msecs_to_jiffies(LED_BLINK_WPS_SUCCESS_INTERVAL_ALPHA));
240                 }
241                 break;
242         default:
243                 break;
244         }
245 }
246
247  /* ALPHA, added by chiyoko, 20090106 */
248 static void SwLedControlMode1(struct adapter *padapter, enum LED_CTL_MODE LedAction)
249 {
250         struct led_priv *ledpriv = &(padapter->ledpriv);
251         struct LED_871x *pLed = &(ledpriv->SwLed0);
252         struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
253
254         switch (LedAction) {
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))
260                                 return;
261                         if (pLed->bLedLinkBlinkInProgress) {
262                                 del_timer_sync(&(pLed->BlinkTimer));
263                                 pLed->bLedLinkBlinkInProgress = false;
264                         }
265                         if (pLed->bLedBlinkInProgress) {
266                                 del_timer_sync(&(pLed->BlinkTimer));
267                                 pLed->bLedBlinkInProgress = false;
268                         }
269
270                         pLed->bLedNoLinkBlinkInProgress = true;
271                         pLed->CurrLedState = LED_BLINK_SLOWLY;
272                         if (pLed->bLedOn)
273                                 pLed->BlinkingLedState = RTW_LED_OFF;
274                         else
275                                 pLed->BlinkingLedState = RTW_LED_ON;
276                         mod_timer(&pLed->BlinkTimer, jiffies +
277                                   msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA));
278                 }
279                 break;
280         case LED_CTL_LINK:
281                 if (!pLed->bLedLinkBlinkInProgress) {
282                         if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed))
283                                 return;
284                         if (pLed->bLedNoLinkBlinkInProgress) {
285                                 del_timer_sync(&(pLed->BlinkTimer));
286                                 pLed->bLedNoLinkBlinkInProgress = false;
287                         }
288                         if (pLed->bLedBlinkInProgress) {
289                                 del_timer_sync(&(pLed->BlinkTimer));
290                                 pLed->bLedBlinkInProgress = false;
291                         }
292                         pLed->bLedLinkBlinkInProgress = true;
293                         pLed->CurrLedState = LED_BLINK_NORMAL;
294                         if (pLed->bLedOn)
295                                 pLed->BlinkingLedState = RTW_LED_OFF;
296                         else
297                                 pLed->BlinkingLedState = RTW_LED_ON;
298                         mod_timer(&pLed->BlinkTimer, jiffies +
299                                   msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA));
300                 }
301                 break;
302         case LED_CTL_SITE_SURVEY:
303                 if ((pmlmepriv->LinkDetectInfo.bBusyTraffic) && (check_fwstate(pmlmepriv, _FW_LINKED))) {
304                         ;
305                 } else if (!pLed->bLedScanBlinkInProgress) {
306                         if (IS_LED_WPS_BLINKING(pLed))
307                                 return;
308                         if (pLed->bLedNoLinkBlinkInProgress) {
309                                 del_timer_sync(&(pLed->BlinkTimer));
310                                 pLed->bLedNoLinkBlinkInProgress = false;
311                         }
312                         if (pLed->bLedLinkBlinkInProgress) {
313                                 del_timer_sync(&(pLed->BlinkTimer));
314                                  pLed->bLedLinkBlinkInProgress = false;
315                         }
316                         if (pLed->bLedBlinkInProgress) {
317                                 del_timer_sync(&(pLed->BlinkTimer));
318                                 pLed->bLedBlinkInProgress = false;
319                         }
320                         pLed->bLedScanBlinkInProgress = true;
321                         pLed->CurrLedState = LED_BLINK_SCAN;
322                         pLed->BlinkTimes = 24;
323                         if (pLed->bLedOn)
324                                 pLed->BlinkingLedState = RTW_LED_OFF;
325                         else
326                                 pLed->BlinkingLedState = RTW_LED_ON;
327                         mod_timer(&pLed->BlinkTimer, jiffies +
328                                   msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA));
329                  }
330                 break;
331         case LED_CTL_TX:
332         case LED_CTL_RX:
333                 if (!pLed->bLedBlinkInProgress) {
334                         if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed))
335                                 return;
336                         if (pLed->bLedNoLinkBlinkInProgress) {
337                                 del_timer_sync(&(pLed->BlinkTimer));
338                                 pLed->bLedNoLinkBlinkInProgress = false;
339                         }
340                         if (pLed->bLedLinkBlinkInProgress) {
341                                 del_timer_sync(&(pLed->BlinkTimer));
342                                 pLed->bLedLinkBlinkInProgress = false;
343                         }
344                         pLed->bLedBlinkInProgress = true;
345                         pLed->CurrLedState = LED_BLINK_TXRX;
346                         pLed->BlinkTimes = 2;
347                         if (pLed->bLedOn)
348                                 pLed->BlinkingLedState = RTW_LED_OFF;
349                         else
350                                 pLed->BlinkingLedState = RTW_LED_ON;
351                         mod_timer(&pLed->BlinkTimer, jiffies +
352                                   msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA));
353                 }
354                 break;
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;
361                         }
362                         if (pLed->bLedLinkBlinkInProgress) {
363                                 del_timer_sync(&(pLed->BlinkTimer));
364                                  pLed->bLedLinkBlinkInProgress = false;
365                         }
366                         if (pLed->bLedBlinkInProgress) {
367                                 del_timer_sync(&(pLed->BlinkTimer));
368                                 pLed->bLedBlinkInProgress = false;
369                         }
370                         if (pLed->bLedScanBlinkInProgress) {
371                                 del_timer_sync(&(pLed->BlinkTimer));
372                                 pLed->bLedScanBlinkInProgress = false;
373                         }
374                         pLed->bLedWPSBlinkInProgress = true;
375                         pLed->CurrLedState = LED_BLINK_WPS;
376                         if (pLed->bLedOn)
377                                 pLed->BlinkingLedState = RTW_LED_OFF;
378                         else
379                                 pLed->BlinkingLedState = RTW_LED_ON;
380                         mod_timer(&pLed->BlinkTimer, jiffies +
381                                   msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA));
382                  }
383                 break;
384         case LED_CTL_STOP_WPS:
385                 if (pLed->bLedNoLinkBlinkInProgress) {
386                         del_timer_sync(&(pLed->BlinkTimer));
387                         pLed->bLedNoLinkBlinkInProgress = false;
388                 }
389                 if (pLed->bLedLinkBlinkInProgress) {
390                         del_timer_sync(&(pLed->BlinkTimer));
391                          pLed->bLedLinkBlinkInProgress = false;
392                 }
393                 if (pLed->bLedBlinkInProgress) {
394                         del_timer_sync(&(pLed->BlinkTimer));
395                         pLed->bLedBlinkInProgress = false;
396                 }
397                 if (pLed->bLedScanBlinkInProgress) {
398                         del_timer_sync(&(pLed->BlinkTimer));
399                         pLed->bLedScanBlinkInProgress = false;
400                 }
401                 if (pLed->bLedWPSBlinkInProgress)
402                         del_timer_sync(&(pLed->BlinkTimer));
403                 else
404                         pLed->bLedWPSBlinkInProgress = true;
405                 pLed->CurrLedState = LED_BLINK_WPS_STOP;
406                 if (pLed->bLedOn) {
407                         pLed->BlinkingLedState = RTW_LED_OFF;
408                         mod_timer(&pLed->BlinkTimer, jiffies +
409                                   msecs_to_jiffies(LED_BLINK_WPS_SUCCESS_INTERVAL_ALPHA));
410                 } else {
411                         pLed->BlinkingLedState = RTW_LED_ON;
412                         mod_timer(&pLed->BlinkTimer,
413                                   jiffies + msecs_to_jiffies(0));
414                 }
415                 break;
416         case LED_CTL_STOP_WPS_FAIL:
417                 if (pLed->bLedWPSBlinkInProgress) {
418                         del_timer_sync(&(pLed->BlinkTimer));
419                         pLed->bLedWPSBlinkInProgress = false;
420                 }
421                 pLed->bLedNoLinkBlinkInProgress = true;
422                 pLed->CurrLedState = LED_BLINK_SLOWLY;
423                 if (pLed->bLedOn)
424                         pLed->BlinkingLedState = RTW_LED_OFF;
425                 else
426                         pLed->BlinkingLedState = RTW_LED_ON;
427                 mod_timer(&pLed->BlinkTimer, jiffies +
428                           msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA));
429                 break;
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;
436                 }
437                 if (pLed->bLedLinkBlinkInProgress) {
438                         del_timer_sync(&(pLed->BlinkTimer));
439                         pLed->bLedLinkBlinkInProgress = false;
440                 }
441                 if (pLed->bLedBlinkInProgress) {
442                         del_timer_sync(&(pLed->BlinkTimer));
443                         pLed->bLedBlinkInProgress = false;
444                 }
445                 if (pLed->bLedWPSBlinkInProgress) {
446                         del_timer_sync(&(pLed->BlinkTimer));
447                         pLed->bLedWPSBlinkInProgress = false;
448                 }
449                 if (pLed->bLedScanBlinkInProgress) {
450                         del_timer_sync(&(pLed->BlinkTimer));
451                         pLed->bLedScanBlinkInProgress = false;
452                 }
453                 SwLedOff(padapter, pLed);
454                 break;
455         default:
456                 break;
457         }
458
459         RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Led %d\n", pLed->CurrLedState));
460 }
461
462 /*  */
463 /*      Description: */
464 /*              Handler function of LED Blinking. */
465 /*  */
466 void BlinkHandler(struct LED_871x *pLed)
467 {
468         struct adapter *padapter = pLed->padapter;
469
470         if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped))
471                 return;
472
473         SwLedBlink1(pLed);
474 }
475
476 void LedControl8188eu(struct adapter *padapter, enum LED_CTL_MODE LedAction)
477 {
478         struct led_priv *ledpriv = &(padapter->ledpriv);
479
480        if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped) ||
481            (!padapter->hw_init_completed))
482                 return;
483
484         if (!ledpriv->bRegUseLed)
485                 return;
486
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))
494                 return;
495
496         SwLedControlMode1(padapter, LedAction);
497 }