Kernel  |  3.18

下载     查看原文件
C++程序  |  953行  |  26.46 KB
#include "headers.h"

#define STATUS_IMAGE_CHECKSUM_MISMATCH -199
#define EVENT_SIGNALED 1

static B_UINT16 CFG_CalculateChecksum(B_UINT8 *pu8Buffer, B_UINT32 u32Size)
{
	B_UINT16 u16CheckSum = 0;

	while (u32Size--) {
		u16CheckSum += (B_UINT8)~(*pu8Buffer);
		pu8Buffer++;
	}
	return u16CheckSum;
}

bool IsReqGpioIsLedInNVM(struct bcm_mini_adapter *Adapter, UINT gpios)
{
	INT Status;

	Status = (Adapter->gpioBitMap & gpios) ^ gpios;
	if (Status)
		return false;
	else
		return TRUE;
}

static INT LED_Blink(struct bcm_mini_adapter *Adapter,
		     UINT GPIO_Num,
		     UCHAR uiLedIndex,
		     ULONG timeout,
		     INT num_of_time,
		     enum bcm_led_events currdriverstate)
{
	int Status = STATUS_SUCCESS;
	bool bInfinite = false;

	/* Check if num_of_time is -ve. If yes, blink led in infinite loop */
	if (num_of_time < 0) {
		bInfinite = TRUE;
		num_of_time = 1;
	}
	while (num_of_time) {
		if (currdriverstate == Adapter->DriverState)
			TURN_ON_LED(Adapter, GPIO_Num, uiLedIndex);

		/* Wait for timeout after setting on the LED */
		Status = wait_event_interruptible_timeout(
				Adapter->LEDInfo.notify_led_event,
				currdriverstate != Adapter->DriverState ||
					kthread_should_stop(),
				msecs_to_jiffies(timeout));

		if (kthread_should_stop()) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO,
				DBG_LVL_ALL,
				"Led thread got signal to exit..hence exiting");
			Adapter->LEDInfo.led_thread_running =
					BCM_LED_THREAD_DISABLED;
			TURN_OFF_LED(Adapter, GPIO_Num, uiLedIndex);
			Status = EVENT_SIGNALED;
			break;
		}
		if (Status) {
			TURN_OFF_LED(Adapter, GPIO_Num, uiLedIndex);
			Status = EVENT_SIGNALED;
			break;
		}

		TURN_OFF_LED(Adapter, GPIO_Num, uiLedIndex);
		Status = wait_event_interruptible_timeout(
				Adapter->LEDInfo.notify_led_event,
				currdriverstate != Adapter->DriverState ||
					kthread_should_stop(),
				msecs_to_jiffies(timeout));
		if (bInfinite == false)
			num_of_time--;
	}
	return Status;
}

static INT ScaleRateofTransfer(ULONG rate)
{
	if (rate <= 3)
		return rate;
	else if ((rate > 3) && (rate <= 100))
		return 5;
	else if ((rate > 100) && (rate <= 200))
		return 6;
	else if ((rate > 200) && (rate <= 300))
		return 7;
	else if ((rate > 300) && (rate <= 400))
		return 8;
	else if ((rate > 400) && (rate <= 500))
		return 9;
	else if ((rate > 500) && (rate <= 600))
		return 10;
	else
		return MAX_NUM_OF_BLINKS;
}

static INT blink_in_normal_bandwidth(struct bcm_mini_adapter *ad,
				     INT *time,
				     INT *time_tx,
				     INT *time_rx,
				     UCHAR GPIO_Num_tx,
				     UCHAR uiTxLedIndex,
				     UCHAR GPIO_Num_rx,
				     UCHAR uiRxLedIndex,
				     enum bcm_led_events currdriverstate,
				     ulong *timeout)
{
	/*
	 * Assign minimum number of blinks of
	 * either Tx or Rx.
	 */
	*time = (*time_tx > *time_rx ? *time_rx : *time_tx);

	if (*time > 0) {
		/* Blink both Tx and Rx LEDs */
		if ((LED_Blink(ad, 1 << GPIO_Num_tx, uiTxLedIndex, *timeout,
			      *time, currdriverstate) == EVENT_SIGNALED) ||
		    (LED_Blink(ad, 1 << GPIO_Num_rx, uiRxLedIndex, *timeout,
			      *time, currdriverstate) == EVENT_SIGNALED))
			return EVENT_SIGNALED;
	}

	if (*time == *time_tx) {
		/* Blink pending rate of Rx */
		if (LED_Blink(ad, (1 << GPIO_Num_rx), uiRxLedIndex, *timeout,
			      *time_rx - *time,
			      currdriverstate) == EVENT_SIGNALED)
			return EVENT_SIGNALED;

		*time = *time_rx;
	} else {
		/* Blink pending rate of Tx */
		if (LED_Blink(ad, 1 << GPIO_Num_tx, uiTxLedIndex, *timeout,
			      *time_tx - *time,
			      currdriverstate) == EVENT_SIGNALED)
			return EVENT_SIGNALED;

		*time = *time_tx;
	}

	return 0;
}

static INT LED_Proportional_Blink(struct bcm_mini_adapter *Adapter,
				  UCHAR GPIO_Num_tx,
				  UCHAR uiTxLedIndex,
				  UCHAR GPIO_Num_rx,
				  UCHAR uiRxLedIndex,
				  enum bcm_led_events currdriverstate)
{
	/* Initial values of TX and RX packets */
	ULONG64 Initial_num_of_packts_tx = 0, Initial_num_of_packts_rx = 0;
	/* values of TX and RX packets after 1 sec */
	ULONG64 Final_num_of_packts_tx = 0, Final_num_of_packts_rx = 0;
	/* Rate of transfer of Tx and Rx in 1 sec */
	ULONG64 rate_of_transfer_tx = 0, rate_of_transfer_rx = 0;
	int Status = STATUS_SUCCESS;
	INT num_of_time = 0, num_of_time_tx = 0, num_of_time_rx = 0;
	UINT remDelay = 0;
	/* UINT GPIO_num = DISABLE_GPIO_NUM; */
	ulong timeout = 0;

	/* Read initial value of packets sent/received */
	Initial_num_of_packts_tx = Adapter->dev->stats.tx_packets;
	Initial_num_of_packts_rx = Adapter->dev->stats.rx_packets;

	/* Scale the rate of transfer to no of blinks. */
	num_of_time_tx = ScaleRateofTransfer((ULONG)rate_of_transfer_tx);
	num_of_time_rx = ScaleRateofTransfer((ULONG)rate_of_transfer_rx);

	while ((Adapter->device_removed == false)) {
		timeout = 50;

		if (EVENT_SIGNALED == blink_in_normal_bandwidth(Adapter,
								&num_of_time,
								&num_of_time_tx,
								&num_of_time_rx,
								GPIO_Num_tx,
								uiTxLedIndex,
								GPIO_Num_rx,
								uiRxLedIndex,
								currdriverstate,
								&timeout))
			return EVENT_SIGNALED;


		/*
		 * If Tx/Rx rate is less than maximum blinks per second,
		 * wait till delay completes to 1 second
		 */
		remDelay = MAX_NUM_OF_BLINKS - num_of_time;
		if (remDelay > 0) {
			timeout = 100 * remDelay;
			Status = wait_event_interruptible_timeout(
					Adapter->LEDInfo.notify_led_event,
					currdriverstate != Adapter->DriverState
						|| kthread_should_stop(),
					msecs_to_jiffies(timeout));

			if (kthread_should_stop()) {
				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
					LED_DUMP_INFO, DBG_LVL_ALL,
					"Led thread got signal to exit..hence exiting");
				Adapter->LEDInfo.led_thread_running =
						BCM_LED_THREAD_DISABLED;
				return EVENT_SIGNALED;
			}
			if (Status)
				return EVENT_SIGNALED;
		}

		/* Turn off both Tx and Rx LEDs before next second */
		TURN_OFF_LED(Adapter, 1 << GPIO_Num_tx, uiTxLedIndex);
		TURN_OFF_LED(Adapter, 1 << GPIO_Num_rx, uiTxLedIndex);

		/*
		 * Read the Tx & Rx packets transmission after 1 second and
		 * calculate rate of transfer
		 */
		Final_num_of_packts_tx = Adapter->dev->stats.tx_packets;
		Final_num_of_packts_rx = Adapter->dev->stats.rx_packets;

		rate_of_transfer_tx = Final_num_of_packts_tx -
						Initial_num_of_packts_tx;
		rate_of_transfer_rx = Final_num_of_packts_rx -
						Initial_num_of_packts_rx;

		/* Read initial value of packets sent/received */
		Initial_num_of_packts_tx = Final_num_of_packts_tx;
		Initial_num_of_packts_rx = Final_num_of_packts_rx;

		/* Scale the rate of transfer to no of blinks. */
		num_of_time_tx =
			ScaleRateofTransfer((ULONG)rate_of_transfer_tx);
		num_of_time_rx =
			ScaleRateofTransfer((ULONG)rate_of_transfer_rx);

	}
	return Status;
}

/*
 * -----------------------------------------------------------------------------
 * Procedure:   ValidateDSDParamsChecksum
 *
 * Description: Reads DSD Params and validates checkusm.
 *
 * Arguments:
 *      Adapter - Pointer to Adapter structure.
 *      ulParamOffset - Start offset of the DSD parameter to be read and
 *			validated.
 *      usParamLen - Length of the DSD Parameter.
 *
 * Returns:
 *  <OSAL_STATUS_CODE>
 * -----------------------------------------------------------------------------
 */
static INT ValidateDSDParamsChecksum(struct bcm_mini_adapter *Adapter,
				     ULONG ulParamOffset,
				     USHORT usParamLen)
{
	INT Status = STATUS_SUCCESS;
	PUCHAR puBuffer = NULL;
	USHORT usChksmOrg = 0;
	USHORT usChecksumCalculated = 0;

	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,
			"LED Thread:ValidateDSDParamsChecksum: 0x%lx 0x%X",
			ulParamOffset, usParamLen);

	puBuffer = kmalloc(usParamLen, GFP_KERNEL);
	if (!puBuffer) {
		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO,
				DBG_LVL_ALL,
				"LED Thread: ValidateDSDParamsChecksum Allocation failed");
		return -ENOMEM;

	}

	/* Read the DSD data from the parameter offset. */
	if (STATUS_SUCCESS != BeceemNVMRead(Adapter, (PUINT)puBuffer,
					    ulParamOffset, usParamLen)) {
		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO,
				DBG_LVL_ALL,
				"LED Thread: ValidateDSDParamsChecksum BeceemNVMRead failed");
		Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
		goto exit;
	}

	/* Calculate the checksum of the data read from the DSD parameter. */
	usChecksumCalculated = CFG_CalculateChecksum(puBuffer, usParamLen);
	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,
			"LED Thread: usCheckSumCalculated = 0x%x\n",
			usChecksumCalculated);

	/*
	 * End of the DSD parameter will have a TWO bytes checksum stored in it.
	 * Read it and compare with the calculated Checksum.
	 */
	if (STATUS_SUCCESS != BeceemNVMRead(Adapter, (PUINT)&usChksmOrg,
					    ulParamOffset+usParamLen, 2)) {
		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO,
				DBG_LVL_ALL,
				"LED Thread: ValidateDSDParamsChecksum BeceemNVMRead failed");
		Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
		goto exit;
	}
	usChksmOrg = ntohs(usChksmOrg);
	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,
			"LED Thread: usChksmOrg = 0x%x", usChksmOrg);

	/*
	 * Compare the checksum calculated with the checksum read
	 * from DSD section
	 */
	if (usChecksumCalculated ^ usChksmOrg) {
		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO,
				DBG_LVL_ALL,
				"LED Thread: ValidateDSDParamsChecksum: Checksums don't match");
		Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
		goto exit;
	}

exit:
	kfree(puBuffer);
	return Status;
}


/*
 * -----------------------------------------------------------------------------
 * Procedure:   ValidateHWParmStructure
 *
 * Description: Validates HW Parameters.
 *
 * Arguments:
 *      Adapter - Pointer to Adapter structure.
 *      ulHwParamOffset - Start offset of the HW parameter Section to be read
 *				and validated.
 *
 * Returns:
 *  <OSAL_STATUS_CODE>
 * -----------------------------------------------------------------------------
 */
static INT ValidateHWParmStructure(struct bcm_mini_adapter *Adapter,
				   ULONG ulHwParamOffset)
{

	INT Status = STATUS_SUCCESS;
	USHORT HwParamLen = 0;
	/*
	 * Add DSD start offset to the hwParamOffset to get
	 * the actual address.
	 */
	ulHwParamOffset += DSD_START_OFFSET;

	/* Read the Length of HW_PARAM structure */
	BeceemNVMRead(Adapter, (PUINT)&HwParamLen, ulHwParamOffset, 2);
	HwParamLen = ntohs(HwParamLen);
	if (0 == HwParamLen || HwParamLen > Adapter->uiNVMDSDSize)
		return STATUS_IMAGE_CHECKSUM_MISMATCH;

	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,
			"LED Thread:HwParamLen = 0x%x", HwParamLen);
	Status = ValidateDSDParamsChecksum(Adapter, ulHwParamOffset,
					   HwParamLen);
	return Status;
} /* ValidateHWParmStructure() */

static int ReadLEDInformationFromEEPROM(struct bcm_mini_adapter *Adapter,
					UCHAR GPIO_Array[])
{
	int Status = STATUS_SUCCESS;

	ULONG  dwReadValue	= 0;
	USHORT usHwParamData	= 0;
	USHORT usEEPROMVersion	= 0;
	UCHAR  ucIndex		= 0;
	UCHAR  ucGPIOInfo[32]	= {0};

	BeceemNVMRead(Adapter, (PUINT)&usEEPROMVersion,
		      EEPROM_VERSION_OFFSET, 2);

	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,
			"usEEPROMVersion: Minor:0x%X Major:0x%x",
			usEEPROMVersion & 0xFF,
			((usEEPROMVersion >> 8) & 0xFF));


	if (((usEEPROMVersion>>8)&0xFF) < EEPROM_MAP5_MAJORVERSION) {
		BeceemNVMRead(Adapter, (PUINT)&usHwParamData,
			      EEPROM_HW_PARAM_POINTER_ADDRESS, 2);
		usHwParamData = ntohs(usHwParamData);
		dwReadValue   = usHwParamData;
	} else {
		/*
		 * Validate Compatibility section and then read HW param
		 * if compatibility section is valid.
		 */
		Status = ValidateDSDParamsChecksum(Adapter,
						   DSD_START_OFFSET,
						   COMPATIBILITY_SECTION_LENGTH_MAP5);

		if (Status != STATUS_SUCCESS)
			return Status;

		BeceemNVMRead(Adapter, (PUINT)&dwReadValue,
			      EEPROM_HW_PARAM_POINTER_ADDRRES_MAP5, 4);
		dwReadValue = ntohl(dwReadValue);
	}


	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,
			"LED Thread: Start address of HW_PARAM structure = 0x%lx",
			dwReadValue);

	/*
	 * Validate if the address read out is within the DSD.
	 * Adapter->uiNVMDSDSize gives whole DSD size inclusive of Autoinit.
	 * lower limit should be above DSD_START_OFFSET and
	 * upper limit should be below (Adapter->uiNVMDSDSize-DSD_START_OFFSET)
	 */
	if (dwReadValue < DSD_START_OFFSET ||
			dwReadValue > (Adapter->uiNVMDSDSize-DSD_START_OFFSET))
		return STATUS_IMAGE_CHECKSUM_MISMATCH;

	Status = ValidateHWParmStructure(Adapter, dwReadValue);
	if (Status)
		return Status;

	/*
	 * Add DSD_START_OFFSET to the offset read from the EEPROM.
	 * This will give the actual start HW Parameters start address.
	 * To read GPIO section, add GPIO offset further.
	 */

	dwReadValue += DSD_START_OFFSET;
			/* = start address of hw param section. */
	dwReadValue += GPIO_SECTION_START_OFFSET;
			/* = GPIO start offset within HW Param section. */

	/*
	 * Read the GPIO values for 32 GPIOs from EEPROM and map the function
	 * number to GPIO pin number to GPIO_Array
	 */
	BeceemNVMRead(Adapter, (UINT *)ucGPIOInfo, dwReadValue, 32);
	for (ucIndex = 0; ucIndex < 32; ucIndex++) {

		switch (ucGPIOInfo[ucIndex]) {
		case RED_LED:
			GPIO_Array[RED_LED] = ucIndex;
			Adapter->gpioBitMap |= (1 << ucIndex);
			break;
		case BLUE_LED:
			GPIO_Array[BLUE_LED] = ucIndex;
			Adapter->gpioBitMap |= (1 << ucIndex);
			break;
		case YELLOW_LED:
			GPIO_Array[YELLOW_LED] = ucIndex;
			Adapter->gpioBitMap |= (1 << ucIndex);
			break;
		case GREEN_LED:
			GPIO_Array[GREEN_LED] = ucIndex;
			Adapter->gpioBitMap |= (1 << ucIndex);
			break;
		default:
			break;
		}

	}
	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,
			"GPIO's bit map correspond to LED :0x%X",
			Adapter->gpioBitMap);
	return Status;
}


static int ReadConfigFileStructure(struct bcm_mini_adapter *Adapter,
				   bool *bEnableThread)
{
	int Status = STATUS_SUCCESS;
	/* Array to store GPIO numbers from EEPROM */
	UCHAR GPIO_Array[NUM_OF_LEDS+1];
	UINT uiIndex = 0;
	UINT uiNum_of_LED_Type = 0;
	PUCHAR puCFGData	= NULL;
	UCHAR bData = 0;
	struct bcm_led_state_info *curr_led_state;

	memset(GPIO_Array, DISABLE_GPIO_NUM, NUM_OF_LEDS+1);

	if (!Adapter->pstargetparams || IS_ERR(Adapter->pstargetparams)) {
		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO,
				DBG_LVL_ALL, "Target Params not Avail.\n");
		return -ENOENT;
	}

	/* Populate GPIO_Array with GPIO numbers for LED functions */
	/* Read the GPIO numbers from EEPROM */
	Status = ReadLEDInformationFromEEPROM(Adapter, GPIO_Array);
	if (Status == STATUS_IMAGE_CHECKSUM_MISMATCH) {
		*bEnableThread = false;
		return STATUS_SUCCESS;
	} else if (Status) {
		*bEnableThread = false;
		return Status;
	}

	/*
	 * CONFIG file read successfully. Deallocate the memory of
	 * uiFileNameBufferSize
	 */
	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,
			"LED Thread: Config file read successfully\n");
	puCFGData = (PUCHAR) &Adapter->pstargetparams->HostDrvrConfig1;

	/*
	 * Offset for HostDrvConfig1, HostDrvConfig2, HostDrvConfig3 which
	 * will have the information of LED type, LED on state for different
	 * driver state and LED blink state.
	 */

	for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) {
		bData = *puCFGData;
		curr_led_state = &Adapter->LEDInfo.LEDState[uiIndex];

		/*
		 * Check Bit 8 for polarity. If it is set,
		 * polarity is reverse polarity
		 */
		if (bData & 0x80) {
			curr_led_state->BitPolarity = 0;
			/* unset the bit 8 */
			bData = bData & 0x7f;
		}

		curr_led_state->LED_Type = bData;
		if (bData <= NUM_OF_LEDS)
			curr_led_state->GPIO_Num = GPIO_Array[bData];
		else
			curr_led_state->GPIO_Num = DISABLE_GPIO_NUM;

		puCFGData++;
		bData = *puCFGData;
		curr_led_state->LED_On_State = bData;
		puCFGData++;
		bData = *puCFGData;
		curr_led_state->LED_Blink_State = bData;
		puCFGData++;
	}

	/*
	 * Check if all the LED settings are disabled. If it is disabled,
	 * dont launch the LED control thread.
	 */
	for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) {
		curr_led_state = &Adapter->LEDInfo.LEDState[uiIndex];

		if ((curr_led_state->LED_Type == DISABLE_GPIO_NUM) ||
			(curr_led_state->LED_Type == 0x7f) ||
			(curr_led_state->LED_Type == 0))
			uiNum_of_LED_Type++;
	}
	if (uiNum_of_LED_Type >= NUM_OF_LEDS)
		*bEnableThread = false;

	return Status;
}

/*
 * -----------------------------------------------------------------------------
 * Procedure:   LedGpioInit
 *
 * Description: Initializes LED GPIOs. Makes the LED GPIOs to OUTPUT mode
 *			  and make the initial state to be OFF.
 *
 * Arguments:
 *      Adapter - Pointer to MINI_ADAPTER structure.
 *
 * Returns: VOID
 *
 * -----------------------------------------------------------------------------
 */
static VOID LedGpioInit(struct bcm_mini_adapter *Adapter)
{
	UINT uiResetValue = 0;
	UINT uiIndex      = 0;
	struct bcm_led_state_info *curr_led_state;

	/* Set all LED GPIO Mode to output mode */
	if (rdmalt(Adapter, GPIO_MODE_REGISTER, &uiResetValue,
		   sizeof(uiResetValue)) < 0)
		BCM_DEBUG_PRINT (Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO,
			DBG_LVL_ALL, "LED Thread: RDM Failed\n");
	for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) {
		curr_led_state = &Adapter->LEDInfo.LEDState[uiIndex];

		if (curr_led_state->GPIO_Num != DISABLE_GPIO_NUM)
			uiResetValue |= (1 << curr_led_state->GPIO_Num);

		TURN_OFF_LED(Adapter, 1 << curr_led_state->GPIO_Num, uiIndex);

	}
	if (wrmalt(Adapter, GPIO_MODE_REGISTER, &uiResetValue,
		   sizeof(uiResetValue)) < 0)
		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO,
				DBG_LVL_ALL, "LED Thread: WRM Failed\n");

	Adapter->LEDInfo.bIdle_led_off = false;
}

static INT BcmGetGPIOPinInfo(struct bcm_mini_adapter *Adapter,
			     UCHAR *GPIO_num_tx,
			     UCHAR *GPIO_num_rx,
			     UCHAR *uiLedTxIndex,
			     UCHAR *uiLedRxIndex,
			     enum bcm_led_events currdriverstate)
{
	UINT uiIndex = 0;
	struct bcm_led_state_info *led_state_info;

	*GPIO_num_tx = DISABLE_GPIO_NUM;
	*GPIO_num_rx = DISABLE_GPIO_NUM;

	for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) {
		led_state_info = &Adapter->LEDInfo.LEDState[uiIndex];

		if (((currdriverstate == NORMAL_OPERATION) ||
			(currdriverstate == IDLEMODE_EXIT) ||
			(currdriverstate == FW_DOWNLOAD)) &&
		    (led_state_info->LED_Blink_State & currdriverstate) &&
		    (led_state_info->GPIO_Num != DISABLE_GPIO_NUM)) {
			if (*GPIO_num_tx == DISABLE_GPIO_NUM) {
				*GPIO_num_tx = led_state_info->GPIO_Num;
				*uiLedTxIndex = uiIndex;
			} else {
				*GPIO_num_rx = led_state_info->GPIO_Num;
				*uiLedRxIndex = uiIndex;
			}
		} else {
			if ((led_state_info->LED_On_State & currdriverstate) &&
			    (led_state_info->GPIO_Num != DISABLE_GPIO_NUM)) {
				*GPIO_num_tx = led_state_info->GPIO_Num;
				*uiLedTxIndex = uiIndex;
			}
		}
	}
	return STATUS_SUCCESS;
}

static void handle_adapter_driver_state(struct bcm_mini_adapter *ad,
					enum bcm_led_events currdriverstate,
					UCHAR GPIO_num,
					UCHAR dummyGPIONum,
					UCHAR uiLedIndex,
					UCHAR dummyIndex,
					ulong timeout,
					UINT uiResetValue,
					UINT uiIndex)
{
	switch (ad->DriverState) {
	case DRIVER_INIT:
		currdriverstate = DRIVER_INIT;
				/* ad->DriverState; */
		BcmGetGPIOPinInfo(ad, &GPIO_num, &dummyGPIONum,
				  &uiLedIndex, &dummyIndex,
				  currdriverstate);

		if (GPIO_num != DISABLE_GPIO_NUM)
			TURN_ON_LED(ad, 1 << GPIO_num, uiLedIndex);

		break;
	case FW_DOWNLOAD:
		/*
		 * BCM_DEBUG_PRINT(ad, DBG_TYPE_OTHERS,
		 *	LED_DUMP_INFO, DBG_LVL_ALL,
		 *	"LED Thread: FW_DN_DONE called\n");
		 */
		currdriverstate = FW_DOWNLOAD;
		BcmGetGPIOPinInfo(ad, &GPIO_num, &dummyGPIONum,
				  &uiLedIndex, &dummyIndex,
				  currdriverstate);

		if (GPIO_num != DISABLE_GPIO_NUM) {
			timeout = 50;
			LED_Blink(ad, 1 << GPIO_num, uiLedIndex, timeout,
				  -1, currdriverstate);
		}
		break;
	case FW_DOWNLOAD_DONE:
		currdriverstate = FW_DOWNLOAD_DONE;
		BcmGetGPIOPinInfo(ad, &GPIO_num, &dummyGPIONum,
				  &uiLedIndex, &dummyIndex, currdriverstate);
		if (GPIO_num != DISABLE_GPIO_NUM)
			TURN_ON_LED(ad, 1 << GPIO_num, uiLedIndex);
		break;

	case SHUTDOWN_EXIT:
		/*
		 * no break, continue to NO_NETWORK_ENTRY
		 * state as well.
		 */
	case NO_NETWORK_ENTRY:
		currdriverstate = NO_NETWORK_ENTRY;
		BcmGetGPIOPinInfo(ad, &GPIO_num, &dummyGPIONum,
				  &uiLedIndex, &dummyGPIONum, currdriverstate);
		if (GPIO_num != DISABLE_GPIO_NUM)
			TURN_ON_LED(ad, 1 << GPIO_num, uiLedIndex);
		break;
	case NORMAL_OPERATION:
		{
			UCHAR GPIO_num_tx = DISABLE_GPIO_NUM;
			UCHAR GPIO_num_rx = DISABLE_GPIO_NUM;
			UCHAR uiLEDTx = 0;
			UCHAR uiLEDRx = 0;

			currdriverstate = NORMAL_OPERATION;
			ad->LEDInfo.bIdle_led_off = false;

			BcmGetGPIOPinInfo(ad, &GPIO_num_tx, &GPIO_num_rx,
					  &uiLEDTx, &uiLEDRx, currdriverstate);
			if ((GPIO_num_tx == DISABLE_GPIO_NUM) &&
					(GPIO_num_rx == DISABLE_GPIO_NUM)) {
				GPIO_num = DISABLE_GPIO_NUM;
			} else {
				/*
				 * If single LED is selected, use same
				 * for both Tx and Rx
				 */
				if (GPIO_num_tx == DISABLE_GPIO_NUM) {
					GPIO_num_tx = GPIO_num_rx;
					uiLEDTx = uiLEDRx;
				} else if (GPIO_num_rx == DISABLE_GPIO_NUM) {
					GPIO_num_rx = GPIO_num_tx;
					uiLEDRx = uiLEDTx;
				}
				/*
				 * Blink the LED in proportionate
				 * to Tx and Rx transmissions.
				 */
				LED_Proportional_Blink(ad,
						       GPIO_num_tx, uiLEDTx,
						       GPIO_num_rx, uiLEDRx,
						       currdriverstate);
			}
		}
		break;
	case LOWPOWER_MODE_ENTER:
		currdriverstate = LOWPOWER_MODE_ENTER;
		if (DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING ==
				ad->ulPowerSaveMode) {
			/* Turn OFF all the LED */
			uiResetValue = 0;
			for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) {
				if (ad->LEDInfo.LEDState[uiIndex].GPIO_Num != DISABLE_GPIO_NUM)
					TURN_OFF_LED(ad,
						     (1 << ad->LEDInfo.LEDState[uiIndex].GPIO_Num),
						     uiIndex);
			}

		}
		/* Turn off LED And WAKE-UP for Sendinf IDLE mode ACK */
		ad->LEDInfo.bLedInitDone = false;
		ad->LEDInfo.bIdle_led_off = TRUE;
		wake_up(&ad->LEDInfo.idleModeSyncEvent);
		GPIO_num = DISABLE_GPIO_NUM;
		break;
	case IDLEMODE_CONTINUE:
		currdriverstate = IDLEMODE_CONTINUE;
		GPIO_num = DISABLE_GPIO_NUM;
		break;
	case IDLEMODE_EXIT:
		break;
	case DRIVER_HALT:
		currdriverstate = DRIVER_HALT;
		GPIO_num = DISABLE_GPIO_NUM;
		for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) {
			if (ad->LEDInfo.LEDState[uiIndex].GPIO_Num !=
					DISABLE_GPIO_NUM)
				TURN_OFF_LED(ad,
					     (1 << ad->LEDInfo.LEDState[uiIndex].GPIO_Num),
					     uiIndex);
		}
		/* ad->DriverState = DRIVER_INIT; */
		break;
	case LED_THREAD_INACTIVE:
		BCM_DEBUG_PRINT(ad, DBG_TYPE_OTHERS, LED_DUMP_INFO,
				DBG_LVL_ALL, "InActivating LED thread...");
		currdriverstate = LED_THREAD_INACTIVE;
		ad->LEDInfo.led_thread_running =
				BCM_LED_THREAD_RUNNING_INACTIVELY;
		ad->LEDInfo.bLedInitDone = false;
		/* disable ALL LED */
		for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) {
			if (ad->LEDInfo.LEDState[uiIndex].GPIO_Num !=
					DISABLE_GPIO_NUM)
				TURN_OFF_LED(ad,
					     (1 << ad->LEDInfo.LEDState[uiIndex].GPIO_Num),
					     uiIndex);
		}
		break;
	case LED_THREAD_ACTIVE:
		BCM_DEBUG_PRINT(ad, DBG_TYPE_OTHERS, LED_DUMP_INFO,
				DBG_LVL_ALL, "Activating LED thread again...");
		if (ad->LinkUpStatus == false)
			ad->DriverState = NO_NETWORK_ENTRY;
		else
			ad->DriverState = NORMAL_OPERATION;

		ad->LEDInfo.led_thread_running =
				BCM_LED_THREAD_RUNNING_ACTIVELY;
		break;
		/* return; */
	default:
		break;
	}
}

static VOID LEDControlThread(struct bcm_mini_adapter *Adapter)
{
	UINT uiIndex = 0;
	UCHAR GPIO_num = 0;
	UCHAR uiLedIndex = 0;
	UINT uiResetValue = 0;
	enum bcm_led_events currdriverstate = 0;
	ulong timeout = 0;

	INT Status = 0;

	UCHAR dummyGPIONum = 0;
	UCHAR dummyIndex = 0;

	/* currdriverstate = Adapter->DriverState; */
	Adapter->LEDInfo.bIdleMode_tx_from_host = false;

	/*
	 * Wait till event is triggered
	 *
	 * wait_event(Adapter->LEDInfo.notify_led_event,
	 *	currdriverstate!= Adapter->DriverState);
	 */

	GPIO_num = DISABLE_GPIO_NUM;

	while (TRUE) {
		/* Wait till event is triggered */
		if ((GPIO_num == DISABLE_GPIO_NUM)
						||
				((currdriverstate != FW_DOWNLOAD) &&
				 (currdriverstate != NORMAL_OPERATION) &&
				 (currdriverstate != LOWPOWER_MODE_ENTER))
						||
				(currdriverstate == LED_THREAD_INACTIVE))
			Status = wait_event_interruptible(
					Adapter->LEDInfo.notify_led_event,
					currdriverstate != Adapter->DriverState
						|| kthread_should_stop());

		if (kthread_should_stop() || Adapter->device_removed) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO,
				DBG_LVL_ALL,
				"Led thread got signal to exit..hence exiting");
			Adapter->LEDInfo.led_thread_running =
						BCM_LED_THREAD_DISABLED;
			TURN_OFF_LED(Adapter, 1 << GPIO_num, uiLedIndex);
			return; /* STATUS_FAILURE; */
		}

		if (GPIO_num != DISABLE_GPIO_NUM)
			TURN_OFF_LED(Adapter, 1 << GPIO_num, uiLedIndex);

		if (Adapter->LEDInfo.bLedInitDone == false) {
			LedGpioInit(Adapter);
			Adapter->LEDInfo.bLedInitDone = TRUE;
		}

		handle_adapter_driver_state(Adapter,
					    currdriverstate,
					    GPIO_num,
					    dummyGPIONum,
					    uiLedIndex,
					    dummyIndex,
					    timeout,
					    uiResetValue,
					    uiIndex
					    );
	}
	Adapter->LEDInfo.led_thread_running = BCM_LED_THREAD_DISABLED;
}

int InitLedSettings(struct bcm_mini_adapter *Adapter)
{
	int Status = STATUS_SUCCESS;
	bool bEnableThread = TRUE;
	UCHAR uiIndex = 0;

	/*
	 * Initially set BitPolarity to normal polarity. The bit 8 of LED type
	 * is used to change the polarity of the LED.
	 */

	for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++)
		Adapter->LEDInfo.LEDState[uiIndex].BitPolarity = 1;

	/*
	 * Read the LED settings of CONFIG file and map it
	 * to GPIO numbers in EEPROM
	 */
	Status = ReadConfigFileStructure(Adapter, &bEnableThread);
	if (STATUS_SUCCESS != Status) {
		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO,
				DBG_LVL_ALL,
				"LED Thread: FAILED in ReadConfigFileStructure\n");
		return Status;
	}

	if (Adapter->LEDInfo.led_thread_running) {
		if (bEnableThread) {
			;
		} else {
			Adapter->DriverState = DRIVER_HALT;
			wake_up(&Adapter->LEDInfo.notify_led_event);
			Adapter->LEDInfo.led_thread_running =
						BCM_LED_THREAD_DISABLED;
		}

	} else if (bEnableThread) {
		/* Create secondary thread to handle the LEDs */
		init_waitqueue_head(&Adapter->LEDInfo.notify_led_event);
		init_waitqueue_head(&Adapter->LEDInfo.idleModeSyncEvent);
		Adapter->LEDInfo.led_thread_running =
					BCM_LED_THREAD_RUNNING_ACTIVELY;
		Adapter->LEDInfo.bIdle_led_off = false;
		Adapter->LEDInfo.led_cntrl_threadid =
			kthread_run((int (*)(void *)) LEDControlThread,
				    Adapter, "led_control_thread");
		if (IS_ERR(Adapter->LEDInfo.led_cntrl_threadid)) {
			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO,
					DBG_LVL_ALL,
					"Not able to spawn Kernel Thread\n");
			Adapter->LEDInfo.led_thread_running =
				BCM_LED_THREAD_DISABLED;
			return PTR_ERR(Adapter->LEDInfo.led_cntrl_threadid);
		}
	}
	return Status;
}