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