GNU Linux-libre 5.10.153-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         blink_handler(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
94         /*  Change LED according to BlinkingLedState specified. */
95         if (pLed->BlinkingLedState == RTW_LED_ON) {
96                 sw_led_on(padapter, pLed);
97                 RT_TRACE(_module_rtl8712_led_c_, _drv_info_,
98                          ("Blinktimes (%d): turn on\n", pLed->BlinkTimes));
99         } else {
100                 sw_led_off(padapter, pLed);
101                 RT_TRACE(_module_rtl8712_led_c_, _drv_info_,
102                          ("Blinktimes (%d): turn off\n", pLed->BlinkTimes));
103         }
104
105         if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
106                 sw_led_off(padapter, pLed);
107                 ResetLedStatus(pLed);
108                 return;
109         }
110
111         switch (pLed->CurrLedState) {
112         case LED_BLINK_SLOWLY:
113                 if (pLed->bLedOn)
114                         pLed->BlinkingLedState = RTW_LED_OFF;
115                 else
116                         pLed->BlinkingLedState = RTW_LED_ON;
117                 mod_timer(&pLed->BlinkTimer, jiffies +
118                           msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA));
119                 break;
120         case LED_BLINK_NORMAL:
121                 if (pLed->bLedOn)
122                         pLed->BlinkingLedState = RTW_LED_OFF;
123                 else
124                         pLed->BlinkingLedState = RTW_LED_ON;
125                 mod_timer(&pLed->BlinkTimer, jiffies +
126                           msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA));
127                 break;
128         case LED_BLINK_SCAN:
129                 pLed->BlinkTimes--;
130                 if (pLed->BlinkTimes == 0) {
131                         if (check_fwstate(pmlmepriv, _FW_LINKED)) {
132                                 pLed->bLedLinkBlinkInProgress = true;
133                                 pLed->CurrLedState = LED_BLINK_NORMAL;
134                                 if (pLed->bLedOn)
135                                         pLed->BlinkingLedState = RTW_LED_OFF;
136                                 else
137                                         pLed->BlinkingLedState = RTW_LED_ON;
138                                 mod_timer(&pLed->BlinkTimer, jiffies +
139                                           msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA));
140                                 RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
141                         } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) {
142                                 pLed->bLedNoLinkBlinkInProgress = true;
143                                 pLed->CurrLedState = LED_BLINK_SLOWLY;
144                                 if (pLed->bLedOn)
145                                         pLed->BlinkingLedState = RTW_LED_OFF;
146                                 else
147                                         pLed->BlinkingLedState = RTW_LED_ON;
148                                 mod_timer(&pLed->BlinkTimer, jiffies +
149                                           msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA));
150                                 RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
151                         }
152                         pLed->bLedScanBlinkInProgress = false;
153                 } else {
154                         if (pLed->bLedOn)
155                                 pLed->BlinkingLedState = RTW_LED_OFF;
156                         else
157                                 pLed->BlinkingLedState = RTW_LED_ON;
158                         mod_timer(&pLed->BlinkTimer, jiffies +
159                                   msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA));
160                 }
161                 break;
162         case LED_BLINK_TXRX:
163                 pLed->BlinkTimes--;
164                 if (pLed->BlinkTimes == 0) {
165                         if (check_fwstate(pmlmepriv, _FW_LINKED)) {
166                                 pLed->bLedLinkBlinkInProgress = true;
167                                 pLed->CurrLedState = LED_BLINK_NORMAL;
168                                 if (pLed->bLedOn)
169                                         pLed->BlinkingLedState = RTW_LED_OFF;
170                                 else
171                                         pLed->BlinkingLedState = RTW_LED_ON;
172                                 mod_timer(&pLed->BlinkTimer, jiffies +
173                                           msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA));
174                                 RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
175                         } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) {
176                                 pLed->bLedNoLinkBlinkInProgress = true;
177                                 pLed->CurrLedState = LED_BLINK_SLOWLY;
178                                 if (pLed->bLedOn)
179                                         pLed->BlinkingLedState = RTW_LED_OFF;
180                                 else
181                                         pLed->BlinkingLedState = RTW_LED_ON;
182                                 mod_timer(&pLed->BlinkTimer, jiffies +
183                                           msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA));
184                                 RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
185                         }
186                         pLed->bLedBlinkInProgress = false;
187                 } else {
188                         if (pLed->bLedOn)
189                                 pLed->BlinkingLedState = RTW_LED_OFF;
190                         else
191                                 pLed->BlinkingLedState = RTW_LED_ON;
192                         mod_timer(&pLed->BlinkTimer, jiffies +
193                                   msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA));
194                 }
195                 break;
196         case LED_BLINK_WPS:
197                 if (pLed->bLedOn)
198                         pLed->BlinkingLedState = RTW_LED_OFF;
199                 else
200                         pLed->BlinkingLedState = RTW_LED_ON;
201                 mod_timer(&pLed->BlinkTimer, jiffies +
202                           msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA));
203                 break;
204         case LED_BLINK_WPS_STOP:        /* WPS success */
205                 if (pLed->BlinkingLedState != RTW_LED_ON) {
206                         pLed->bLedLinkBlinkInProgress = true;
207                         pLed->CurrLedState = LED_BLINK_NORMAL;
208                         if (pLed->bLedOn)
209                                 pLed->BlinkingLedState = RTW_LED_OFF;
210                         else
211                                 pLed->BlinkingLedState = RTW_LED_ON;
212                         mod_timer(&pLed->BlinkTimer, jiffies +
213                                   msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA));
214                         RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
215
216                         pLed->bLedWPSBlinkInProgress = false;
217                 } else {
218                         pLed->BlinkingLedState = RTW_LED_OFF;
219                         mod_timer(&pLed->BlinkTimer, jiffies +
220                                   msecs_to_jiffies(LED_BLINK_WPS_SUCCESS_INTERVAL_ALPHA));
221                 }
222                 break;
223         default:
224                 break;
225         }
226 }
227
228  /* ALPHA, added by chiyoko, 20090106 */
229 static void SwLedControlMode1(struct adapter *padapter, enum LED_CTL_MODE LedAction)
230 {
231         struct led_priv *ledpriv = &padapter->ledpriv;
232         struct LED_871x *pLed = &ledpriv->sw_led;
233         struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
234
235         switch (LedAction) {
236         case LED_CTL_POWER_ON:
237         case LED_CTL_START_TO_LINK:
238         case LED_CTL_NO_LINK:
239                 if (pLed->bLedNoLinkBlinkInProgress)
240                         break;
241                 if (pLed->CurrLedState == LED_BLINK_SCAN ||
242                     IS_LED_WPS_BLINKING(pLed))
243                         return;
244                 if (pLed->bLedLinkBlinkInProgress) {
245                         del_timer_sync(&pLed->BlinkTimer);
246                         pLed->bLedLinkBlinkInProgress = false;
247                 }
248                 if (pLed->bLedBlinkInProgress) {
249                         del_timer_sync(&pLed->BlinkTimer);
250                         pLed->bLedBlinkInProgress = false;
251                 }
252                 pLed->bLedNoLinkBlinkInProgress = true;
253                 pLed->CurrLedState = LED_BLINK_SLOWLY;
254                 if (pLed->bLedOn)
255                         pLed->BlinkingLedState = RTW_LED_OFF;
256                 else
257                         pLed->BlinkingLedState = RTW_LED_ON;
258                 mod_timer(&pLed->BlinkTimer, jiffies +
259                           msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA));
260                 break;
261         case LED_CTL_LINK:
262                 if (pLed->bLedLinkBlinkInProgress)
263                         break;
264                 if (pLed->CurrLedState == LED_BLINK_SCAN ||
265                     IS_LED_WPS_BLINKING(pLed))
266                         return;
267                 if (pLed->bLedNoLinkBlinkInProgress) {
268                         del_timer_sync(&pLed->BlinkTimer);
269                         pLed->bLedNoLinkBlinkInProgress = false;
270                 }
271                 if (pLed->bLedBlinkInProgress) {
272                         del_timer_sync(&pLed->BlinkTimer);
273                         pLed->bLedBlinkInProgress = false;
274                 }
275                 pLed->bLedLinkBlinkInProgress = true;
276                 pLed->CurrLedState = LED_BLINK_NORMAL;
277                 if (pLed->bLedOn)
278                         pLed->BlinkingLedState = RTW_LED_OFF;
279                 else
280                         pLed->BlinkingLedState = RTW_LED_ON;
281                 mod_timer(&pLed->BlinkTimer, jiffies +
282                           msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA));
283                 break;
284         case LED_CTL_SITE_SURVEY:
285                 if (pmlmepriv->LinkDetectInfo.bBusyTraffic &&
286                     check_fwstate(pmlmepriv, _FW_LINKED))
287                         break;
288                 if (pLed->bLedScanBlinkInProgress)
289                         break;
290                 if (IS_LED_WPS_BLINKING(pLed))
291                         return;
292                 if (pLed->bLedNoLinkBlinkInProgress) {
293                         del_timer_sync(&pLed->BlinkTimer);
294                         pLed->bLedNoLinkBlinkInProgress = false;
295                 }
296                 if (pLed->bLedLinkBlinkInProgress) {
297                         del_timer_sync(&pLed->BlinkTimer);
298                         pLed->bLedLinkBlinkInProgress = false;
299                 }
300                 if (pLed->bLedBlinkInProgress) {
301                         del_timer_sync(&pLed->BlinkTimer);
302                         pLed->bLedBlinkInProgress = false;
303                 }
304                 pLed->bLedScanBlinkInProgress = true;
305                 pLed->CurrLedState = LED_BLINK_SCAN;
306                 pLed->BlinkTimes = 24;
307                 if (pLed->bLedOn)
308                         pLed->BlinkingLedState = RTW_LED_OFF;
309                 else
310                         pLed->BlinkingLedState = RTW_LED_ON;
311                 mod_timer(&pLed->BlinkTimer, jiffies +
312                           msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA));
313                 break;
314         case LED_CTL_TX:
315         case LED_CTL_RX:
316                 if (pLed->bLedBlinkInProgress)
317                         break;
318                 if (pLed->CurrLedState == LED_BLINK_SCAN ||
319                     IS_LED_WPS_BLINKING(pLed))
320                         return;
321                 if (pLed->bLedNoLinkBlinkInProgress) {
322                         del_timer_sync(&pLed->BlinkTimer);
323                         pLed->bLedNoLinkBlinkInProgress = false;
324                 }
325                 if (pLed->bLedLinkBlinkInProgress) {
326                         del_timer_sync(&pLed->BlinkTimer);
327                         pLed->bLedLinkBlinkInProgress = false;
328                 }
329                 pLed->bLedBlinkInProgress = true;
330                 pLed->CurrLedState = LED_BLINK_TXRX;
331                 pLed->BlinkTimes = 2;
332                 if (pLed->bLedOn)
333                         pLed->BlinkingLedState = RTW_LED_OFF;
334                 else
335                         pLed->BlinkingLedState = RTW_LED_ON;
336                 mod_timer(&pLed->BlinkTimer, jiffies +
337                           msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA));
338                 break;
339         case LED_CTL_START_WPS: /* wait until xinpin finish */
340         case LED_CTL_START_WPS_BOTTON:
341                 if (pLed->bLedWPSBlinkInProgress)
342                         break;
343                 if (pLed->bLedNoLinkBlinkInProgress) {
344                         del_timer_sync(&pLed->BlinkTimer);
345                         pLed->bLedNoLinkBlinkInProgress = false;
346                 }
347                 if (pLed->bLedLinkBlinkInProgress) {
348                         del_timer_sync(&pLed->BlinkTimer);
349                         pLed->bLedLinkBlinkInProgress = false;
350                 }
351                 if (pLed->bLedBlinkInProgress) {
352                         del_timer_sync(&pLed->BlinkTimer);
353                         pLed->bLedBlinkInProgress = false;
354                 }
355                 if (pLed->bLedScanBlinkInProgress) {
356                         del_timer_sync(&pLed->BlinkTimer);
357                         pLed->bLedScanBlinkInProgress = false;
358                 }
359                 pLed->bLedWPSBlinkInProgress = true;
360                 pLed->CurrLedState = LED_BLINK_WPS;
361                 if (pLed->bLedOn)
362                         pLed->BlinkingLedState = RTW_LED_OFF;
363                 else
364                         pLed->BlinkingLedState = RTW_LED_ON;
365                 mod_timer(&pLed->BlinkTimer, jiffies +
366                           msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA));
367                 break;
368         case LED_CTL_STOP_WPS:
369                 if (pLed->bLedNoLinkBlinkInProgress) {
370                         del_timer_sync(&pLed->BlinkTimer);
371                         pLed->bLedNoLinkBlinkInProgress = false;
372                 }
373                 if (pLed->bLedLinkBlinkInProgress) {
374                         del_timer_sync(&pLed->BlinkTimer);
375                         pLed->bLedLinkBlinkInProgress = false;
376                 }
377                 if (pLed->bLedBlinkInProgress) {
378                         del_timer_sync(&pLed->BlinkTimer);
379                         pLed->bLedBlinkInProgress = false;
380                 }
381                 if (pLed->bLedScanBlinkInProgress) {
382                         del_timer_sync(&pLed->BlinkTimer);
383                         pLed->bLedScanBlinkInProgress = false;
384                 }
385                 if (pLed->bLedWPSBlinkInProgress)
386                         del_timer_sync(&pLed->BlinkTimer);
387                 else
388                         pLed->bLedWPSBlinkInProgress = true;
389                 pLed->CurrLedState = LED_BLINK_WPS_STOP;
390                 if (pLed->bLedOn) {
391                         pLed->BlinkingLedState = RTW_LED_OFF;
392                         mod_timer(&pLed->BlinkTimer, jiffies +
393                                   msecs_to_jiffies(LED_BLINK_WPS_SUCCESS_INTERVAL_ALPHA));
394                 } else {
395                         pLed->BlinkingLedState = RTW_LED_ON;
396                         mod_timer(&pLed->BlinkTimer,
397                                   jiffies + msecs_to_jiffies(0));
398                 }
399                 break;
400         case LED_CTL_STOP_WPS_FAIL:
401                 if (pLed->bLedWPSBlinkInProgress) {
402                         del_timer_sync(&pLed->BlinkTimer);
403                         pLed->bLedWPSBlinkInProgress = false;
404                 }
405                 pLed->bLedNoLinkBlinkInProgress = true;
406                 pLed->CurrLedState = LED_BLINK_SLOWLY;
407                 if (pLed->bLedOn)
408                         pLed->BlinkingLedState = RTW_LED_OFF;
409                 else
410                         pLed->BlinkingLedState = RTW_LED_ON;
411                 mod_timer(&pLed->BlinkTimer, jiffies +
412                           msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA));
413                 break;
414         case LED_CTL_POWER_OFF:
415                 pLed->CurrLedState = RTW_LED_OFF;
416                 pLed->BlinkingLedState = RTW_LED_OFF;
417                 if (pLed->bLedNoLinkBlinkInProgress) {
418                         del_timer_sync(&pLed->BlinkTimer);
419                         pLed->bLedNoLinkBlinkInProgress = false;
420                 }
421                 if (pLed->bLedLinkBlinkInProgress) {
422                         del_timer_sync(&pLed->BlinkTimer);
423                         pLed->bLedLinkBlinkInProgress = false;
424                 }
425                 if (pLed->bLedBlinkInProgress) {
426                         del_timer_sync(&pLed->BlinkTimer);
427                         pLed->bLedBlinkInProgress = false;
428                 }
429                 if (pLed->bLedWPSBlinkInProgress) {
430                         del_timer_sync(&pLed->BlinkTimer);
431                         pLed->bLedWPSBlinkInProgress = false;
432                 }
433                 if (pLed->bLedScanBlinkInProgress) {
434                         del_timer_sync(&pLed->BlinkTimer);
435                         pLed->bLedScanBlinkInProgress = false;
436                 }
437                 sw_led_off(padapter, pLed);
438                 break;
439         default:
440                 break;
441         }
442
443         RT_TRACE(_module_rtl8712_led_c_, _drv_info_,
444                  ("Led %d\n", pLed->CurrLedState));
445 }
446
447 void blink_handler(struct LED_871x *pLed)
448 {
449         struct adapter *padapter = pLed->padapter;
450
451         if (padapter->bSurpriseRemoved || padapter->bDriverStopped)
452                 return;
453
454         SwLedBlink1(pLed);
455 }
456
457 void led_control_8188eu(struct adapter *padapter, enum LED_CTL_MODE LedAction)
458 {
459         if (padapter->bSurpriseRemoved || padapter->bDriverStopped ||
460             !padapter->hw_init_completed)
461                 return;
462
463         if ((padapter->pwrctrlpriv.rf_pwrstate != rf_on &&
464              padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) &&
465             (LedAction == LED_CTL_TX || LedAction == LED_CTL_RX ||
466              LedAction == LED_CTL_SITE_SURVEY ||
467              LedAction == LED_CTL_LINK ||
468              LedAction == LED_CTL_NO_LINK ||
469              LedAction == LED_CTL_POWER_ON))
470                 return;
471
472         SwLedControlMode1(padapter, LedAction);
473 }