]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/staging/bcm/led_control.c
3b3775b26b477b64f00a34431ef4219023f25367
[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(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(GPIO_Num, uiLedIndex);
59                         Status = EVENT_SIGNALED;
60                         break;
61                 }
62                 if (Status) {
63                         TURN_OFF_LED(GPIO_Num, uiLedIndex);
64                         Status = EVENT_SIGNALED;
65                         break;
66                 }
67
68                 TURN_OFF_LED(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(1 << GPIO_Num_tx, uiTxLedIndex);
227                 TURN_OFF_LED(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(1 << Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num,
610                                 uiIndex);
611         }
612         if (wrmalt(Adapter, GPIO_MODE_REGISTER, &uiResetValue,
613                    sizeof(uiResetValue)) < 0)
614                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO,
615                                 DBG_LVL_ALL, "LED Thread: WRM Failed\n");
616
617         Adapter->LEDInfo.bIdle_led_off = false;
618 }
619
620 static INT BcmGetGPIOPinInfo(struct bcm_mini_adapter *Adapter,
621                              UCHAR *GPIO_num_tx,
622                              UCHAR *GPIO_num_rx,
623                              UCHAR *uiLedTxIndex,
624                              UCHAR *uiLedRxIndex,
625                              enum bcm_led_events currdriverstate)
626 {
627         UINT uiIndex = 0;
628
629         *GPIO_num_tx = DISABLE_GPIO_NUM;
630         *GPIO_num_rx = DISABLE_GPIO_NUM;
631
632         for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) {
633
634                 if ((currdriverstate == NORMAL_OPERATION) ||
635                                 (currdriverstate == IDLEMODE_EXIT) ||
636                                 (currdriverstate == FW_DOWNLOAD)) {
637                         if (Adapter->LEDInfo.LEDState[uiIndex].LED_Blink_State &
638                                         currdriverstate) {
639                                 if (Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num
640                                                 != DISABLE_GPIO_NUM) {
641                                         if (*GPIO_num_tx == DISABLE_GPIO_NUM) {
642                                                 *GPIO_num_tx = Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num;
643                                                 *uiLedTxIndex = uiIndex;
644                                         } else {
645                                                 *GPIO_num_rx = Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num;
646                                                 *uiLedRxIndex = uiIndex;
647                                         }
648                                 }
649                         }
650                 } else {
651                         if (Adapter->LEDInfo.LEDState[uiIndex].LED_On_State
652                                         & currdriverstate) {
653                                 if (Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num
654                                                 != DISABLE_GPIO_NUM) {
655                                         *GPIO_num_tx = Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num;
656                                         *uiLedTxIndex = uiIndex;
657                                 }
658                         }
659                 }
660         }
661         return STATUS_SUCCESS;
662 }
663
664 static void handle_adapter_driver_state(struct bcm_mini_adapter *ad,
665                                         enum bcm_led_events currdriverstate,
666                                         UCHAR GPIO_num,
667                                         UCHAR dummyGPIONum,
668                                         UCHAR uiLedIndex,
669                                         UCHAR dummyIndex,
670                                         ulong timeout,
671                                         UINT uiResetValue,
672                                         UINT uiIndex)
673 {
674         switch (ad->DriverState) {
675         case DRIVER_INIT:
676                 currdriverstate = DRIVER_INIT;
677                                 /* ad->DriverState; */
678                 BcmGetGPIOPinInfo(ad, &GPIO_num, &dummyGPIONum,
679                                   &uiLedIndex, &dummyIndex,
680                                   currdriverstate);
681
682                 if (GPIO_num != DISABLE_GPIO_NUM)
683                         TURN_ON_LED(1 << GPIO_num, uiLedIndex);
684
685                 break;
686         case FW_DOWNLOAD:
687                 /*
688                  * BCM_DEBUG_PRINT(ad, DBG_TYPE_OTHERS,
689                  *      LED_DUMP_INFO, DBG_LVL_ALL,
690                  *      "LED Thread: FW_DN_DONE called\n");
691                  */
692                 currdriverstate = FW_DOWNLOAD;
693                 BcmGetGPIOPinInfo(ad, &GPIO_num, &dummyGPIONum,
694                                   &uiLedIndex, &dummyIndex,
695                                   currdriverstate);
696
697                 if (GPIO_num != DISABLE_GPIO_NUM) {
698                         timeout = 50;
699                         LED_Blink(ad, 1 << GPIO_num, uiLedIndex, timeout,
700                                   -1, currdriverstate);
701                 }
702                 break;
703         case FW_DOWNLOAD_DONE:
704                 currdriverstate = FW_DOWNLOAD_DONE;
705                 BcmGetGPIOPinInfo(ad, &GPIO_num, &dummyGPIONum,
706                                   &uiLedIndex, &dummyIndex, currdriverstate);
707                 if (GPIO_num != DISABLE_GPIO_NUM)
708                         TURN_ON_LED(1 << GPIO_num, uiLedIndex);
709                 break;
710
711         case SHUTDOWN_EXIT:
712                 /*
713                  * no break, continue to NO_NETWORK_ENTRY
714                  * state as well.
715                  */
716         case NO_NETWORK_ENTRY:
717                 currdriverstate = NO_NETWORK_ENTRY;
718                 BcmGetGPIOPinInfo(ad, &GPIO_num, &dummyGPIONum,
719                                   &uiLedIndex, &dummyGPIONum, currdriverstate);
720                 if (GPIO_num != DISABLE_GPIO_NUM)
721                         TURN_ON_LED(1 << GPIO_num, uiLedIndex);
722                 break;
723         case NORMAL_OPERATION:
724                 {
725                         UCHAR GPIO_num_tx = DISABLE_GPIO_NUM;
726                         UCHAR GPIO_num_rx = DISABLE_GPIO_NUM;
727                         UCHAR uiLEDTx = 0;
728                         UCHAR uiLEDRx = 0;
729                         currdriverstate = NORMAL_OPERATION;
730                         ad->LEDInfo.bIdle_led_off = false;
731
732                         BcmGetGPIOPinInfo(ad, &GPIO_num_tx, &GPIO_num_rx,
733                                           &uiLEDTx, &uiLEDRx, currdriverstate);
734                         if ((GPIO_num_tx == DISABLE_GPIO_NUM) &&
735                                         (GPIO_num_rx == DISABLE_GPIO_NUM)) {
736                                 GPIO_num = DISABLE_GPIO_NUM;
737                         } else {
738                                 /*
739                                  * If single LED is selected, use same
740                                  * for both Tx and Rx
741                                  */
742                                 if (GPIO_num_tx == DISABLE_GPIO_NUM) {
743                                         GPIO_num_tx = GPIO_num_rx;
744                                         uiLEDTx = uiLEDRx;
745                                 } else if (GPIO_num_rx == DISABLE_GPIO_NUM) {
746                                         GPIO_num_rx = GPIO_num_tx;
747                                         uiLEDRx = uiLEDTx;
748                                 }
749                                 /*
750                                  * Blink the LED in proportionate
751                                  * to Tx and Rx transmissions.
752                                  */
753                                 LED_Proportional_Blink(ad,
754                                                        GPIO_num_tx, uiLEDTx,
755                                                        GPIO_num_rx, uiLEDRx,
756                                                        currdriverstate);
757                         }
758                 }
759                 break;
760         case LOWPOWER_MODE_ENTER:
761                 currdriverstate = LOWPOWER_MODE_ENTER;
762                 if (DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING ==
763                                 ad->ulPowerSaveMode) {
764                         /* Turn OFF all the LED */
765                         uiResetValue = 0;
766                         for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) {
767                                 if (ad->LEDInfo.LEDState[uiIndex].GPIO_Num != DISABLE_GPIO_NUM)
768                                         TURN_OFF_LED((1 << ad->LEDInfo.LEDState[uiIndex].GPIO_Num), uiIndex);
769                         }
770
771                 }
772                 /* Turn off LED And WAKE-UP for Sendinf IDLE mode ACK */
773                 ad->LEDInfo.bLedInitDone = false;
774                 ad->LEDInfo.bIdle_led_off = TRUE;
775                 wake_up(&ad->LEDInfo.idleModeSyncEvent);
776                 GPIO_num = DISABLE_GPIO_NUM;
777                 break;
778         case IDLEMODE_CONTINUE:
779                 currdriverstate = IDLEMODE_CONTINUE;
780                 GPIO_num = DISABLE_GPIO_NUM;
781                 break;
782         case IDLEMODE_EXIT:
783                 break;
784         case DRIVER_HALT:
785                 currdriverstate = DRIVER_HALT;
786                 GPIO_num = DISABLE_GPIO_NUM;
787                 for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) {
788                         if (ad->LEDInfo.LEDState[uiIndex].GPIO_Num !=
789                                         DISABLE_GPIO_NUM)
790                                 TURN_OFF_LED((1 << ad->LEDInfo.LEDState[uiIndex].GPIO_Num), uiIndex);
791                 }
792                 /* ad->DriverState = DRIVER_INIT; */
793                 break;
794         case LED_THREAD_INACTIVE:
795                 BCM_DEBUG_PRINT(ad, DBG_TYPE_OTHERS, LED_DUMP_INFO,
796                                 DBG_LVL_ALL, "InActivating LED thread...");
797                 currdriverstate = LED_THREAD_INACTIVE;
798                 ad->LEDInfo.led_thread_running =
799                                 BCM_LED_THREAD_RUNNING_INACTIVELY;
800                 ad->LEDInfo.bLedInitDone = false;
801                 /* disable ALL LED */
802                 for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) {
803                         if (ad->LEDInfo.LEDState[uiIndex].GPIO_Num !=
804                                         DISABLE_GPIO_NUM)
805                                 TURN_OFF_LED((1 << ad->LEDInfo.LEDState[uiIndex].GPIO_Num), uiIndex);
806                 }
807                 break;
808         case LED_THREAD_ACTIVE:
809                 BCM_DEBUG_PRINT(ad, DBG_TYPE_OTHERS, LED_DUMP_INFO,
810                                 DBG_LVL_ALL, "Activating LED thread again...");
811                 if (ad->LinkUpStatus == false)
812                         ad->DriverState = NO_NETWORK_ENTRY;
813                 else
814                         ad->DriverState = NORMAL_OPERATION;
815
816                 ad->LEDInfo.led_thread_running =
817                                 BCM_LED_THREAD_RUNNING_ACTIVELY;
818                 break;
819                 /* return; */
820         default:
821                 break;
822         }
823 }
824
825 static VOID LEDControlThread(struct bcm_mini_adapter *Adapter)
826 {
827         UINT uiIndex = 0;
828         UCHAR GPIO_num = 0;
829         UCHAR uiLedIndex = 0;
830         UINT uiResetValue = 0;
831         enum bcm_led_events currdriverstate = 0;
832         ulong timeout = 0;
833
834         INT Status = 0;
835
836         UCHAR dummyGPIONum = 0;
837         UCHAR dummyIndex = 0;
838
839         /* currdriverstate = Adapter->DriverState; */
840         Adapter->LEDInfo.bIdleMode_tx_from_host = false;
841
842         /*
843          * Wait till event is triggered
844          *
845          * wait_event(Adapter->LEDInfo.notify_led_event,
846          *      currdriverstate!= Adapter->DriverState);
847          */
848
849         GPIO_num = DISABLE_GPIO_NUM;
850
851         while (TRUE) {
852                 /* Wait till event is triggered */
853                 if ((GPIO_num == DISABLE_GPIO_NUM)
854                                                 ||
855                                 ((currdriverstate != FW_DOWNLOAD) &&
856                                  (currdriverstate != NORMAL_OPERATION) &&
857                                  (currdriverstate != LOWPOWER_MODE_ENTER))
858                                                 ||
859                                 (currdriverstate == LED_THREAD_INACTIVE))
860                         Status = wait_event_interruptible(
861                                         Adapter->LEDInfo.notify_led_event,
862                                         currdriverstate != Adapter->DriverState
863                                                 || kthread_should_stop());
864
865                 if (kthread_should_stop() || Adapter->device_removed) {
866                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO,
867                                 DBG_LVL_ALL,
868                                 "Led thread got signal to exit..hence exiting");
869                         Adapter->LEDInfo.led_thread_running =
870                                                 BCM_LED_THREAD_DISABLED;
871                         TURN_OFF_LED(1 << GPIO_num, uiLedIndex);
872                         return; /* STATUS_FAILURE; */
873                 }
874
875                 if (GPIO_num != DISABLE_GPIO_NUM)
876                         TURN_OFF_LED(1 << GPIO_num, uiLedIndex);
877
878                 if (Adapter->LEDInfo.bLedInitDone == false) {
879                         LedGpioInit(Adapter);
880                         Adapter->LEDInfo.bLedInitDone = TRUE;
881                 }
882
883                 handle_adapter_driver_state(Adapter,
884                                             currdriverstate,
885                                             GPIO_num,
886                                             dummyGPIONum,
887                                             uiLedIndex,
888                                             dummyIndex,
889                                             timeout,
890                                             uiResetValue,
891                                             uiIndex
892                                             );
893         }
894         Adapter->LEDInfo.led_thread_running = BCM_LED_THREAD_DISABLED;
895 }
896
897 int InitLedSettings(struct bcm_mini_adapter *Adapter)
898 {
899         int Status = STATUS_SUCCESS;
900         bool bEnableThread = TRUE;
901         UCHAR uiIndex = 0;
902
903         /*
904          * Initially set BitPolarity to normal polarity. The bit 8 of LED type
905          * is used to change the polarity of the LED.
906          */
907
908         for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++)
909                 Adapter->LEDInfo.LEDState[uiIndex].BitPolarity = 1;
910
911         /*
912          * Read the LED settings of CONFIG file and map it
913          * to GPIO numbers in EEPROM
914          */
915         Status = ReadConfigFileStructure(Adapter, &bEnableThread);
916         if (STATUS_SUCCESS != Status) {
917                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO,
918                                 DBG_LVL_ALL,
919                                 "LED Thread: FAILED in ReadConfigFileStructure\n");
920                 return Status;
921         }
922
923         if (Adapter->LEDInfo.led_thread_running) {
924                 if (bEnableThread) {
925                         ;
926                 } else {
927                         Adapter->DriverState = DRIVER_HALT;
928                         wake_up(&Adapter->LEDInfo.notify_led_event);
929                         Adapter->LEDInfo.led_thread_running =
930                                                 BCM_LED_THREAD_DISABLED;
931                 }
932
933         } else if (bEnableThread) {
934                 /* Create secondary thread to handle the LEDs */
935                 init_waitqueue_head(&Adapter->LEDInfo.notify_led_event);
936                 init_waitqueue_head(&Adapter->LEDInfo.idleModeSyncEvent);
937                 Adapter->LEDInfo.led_thread_running =
938                                         BCM_LED_THREAD_RUNNING_ACTIVELY;
939                 Adapter->LEDInfo.bIdle_led_off = false;
940                 Adapter->LEDInfo.led_cntrl_threadid =
941                         kthread_run((int (*)(void *)) LEDControlThread,
942                                     Adapter, "led_control_thread");
943                 if (IS_ERR(Adapter->LEDInfo.led_cntrl_threadid)) {
944                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO,
945                                         DBG_LVL_ALL,
946                                         "Not able to spawn Kernel Thread\n");
947                         Adapter->LEDInfo.led_thread_running =
948                                 BCM_LED_THREAD_DISABLED;
949                         return PTR_ERR(Adapter->LEDInfo.led_cntrl_threadid);
950                 }
951         }
952         return Status;
953 }