]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/staging/bcm/led_control.c
Merge branch 'master' into tk71
[mv-sheeva.git] / drivers / staging / bcm / led_control.c
diff --git a/drivers/staging/bcm/led_control.c b/drivers/staging/bcm/led_control.c
new file mode 100644 (file)
index 0000000..16e939f
--- /dev/null
@@ -0,0 +1,887 @@
+#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;
+}
+BOOLEAN IsReqGpioIsLedInNVM(PMINI_ADAPTER Adapter, UINT gpios)
+{
+       INT Status ;
+       Status = (Adapter->gpioBitMap & gpios) ^ gpios ;
+       if(Status)
+               return FALSE;
+       else
+               return TRUE;
+}
+
+static INT LED_Blink(PMINI_ADAPTER Adapter, UINT GPIO_Num, UCHAR uiLedIndex, ULONG timeout, INT num_of_time, LedEventInfo_t currdriverstate)
+{
+       int Status = STATUS_SUCCESS;
+       BOOLEAN 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(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(GPIO_Num, uiLedIndex);
+                       Status=EVENT_SIGNALED;
+                       break;
+               }
+               if(Status)
+               {
+                       TURN_OFF_LED(GPIO_Num, uiLedIndex);
+                       Status=EVENT_SIGNALED;
+                       break;
+               }
+
+               TURN_OFF_LED(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 LED_Proportional_Blink(PMINI_ADAPTER Adapter, UCHAR GPIO_Num_tx,
+               UCHAR uiTxLedIndex, UCHAR GPIO_Num_rx, UCHAR uiRxLedIndex, LedEventInfo_t 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;
+       BOOLEAN bBlinkBothLED = TRUE;
+       //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;
+               /*Blink Tx and Rx LED when both Tx and Rx is in normal bandwidth*/
+               if(bBlinkBothLED)
+               {
+                       /*Assign minimum number of blinks of either Tx or Rx.*/
+                       if(num_of_time_tx > num_of_time_rx)
+                               num_of_time = num_of_time_rx;
+                       else
+                               num_of_time = num_of_time_tx;
+                       if(num_of_time > 0)
+                       {
+                               /*Blink both Tx and Rx LEDs*/
+                               if(LED_Blink(Adapter, 1<<GPIO_Num_tx, uiTxLedIndex, timeout, num_of_time,currdriverstate)
+                                                       == EVENT_SIGNALED)
+                               {
+                                       return EVENT_SIGNALED;
+                               }
+                               if(LED_Blink(Adapter, 1<<GPIO_Num_rx, uiRxLedIndex, timeout, num_of_time,currdriverstate)
+                                                       == EVENT_SIGNALED)
+                               {
+                                       return EVENT_SIGNALED;
+                               }
+
+                       }
+
+                       if(num_of_time == num_of_time_tx)
+                       {
+                               /*Blink pending rate of Rx*/
+                               if(LED_Blink(Adapter, (1 << GPIO_Num_rx), uiRxLedIndex, timeout,
+                                               num_of_time_rx-num_of_time,currdriverstate) == EVENT_SIGNALED)
+                               {
+                                       return EVENT_SIGNALED;
+                               }
+                               num_of_time = num_of_time_rx;
+                       }
+                       else
+                       {
+                               /*Blink pending rate of Tx*/
+                               if(LED_Blink(Adapter, 1<<GPIO_Num_tx, uiTxLedIndex, timeout,
+                                       num_of_time_tx-num_of_time,currdriverstate) == EVENT_SIGNALED)
+                               {
+                                       return EVENT_SIGNALED;
+                               }
+                               num_of_time = num_of_time_tx;
+                       }
+               }
+               else
+               {
+                       if(num_of_time == num_of_time_tx)
+                       {
+                               /*Blink pending rate of Rx*/
+                               if(LED_Blink(Adapter, 1<<GPIO_Num_tx, uiTxLedIndex, timeout, num_of_time,currdriverstate)
+                                                       == EVENT_SIGNALED)
+                               {
+                                       return EVENT_SIGNALED;
+                               }
+                       }
+                       else
+                       {
+                               /*Blink pending rate of Tx*/
+                               if(LED_Blink(Adapter, 1<<GPIO_Num_rx, uiRxLedIndex, timeout,
+                                               num_of_time,currdriverstate) == EVENT_SIGNALED)
+                               {
+                                       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(1<<GPIO_Num_tx, uiTxLedIndex);
+               TURN_OFF_LED(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(
+                                                                                                       PMINI_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(PMINI_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(PMINI_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(PMINI_ADAPTER Adapter, BOOLEAN *bEnableThread)
+{
+       int Status = STATUS_SUCCESS;
+       UCHAR GPIO_Array[NUM_OF_LEDS+1]; /*Array to store GPIO numbers from EEPROM*/
+       UINT uiIndex = 0;
+       UINT uiNum_of_LED_Type = 0;
+       PUCHAR puCFGData        = NULL;
+       UCHAR bData = 0;
+       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;
+
+               /*Check Bit 8 for polarity. If it is set, polarity is reverse polarity*/
+               if(bData & 0x80)
+               {
+                       Adapter->LEDInfo.LEDState[uiIndex].BitPolarity = 0;
+                       /*unset the bit 8*/
+                       bData = bData & 0x7f;
+               }
+
+               Adapter->LEDInfo.LEDState[uiIndex].LED_Type = bData;
+               if(bData <= NUM_OF_LEDS)
+                       Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num = GPIO_Array[bData];
+               else
+                       Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num = DISABLE_GPIO_NUM;
+
+               puCFGData++;
+               bData = *puCFGData;
+               Adapter->LEDInfo.LEDState[uiIndex].LED_On_State = bData;
+               puCFGData++;
+               bData = *puCFGData;
+               Adapter->LEDInfo.LEDState[uiIndex].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++)
+       {
+               if((Adapter->LEDInfo.LEDState[uiIndex].LED_Type == DISABLE_GPIO_NUM) ||
+                       (Adapter->LEDInfo.LEDState[uiIndex].LED_Type == 0x7f) ||
+                       (Adapter->LEDInfo.LEDState[uiIndex].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(PMINI_ADAPTER Adapter)
+{
+       UINT uiResetValue = 0;
+       UINT uiIndex      = 0;
+
+       /* 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++)
+       {
+               if(Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num != DISABLE_GPIO_NUM)
+                       uiResetValue |= (1 << Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num);
+               TURN_OFF_LED(1<<Adapter->LEDInfo.LEDState[uiIndex].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(PMINI_ADAPTER Adapter, UCHAR *GPIO_num_tx, UCHAR *GPIO_num_rx ,UCHAR *uiLedTxIndex, UCHAR *uiLedRxIndex,LedEventInfo_t currdriverstate)
+{
+       UINT uiIndex = 0;
+
+       *GPIO_num_tx = DISABLE_GPIO_NUM;
+       *GPIO_num_rx = DISABLE_GPIO_NUM;
+
+       for(uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++)
+       {
+
+               if((currdriverstate == NORMAL_OPERATION)||
+                       (currdriverstate == IDLEMODE_EXIT)||
+                       (currdriverstate == FW_DOWNLOAD))
+               {
+                       if(Adapter->LEDInfo.LEDState[uiIndex].LED_Blink_State & currdriverstate)
+                       {
+                               if(Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num != DISABLE_GPIO_NUM)
+                               {
+                                       if(*GPIO_num_tx == DISABLE_GPIO_NUM)
+                                       {
+                                               *GPIO_num_tx = Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num;
+                                               *uiLedTxIndex = uiIndex;
+                                       }
+                                       else
+                                       {
+                                               *GPIO_num_rx = Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num;
+                                               *uiLedRxIndex = uiIndex;
+                                       }
+                               }
+                       }
+               }
+               else
+               {
+                       if(Adapter->LEDInfo.LEDState[uiIndex].LED_On_State & currdriverstate)
+                       {
+                               if(Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num != DISABLE_GPIO_NUM)
+                               {
+                                       *GPIO_num_tx = Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num;
+                                       *uiLedTxIndex = uiIndex;
+                               }
+                       }
+               }
+       }
+       return STATUS_SUCCESS ;
+}
+static VOID LEDControlThread(PMINI_ADAPTER Adapter)
+{
+       UINT uiIndex = 0;
+       UCHAR GPIO_num = 0;
+       UCHAR uiLedIndex = 0 ;
+       UINT uiResetValue = 0;
+       LedEventInfo_t 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(1<<GPIO_num, uiLedIndex);
+                       return ;//STATUS_FAILURE;
+               }
+
+               if(GPIO_num != DISABLE_GPIO_NUM)
+               {
+                       TURN_OFF_LED(1<<GPIO_num, uiLedIndex);
+               }
+
+               if(Adapter->LEDInfo.bLedInitDone == FALSE)
+               {
+                       LedGpioInit(Adapter);
+                       Adapter->LEDInfo.bLedInitDone = TRUE;
+               }
+
+               switch(Adapter->DriverState)
+               {
+                       case DRIVER_INIT:
+                       {
+                               currdriverstate = DRIVER_INIT;//Adapter->DriverState;
+                               BcmGetGPIOPinInfo(Adapter, &GPIO_num, &dummyGPIONum, &uiLedIndex, &dummyIndex, currdriverstate);
+
+                               if(GPIO_num  != DISABLE_GPIO_NUM)
+                               {
+                                       TURN_ON_LED(1<<GPIO_num, uiLedIndex);
+                               }
+                       }
+                       break;
+                       case FW_DOWNLOAD:
+                       {
+                               //BCM_DEBUG_PRINT (Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LED Thread: FW_DN_DONE called\n");
+                               currdriverstate = FW_DOWNLOAD;
+                               BcmGetGPIOPinInfo(Adapter, &GPIO_num, &dummyGPIONum,  &uiLedIndex, &dummyIndex, currdriverstate);
+
+                               if(GPIO_num != DISABLE_GPIO_NUM)
+                               {
+                                       timeout = 50;
+                                       LED_Blink(Adapter, 1<<GPIO_num, uiLedIndex, timeout, -1,currdriverstate);
+                               }
+                       }
+                       break;
+                       case FW_DOWNLOAD_DONE:
+                       {
+                               currdriverstate = FW_DOWNLOAD_DONE;
+                               BcmGetGPIOPinInfo(Adapter, &GPIO_num, &dummyGPIONum, &uiLedIndex, &dummyIndex,currdriverstate);
+                               if(GPIO_num != DISABLE_GPIO_NUM)
+                               {
+                                       TURN_ON_LED(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(Adapter, &GPIO_num, &dummyGPIONum, &uiLedIndex,&dummyGPIONum,currdriverstate);
+                               if(GPIO_num != DISABLE_GPIO_NUM)
+                               {
+                                       TURN_ON_LED(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;
+                               Adapter->LEDInfo.bIdle_led_off =  FALSE;
+
+                               BcmGetGPIOPinInfo(Adapter, &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(Adapter, 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 == Adapter->ulPowerSaveMode)
+                               {
+                                       /* Turn OFF all the LED */
+                                       uiResetValue = 0;
+                                       for(uiIndex =0; uiIndex < NUM_OF_LEDS; uiIndex++)
+                                       {
+                                               if(Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num != DISABLE_GPIO_NUM)
+                                               TURN_OFF_LED((1<<Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num),uiIndex);
+                                       }
+
+                               }
+                               /* Turn off LED And WAKE-UP for Sendinf IDLE mode ACK */
+                               Adapter->LEDInfo.bLedInitDone = FALSE;
+                               Adapter->LEDInfo.bIdle_led_off =  TRUE;
+                               wake_up(&Adapter->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(Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num !=
+                                               DISABLE_GPIO_NUM)
+                                               TURN_OFF_LED((1<<Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num),uiIndex);
+                               }
+                               //Adapter->DriverState = DRIVER_INIT;
+                       }
+                       break;
+                       case LED_THREAD_INACTIVE :
+                       {
+                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"InActivating LED thread...");
+                               currdriverstate = LED_THREAD_INACTIVE;
+                               Adapter->LEDInfo.led_thread_running = BCM_LED_THREAD_RUNNING_INACTIVELY ;
+                               Adapter->LEDInfo.bLedInitDone = FALSE ;
+                               //disable ALL LED
+                               for(uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++)
+                               {
+                                       if(Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num !=
+                                               DISABLE_GPIO_NUM)
+                                               TURN_OFF_LED((1<<Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num),uiIndex);
+                               }
+                       }
+                       break;
+                       case LED_THREAD_ACTIVE :
+                       {
+                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"Activating LED thread again...");
+                               if(Adapter->LinkUpStatus == FALSE)
+                                       Adapter->DriverState = NO_NETWORK_ENTRY;
+                               else
+                                       Adapter->DriverState = NORMAL_OPERATION;
+
+                               Adapter->LEDInfo.led_thread_running = BCM_LED_THREAD_RUNNING_ACTIVELY ;
+                       }
+                       break;
+                       //return;
+                       default:
+                               break;
+               }
+       }
+       Adapter->LEDInfo.led_thread_running = BCM_LED_THREAD_DISABLED;
+}
+
+int InitLedSettings(PMINI_ADAPTER Adapter)
+{
+       int Status = STATUS_SUCCESS;
+       BOOLEAN 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;
+}