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