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