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