GNU Linux-libre 4.14.266-gnu1
[releases.git] / 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,
43                                                 BlinkWorkItem);
44
45         BlinkHandler(pLed);
46 }
47
48 /*  */
49 /*      Description: */
50 /*              Reset status of LED_871x object. */
51 /*  */
52 void ResetLedStatus(struct LED_871x *pLed)
53 {
54         pLed->CurrLedState = RTW_LED_OFF; /*  Current LED state. */
55         pLed->bLedOn = false; /*  true if LED is ON, false if LED is OFF. */
56
57         pLed->bLedBlinkInProgress = false; /*  true if it is blinking, false o.w.. */
58         pLed->bLedWPSBlinkInProgress = false;
59
60         pLed->BlinkTimes = 0; /*  Number of times to toggle led state for blinking. */
61         pLed->BlinkingLedState = LED_UNKNOWN; /*  Next state for blinking, either RTW_LED_ON or RTW_LED_OFF are. */
62
63         pLed->bLedNoLinkBlinkInProgress = false;
64         pLed->bLedLinkBlinkInProgress = false;
65         pLed->bLedScanBlinkInProgress = false;
66 }
67
68 /*Description: */
69 /*              Initialize an LED_871x object. */
70 void InitLed871x(struct adapter *padapter, struct LED_871x *pLed)
71 {
72         pLed->padapter = padapter;
73
74         ResetLedStatus(pLed);
75
76         setup_timer(&pLed->BlinkTimer, BlinkTimerCallback,
77                     (unsigned long)pLed);
78
79         INIT_WORK(&pLed->BlinkWorkItem, BlinkWorkItemCallback);
80 }
81
82
83 /*  */
84 /*      Description: */
85 /*              DeInitialize an LED_871x object. */
86 /*  */
87 void DeInitLed871x(struct LED_871x *pLed)
88 {
89         cancel_work_sync(&pLed->BlinkWorkItem);
90         del_timer_sync(&pLed->BlinkTimer);
91         ResetLedStatus(pLed);
92 }
93
94 /*  */
95 /*      Description: */
96 /*              Implementation of LED blinking behavior. */
97 /*              It toggle off LED and schedule corresponding timer if necessary. */
98 /*  */
99
100 static void SwLedBlink1(struct LED_871x *pLed)
101 {
102         struct adapter *padapter = pLed->padapter;
103         struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
104         u8 bStopBlinking = false;
105
106         /*  Change LED according to BlinkingLedState specified. */
107         if (pLed->BlinkingLedState == RTW_LED_ON) {
108                 SwLedOn(padapter, pLed);
109                 RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes));
110         } else {
111                 SwLedOff(padapter, pLed);
112                 RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes));
113         }
114
115         if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
116                 SwLedOff(padapter, pLed);
117                 ResetLedStatus(pLed);
118                 return;
119         }
120
121         switch (pLed->CurrLedState) {
122         case LED_BLINK_SLOWLY:
123                 if (pLed->bLedOn)
124                         pLed->BlinkingLedState = RTW_LED_OFF;
125                 else
126                         pLed->BlinkingLedState = RTW_LED_ON;
127                 mod_timer(&pLed->BlinkTimer, jiffies +
128                           msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA));
129                 break;
130         case LED_BLINK_NORMAL:
131                 if (pLed->bLedOn)
132                         pLed->BlinkingLedState = RTW_LED_OFF;
133                 else
134                         pLed->BlinkingLedState = RTW_LED_ON;
135                 mod_timer(&pLed->BlinkTimer, jiffies +
136                           msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA));
137                 break;
138         case LED_BLINK_SCAN:
139                 pLed->BlinkTimes--;
140                 if (pLed->BlinkTimes == 0)
141                         bStopBlinking = true;
142                 if (bStopBlinking) {
143                         if (check_fwstate(pmlmepriv, _FW_LINKED)) {
144                                 pLed->bLedLinkBlinkInProgress = true;
145                                 pLed->CurrLedState = LED_BLINK_NORMAL;
146                                 if (pLed->bLedOn)
147                                         pLed->BlinkingLedState = RTW_LED_OFF;
148                                 else
149                                         pLed->BlinkingLedState = RTW_LED_ON;
150                                 mod_timer(&pLed->BlinkTimer, jiffies +
151                                           msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA));
152                                 RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
153                         } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) {
154                                 pLed->bLedNoLinkBlinkInProgress = true;
155                                 pLed->CurrLedState = LED_BLINK_SLOWLY;
156                                 if (pLed->bLedOn)
157                                         pLed->BlinkingLedState = RTW_LED_OFF;
158                                 else
159                                         pLed->BlinkingLedState = RTW_LED_ON;
160                                 mod_timer(&pLed->BlinkTimer, jiffies +
161                                           msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA));
162                                 RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
163                         }
164                         pLed->bLedScanBlinkInProgress = false;
165                 } else {
166                         if (pLed->bLedOn)
167                                 pLed->BlinkingLedState = RTW_LED_OFF;
168                         else
169                                 pLed->BlinkingLedState = RTW_LED_ON;
170                         mod_timer(&pLed->BlinkTimer, jiffies +
171                                   msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA));
172                 }
173                 break;
174         case LED_BLINK_TXRX:
175                 pLed->BlinkTimes--;
176                 if (pLed->BlinkTimes == 0)
177                         bStopBlinking = true;
178                 if (bStopBlinking) {
179                         if (check_fwstate(pmlmepriv, _FW_LINKED)) {
180                                 pLed->bLedLinkBlinkInProgress = true;
181                                 pLed->CurrLedState = LED_BLINK_NORMAL;
182                                 if (pLed->bLedOn)
183                                         pLed->BlinkingLedState = RTW_LED_OFF;
184                                 else
185                                         pLed->BlinkingLedState = RTW_LED_ON;
186                                 mod_timer(&pLed->BlinkTimer, jiffies +
187                                           msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA));
188                                 RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
189                         } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) {
190                                 pLed->bLedNoLinkBlinkInProgress = true;
191                                 pLed->CurrLedState = LED_BLINK_SLOWLY;
192                                 if (pLed->bLedOn)
193                                         pLed->BlinkingLedState = RTW_LED_OFF;
194                                 else
195                                         pLed->BlinkingLedState = RTW_LED_ON;
196                                 mod_timer(&pLed->BlinkTimer, jiffies +
197                                           msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA));
198                                 RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
199                         }
200                         pLed->BlinkTimes = 0;
201                         pLed->bLedBlinkInProgress = false;
202                 } else {
203                         if (pLed->bLedOn)
204                                 pLed->BlinkingLedState = RTW_LED_OFF;
205                         else
206                                 pLed->BlinkingLedState = RTW_LED_ON;
207                         mod_timer(&pLed->BlinkTimer, jiffies +
208                                   msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA));
209                 }
210                 break;
211         case LED_BLINK_WPS:
212                 if (pLed->bLedOn)
213                         pLed->BlinkingLedState = RTW_LED_OFF;
214                 else
215                         pLed->BlinkingLedState = RTW_LED_ON;
216                 mod_timer(&pLed->BlinkTimer, jiffies +
217                           msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA));
218                 break;
219         case LED_BLINK_WPS_STOP:        /* WPS success */
220                 if (pLed->BlinkingLedState == RTW_LED_ON)
221                         bStopBlinking = false;
222                 else
223                         bStopBlinking = true;
224
225                 if (bStopBlinking) {
226                         pLed->bLedLinkBlinkInProgress = true;
227                         pLed->CurrLedState = LED_BLINK_NORMAL;
228                         if (pLed->bLedOn)
229                                 pLed->BlinkingLedState = RTW_LED_OFF;
230                         else
231                                 pLed->BlinkingLedState = RTW_LED_ON;
232                         mod_timer(&pLed->BlinkTimer, jiffies +
233                                   msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA));
234                         RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
235
236                         pLed->bLedWPSBlinkInProgress = false;
237                 } else {
238                         pLed->BlinkingLedState = RTW_LED_OFF;
239                         mod_timer(&pLed->BlinkTimer, jiffies +
240                                   msecs_to_jiffies(LED_BLINK_WPS_SUCCESS_INTERVAL_ALPHA));
241                 }
242                 break;
243         default:
244                 break;
245         }
246 }
247
248  /* ALPHA, added by chiyoko, 20090106 */
249 static void SwLedControlMode1(struct adapter *padapter, enum LED_CTL_MODE LedAction)
250 {
251         struct led_priv *ledpriv = &padapter->ledpriv;
252         struct LED_871x *pLed = &ledpriv->SwLed0;
253         struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
254
255         switch (LedAction) {
256         case LED_CTL_POWER_ON:
257         case LED_CTL_START_TO_LINK:
258         case LED_CTL_NO_LINK:
259                 if (!pLed->bLedNoLinkBlinkInProgress) {
260                         if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed))
261                                 return;
262                         if (pLed->bLedLinkBlinkInProgress) {
263                                 del_timer_sync(&pLed->BlinkTimer);
264                                 pLed->bLedLinkBlinkInProgress = false;
265                         }
266                         if (pLed->bLedBlinkInProgress) {
267                                 del_timer_sync(&pLed->BlinkTimer);
268                                 pLed->bLedBlinkInProgress = false;
269                         }
270
271                         pLed->bLedNoLinkBlinkInProgress = true;
272                         pLed->CurrLedState = LED_BLINK_SLOWLY;
273                         if (pLed->bLedOn)
274                                 pLed->BlinkingLedState = RTW_LED_OFF;
275                         else
276                                 pLed->BlinkingLedState = RTW_LED_ON;
277                         mod_timer(&pLed->BlinkTimer, jiffies +
278                                   msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA));
279                 }
280                 break;
281         case LED_CTL_LINK:
282                 if (!pLed->bLedLinkBlinkInProgress) {
283                         if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed))
284                                 return;
285                         if (pLed->bLedNoLinkBlinkInProgress) {
286                                 del_timer_sync(&pLed->BlinkTimer);
287                                 pLed->bLedNoLinkBlinkInProgress = false;
288                         }
289                         if (pLed->bLedBlinkInProgress) {
290                                 del_timer_sync(&pLed->BlinkTimer);
291                                 pLed->bLedBlinkInProgress = false;
292                         }
293                         pLed->bLedLinkBlinkInProgress = true;
294                         pLed->CurrLedState = LED_BLINK_NORMAL;
295                         if (pLed->bLedOn)
296                                 pLed->BlinkingLedState = RTW_LED_OFF;
297                         else
298                                 pLed->BlinkingLedState = RTW_LED_ON;
299                         mod_timer(&pLed->BlinkTimer, jiffies +
300                                   msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA));
301                 }
302                 break;
303         case LED_CTL_SITE_SURVEY:
304                 if ((pmlmepriv->LinkDetectInfo.bBusyTraffic) && (check_fwstate(pmlmepriv, _FW_LINKED))) {
305                         ;
306                 } else if (!pLed->bLedScanBlinkInProgress) {
307                         if (IS_LED_WPS_BLINKING(pLed))
308                                 return;
309                         if (pLed->bLedNoLinkBlinkInProgress) {
310                                 del_timer_sync(&pLed->BlinkTimer);
311                                 pLed->bLedNoLinkBlinkInProgress = false;
312                         }
313                         if (pLed->bLedLinkBlinkInProgress) {
314                                 del_timer_sync(&pLed->BlinkTimer);
315                                  pLed->bLedLinkBlinkInProgress = false;
316                         }
317                         if (pLed->bLedBlinkInProgress) {
318                                 del_timer_sync(&pLed->BlinkTimer);
319                                 pLed->bLedBlinkInProgress = false;
320                         }
321                         pLed->bLedScanBlinkInProgress = true;
322                         pLed->CurrLedState = LED_BLINK_SCAN;
323                         pLed->BlinkTimes = 24;
324                         if (pLed->bLedOn)
325                                 pLed->BlinkingLedState = RTW_LED_OFF;
326                         else
327                                 pLed->BlinkingLedState = RTW_LED_ON;
328                         mod_timer(&pLed->BlinkTimer, jiffies +
329                                   msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA));
330                 }
331                 break;
332         case LED_CTL_TX:
333         case LED_CTL_RX:
334                 if (!pLed->bLedBlinkInProgress) {
335                         if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed))
336                                 return;
337                         if (pLed->bLedNoLinkBlinkInProgress) {
338                                 del_timer_sync(&pLed->BlinkTimer);
339                                 pLed->bLedNoLinkBlinkInProgress = false;
340                         }
341                         if (pLed->bLedLinkBlinkInProgress) {
342                                 del_timer_sync(&pLed->BlinkTimer);
343                                 pLed->bLedLinkBlinkInProgress = false;
344                         }
345                         pLed->bLedBlinkInProgress = true;
346                         pLed->CurrLedState = LED_BLINK_TXRX;
347                         pLed->BlinkTimes = 2;
348                         if (pLed->bLedOn)
349                                 pLed->BlinkingLedState = RTW_LED_OFF;
350                         else
351                                 pLed->BlinkingLedState = RTW_LED_ON;
352                         mod_timer(&pLed->BlinkTimer, jiffies +
353                                   msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA));
354                 }
355                 break;
356         case LED_CTL_START_WPS: /* wait until xinpin finish */
357         case LED_CTL_START_WPS_BOTTON:
358                 if (!pLed->bLedWPSBlinkInProgress) {
359                         if (pLed->bLedNoLinkBlinkInProgress) {
360                                 del_timer_sync(&pLed->BlinkTimer);
361                                 pLed->bLedNoLinkBlinkInProgress = false;
362                         }
363                         if (pLed->bLedLinkBlinkInProgress) {
364                                 del_timer_sync(&pLed->BlinkTimer);
365                                  pLed->bLedLinkBlinkInProgress = false;
366                         }
367                         if (pLed->bLedBlinkInProgress) {
368                                 del_timer_sync(&pLed->BlinkTimer);
369                                 pLed->bLedBlinkInProgress = false;
370                         }
371                         if (pLed->bLedScanBlinkInProgress) {
372                                 del_timer_sync(&pLed->BlinkTimer);
373                                 pLed->bLedScanBlinkInProgress = false;
374                         }
375                         pLed->bLedWPSBlinkInProgress = true;
376                         pLed->CurrLedState = LED_BLINK_WPS;
377                         if (pLed->bLedOn)
378                                 pLed->BlinkingLedState = RTW_LED_OFF;
379                         else
380                                 pLed->BlinkingLedState = RTW_LED_ON;
381                         mod_timer(&pLed->BlinkTimer, jiffies +
382                                   msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA));
383                 }
384                 break;
385         case LED_CTL_STOP_WPS:
386                 if (pLed->bLedNoLinkBlinkInProgress) {
387                         del_timer_sync(&pLed->BlinkTimer);
388                         pLed->bLedNoLinkBlinkInProgress = false;
389                 }
390                 if (pLed->bLedLinkBlinkInProgress) {
391                         del_timer_sync(&pLed->BlinkTimer);
392                          pLed->bLedLinkBlinkInProgress = false;
393                 }
394                 if (pLed->bLedBlinkInProgress) {
395                         del_timer_sync(&pLed->BlinkTimer);
396                         pLed->bLedBlinkInProgress = false;
397                 }
398                 if (pLed->bLedScanBlinkInProgress) {
399                         del_timer_sync(&pLed->BlinkTimer);
400                         pLed->bLedScanBlinkInProgress = false;
401                 }
402                 if (pLed->bLedWPSBlinkInProgress)
403                         del_timer_sync(&pLed->BlinkTimer);
404                 else
405                         pLed->bLedWPSBlinkInProgress = true;
406                 pLed->CurrLedState = LED_BLINK_WPS_STOP;
407                 if (pLed->bLedOn) {
408                         pLed->BlinkingLedState = RTW_LED_OFF;
409                         mod_timer(&pLed->BlinkTimer, jiffies +
410                                   msecs_to_jiffies(LED_BLINK_WPS_SUCCESS_INTERVAL_ALPHA));
411                 } else {
412                         pLed->BlinkingLedState = RTW_LED_ON;
413                         mod_timer(&pLed->BlinkTimer,
414                                   jiffies + msecs_to_jiffies(0));
415                 }
416                 break;
417         case LED_CTL_STOP_WPS_FAIL:
418                 if (pLed->bLedWPSBlinkInProgress) {
419                         del_timer_sync(&pLed->BlinkTimer);
420                         pLed->bLedWPSBlinkInProgress = false;
421                 }
422                 pLed->bLedNoLinkBlinkInProgress = true;
423                 pLed->CurrLedState = LED_BLINK_SLOWLY;
424                 if (pLed->bLedOn)
425                         pLed->BlinkingLedState = RTW_LED_OFF;
426                 else
427                         pLed->BlinkingLedState = RTW_LED_ON;
428                 mod_timer(&pLed->BlinkTimer, jiffies +
429                           msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA));
430                 break;
431         case LED_CTL_POWER_OFF:
432                 pLed->CurrLedState = RTW_LED_OFF;
433                 pLed->BlinkingLedState = RTW_LED_OFF;
434                 if (pLed->bLedNoLinkBlinkInProgress) {
435                         del_timer_sync(&pLed->BlinkTimer);
436                         pLed->bLedNoLinkBlinkInProgress = false;
437                 }
438                 if (pLed->bLedLinkBlinkInProgress) {
439                         del_timer_sync(&pLed->BlinkTimer);
440                         pLed->bLedLinkBlinkInProgress = false;
441                 }
442                 if (pLed->bLedBlinkInProgress) {
443                         del_timer_sync(&pLed->BlinkTimer);
444                         pLed->bLedBlinkInProgress = false;
445                 }
446                 if (pLed->bLedWPSBlinkInProgress) {
447                         del_timer_sync(&pLed->BlinkTimer);
448                         pLed->bLedWPSBlinkInProgress = false;
449                 }
450                 if (pLed->bLedScanBlinkInProgress) {
451                         del_timer_sync(&pLed->BlinkTimer);
452                         pLed->bLedScanBlinkInProgress = false;
453                 }
454                 SwLedOff(padapter, pLed);
455                 break;
456         default:
457                 break;
458         }
459
460         RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Led %d\n", pLed->CurrLedState));
461 }
462
463 /*  */
464 /*      Description: */
465 /*              Handler function of LED Blinking. */
466 /*  */
467 void BlinkHandler(struct LED_871x *pLed)
468 {
469         struct adapter *padapter = pLed->padapter;
470
471         if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped))
472                 return;
473
474         SwLedBlink1(pLed);
475 }
476
477 void LedControl8188eu(struct adapter *padapter, enum LED_CTL_MODE LedAction)
478 {
479         if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped) ||
480            (!padapter->hw_init_completed))
481                 return;
482
483         if ((padapter->pwrctrlpriv.rf_pwrstate != rf_on &&
484              padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) &&
485             (LedAction == LED_CTL_TX || LedAction == LED_CTL_RX ||
486              LedAction == LED_CTL_SITE_SURVEY ||
487              LedAction == LED_CTL_LINK ||
488              LedAction == LED_CTL_NO_LINK ||
489              LedAction == LED_CTL_POWER_ON))
490                 return;
491
492         SwLedControlMode1(padapter, LedAction);
493 }