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