1 #include "headers.h"
2 
3 #define STATUS_IMAGE_CHECKSUM_MISMATCH -199
4 #define EVENT_SIGNALED 1
5 
CFG_CalculateChecksum(B_UINT8 * pu8Buffer,B_UINT32 u32Size)6 static B_UINT16 CFG_CalculateChecksum(B_UINT8 *pu8Buffer, B_UINT32 u32Size)
7 {
8 	B_UINT16 u16CheckSum = 0;
9 	while (u32Size--) {
10 		u16CheckSum += (B_UINT8)~(*pu8Buffer);
11 		pu8Buffer++;
12 	}
13 	return u16CheckSum;
14 }
15 
IsReqGpioIsLedInNVM(PMINI_ADAPTER Adapter,UINT gpios)16 BOOLEAN IsReqGpioIsLedInNVM(PMINI_ADAPTER Adapter, UINT gpios)
17 {
18 	INT Status;
19 	Status = (Adapter->gpioBitMap & gpios) ^ gpios;
20 	if (Status)
21 		return FALSE;
22 	else
23 		return TRUE;
24 }
25 
LED_Blink(PMINI_ADAPTER Adapter,UINT GPIO_Num,UCHAR uiLedIndex,ULONG timeout,INT num_of_time,LedEventInfo_t currdriverstate)26 static INT LED_Blink(PMINI_ADAPTER Adapter, UINT GPIO_Num, UCHAR uiLedIndex,
27 		ULONG timeout, INT num_of_time, LedEventInfo_t currdriverstate)
28 {
29 	int Status = STATUS_SUCCESS;
30 	BOOLEAN bInfinite = FALSE;
31 
32 	/* Check if num_of_time is -ve. If yes, blink led in infinite loop */
33 	if (num_of_time < 0) {
34 		bInfinite = TRUE;
35 		num_of_time = 1;
36 	}
37 	while (num_of_time) {
38 		if (currdriverstate == Adapter->DriverState)
39 			TURN_ON_LED(GPIO_Num, uiLedIndex);
40 
41 		/* Wait for timeout after setting on the LED */
42 		Status = wait_event_interruptible_timeout(
43 				Adapter->LEDInfo.notify_led_event,
44 				currdriverstate != Adapter->DriverState ||
45 					kthread_should_stop(),
46 				msecs_to_jiffies(timeout));
47 
48 		if (kthread_should_stop()) {
49 			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO,
50 				DBG_LVL_ALL,
51 				"Led thread got signal to exit..hence exiting");
52 			Adapter->LEDInfo.led_thread_running =
53 					BCM_LED_THREAD_DISABLED;
54 			TURN_OFF_LED(GPIO_Num, uiLedIndex);
55 			Status = EVENT_SIGNALED;
56 			break;
57 		}
58 		if (Status) {
59 			TURN_OFF_LED(GPIO_Num, uiLedIndex);
60 			Status = EVENT_SIGNALED;
61 			break;
62 		}
63 
64 		TURN_OFF_LED(GPIO_Num, uiLedIndex);
65 		Status = wait_event_interruptible_timeout(
66 				Adapter->LEDInfo.notify_led_event,
67 				currdriverstate != Adapter->DriverState ||
68 					kthread_should_stop(),
69 				msecs_to_jiffies(timeout));
70 		if (bInfinite == FALSE)
71 			num_of_time--;
72 	}
73 	return Status;
74 }
75 
ScaleRateofTransfer(ULONG rate)76 static INT ScaleRateofTransfer(ULONG rate)
77 {
78 	if (rate <= 3)
79 		return rate;
80 	else if ((rate > 3) && (rate <= 100))
81 		return 5;
82 	else if ((rate > 100) && (rate <= 200))
83 		return 6;
84 	else if ((rate > 200) && (rate <= 300))
85 		return 7;
86 	else if ((rate > 300) && (rate <= 400))
87 		return 8;
88 	else if ((rate > 400) && (rate <= 500))
89 		return 9;
90 	else if ((rate > 500) && (rate <= 600))
91 		return 10;
92 	else
93 		return MAX_NUM_OF_BLINKS;
94 }
95 
96 
97 
LED_Proportional_Blink(PMINI_ADAPTER Adapter,UCHAR GPIO_Num_tx,UCHAR uiTxLedIndex,UCHAR GPIO_Num_rx,UCHAR uiRxLedIndex,LedEventInfo_t currdriverstate)98 static INT LED_Proportional_Blink(PMINI_ADAPTER Adapter, UCHAR GPIO_Num_tx,
99 		UCHAR uiTxLedIndex, UCHAR GPIO_Num_rx, UCHAR uiRxLedIndex,
100 		LedEventInfo_t currdriverstate)
101 {
102 	/* Initial values of TX and RX packets */
103 	ULONG64 Initial_num_of_packts_tx = 0, Initial_num_of_packts_rx = 0;
104 	/* values of TX and RX packets after 1 sec */
105 	ULONG64 Final_num_of_packts_tx = 0, Final_num_of_packts_rx = 0;
106 	/* Rate of transfer of Tx and Rx in 1 sec */
107 	ULONG64 rate_of_transfer_tx = 0, rate_of_transfer_rx = 0;
108 	int Status = STATUS_SUCCESS;
109 	INT num_of_time = 0, num_of_time_tx = 0, num_of_time_rx = 0;
110 	UINT remDelay = 0;
111 	BOOLEAN bBlinkBothLED = TRUE;
112 	/* UINT GPIO_num = DISABLE_GPIO_NUM; */
113 	ulong timeout = 0;
114 
115 	/* Read initial value of packets sent/received */
116 	Initial_num_of_packts_tx = Adapter->dev->stats.tx_packets;
117 	Initial_num_of_packts_rx = Adapter->dev->stats.rx_packets;
118 
119 	/* Scale the rate of transfer to no of blinks. */
120 	num_of_time_tx = ScaleRateofTransfer((ULONG)rate_of_transfer_tx);
121 	num_of_time_rx = ScaleRateofTransfer((ULONG)rate_of_transfer_rx);
122 
123 	while ((Adapter->device_removed == FALSE)) {
124 		timeout = 50;
125 		/*
126 		 * Blink Tx and Rx LED when both Tx and Rx is
127 		 * in normal bandwidth
128 		 */
129 		if (bBlinkBothLED) {
130 			/*
131 			 * Assign minimum number of blinks of
132 			 * either Tx or Rx.
133 			 */
134 			if (num_of_time_tx > num_of_time_rx)
135 				num_of_time = num_of_time_rx;
136 			else
137 				num_of_time = num_of_time_tx;
138 			if (num_of_time > 0) {
139 				/* Blink both Tx and Rx LEDs */
140 				if (LED_Blink(Adapter, 1 << GPIO_Num_tx,
141 						uiTxLedIndex, timeout,
142 						num_of_time, currdriverstate)
143 							== EVENT_SIGNALED)
144 					return EVENT_SIGNALED;
145 
146 				if (LED_Blink(Adapter, 1 << GPIO_Num_rx,
147 						uiRxLedIndex, timeout,
148 						num_of_time, currdriverstate)
149 							== EVENT_SIGNALED)
150 					return EVENT_SIGNALED;
151 
152 			}
153 
154 			if (num_of_time == num_of_time_tx) {
155 				/* Blink pending rate of Rx */
156 				if (LED_Blink(Adapter, (1 << GPIO_Num_rx),
157 						uiRxLedIndex, timeout,
158 						num_of_time_rx-num_of_time,
159 						currdriverstate)
160 							== EVENT_SIGNALED)
161 					return EVENT_SIGNALED;
162 
163 				num_of_time = num_of_time_rx;
164 			} else {
165 				/* Blink pending rate of Tx */
166 				if (LED_Blink(Adapter, 1 << GPIO_Num_tx,
167 						uiTxLedIndex, timeout,
168 						num_of_time_tx-num_of_time,
169 						currdriverstate)
170 							== EVENT_SIGNALED)
171 					return EVENT_SIGNALED;
172 
173 				num_of_time = num_of_time_tx;
174 			}
175 		} else {
176 			if (num_of_time == num_of_time_tx) {
177 				/* Blink pending rate of Rx */
178 				if (LED_Blink(Adapter, 1 << GPIO_Num_tx,
179 						uiTxLedIndex, timeout,
180 						num_of_time, currdriverstate)
181 							== EVENT_SIGNALED)
182 					return EVENT_SIGNALED;
183 			} else {
184 				/* Blink pending rate of Tx */
185 				if (LED_Blink(Adapter, 1 << GPIO_Num_rx,
186 						uiRxLedIndex, timeout,
187 						num_of_time, currdriverstate)
188 							== EVENT_SIGNALED)
189 					return EVENT_SIGNALED;
190 			}
191 		}
192 
193 		/*
194 		 * If Tx/Rx rate is less than maximum blinks per second,
195 		 * wait till delay completes to 1 second
196 		 */
197 		remDelay = MAX_NUM_OF_BLINKS - num_of_time;
198 		if (remDelay > 0) {
199 			timeout = 100 * remDelay;
200 			Status = wait_event_interruptible_timeout(
201 					Adapter->LEDInfo.notify_led_event,
202 					currdriverstate != Adapter->DriverState
203 						|| kthread_should_stop(),
204 					msecs_to_jiffies(timeout));
205 
206 			if (kthread_should_stop()) {
207 				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
208 					LED_DUMP_INFO, DBG_LVL_ALL,
209 					"Led thread got signal to exit..hence exiting");
210 				Adapter->LEDInfo.led_thread_running =
211 						BCM_LED_THREAD_DISABLED;
212 				return EVENT_SIGNALED;
213 			}
214 			if (Status)
215 				return EVENT_SIGNALED;
216 		}
217 
218 		/* Turn off both Tx and Rx LEDs before next second */
219 		TURN_OFF_LED(1 << GPIO_Num_tx, uiTxLedIndex);
220 		TURN_OFF_LED(1 << GPIO_Num_rx, uiTxLedIndex);
221 
222 		/*
223 		 * Read the Tx & Rx packets transmission after 1 second and
224 		 * calculate rate of transfer
225 		 */
226 		Final_num_of_packts_tx = Adapter->dev->stats.tx_packets;
227 		Final_num_of_packts_rx = Adapter->dev->stats.rx_packets;
228 
229 		rate_of_transfer_tx = Final_num_of_packts_tx -
230 						Initial_num_of_packts_tx;
231 		rate_of_transfer_rx = Final_num_of_packts_rx -
232 						Initial_num_of_packts_rx;
233 
234 		/* Read initial value of packets sent/received */
235 		Initial_num_of_packts_tx = Final_num_of_packts_tx;
236 		Initial_num_of_packts_rx = Final_num_of_packts_rx;
237 
238 		/* Scale the rate of transfer to no of blinks. */
239 		num_of_time_tx =
240 			ScaleRateofTransfer((ULONG)rate_of_transfer_tx);
241 		num_of_time_rx =
242 			ScaleRateofTransfer((ULONG)rate_of_transfer_rx);
243 
244 	}
245 	return Status;
246 }
247 
248 /*
249  * -----------------------------------------------------------------------------
250  * Procedure:   ValidateDSDParamsChecksum
251  *
252  * Description: Reads DSD Params and validates checkusm.
253  *
254  * Arguments:
255  *      Adapter - Pointer to Adapter structure.
256  *      ulParamOffset - Start offset of the DSD parameter to be read and
257  *			validated.
258  *      usParamLen - Length of the DSD Parameter.
259  *
260  * Returns:
261  *  <OSAL_STATUS_CODE>
262  * -----------------------------------------------------------------------------
263  */
ValidateDSDParamsChecksum(PMINI_ADAPTER Adapter,ULONG ulParamOffset,USHORT usParamLen)264 static INT ValidateDSDParamsChecksum(PMINI_ADAPTER Adapter, ULONG ulParamOffset,
265 					USHORT usParamLen)
266 {
267 	INT Status = STATUS_SUCCESS;
268 	PUCHAR puBuffer = NULL;
269 	USHORT usChksmOrg = 0;
270 	USHORT usChecksumCalculated = 0;
271 
272 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,
273 		"LED Thread:ValidateDSDParamsChecksum: 0x%lx 0x%X",
274 		ulParamOffset, usParamLen);
275 
276 	puBuffer = kmalloc(usParamLen, GFP_KERNEL);
277 	if (!puBuffer) {
278 		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO,
279 			DBG_LVL_ALL,
280 			"LED Thread: ValidateDSDParamsChecksum Allocation failed");
281 		return -ENOMEM;
282 
283 	}
284 
285 	/* Read the DSD data from the parameter offset. */
286 	if (STATUS_SUCCESS != BeceemNVMRead(Adapter, (PUINT)puBuffer,
287 			ulParamOffset, usParamLen)) {
288 		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO,
289 			DBG_LVL_ALL,
290 			"LED Thread: ValidateDSDParamsChecksum BeceemNVMRead failed");
291 		Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
292 		goto exit;
293 	}
294 
295 	/* Calculate the checksum of the data read from the DSD parameter. */
296 	usChecksumCalculated = CFG_CalculateChecksum(puBuffer, usParamLen);
297 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,
298 		"LED Thread: usCheckSumCalculated = 0x%x\n",
299 		usChecksumCalculated);
300 
301 	/*
302 	 * End of the DSD parameter will have a TWO bytes checksum stored in it.
303 	 * Read it and compare with the calculated Checksum.
304 	 */
305 	if (STATUS_SUCCESS != BeceemNVMRead(Adapter, (PUINT)&usChksmOrg,
306 			ulParamOffset+usParamLen, 2)) {
307 		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO,
308 			DBG_LVL_ALL,
309 			"LED Thread: ValidateDSDParamsChecksum BeceemNVMRead failed");
310 		Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
311 		goto exit;
312 	}
313 	usChksmOrg = ntohs(usChksmOrg);
314 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,
315 		"LED Thread: usChksmOrg = 0x%x", usChksmOrg);
316 
317 	/*
318 	 * Compare the checksum calculated with the checksum read
319 	 * from DSD section
320 	 */
321 	if (usChecksumCalculated ^ usChksmOrg) {
322 		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO,
323 			DBG_LVL_ALL,
324 			"LED Thread: ValidateDSDParamsChecksum: Checksums don't match");
325 		Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
326 		goto exit;
327 	}
328 
329 exit:
330 	kfree(puBuffer);
331 	return Status;
332 }
333 
334 
335 /*
336  * -----------------------------------------------------------------------------
337  * Procedure:   ValidateHWParmStructure
338  *
339  * Description: Validates HW Parameters.
340  *
341  * Arguments:
342  *      Adapter - Pointer to Adapter structure.
343  *      ulHwParamOffset - Start offset of the HW parameter Section to be read
344  *				and validated.
345  *
346  * Returns:
347  *  <OSAL_STATUS_CODE>
348  * -----------------------------------------------------------------------------
349  */
ValidateHWParmStructure(PMINI_ADAPTER Adapter,ULONG ulHwParamOffset)350 static INT ValidateHWParmStructure(PMINI_ADAPTER Adapter, ULONG ulHwParamOffset)
351 {
352 
353 	INT Status = STATUS_SUCCESS;
354 	USHORT HwParamLen = 0;
355 	/*
356 	 * Add DSD start offset to the hwParamOffset to get
357 	 * the actual address.
358 	 */
359 	ulHwParamOffset += DSD_START_OFFSET;
360 
361 	/* Read the Length of HW_PARAM structure */
362 	BeceemNVMRead(Adapter, (PUINT)&HwParamLen, ulHwParamOffset, 2);
363 	HwParamLen = ntohs(HwParamLen);
364 	if (0 == HwParamLen || HwParamLen > Adapter->uiNVMDSDSize)
365 		return STATUS_IMAGE_CHECKSUM_MISMATCH;
366 
367 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,
368 		"LED Thread:HwParamLen = 0x%x", HwParamLen);
369 	Status = ValidateDSDParamsChecksum(Adapter, ulHwParamOffset,
370 						HwParamLen);
371 	return Status;
372 } /* ValidateHWParmStructure() */
373 
ReadLEDInformationFromEEPROM(PMINI_ADAPTER Adapter,UCHAR GPIO_Array[])374 static int ReadLEDInformationFromEEPROM(PMINI_ADAPTER Adapter,
375 					UCHAR GPIO_Array[])
376 {
377 	int Status = STATUS_SUCCESS;
378 
379 	ULONG  dwReadValue	= 0;
380 	USHORT usHwParamData	= 0;
381 	USHORT usEEPROMVersion	= 0;
382 	UCHAR  ucIndex		= 0;
383 	UCHAR  ucGPIOInfo[32]	= {0};
384 
385 	BeceemNVMRead(Adapter, (PUINT)&usEEPROMVersion,
386 			EEPROM_VERSION_OFFSET, 2);
387 
388 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,
389 		"usEEPROMVersion: Minor:0x%X Major:0x%x",
390 		usEEPROMVersion&0xFF, ((usEEPROMVersion>>8)&0xFF));
391 
392 
393 	if (((usEEPROMVersion>>8)&0xFF) < EEPROM_MAP5_MAJORVERSION) {
394 		BeceemNVMRead(Adapter, (PUINT)&usHwParamData,
395 			EEPROM_HW_PARAM_POINTER_ADDRESS, 2);
396 		usHwParamData = ntohs(usHwParamData);
397 		dwReadValue   = usHwParamData;
398 	} else {
399 		/*
400 		 * Validate Compatibility section and then read HW param
401 		 * if compatibility section is valid.
402 		 */
403 		Status = ValidateDSDParamsChecksum(Adapter,
404 				DSD_START_OFFSET,
405 				COMPATIBILITY_SECTION_LENGTH_MAP5);
406 
407 		if (Status != STATUS_SUCCESS)
408 			return Status;
409 
410 		BeceemNVMRead(Adapter, (PUINT)&dwReadValue,
411 			EEPROM_HW_PARAM_POINTER_ADDRRES_MAP5, 4);
412 		dwReadValue = ntohl(dwReadValue);
413 	}
414 
415 
416 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,
417 		"LED Thread: Start address of HW_PARAM structure = 0x%lx",
418 		dwReadValue);
419 
420 	/*
421 	 * Validate if the address read out is within the DSD.
422 	 * Adapter->uiNVMDSDSize gives whole DSD size inclusive of Autoinit.
423 	 * lower limit should be above DSD_START_OFFSET and
424 	 * upper limit should be below (Adapter->uiNVMDSDSize-DSD_START_OFFSET)
425 	 */
426 	if (dwReadValue < DSD_START_OFFSET ||
427 			dwReadValue > (Adapter->uiNVMDSDSize-DSD_START_OFFSET))
428 		return STATUS_IMAGE_CHECKSUM_MISMATCH;
429 
430 	Status = ValidateHWParmStructure(Adapter, dwReadValue);
431 	if (Status)
432 		return Status;
433 
434 	/*
435 	 * Add DSD_START_OFFSET to the offset read from the EEPROM.
436 	 * This will give the actual start HW Parameters start address.
437 	 * To read GPIO section, add GPIO offset further.
438 	 */
439 
440 	dwReadValue +=
441 		DSD_START_OFFSET; /* = start address of hw param section. */
442 	dwReadValue += GPIO_SECTION_START_OFFSET;
443 			/* = GPIO start offset within HW Param section. */
444 
445 	/*
446 	 * Read the GPIO values for 32 GPIOs from EEPROM and map the function
447 	 * number to GPIO pin number to GPIO_Array
448 	 */
449 	BeceemNVMRead(Adapter, (UINT *)ucGPIOInfo, dwReadValue, 32);
450 	for (ucIndex = 0; ucIndex < 32; ucIndex++) {
451 
452 		switch (ucGPIOInfo[ucIndex]) {
453 		case RED_LED:
454 			GPIO_Array[RED_LED] = ucIndex;
455 			Adapter->gpioBitMap |= (1 << ucIndex);
456 			break;
457 		case BLUE_LED:
458 			GPIO_Array[BLUE_LED] = ucIndex;
459 			Adapter->gpioBitMap |= (1 << ucIndex);
460 			break;
461 		case YELLOW_LED:
462 			GPIO_Array[YELLOW_LED] = ucIndex;
463 			Adapter->gpioBitMap |= (1 << ucIndex);
464 			break;
465 		case GREEN_LED:
466 			GPIO_Array[GREEN_LED] = ucIndex;
467 			Adapter->gpioBitMap |= (1 << ucIndex);
468 			break;
469 		default:
470 			break;
471 		}
472 
473 	}
474 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,
475 		"GPIO's bit map correspond to LED :0x%X", Adapter->gpioBitMap);
476 	return Status;
477 }
478 
479 
ReadConfigFileStructure(PMINI_ADAPTER Adapter,BOOLEAN * bEnableThread)480 static int ReadConfigFileStructure(PMINI_ADAPTER Adapter,
481 					BOOLEAN *bEnableThread)
482 {
483 	int Status = STATUS_SUCCESS;
484 	/* Array to store GPIO numbers from EEPROM */
485 	UCHAR GPIO_Array[NUM_OF_LEDS+1];
486 	UINT uiIndex = 0;
487 	UINT uiNum_of_LED_Type = 0;
488 	PUCHAR puCFGData	= NULL;
489 	UCHAR bData = 0;
490 	memset(GPIO_Array, DISABLE_GPIO_NUM, NUM_OF_LEDS+1);
491 
492 	if (!Adapter->pstargetparams || IS_ERR(Adapter->pstargetparams)) {
493 		BCM_DEBUG_PRINT (Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO,
494 			DBG_LVL_ALL, "Target Params not Avail.\n");
495 		return -ENOENT;
496 	}
497 
498 	/* Populate GPIO_Array with GPIO numbers for LED functions */
499 	/* Read the GPIO numbers from EEPROM */
500 	Status = ReadLEDInformationFromEEPROM(Adapter, GPIO_Array);
501 	if (Status == STATUS_IMAGE_CHECKSUM_MISMATCH) {
502 		*bEnableThread = FALSE;
503 		return STATUS_SUCCESS;
504 	} else if (Status) {
505 		*bEnableThread = FALSE;
506 		return Status;
507 	}
508 
509 	/*
510 	 * CONFIG file read successfully. Deallocate the memory of
511 	 * uiFileNameBufferSize
512 	 */
513 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,
514 		"LED Thread: Config file read successfully\n");
515 	puCFGData = (PUCHAR) &Adapter->pstargetparams->HostDrvrConfig1;
516 
517 	/*
518 	 * Offset for HostDrvConfig1, HostDrvConfig2, HostDrvConfig3 which
519 	 * will have the information of LED type, LED on state for different
520 	 * driver state and LED blink state.
521 	 */
522 
523 	for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) {
524 		bData = *puCFGData;
525 
526 		/*
527 		 * Check Bit 8 for polarity. If it is set,
528 		 * polarity is reverse polarity
529 		 */
530 		if (bData & 0x80) {
531 			Adapter->LEDInfo.LEDState[uiIndex].BitPolarity = 0;
532 			/* unset the bit 8 */
533 			bData = bData & 0x7f;
534 		}
535 
536 		Adapter->LEDInfo.LEDState[uiIndex].LED_Type = bData;
537 		if (bData <= NUM_OF_LEDS)
538 			Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num =
539 							GPIO_Array[bData];
540 		else
541 			Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num =
542 							DISABLE_GPIO_NUM;
543 
544 		puCFGData++;
545 		bData = *puCFGData;
546 		Adapter->LEDInfo.LEDState[uiIndex].LED_On_State = bData;
547 		puCFGData++;
548 		bData = *puCFGData;
549 		Adapter->LEDInfo.LEDState[uiIndex].LED_Blink_State = bData;
550 		puCFGData++;
551 	}
552 
553 	/*
554 	 * Check if all the LED settings are disabled. If it is disabled,
555 	 * dont launch the LED control thread.
556 	 */
557 	for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) {
558 		if ((Adapter->LEDInfo.LEDState[uiIndex].LED_Type == DISABLE_GPIO_NUM) ||
559 			(Adapter->LEDInfo.LEDState[uiIndex].LED_Type == 0x7f) ||
560 			(Adapter->LEDInfo.LEDState[uiIndex].LED_Type == 0))
561 			uiNum_of_LED_Type++;
562 	}
563 	if (uiNum_of_LED_Type >= NUM_OF_LEDS)
564 		*bEnableThread = FALSE;
565 
566 	return Status;
567 }
568 
569 /*
570  * -----------------------------------------------------------------------------
571  * Procedure:   LedGpioInit
572  *
573  * Description: Initializes LED GPIOs. Makes the LED GPIOs to OUTPUT mode
574  *			  and make the initial state to be OFF.
575  *
576  * Arguments:
577  *      Adapter - Pointer to MINI_ADAPTER structure.
578  *
579  * Returns: VOID
580  *
581  * -----------------------------------------------------------------------------
582  */
LedGpioInit(PMINI_ADAPTER Adapter)583 static VOID LedGpioInit(PMINI_ADAPTER Adapter)
584 {
585 	UINT uiResetValue = 0;
586 	UINT uiIndex      = 0;
587 
588 	/* Set all LED GPIO Mode to output mode */
589 	if (rdmalt(Adapter, GPIO_MODE_REGISTER, &uiResetValue,
590 			sizeof(uiResetValue)) < 0)
591 		BCM_DEBUG_PRINT (Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO,
592 			DBG_LVL_ALL, "LED Thread: RDM Failed\n");
593 	for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) {
594 		if (Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num !=
595 				DISABLE_GPIO_NUM)
596 			uiResetValue |= (1 << Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num);
597 		TURN_OFF_LED(1 << Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num,
598 				uiIndex);
599 	}
600 	if (wrmalt(Adapter, GPIO_MODE_REGISTER, &uiResetValue,
601 			sizeof(uiResetValue)) < 0)
602 		BCM_DEBUG_PRINT (Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO,
603 			DBG_LVL_ALL, "LED Thread: WRM Failed\n");
604 
605 	Adapter->LEDInfo.bIdle_led_off = FALSE;
606 }
607 
BcmGetGPIOPinInfo(PMINI_ADAPTER Adapter,UCHAR * GPIO_num_tx,UCHAR * GPIO_num_rx,UCHAR * uiLedTxIndex,UCHAR * uiLedRxIndex,LedEventInfo_t currdriverstate)608 static INT BcmGetGPIOPinInfo(PMINI_ADAPTER Adapter, UCHAR *GPIO_num_tx,
609 		UCHAR *GPIO_num_rx, UCHAR *uiLedTxIndex, UCHAR *uiLedRxIndex,
610 		LedEventInfo_t currdriverstate)
611 {
612 	UINT uiIndex = 0;
613 
614 	*GPIO_num_tx = DISABLE_GPIO_NUM;
615 	*GPIO_num_rx = DISABLE_GPIO_NUM;
616 
617 	for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) {
618 
619 		if ((currdriverstate == NORMAL_OPERATION) ||
620 				(currdriverstate == IDLEMODE_EXIT) ||
621 				(currdriverstate == FW_DOWNLOAD)) {
622 			if (Adapter->LEDInfo.LEDState[uiIndex].LED_Blink_State &
623 					currdriverstate) {
624 				if (Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num
625 						!= DISABLE_GPIO_NUM) {
626 					if (*GPIO_num_tx == DISABLE_GPIO_NUM) {
627 						*GPIO_num_tx = Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num;
628 						*uiLedTxIndex = uiIndex;
629 					} else {
630 						*GPIO_num_rx = Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num;
631 						*uiLedRxIndex = uiIndex;
632 					}
633 				}
634 			}
635 		} else {
636 			if (Adapter->LEDInfo.LEDState[uiIndex].LED_On_State
637 					& currdriverstate) {
638 				if (Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num
639 						!= DISABLE_GPIO_NUM) {
640 					*GPIO_num_tx = Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num;
641 					*uiLedTxIndex = uiIndex;
642 				}
643 			}
644 		}
645 	}
646 	return STATUS_SUCCESS;
647 }
LEDControlThread(PMINI_ADAPTER Adapter)648 static VOID LEDControlThread(PMINI_ADAPTER Adapter)
649 {
650 	UINT uiIndex = 0;
651 	UCHAR GPIO_num = 0;
652 	UCHAR uiLedIndex = 0;
653 	UINT uiResetValue = 0;
654 	LedEventInfo_t currdriverstate = 0;
655 	ulong timeout = 0;
656 
657 	INT Status = 0;
658 
659 	UCHAR dummyGPIONum = 0;
660 	UCHAR dummyIndex = 0;
661 
662 	/* currdriverstate = Adapter->DriverState; */
663 	Adapter->LEDInfo.bIdleMode_tx_from_host = FALSE;
664 
665 	/*
666 	 * Wait till event is triggered
667 	 *
668 	 * wait_event(Adapter->LEDInfo.notify_led_event,
669 	 *	currdriverstate!= Adapter->DriverState);
670 	 */
671 
672 	GPIO_num = DISABLE_GPIO_NUM;
673 
674 	while (TRUE) {
675 		/* Wait till event is triggered */
676 		if ((GPIO_num == DISABLE_GPIO_NUM)
677 						||
678 				((currdriverstate != FW_DOWNLOAD) &&
679 				 (currdriverstate != NORMAL_OPERATION) &&
680 				 (currdriverstate != LOWPOWER_MODE_ENTER))
681 						||
682 				(currdriverstate == LED_THREAD_INACTIVE))
683 			Status = wait_event_interruptible(
684 					Adapter->LEDInfo.notify_led_event,
685 					currdriverstate != Adapter->DriverState
686 						|| kthread_should_stop());
687 
688 		if (kthread_should_stop() || Adapter->device_removed) {
689 			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO,
690 				DBG_LVL_ALL,
691 				"Led thread got signal to exit..hence exiting");
692 			Adapter->LEDInfo.led_thread_running =
693 						BCM_LED_THREAD_DISABLED;
694 			TURN_OFF_LED(1 << GPIO_num, uiLedIndex);
695 			return; /* STATUS_FAILURE; */
696 		}
697 
698 		if (GPIO_num != DISABLE_GPIO_NUM)
699 			TURN_OFF_LED(1 << GPIO_num, uiLedIndex);
700 
701 		if (Adapter->LEDInfo.bLedInitDone == FALSE) {
702 			LedGpioInit(Adapter);
703 			Adapter->LEDInfo.bLedInitDone = TRUE;
704 		}
705 
706 		switch (Adapter->DriverState) {
707 		case DRIVER_INIT:
708 			currdriverstate = DRIVER_INIT;
709 					/* Adapter->DriverState; */
710 			BcmGetGPIOPinInfo(Adapter, &GPIO_num, &dummyGPIONum,
711 				&uiLedIndex, &dummyIndex, currdriverstate);
712 
713 			if (GPIO_num != DISABLE_GPIO_NUM)
714 				TURN_ON_LED(1 << GPIO_num, uiLedIndex);
715 
716 			break;
717 		case FW_DOWNLOAD:
718 			/*
719 			 * BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
720 			 *	LED_DUMP_INFO, DBG_LVL_ALL,
721 			 *	"LED Thread: FW_DN_DONE called\n");
722 			 */
723 			currdriverstate = FW_DOWNLOAD;
724 			BcmGetGPIOPinInfo(Adapter, &GPIO_num, &dummyGPIONum,
725 				&uiLedIndex, &dummyIndex, currdriverstate);
726 
727 			if (GPIO_num != DISABLE_GPIO_NUM) {
728 				timeout = 50;
729 				LED_Blink(Adapter, 1 << GPIO_num, uiLedIndex,
730 					timeout, -1, currdriverstate);
731 			}
732 			break;
733 		case FW_DOWNLOAD_DONE:
734 			currdriverstate = FW_DOWNLOAD_DONE;
735 			BcmGetGPIOPinInfo(Adapter, &GPIO_num, &dummyGPIONum,
736 				&uiLedIndex, &dummyIndex, currdriverstate);
737 			if (GPIO_num != DISABLE_GPIO_NUM)
738 				TURN_ON_LED(1 << GPIO_num, uiLedIndex);
739 			break;
740 
741 		case SHUTDOWN_EXIT:
742 			/*
743 			 * no break, continue to NO_NETWORK_ENTRY
744 			 * state as well.
745 			 */
746 		case NO_NETWORK_ENTRY:
747 			currdriverstate = NO_NETWORK_ENTRY;
748 			BcmGetGPIOPinInfo(Adapter, &GPIO_num, &dummyGPIONum,
749 				&uiLedIndex, &dummyGPIONum, currdriverstate);
750 			if (GPIO_num != DISABLE_GPIO_NUM)
751 				TURN_ON_LED(1 << GPIO_num, uiLedIndex);
752 			break;
753 		case NORMAL_OPERATION:
754 			{
755 				UCHAR GPIO_num_tx = DISABLE_GPIO_NUM;
756 				UCHAR GPIO_num_rx = DISABLE_GPIO_NUM;
757 				UCHAR uiLEDTx = 0;
758 				UCHAR uiLEDRx = 0;
759 				currdriverstate = NORMAL_OPERATION;
760 				Adapter->LEDInfo.bIdle_led_off = FALSE;
761 
762 				BcmGetGPIOPinInfo(Adapter, &GPIO_num_tx,
763 					&GPIO_num_rx, &uiLEDTx, &uiLEDRx,
764 					currdriverstate);
765 				if ((GPIO_num_tx == DISABLE_GPIO_NUM) &&
766 						(GPIO_num_rx ==
767 						 DISABLE_GPIO_NUM)) {
768 					GPIO_num = DISABLE_GPIO_NUM;
769 				} else {
770 					/*
771 					 * If single LED is selected, use same
772 					 * for both Tx and Rx
773 					 */
774 					if (GPIO_num_tx == DISABLE_GPIO_NUM) {
775 						GPIO_num_tx = GPIO_num_rx;
776 						uiLEDTx = uiLEDRx;
777 					} else if (GPIO_num_rx ==
778 							DISABLE_GPIO_NUM) {
779 						GPIO_num_rx = GPIO_num_tx;
780 						uiLEDRx = uiLEDTx;
781 					}
782 					/*
783 					 * Blink the LED in proportionate
784 					 * to Tx and Rx transmissions.
785 					 */
786 					LED_Proportional_Blink(Adapter,
787 						GPIO_num_tx, uiLEDTx,
788 						GPIO_num_rx, uiLEDRx,
789 						currdriverstate);
790 				}
791 			}
792 			break;
793 		case LOWPOWER_MODE_ENTER:
794 			currdriverstate = LOWPOWER_MODE_ENTER;
795 			if (DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING ==
796 					Adapter->ulPowerSaveMode) {
797 				/* Turn OFF all the LED */
798 				uiResetValue = 0;
799 				for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) {
800 					if (Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num != DISABLE_GPIO_NUM)
801 						TURN_OFF_LED((1 << Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num), uiIndex);
802 				}
803 
804 			}
805 			/* Turn off LED And WAKE-UP for Sendinf IDLE mode ACK */
806 			Adapter->LEDInfo.bLedInitDone = FALSE;
807 			Adapter->LEDInfo.bIdle_led_off = TRUE;
808 			wake_up(&Adapter->LEDInfo.idleModeSyncEvent);
809 			GPIO_num = DISABLE_GPIO_NUM;
810 			break;
811 		case IDLEMODE_CONTINUE:
812 			currdriverstate = IDLEMODE_CONTINUE;
813 			GPIO_num = DISABLE_GPIO_NUM;
814 			break;
815 		case IDLEMODE_EXIT:
816 			break;
817 		case DRIVER_HALT:
818 			currdriverstate = DRIVER_HALT;
819 			GPIO_num = DISABLE_GPIO_NUM;
820 			for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) {
821 				if (Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num
822 						!= DISABLE_GPIO_NUM)
823 					TURN_OFF_LED((1 << Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num), uiIndex);
824 			}
825 			/* Adapter->DriverState = DRIVER_INIT; */
826 			break;
827 		case LED_THREAD_INACTIVE:
828 			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO,
829 				DBG_LVL_ALL, "InActivating LED thread...");
830 			currdriverstate = LED_THREAD_INACTIVE;
831 			Adapter->LEDInfo.led_thread_running =
832 					BCM_LED_THREAD_RUNNING_INACTIVELY;
833 			Adapter->LEDInfo.bLedInitDone = FALSE;
834 			/* disable ALL LED */
835 			for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) {
836 				if (Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num
837 						!= DISABLE_GPIO_NUM)
838 					TURN_OFF_LED((1 << Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num), uiIndex);
839 			}
840 			break;
841 		case LED_THREAD_ACTIVE:
842 			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO,
843 				DBG_LVL_ALL, "Activating LED thread again...");
844 			if (Adapter->LinkUpStatus == FALSE)
845 				Adapter->DriverState = NO_NETWORK_ENTRY;
846 			else
847 				Adapter->DriverState = NORMAL_OPERATION;
848 
849 			Adapter->LEDInfo.led_thread_running =
850 					BCM_LED_THREAD_RUNNING_ACTIVELY;
851 			break;
852 			/* return; */
853 		default:
854 			break;
855 		}
856 	}
857 	Adapter->LEDInfo.led_thread_running = BCM_LED_THREAD_DISABLED;
858 }
859 
InitLedSettings(PMINI_ADAPTER Adapter)860 int InitLedSettings(PMINI_ADAPTER Adapter)
861 {
862 	int Status = STATUS_SUCCESS;
863 	BOOLEAN bEnableThread = TRUE;
864 	UCHAR uiIndex = 0;
865 
866 	/*
867 	 * Initially set BitPolarity to normal polarity. The bit 8 of LED type
868 	 * is used to change the polarity of the LED.
869 	 */
870 
871 	for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++)
872 		Adapter->LEDInfo.LEDState[uiIndex].BitPolarity = 1;
873 
874 	/*
875 	 * Read the LED settings of CONFIG file and map it
876 	 * to GPIO numbers in EEPROM
877 	 */
878 	Status = ReadConfigFileStructure(Adapter, &bEnableThread);
879 	if (STATUS_SUCCESS != Status) {
880 		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO,
881 			DBG_LVL_ALL,
882 			"LED Thread: FAILED in ReadConfigFileStructure\n");
883 		return Status;
884 	}
885 
886 	if (Adapter->LEDInfo.led_thread_running) {
887 		if (bEnableThread) {
888 			;
889 		} else {
890 			Adapter->DriverState = DRIVER_HALT;
891 			wake_up(&Adapter->LEDInfo.notify_led_event);
892 			Adapter->LEDInfo.led_thread_running =
893 						BCM_LED_THREAD_DISABLED;
894 		}
895 
896 	} else if (bEnableThread) {
897 		/* Create secondary thread to handle the LEDs */
898 		init_waitqueue_head(&Adapter->LEDInfo.notify_led_event);
899 		init_waitqueue_head(&Adapter->LEDInfo.idleModeSyncEvent);
900 		Adapter->LEDInfo.led_thread_running =
901 					BCM_LED_THREAD_RUNNING_ACTIVELY;
902 		Adapter->LEDInfo.bIdle_led_off = FALSE;
903 		Adapter->LEDInfo.led_cntrl_threadid =
904 			kthread_run((int (*)(void *)) LEDControlThread,
905 			Adapter, "led_control_thread");
906 		if (IS_ERR(Adapter->LEDInfo.led_cntrl_threadid)) {
907 			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO,
908 				DBG_LVL_ALL,
909 				"Not able to spawn Kernel Thread\n");
910 			Adapter->LEDInfo.led_thread_running =
911 				BCM_LED_THREAD_DISABLED;
912 			return PTR_ERR(Adapter->LEDInfo.led_cntrl_threadid);
913 		}
914 	}
915 	return Status;
916 }
917