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 /*  */
BlinkTimerCallback(struct timer_list * t)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 /*  */
BlinkWorkItemCallback(struct work_struct * work)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 /*  */
ResetLedStatus(struct LED_871x * pLed)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. */
InitLed871x(struct adapter * padapter,struct LED_871x * pLed)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 /*  */
DeInitLed871x(struct LED_871x * pLed)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 
SwLedBlink1(struct LED_871x * pLed)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 */
SwLedControlMode1(struct adapter * padapter,enum LED_CTL_MODE LedAction)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 /*  */
BlinkHandler(struct LED_871x * pLed)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 
LedControl8188eu(struct adapter * padapter,enum LED_CTL_MODE LedAction)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 }
483