linux/drivers/staging/rtl8188eu/core/rtw_led.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/******************************************************************************
   3 *
   4 * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
   5 *
   6 ******************************************************************************/
   7
   8#include <drv_types.h>
   9#include "rtw_led.h"
  10
  11/*  */
  12/*      Description: */
  13/*              Callback function of LED BlinkTimer, */
  14/*              it just schedules to corresponding BlinkWorkItem/led_blink_hdl */
  15/*  */
  16static void BlinkTimerCallback(struct timer_list *t)
  17{
  18        struct LED_871x *pLed = from_timer(pLed, t, BlinkTimer);
  19        struct adapter *padapter = pLed->padapter;
  20
  21        if (padapter->bSurpriseRemoved || padapter->bDriverStopped)
  22                return;
  23
  24        schedule_work(&pLed->BlinkWorkItem);
  25}
  26
  27/*  */
  28/*      Description: */
  29/*              Callback function of LED BlinkWorkItem. */
  30/*  */
  31void BlinkWorkItemCallback(struct work_struct *work)
  32{
  33        struct LED_871x *pLed = container_of(work, struct LED_871x,
  34                                                BlinkWorkItem);
  35
  36        blink_handler(pLed);
  37}
  38
  39/*  */
  40/*      Description: */
  41/*              Reset status of LED_871x object. */
  42/*  */
  43void ResetLedStatus(struct LED_871x *pLed)
  44{
  45        pLed->CurrLedState = RTW_LED_OFF; /*  Current LED state. */
  46        pLed->led_on = false; /*  true if LED is ON, false if LED is OFF. */
  47
  48        pLed->bLedBlinkInProgress = false; /*  true if it is blinking, false o.w.. */
  49        pLed->bLedWPSBlinkInProgress = false;
  50
  51        pLed->BlinkTimes = 0; /*  Number of times to toggle led state for blinking. */
  52        pLed->BlinkingLedState = LED_UNKNOWN; /*  Next state for blinking, either RTW_LED_ON or RTW_LED_OFF are. */
  53
  54        pLed->bLedNoLinkBlinkInProgress = false;
  55        pLed->bLedLinkBlinkInProgress = false;
  56        pLed->bLedScanBlinkInProgress = false;
  57}
  58
  59/*Description: */
  60/*              Initialize an LED_871x object. */
  61void InitLed871x(struct adapter *padapter, struct LED_871x *pLed)
  62{
  63        pLed->padapter = padapter;
  64
  65        ResetLedStatus(pLed);
  66
  67        timer_setup(&pLed->BlinkTimer, BlinkTimerCallback, 0);
  68
  69        INIT_WORK(&pLed->BlinkWorkItem, BlinkWorkItemCallback);
  70}
  71
  72/*  */
  73/*      Description: */
  74/*              DeInitialize an LED_871x object. */
  75/*  */
  76void DeInitLed871x(struct LED_871x *pLed)
  77{
  78        cancel_work_sync(&pLed->BlinkWorkItem);
  79        del_timer_sync(&pLed->BlinkTimer);
  80        ResetLedStatus(pLed);
  81}
  82
  83/*  */
  84/*      Description: */
  85/*              Implementation of LED blinking behavior. */
  86/*              It toggle off LED and schedule corresponding timer if necessary. */
  87/*  */
  88
  89static void SwLedBlink1(struct LED_871x *pLed)
  90{
  91        struct adapter *padapter = pLed->padapter;
  92        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
  93
  94        /*  Change LED according to BlinkingLedState specified. */
  95        if (pLed->BlinkingLedState == RTW_LED_ON)
  96                sw_led_on(padapter, pLed);
  97        else
  98                sw_led_off(padapter, pLed);
  99
 100        if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
 101                sw_led_off(padapter, pLed);
 102                ResetLedStatus(pLed);
 103                return;
 104        }
 105
 106        switch (pLed->CurrLedState) {
 107        case LED_BLINK_SLOWLY:
 108                if (pLed->led_on)
 109                        pLed->BlinkingLedState = RTW_LED_OFF;
 110                else
 111                        pLed->BlinkingLedState = RTW_LED_ON;
 112                mod_timer(&pLed->BlinkTimer, jiffies +
 113                          msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA));
 114                break;
 115        case LED_BLINK_NORMAL:
 116                if (pLed->led_on)
 117                        pLed->BlinkingLedState = RTW_LED_OFF;
 118                else
 119                        pLed->BlinkingLedState = RTW_LED_ON;
 120                mod_timer(&pLed->BlinkTimer, jiffies +
 121                          msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA));
 122                break;
 123        case LED_BLINK_SCAN:
 124                pLed->BlinkTimes--;
 125                if (pLed->BlinkTimes == 0) {
 126                        if (check_fwstate(pmlmepriv, _FW_LINKED)) {
 127                                pLed->bLedLinkBlinkInProgress = true;
 128                                pLed->CurrLedState = LED_BLINK_NORMAL;
 129                                if (pLed->led_on)
 130                                        pLed->BlinkingLedState = RTW_LED_OFF;
 131                                else
 132                                        pLed->BlinkingLedState = RTW_LED_ON;
 133                                mod_timer(&pLed->BlinkTimer, jiffies +
 134                                          msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA));
 135                        } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) {
 136                                pLed->bLedNoLinkBlinkInProgress = true;
 137                                pLed->CurrLedState = LED_BLINK_SLOWLY;
 138                                if (pLed->led_on)
 139                                        pLed->BlinkingLedState = RTW_LED_OFF;
 140                                else
 141                                        pLed->BlinkingLedState = RTW_LED_ON;
 142                                mod_timer(&pLed->BlinkTimer, jiffies +
 143                                          msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA));
 144                        }
 145                        pLed->bLedScanBlinkInProgress = false;
 146                } else {
 147                        if (pLed->led_on)
 148                                pLed->BlinkingLedState = RTW_LED_OFF;
 149                        else
 150                                pLed->BlinkingLedState = RTW_LED_ON;
 151                        mod_timer(&pLed->BlinkTimer, jiffies +
 152                                  msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA));
 153                }
 154                break;
 155        case LED_BLINK_TXRX:
 156                pLed->BlinkTimes--;
 157                if (pLed->BlinkTimes == 0) {
 158                        if (check_fwstate(pmlmepriv, _FW_LINKED)) {
 159                                pLed->bLedLinkBlinkInProgress = true;
 160                                pLed->CurrLedState = LED_BLINK_NORMAL;
 161                                if (pLed->led_on)
 162                                        pLed->BlinkingLedState = RTW_LED_OFF;
 163                                else
 164                                        pLed->BlinkingLedState = RTW_LED_ON;
 165                                mod_timer(&pLed->BlinkTimer, jiffies +
 166                                          msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA));
 167                        } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) {
 168                                pLed->bLedNoLinkBlinkInProgress = true;
 169                                pLed->CurrLedState = LED_BLINK_SLOWLY;
 170                                if (pLed->led_on)
 171                                        pLed->BlinkingLedState = RTW_LED_OFF;
 172                                else
 173                                        pLed->BlinkingLedState = RTW_LED_ON;
 174                                mod_timer(&pLed->BlinkTimer, jiffies +
 175                                          msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA));
 176                        }
 177                        pLed->bLedBlinkInProgress = false;
 178                } else {
 179                        if (pLed->led_on)
 180                                pLed->BlinkingLedState = RTW_LED_OFF;
 181                        else
 182                                pLed->BlinkingLedState = RTW_LED_ON;
 183                        mod_timer(&pLed->BlinkTimer, jiffies +
 184                                  msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA));
 185                }
 186                break;
 187        case LED_BLINK_WPS:
 188                if (pLed->led_on)
 189                        pLed->BlinkingLedState = RTW_LED_OFF;
 190                else
 191                        pLed->BlinkingLedState = RTW_LED_ON;
 192                mod_timer(&pLed->BlinkTimer, jiffies +
 193                          msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA));
 194                break;
 195        case LED_BLINK_WPS_STOP:        /* WPS success */
 196                if (pLed->BlinkingLedState != RTW_LED_ON) {
 197                        pLed->bLedLinkBlinkInProgress = true;
 198                        pLed->CurrLedState = LED_BLINK_NORMAL;
 199                        if (pLed->led_on)
 200                                pLed->BlinkingLedState = RTW_LED_OFF;
 201                        else
 202                                pLed->BlinkingLedState = RTW_LED_ON;
 203                        mod_timer(&pLed->BlinkTimer, jiffies +
 204                                  msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA));
 205
 206                        pLed->bLedWPSBlinkInProgress = false;
 207                } else {
 208                        pLed->BlinkingLedState = RTW_LED_OFF;
 209                        mod_timer(&pLed->BlinkTimer, jiffies +
 210                                  msecs_to_jiffies(LED_BLINK_WPS_SUCCESS_INTERVAL_ALPHA));
 211                }
 212                break;
 213        default:
 214                break;
 215        }
 216}
 217
 218 /* ALPHA, added by chiyoko, 20090106 */
 219static void SwLedControlMode1(struct adapter *padapter, enum LED_CTL_MODE LedAction)
 220{
 221        struct led_priv *ledpriv = &padapter->ledpriv;
 222        struct LED_871x *pLed = &ledpriv->sw_led;
 223        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
 224
 225        switch (LedAction) {
 226        case LED_CTL_POWER_ON:
 227        case LED_CTL_START_TO_LINK:
 228        case LED_CTL_NO_LINK:
 229                if (pLed->bLedNoLinkBlinkInProgress)
 230                        break;
 231                if (pLed->CurrLedState == LED_BLINK_SCAN ||
 232                    IS_LED_WPS_BLINKING(pLed))
 233                        return;
 234                if (pLed->bLedLinkBlinkInProgress) {
 235                        del_timer_sync(&pLed->BlinkTimer);
 236                        pLed->bLedLinkBlinkInProgress = false;
 237                }
 238                if (pLed->bLedBlinkInProgress) {
 239                        del_timer_sync(&pLed->BlinkTimer);
 240                        pLed->bLedBlinkInProgress = false;
 241                }
 242                pLed->bLedNoLinkBlinkInProgress = true;
 243                pLed->CurrLedState = LED_BLINK_SLOWLY;
 244                if (pLed->led_on)
 245                        pLed->BlinkingLedState = RTW_LED_OFF;
 246                else
 247                        pLed->BlinkingLedState = RTW_LED_ON;
 248                mod_timer(&pLed->BlinkTimer, jiffies +
 249                          msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA));
 250                break;
 251        case LED_CTL_LINK:
 252                if (pLed->bLedLinkBlinkInProgress)
 253                        break;
 254                if (pLed->CurrLedState == LED_BLINK_SCAN ||
 255                    IS_LED_WPS_BLINKING(pLed))
 256                        return;
 257                if (pLed->bLedNoLinkBlinkInProgress) {
 258                        del_timer_sync(&pLed->BlinkTimer);
 259                        pLed->bLedNoLinkBlinkInProgress = false;
 260                }
 261                if (pLed->bLedBlinkInProgress) {
 262                        del_timer_sync(&pLed->BlinkTimer);
 263                        pLed->bLedBlinkInProgress = false;
 264                }
 265                pLed->bLedLinkBlinkInProgress = true;
 266                pLed->CurrLedState = LED_BLINK_NORMAL;
 267                if (pLed->led_on)
 268                        pLed->BlinkingLedState = RTW_LED_OFF;
 269                else
 270                        pLed->BlinkingLedState = RTW_LED_ON;
 271                mod_timer(&pLed->BlinkTimer, jiffies +
 272                          msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA));
 273                break;
 274        case LED_CTL_SITE_SURVEY:
 275                if (pmlmepriv->LinkDetectInfo.bBusyTraffic &&
 276                    check_fwstate(pmlmepriv, _FW_LINKED))
 277                        break;
 278                if (pLed->bLedScanBlinkInProgress)
 279                        break;
 280                if (IS_LED_WPS_BLINKING(pLed))
 281                        return;
 282                if (pLed->bLedNoLinkBlinkInProgress) {
 283                        del_timer_sync(&pLed->BlinkTimer);
 284                        pLed->bLedNoLinkBlinkInProgress = false;
 285                }
 286                if (pLed->bLedLinkBlinkInProgress) {
 287                        del_timer_sync(&pLed->BlinkTimer);
 288                        pLed->bLedLinkBlinkInProgress = false;
 289                }
 290                if (pLed->bLedBlinkInProgress) {
 291                        del_timer_sync(&pLed->BlinkTimer);
 292                        pLed->bLedBlinkInProgress = false;
 293                }
 294                pLed->bLedScanBlinkInProgress = true;
 295                pLed->CurrLedState = LED_BLINK_SCAN;
 296                pLed->BlinkTimes = 24;
 297                if (pLed->led_on)
 298                        pLed->BlinkingLedState = RTW_LED_OFF;
 299                else
 300                        pLed->BlinkingLedState = RTW_LED_ON;
 301                mod_timer(&pLed->BlinkTimer, jiffies +
 302                          msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA));
 303                break;
 304        case LED_CTL_TX:
 305        case LED_CTL_RX:
 306                if (pLed->bLedBlinkInProgress)
 307                        break;
 308                if (pLed->CurrLedState == LED_BLINK_SCAN ||
 309                    IS_LED_WPS_BLINKING(pLed))
 310                        return;
 311                if (pLed->bLedNoLinkBlinkInProgress) {
 312                        del_timer_sync(&pLed->BlinkTimer);
 313                        pLed->bLedNoLinkBlinkInProgress = false;
 314                }
 315                if (pLed->bLedLinkBlinkInProgress) {
 316                        del_timer_sync(&pLed->BlinkTimer);
 317                        pLed->bLedLinkBlinkInProgress = false;
 318                }
 319                pLed->bLedBlinkInProgress = true;
 320                pLed->CurrLedState = LED_BLINK_TXRX;
 321                pLed->BlinkTimes = 2;
 322                if (pLed->led_on)
 323                        pLed->BlinkingLedState = RTW_LED_OFF;
 324                else
 325                        pLed->BlinkingLedState = RTW_LED_ON;
 326                mod_timer(&pLed->BlinkTimer, jiffies +
 327                          msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA));
 328                break;
 329        case LED_CTL_START_WPS: /* wait until xinpin finish */
 330        case LED_CTL_START_WPS_BOTTON:
 331                if (pLed->bLedWPSBlinkInProgress)
 332                        break;
 333                if (pLed->bLedNoLinkBlinkInProgress) {
 334                        del_timer_sync(&pLed->BlinkTimer);
 335                        pLed->bLedNoLinkBlinkInProgress = false;
 336                }
 337                if (pLed->bLedLinkBlinkInProgress) {
 338                        del_timer_sync(&pLed->BlinkTimer);
 339                        pLed->bLedLinkBlinkInProgress = false;
 340                }
 341                if (pLed->bLedBlinkInProgress) {
 342                        del_timer_sync(&pLed->BlinkTimer);
 343                        pLed->bLedBlinkInProgress = false;
 344                }
 345                if (pLed->bLedScanBlinkInProgress) {
 346                        del_timer_sync(&pLed->BlinkTimer);
 347                        pLed->bLedScanBlinkInProgress = false;
 348                }
 349                pLed->bLedWPSBlinkInProgress = true;
 350                pLed->CurrLedState = LED_BLINK_WPS;
 351                if (pLed->led_on)
 352                        pLed->BlinkingLedState = RTW_LED_OFF;
 353                else
 354                        pLed->BlinkingLedState = RTW_LED_ON;
 355                mod_timer(&pLed->BlinkTimer, jiffies +
 356                          msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA));
 357                break;
 358        case LED_CTL_STOP_WPS:
 359                if (pLed->bLedNoLinkBlinkInProgress) {
 360                        del_timer_sync(&pLed->BlinkTimer);
 361                        pLed->bLedNoLinkBlinkInProgress = false;
 362                }
 363                if (pLed->bLedLinkBlinkInProgress) {
 364                        del_timer_sync(&pLed->BlinkTimer);
 365                        pLed->bLedLinkBlinkInProgress = false;
 366                }
 367                if (pLed->bLedBlinkInProgress) {
 368                        del_timer_sync(&pLed->BlinkTimer);
 369                        pLed->bLedBlinkInProgress = false;
 370                }
 371                if (pLed->bLedScanBlinkInProgress) {
 372                        del_timer_sync(&pLed->BlinkTimer);
 373                        pLed->bLedScanBlinkInProgress = false;
 374                }
 375                if (pLed->bLedWPSBlinkInProgress)
 376                        del_timer_sync(&pLed->BlinkTimer);
 377                else
 378                        pLed->bLedWPSBlinkInProgress = true;
 379                pLed->CurrLedState = LED_BLINK_WPS_STOP;
 380                if (pLed->led_on) {
 381                        pLed->BlinkingLedState = RTW_LED_OFF;
 382                        mod_timer(&pLed->BlinkTimer, jiffies +
 383                                  msecs_to_jiffies(LED_BLINK_WPS_SUCCESS_INTERVAL_ALPHA));
 384                } else {
 385                        pLed->BlinkingLedState = RTW_LED_ON;
 386                        mod_timer(&pLed->BlinkTimer,
 387                                  jiffies + msecs_to_jiffies(0));
 388                }
 389                break;
 390        case LED_CTL_STOP_WPS_FAIL:
 391                if (pLed->bLedWPSBlinkInProgress) {
 392                        del_timer_sync(&pLed->BlinkTimer);
 393                        pLed->bLedWPSBlinkInProgress = false;
 394                }
 395                pLed->bLedNoLinkBlinkInProgress = true;
 396                pLed->CurrLedState = LED_BLINK_SLOWLY;
 397                if (pLed->led_on)
 398                        pLed->BlinkingLedState = RTW_LED_OFF;
 399                else
 400                        pLed->BlinkingLedState = RTW_LED_ON;
 401                mod_timer(&pLed->BlinkTimer, jiffies +
 402                          msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA));
 403                break;
 404        case LED_CTL_POWER_OFF:
 405                pLed->CurrLedState = RTW_LED_OFF;
 406                pLed->BlinkingLedState = RTW_LED_OFF;
 407                if (pLed->bLedNoLinkBlinkInProgress) {
 408                        del_timer_sync(&pLed->BlinkTimer);
 409                        pLed->bLedNoLinkBlinkInProgress = false;
 410                }
 411                if (pLed->bLedLinkBlinkInProgress) {
 412                        del_timer_sync(&pLed->BlinkTimer);
 413                        pLed->bLedLinkBlinkInProgress = false;
 414                }
 415                if (pLed->bLedBlinkInProgress) {
 416                        del_timer_sync(&pLed->BlinkTimer);
 417                        pLed->bLedBlinkInProgress = false;
 418                }
 419                if (pLed->bLedWPSBlinkInProgress) {
 420                        del_timer_sync(&pLed->BlinkTimer);
 421                        pLed->bLedWPSBlinkInProgress = false;
 422                }
 423                if (pLed->bLedScanBlinkInProgress) {
 424                        del_timer_sync(&pLed->BlinkTimer);
 425                        pLed->bLedScanBlinkInProgress = false;
 426                }
 427                sw_led_off(padapter, pLed);
 428                break;
 429        default:
 430                break;
 431        }
 432}
 433
 434void blink_handler(struct LED_871x *pLed)
 435{
 436        struct adapter *padapter = pLed->padapter;
 437
 438        if (padapter->bSurpriseRemoved || padapter->bDriverStopped)
 439                return;
 440
 441        SwLedBlink1(pLed);
 442}
 443
 444void led_control_8188eu(struct adapter *padapter, enum LED_CTL_MODE LedAction)
 445{
 446        if (padapter->bSurpriseRemoved || padapter->bDriverStopped ||
 447            !padapter->hw_init_completed)
 448                return;
 449
 450        if ((padapter->pwrctrlpriv.rf_pwrstate != rf_on &&
 451             padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) &&
 452            (LedAction == LED_CTL_TX || LedAction == LED_CTL_RX ||
 453             LedAction == LED_CTL_SITE_SURVEY ||
 454             LedAction == LED_CTL_LINK ||
 455             LedAction == LED_CTL_NO_LINK ||
 456             LedAction == LED_CTL_POWER_ON))
 457                return;
 458
 459        SwLedControlMode1(padapter, LedAction);
 460}
 461