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