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