Linux-libre 3.16.85-gnu
[librecmc/linux-libre.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  * You should have received a copy of the GNU General Public License along with
15  * this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
17  *
18  *
19  ******************************************************************************/
20
21 #include <drv_types.h>
22 #include "rtw_led.h"
23
24 /*  */
25 /*      Description: */
26 /*              Callback function of LED BlinkTimer, */
27 /*              it just schedules to corresponding BlinkWorkItem/led_blink_hdl */
28 /*  */
29 void BlinkTimerCallback(void *data)
30 {
31         struct LED_871x *pLed = (struct LED_871x *)data;
32         struct adapter *padapter = pLed->padapter;
33
34         if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped))
35                 return;
36
37         schedule_work(&(pLed->BlinkWorkItem));
38 }
39
40 /*  */
41 /*      Description: */
42 /*              Callback function of LED BlinkWorkItem. */
43 /*  */
44 void BlinkWorkItemCallback(struct work_struct *work)
45 {
46         struct LED_871x *pLed = container_of(work, struct LED_871x, BlinkWorkItem);
47         BlinkHandler(pLed);
48 }
49
50 /*  */
51 /*      Description: */
52 /*              Reset status of LED_871x object. */
53 /*  */
54 void ResetLedStatus(struct LED_871x *pLed)
55 {
56         pLed->CurrLedState = RTW_LED_OFF; /*  Current LED state. */
57         pLed->bLedOn = false; /*  true if LED is ON, false if LED is OFF. */
58
59         pLed->bLedBlinkInProgress = false; /*  true if it is blinking, false o.w.. */
60         pLed->bLedWPSBlinkInProgress = false;
61
62         pLed->BlinkTimes = 0; /*  Number of times to toggle led state for blinking. */
63         pLed->BlinkingLedState = LED_UNKNOWN; /*  Next state for blinking, either RTW_LED_ON or RTW_LED_OFF are. */
64
65         pLed->bLedNoLinkBlinkInProgress = false;
66         pLed->bLedLinkBlinkInProgress = false;
67         pLed->bLedStartToLinkBlinkInProgress = false;
68         pLed->bLedScanBlinkInProgress = false;
69 }
70
71 /*Description: */
72 /*              Initialize an LED_871x object. */
73 void InitLed871x(struct adapter *padapter, struct LED_871x *pLed)
74 {
75         pLed->padapter = padapter;
76
77         ResetLedStatus(pLed);
78
79         _init_timer(&(pLed->BlinkTimer), padapter->pnetdev, BlinkTimerCallback, pLed);
80
81         INIT_WORK(&(pLed->BlinkWorkItem), BlinkWorkItemCallback);
82 }
83
84
85 /*  */
86 /*      Description: */
87 /*              DeInitialize an LED_871x object. */
88 /*  */
89 void DeInitLed871x(struct LED_871x *pLed)
90 {
91         _cancel_workitem_sync(&(pLed->BlinkWorkItem));
92         _cancel_timer_ex(&(pLed->BlinkTimer));
93         ResetLedStatus(pLed);
94 }
95
96 /*  */
97 /*      Description: */
98 /*              Implementation of LED blinking behavior. */
99 /*              It toggle off LED and schedule corresponding timer if necessary. */
100 /*  */
101
102 static void SwLedBlink1(struct LED_871x *pLed)
103 {
104         struct adapter *padapter = pLed->padapter;
105         struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
106         u8 bStopBlinking = false;
107
108         /*  Change LED according to BlinkingLedState specified. */
109         if (pLed->BlinkingLedState == RTW_LED_ON) {
110                 SwLedOn(padapter, pLed);
111                 RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes));
112         } else {
113                 SwLedOff(padapter, pLed);
114                 RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes));
115         }
116
117         if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
118                 SwLedOff(padapter, pLed);
119                 ResetLedStatus(pLed);
120                 return;
121         }
122
123         switch (pLed->CurrLedState) {
124         case LED_BLINK_SLOWLY:
125                 if (pLed->bLedOn)
126                         pLed->BlinkingLedState = RTW_LED_OFF;
127                 else
128                         pLed->BlinkingLedState = RTW_LED_ON;
129                 _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA);
130                 break;
131         case LED_BLINK_NORMAL:
132                 if (pLed->bLedOn)
133                         pLed->BlinkingLedState = RTW_LED_OFF;
134                 else
135                         pLed->BlinkingLedState = RTW_LED_ON;
136                 _set_timer(&(pLed->BlinkTimer), 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                                 _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA);
151                                 RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
152                         } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) {
153                                 pLed->bLedNoLinkBlinkInProgress = true;
154                                 pLed->CurrLedState = LED_BLINK_SLOWLY;
155                                 if (pLed->bLedOn)
156                                         pLed->BlinkingLedState = RTW_LED_OFF;
157                                 else
158                                         pLed->BlinkingLedState = RTW_LED_ON;
159                                 _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA);
160                                 RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
161                         }
162                         pLed->bLedScanBlinkInProgress = false;
163                 } else {
164                         if (pLed->bLedOn)
165                                 pLed->BlinkingLedState = RTW_LED_OFF;
166                         else
167                                 pLed->BlinkingLedState = RTW_LED_ON;
168                         _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA);
169                 }
170                 break;
171         case LED_BLINK_TXRX:
172                 pLed->BlinkTimes--;
173                 if (pLed->BlinkTimes == 0)
174                         bStopBlinking = true;
175                 if (bStopBlinking) {
176                         if (check_fwstate(pmlmepriv, _FW_LINKED)) {
177                                 pLed->bLedLinkBlinkInProgress = true;
178                                 pLed->CurrLedState = LED_BLINK_NORMAL;
179                                 if (pLed->bLedOn)
180                                         pLed->BlinkingLedState = RTW_LED_OFF;
181                                 else
182                                         pLed->BlinkingLedState = RTW_LED_ON;
183                                 _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA);
184                                 RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
185                         } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) {
186                                 pLed->bLedNoLinkBlinkInProgress = true;
187                                 pLed->CurrLedState = LED_BLINK_SLOWLY;
188                                 if (pLed->bLedOn)
189                                         pLed->BlinkingLedState = RTW_LED_OFF;
190                                 else
191                                         pLed->BlinkingLedState = RTW_LED_ON;
192                                 _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA);
193                                 RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
194                         }
195                         pLed->BlinkTimes = 0;
196                         pLed->bLedBlinkInProgress = false;
197                 } else {
198                         if (pLed->bLedOn)
199                                 pLed->BlinkingLedState = RTW_LED_OFF;
200                         else
201                                 pLed->BlinkingLedState = RTW_LED_ON;
202                         _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA);
203                 }
204                 break;
205         case LED_BLINK_WPS:
206                 if (pLed->bLedOn)
207                         pLed->BlinkingLedState = RTW_LED_OFF;
208                 else
209                         pLed->BlinkingLedState = RTW_LED_ON;
210                 _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA);
211                 break;
212         case LED_BLINK_WPS_STOP:        /* WPS success */
213                 if (pLed->BlinkingLedState == RTW_LED_ON)
214                         bStopBlinking = false;
215                 else
216                         bStopBlinking = true;
217
218                 if (bStopBlinking) {
219                         pLed->bLedLinkBlinkInProgress = true;
220                         pLed->CurrLedState = LED_BLINK_NORMAL;
221                         if (pLed->bLedOn)
222                                 pLed->BlinkingLedState = RTW_LED_OFF;
223                         else
224                                 pLed->BlinkingLedState = RTW_LED_ON;
225                         _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA);
226                         RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
227
228                         pLed->bLedWPSBlinkInProgress = false;
229                 } else {
230                         pLed->BlinkingLedState = RTW_LED_OFF;
231                         _set_timer(&(pLed->BlinkTimer), LED_BLINK_WPS_SUCESS_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->SwLed0);
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                         if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed))
252                                 return;
253                         if (pLed->bLedLinkBlinkInProgress) {
254                                 _cancel_timer_ex(&(pLed->BlinkTimer));
255                                 pLed->bLedLinkBlinkInProgress = false;
256                         }
257                         if (pLed->bLedBlinkInProgress) {
258                                 _cancel_timer_ex(&(pLed->BlinkTimer));
259                                 pLed->bLedBlinkInProgress = false;
260                         }
261
262                         pLed->bLedNoLinkBlinkInProgress = true;
263                         pLed->CurrLedState = LED_BLINK_SLOWLY;
264                         if (pLed->bLedOn)
265                                 pLed->BlinkingLedState = RTW_LED_OFF;
266                         else
267                                 pLed->BlinkingLedState = RTW_LED_ON;
268                         _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA);
269                 }
270                 break;
271         case LED_CTL_LINK:
272                 if (!pLed->bLedLinkBlinkInProgress) {
273                         if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed))
274                                 return;
275                         if (pLed->bLedNoLinkBlinkInProgress) {
276                                 _cancel_timer_ex(&(pLed->BlinkTimer));
277                                 pLed->bLedNoLinkBlinkInProgress = false;
278                         }
279                         if (pLed->bLedBlinkInProgress) {
280                                 _cancel_timer_ex(&(pLed->BlinkTimer));
281                                 pLed->bLedBlinkInProgress = false;
282                         }
283                         pLed->bLedLinkBlinkInProgress = true;
284                         pLed->CurrLedState = LED_BLINK_NORMAL;
285                         if (pLed->bLedOn)
286                                 pLed->BlinkingLedState = RTW_LED_OFF;
287                         else
288                                 pLed->BlinkingLedState = RTW_LED_ON;
289                         _set_timer(&(pLed->BlinkTimer), 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                                 _cancel_timer_ex(&(pLed->BlinkTimer));
300                                 pLed->bLedNoLinkBlinkInProgress = false;
301                         }
302                         if (pLed->bLedLinkBlinkInProgress) {
303                                 _cancel_timer_ex(&(pLed->BlinkTimer));
304                                  pLed->bLedLinkBlinkInProgress = false;
305                         }
306                         if (pLed->bLedBlinkInProgress) {
307                                 _cancel_timer_ex(&(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                         _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA);
318                  }
319                 break;
320         case LED_CTL_TX:
321         case LED_CTL_RX:
322                 if (!pLed->bLedBlinkInProgress) {
323                         if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed))
324                                 return;
325                         if (pLed->bLedNoLinkBlinkInProgress) {
326                                 _cancel_timer_ex(&(pLed->BlinkTimer));
327                                 pLed->bLedNoLinkBlinkInProgress = false;
328                         }
329                         if (pLed->bLedLinkBlinkInProgress) {
330                                 _cancel_timer_ex(&(pLed->BlinkTimer));
331                                 pLed->bLedLinkBlinkInProgress = false;
332                         }
333                         pLed->bLedBlinkInProgress = true;
334                         pLed->CurrLedState = LED_BLINK_TXRX;
335                         pLed->BlinkTimes = 2;
336                         if (pLed->bLedOn)
337                                 pLed->BlinkingLedState = RTW_LED_OFF;
338                         else
339                                 pLed->BlinkingLedState = RTW_LED_ON;
340                         _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA);
341                 }
342                 break;
343         case LED_CTL_START_WPS: /* wait until xinpin finish */
344         case LED_CTL_START_WPS_BOTTON:
345                  if (!pLed->bLedWPSBlinkInProgress) {
346                         if (pLed->bLedNoLinkBlinkInProgress) {
347                                 _cancel_timer_ex(&(pLed->BlinkTimer));
348                                 pLed->bLedNoLinkBlinkInProgress = false;
349                         }
350                         if (pLed->bLedLinkBlinkInProgress) {
351                                 _cancel_timer_ex(&(pLed->BlinkTimer));
352                                  pLed->bLedLinkBlinkInProgress = false;
353                         }
354                         if (pLed->bLedBlinkInProgress) {
355                                 _cancel_timer_ex(&(pLed->BlinkTimer));
356                                 pLed->bLedBlinkInProgress = false;
357                         }
358                         if (pLed->bLedScanBlinkInProgress) {
359                                 _cancel_timer_ex(&(pLed->BlinkTimer));
360                                 pLed->bLedScanBlinkInProgress = false;
361                         }
362                         pLed->bLedWPSBlinkInProgress = true;
363                         pLed->CurrLedState = LED_BLINK_WPS;
364                         if (pLed->bLedOn)
365                                 pLed->BlinkingLedState = RTW_LED_OFF;
366                         else
367                                 pLed->BlinkingLedState = RTW_LED_ON;
368                         _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA);
369                  }
370                 break;
371         case LED_CTL_STOP_WPS:
372                 if (pLed->bLedNoLinkBlinkInProgress) {
373                         _cancel_timer_ex(&(pLed->BlinkTimer));
374                         pLed->bLedNoLinkBlinkInProgress = false;
375                 }
376                 if (pLed->bLedLinkBlinkInProgress) {
377                         _cancel_timer_ex(&(pLed->BlinkTimer));
378                          pLed->bLedLinkBlinkInProgress = false;
379                 }
380                 if (pLed->bLedBlinkInProgress) {
381                         _cancel_timer_ex(&(pLed->BlinkTimer));
382                         pLed->bLedBlinkInProgress = false;
383                 }
384                 if (pLed->bLedScanBlinkInProgress) {
385                         _cancel_timer_ex(&(pLed->BlinkTimer));
386                         pLed->bLedScanBlinkInProgress = false;
387                 }
388                 if (pLed->bLedWPSBlinkInProgress)
389                         _cancel_timer_ex(&(pLed->BlinkTimer));
390                 else
391                         pLed->bLedWPSBlinkInProgress = true;
392                 pLed->CurrLedState = LED_BLINK_WPS_STOP;
393                 if (pLed->bLedOn) {
394                         pLed->BlinkingLedState = RTW_LED_OFF;
395                         _set_timer(&(pLed->BlinkTimer), LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA);
396                 } else {
397                         pLed->BlinkingLedState = RTW_LED_ON;
398                         _set_timer(&(pLed->BlinkTimer), 0);
399                 }
400                 break;
401         case LED_CTL_STOP_WPS_FAIL:
402                 if (pLed->bLedWPSBlinkInProgress) {
403                         _cancel_timer_ex(&(pLed->BlinkTimer));
404                         pLed->bLedWPSBlinkInProgress = false;
405                 }
406                 pLed->bLedNoLinkBlinkInProgress = true;
407                 pLed->CurrLedState = LED_BLINK_SLOWLY;
408                 if (pLed->bLedOn)
409                         pLed->BlinkingLedState = RTW_LED_OFF;
410                 else
411                         pLed->BlinkingLedState = RTW_LED_ON;
412                 _set_timer(&(pLed->BlinkTimer), 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                         _cancel_timer_ex(&(pLed->BlinkTimer));
419                         pLed->bLedNoLinkBlinkInProgress = false;
420                 }
421                 if (pLed->bLedLinkBlinkInProgress) {
422                         _cancel_timer_ex(&(pLed->BlinkTimer));
423                         pLed->bLedLinkBlinkInProgress = false;
424                 }
425                 if (pLed->bLedBlinkInProgress) {
426                         _cancel_timer_ex(&(pLed->BlinkTimer));
427                         pLed->bLedBlinkInProgress = false;
428                 }
429                 if (pLed->bLedWPSBlinkInProgress) {
430                         _cancel_timer_ex(&(pLed->BlinkTimer));
431                         pLed->bLedWPSBlinkInProgress = false;
432                 }
433                 if (pLed->bLedScanBlinkInProgress) {
434                         _cancel_timer_ex(&(pLed->BlinkTimer));
435                         pLed->bLedScanBlinkInProgress = false;
436                 }
437                 SwLedOff(padapter, pLed);
438                 break;
439         default:
440                 break;
441         }
442
443         RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Led %d\n", pLed->CurrLedState));
444 }
445
446 /*  */
447 /*      Description: */
448 /*              Handler function of LED Blinking. */
449 /*  */
450 void BlinkHandler(struct LED_871x *pLed)
451 {
452         struct adapter *padapter = pLed->padapter;
453
454         if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped))
455                 return;
456
457         SwLedBlink1(pLed);
458 }
459
460 void LedControl8188eu(struct adapter *padapter, enum LED_CTL_MODE LedAction)
461 {
462         struct led_priv *ledpriv = &(padapter->ledpriv);
463
464        if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped) ||
465            (!padapter->hw_init_completed))
466                 return;
467
468         if (!ledpriv->bRegUseLed)
469                 return;
470
471         if ((padapter->pwrctrlpriv.rf_pwrstate != rf_on &&
472              padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) &&
473             (LedAction == LED_CTL_TX || LedAction == LED_CTL_RX ||
474              LedAction == LED_CTL_SITE_SURVEY ||
475              LedAction == LED_CTL_LINK ||
476              LedAction == LED_CTL_NO_LINK ||
477              LedAction == LED_CTL_POWER_ON))
478                 return;
479
480         SwLedControlMode1(padapter, LedAction);
481 }