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 	blink_handler(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 		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 */
SwLedControlMode1(struct adapter * padapter,enum LED_CTL_MODE LedAction)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 
blink_handler(struct LED_871x * pLed)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 
led_control_8188eu(struct adapter * padapter,enum LED_CTL_MODE LedAction)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 }
485