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