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