linux/drivers/staging/rtl8723bs/core/rtw_cmd.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/******************************************************************************
   3 *
   4 * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
   5 *
   6 ******************************************************************************/
   7#include <drv_types.h>
   8#include <rtw_debug.h>
   9#include <hal_btcoex.h>
  10#include <linux/jiffies.h>
  11
  12static struct _cmd_callback rtw_cmd_callback[] = {
  13        {GEN_CMD_CODE(_Read_MACREG), NULL}, /*0*/
  14        {GEN_CMD_CODE(_Write_MACREG), NULL},
  15        {GEN_CMD_CODE(_Read_BBREG), &rtw_getbbrfreg_cmdrsp_callback},
  16        {GEN_CMD_CODE(_Write_BBREG), NULL},
  17        {GEN_CMD_CODE(_Read_RFREG), &rtw_getbbrfreg_cmdrsp_callback},
  18        {GEN_CMD_CODE(_Write_RFREG), NULL}, /*5*/
  19        {GEN_CMD_CODE(_Read_EEPROM), NULL},
  20        {GEN_CMD_CODE(_Write_EEPROM), NULL},
  21        {GEN_CMD_CODE(_Read_EFUSE), NULL},
  22        {GEN_CMD_CODE(_Write_EFUSE), NULL},
  23
  24        {GEN_CMD_CODE(_Read_CAM),       NULL},  /*10*/
  25        {GEN_CMD_CODE(_Write_CAM),       NULL},
  26        {GEN_CMD_CODE(_setBCNITV), NULL},
  27        {GEN_CMD_CODE(_setMBIDCFG), NULL},
  28        {GEN_CMD_CODE(_JoinBss), &rtw_joinbss_cmd_callback},  /*14*/
  29        {GEN_CMD_CODE(_DisConnect), &rtw_disassoc_cmd_callback}, /*15*/
  30        {GEN_CMD_CODE(_CreateBss), &rtw_createbss_cmd_callback},
  31        {GEN_CMD_CODE(_SetOpMode), NULL},
  32        {GEN_CMD_CODE(_SiteSurvey), &rtw_survey_cmd_callback}, /*18*/
  33        {GEN_CMD_CODE(_SetAuth), NULL},
  34
  35        {GEN_CMD_CODE(_SetKey), NULL},  /*20*/
  36        {GEN_CMD_CODE(_SetStaKey), &rtw_setstaKey_cmdrsp_callback},
  37        {GEN_CMD_CODE(_SetAssocSta), &rtw_setassocsta_cmdrsp_callback},
  38        {GEN_CMD_CODE(_DelAssocSta), NULL},
  39        {GEN_CMD_CODE(_SetStaPwrState), NULL},
  40        {GEN_CMD_CODE(_SetBasicRate), NULL}, /*25*/
  41        {GEN_CMD_CODE(_GetBasicRate), NULL},
  42        {GEN_CMD_CODE(_SetDataRate), NULL},
  43        {GEN_CMD_CODE(_GetDataRate), NULL},
  44        {GEN_CMD_CODE(_SetPhyInfo), NULL},
  45
  46        {GEN_CMD_CODE(_GetPhyInfo), NULL}, /*30*/
  47        {GEN_CMD_CODE(_SetPhy), NULL},
  48        {GEN_CMD_CODE(_GetPhy), NULL},
  49        {GEN_CMD_CODE(_readRssi), NULL},
  50        {GEN_CMD_CODE(_readGain), NULL},
  51        {GEN_CMD_CODE(_SetAtim), NULL}, /*35*/
  52        {GEN_CMD_CODE(_SetPwrMode), NULL},
  53        {GEN_CMD_CODE(_JoinbssRpt), NULL},
  54        {GEN_CMD_CODE(_SetRaTable), NULL},
  55        {GEN_CMD_CODE(_GetRaTable), NULL},
  56
  57        {GEN_CMD_CODE(_GetCCXReport), NULL}, /*40*/
  58        {GEN_CMD_CODE(_GetDTMReport),   NULL},
  59        {GEN_CMD_CODE(_GetTXRateStatistics), NULL},
  60        {GEN_CMD_CODE(_SetUsbSuspend), NULL},
  61        {GEN_CMD_CODE(_SetH2cLbk), NULL},
  62        {GEN_CMD_CODE(_AddBAReq), NULL}, /*45*/
  63        {GEN_CMD_CODE(_SetChannel), NULL},              /*46*/
  64        {GEN_CMD_CODE(_SetTxPower), NULL},
  65        {GEN_CMD_CODE(_SwitchAntenna), NULL},
  66        {GEN_CMD_CODE(_SetCrystalCap), NULL},
  67        {GEN_CMD_CODE(_SetSingleCarrierTx), NULL},      /*50*/
  68
  69        {GEN_CMD_CODE(_SetSingleToneTx), NULL}, /*51*/
  70        {GEN_CMD_CODE(_SetCarrierSuppressionTx), NULL},
  71        {GEN_CMD_CODE(_SetContinuousTx), NULL},
  72        {GEN_CMD_CODE(_SwitchBandwidth), NULL},         /*54*/
  73        {GEN_CMD_CODE(_TX_Beacon), NULL},/*55*/
  74
  75        {GEN_CMD_CODE(_Set_MLME_EVT), NULL},/*56*/
  76        {GEN_CMD_CODE(_Set_Drv_Extra), NULL},/*57*/
  77        {GEN_CMD_CODE(_Set_H2C_MSG), NULL},/*58*/
  78        {GEN_CMD_CODE(_SetChannelPlan), NULL},/*59*/
  79
  80        {GEN_CMD_CODE(_SetChannelSwitch), NULL},/*60*/
  81        {GEN_CMD_CODE(_TDLS), NULL},/*61*/
  82        {GEN_CMD_CODE(_ChkBMCSleepq), NULL}, /*62*/
  83
  84        {GEN_CMD_CODE(_RunInThreadCMD), NULL},/*63*/
  85};
  86
  87static struct cmd_hdl wlancmds[] = {
  88        GEN_DRV_CMD_HANDLER(0, NULL) /*0*/
  89        GEN_DRV_CMD_HANDLER(0, NULL)
  90        GEN_DRV_CMD_HANDLER(0, NULL)
  91        GEN_DRV_CMD_HANDLER(0, NULL)
  92        GEN_DRV_CMD_HANDLER(0, NULL)
  93        GEN_DRV_CMD_HANDLER(0, NULL)
  94        GEN_MLME_EXT_HANDLER(0, NULL)
  95        GEN_MLME_EXT_HANDLER(0, NULL)
  96        GEN_MLME_EXT_HANDLER(0, NULL)
  97        GEN_MLME_EXT_HANDLER(0, NULL)
  98        GEN_MLME_EXT_HANDLER(0, NULL) /*10*/
  99        GEN_MLME_EXT_HANDLER(0, NULL)
 100        GEN_MLME_EXT_HANDLER(0, NULL)
 101        GEN_MLME_EXT_HANDLER(0, NULL)
 102        GEN_MLME_EXT_HANDLER(sizeof(struct joinbss_parm), join_cmd_hdl) /*14*/
 103        GEN_MLME_EXT_HANDLER(sizeof(struct disconnect_parm), disconnect_hdl)
 104        GEN_MLME_EXT_HANDLER(sizeof(struct createbss_parm), createbss_hdl)
 105        GEN_MLME_EXT_HANDLER(sizeof(struct setopmode_parm), setopmode_hdl)
 106        GEN_MLME_EXT_HANDLER(sizeof(struct sitesurvey_parm), sitesurvey_cmd_hdl) /*18*/
 107        GEN_MLME_EXT_HANDLER(sizeof(struct setauth_parm), setauth_hdl)
 108        GEN_MLME_EXT_HANDLER(sizeof(struct setkey_parm), setkey_hdl) /*20*/
 109        GEN_MLME_EXT_HANDLER(sizeof(struct set_stakey_parm), set_stakey_hdl)
 110        GEN_MLME_EXT_HANDLER(sizeof(struct set_assocsta_parm), NULL)
 111        GEN_MLME_EXT_HANDLER(sizeof(struct del_assocsta_parm), NULL)
 112        GEN_MLME_EXT_HANDLER(sizeof(struct setstapwrstate_parm), NULL)
 113        GEN_MLME_EXT_HANDLER(sizeof(struct setbasicrate_parm), NULL)
 114        GEN_MLME_EXT_HANDLER(sizeof(struct getbasicrate_parm), NULL)
 115        GEN_MLME_EXT_HANDLER(sizeof(struct setdatarate_parm), NULL)
 116        GEN_MLME_EXT_HANDLER(sizeof(struct getdatarate_parm), NULL)
 117        GEN_MLME_EXT_HANDLER(sizeof(struct setphyinfo_parm), NULL)
 118        GEN_MLME_EXT_HANDLER(sizeof(struct getphyinfo_parm), NULL)  /*30*/
 119        GEN_MLME_EXT_HANDLER(sizeof(struct setphy_parm), NULL)
 120        GEN_MLME_EXT_HANDLER(sizeof(struct getphy_parm), NULL)
 121        GEN_MLME_EXT_HANDLER(0, NULL)
 122        GEN_MLME_EXT_HANDLER(0, NULL)
 123        GEN_MLME_EXT_HANDLER(0, NULL)
 124        GEN_MLME_EXT_HANDLER(0, NULL)
 125        GEN_MLME_EXT_HANDLER(0, NULL)
 126        GEN_MLME_EXT_HANDLER(0, NULL)
 127        GEN_MLME_EXT_HANDLER(0, NULL)
 128        GEN_MLME_EXT_HANDLER(0, NULL)   /*40*/
 129        GEN_MLME_EXT_HANDLER(0, NULL)
 130        GEN_MLME_EXT_HANDLER(0, NULL)
 131        GEN_MLME_EXT_HANDLER(0, NULL)
 132        GEN_MLME_EXT_HANDLER(0, NULL)
 133        GEN_MLME_EXT_HANDLER(sizeof(struct addBaReq_parm), add_ba_hdl)
 134        GEN_MLME_EXT_HANDLER(sizeof(struct set_ch_parm), set_ch_hdl) /* 46 */
 135        GEN_MLME_EXT_HANDLER(0, NULL)
 136        GEN_MLME_EXT_HANDLER(0, NULL)
 137        GEN_MLME_EXT_HANDLER(0, NULL)
 138        GEN_MLME_EXT_HANDLER(0, NULL) /*50*/
 139        GEN_MLME_EXT_HANDLER(0, NULL)
 140        GEN_MLME_EXT_HANDLER(0, NULL)
 141        GEN_MLME_EXT_HANDLER(0, NULL)
 142        GEN_MLME_EXT_HANDLER(0, NULL)
 143        GEN_MLME_EXT_HANDLER(sizeof(struct Tx_Beacon_param), tx_beacon_hdl) /*55*/
 144
 145        GEN_MLME_EXT_HANDLER(0, mlme_evt_hdl) /*56*/
 146        GEN_MLME_EXT_HANDLER(0, rtw_drvextra_cmd_hdl) /*57*/
 147
 148        GEN_MLME_EXT_HANDLER(0, h2c_msg_hdl) /*58*/
 149        GEN_MLME_EXT_HANDLER(sizeof(struct SetChannelPlan_param), set_chplan_hdl) /*59*/
 150
 151        GEN_MLME_EXT_HANDLER(sizeof(struct SetChannelSwitch_param), set_csa_hdl) /*60*/
 152        GEN_MLME_EXT_HANDLER(sizeof(struct TDLSoption_param), tdls_hdl) /*61*/
 153        GEN_MLME_EXT_HANDLER(0, chk_bmc_sleepq_hdl) /*62*/
 154        GEN_MLME_EXT_HANDLER(sizeof(struct RunInThread_param), run_in_thread_hdl) /*63*/
 155};
 156
 157/*
 158 * Caller and the rtw_cmd_thread can protect cmd_q by spin_lock.
 159 * No irqsave is necessary.
 160 */
 161
 162int rtw_init_cmd_priv(struct    cmd_priv *pcmdpriv)
 163{
 164        int res = 0;
 165
 166        init_completion(&pcmdpriv->cmd_queue_comp);
 167        init_completion(&pcmdpriv->terminate_cmdthread_comp);
 168
 169        _rtw_init_queue(&(pcmdpriv->cmd_queue));
 170
 171        /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */
 172
 173        pcmdpriv->cmd_seq = 1;
 174
 175        pcmdpriv->cmd_allocated_buf = rtw_zmalloc(MAX_CMDSZ + CMDBUFF_ALIGN_SZ);
 176
 177        if (!pcmdpriv->cmd_allocated_buf) {
 178                res = -ENOMEM;
 179                goto exit;
 180        }
 181
 182        pcmdpriv->cmd_buf = pcmdpriv->cmd_allocated_buf  +  CMDBUFF_ALIGN_SZ - ((SIZE_PTR)(pcmdpriv->cmd_allocated_buf) & (CMDBUFF_ALIGN_SZ-1));
 183
 184        pcmdpriv->rsp_allocated_buf = rtw_zmalloc(MAX_RSPSZ + 4);
 185
 186        if (!pcmdpriv->rsp_allocated_buf) {
 187                res = -ENOMEM;
 188                goto exit;
 189        }
 190
 191        pcmdpriv->rsp_buf = pcmdpriv->rsp_allocated_buf  +  4 - ((SIZE_PTR)(pcmdpriv->rsp_allocated_buf) & 3);
 192
 193        pcmdpriv->cmd_issued_cnt = 0;
 194        pcmdpriv->cmd_done_cnt = 0;
 195        pcmdpriv->rsp_cnt = 0;
 196
 197        mutex_init(&pcmdpriv->sctx_mutex);
 198exit:
 199        return res;
 200}
 201
 202static void c2h_wk_callback(struct work_struct *work);
 203int rtw_init_evt_priv(struct evt_priv *pevtpriv)
 204{
 205        /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */
 206        atomic_set(&pevtpriv->event_seq, 0);
 207        pevtpriv->evt_done_cnt = 0;
 208
 209        _init_workitem(&pevtpriv->c2h_wk, c2h_wk_callback, NULL);
 210        pevtpriv->c2h_wk_alive = false;
 211        pevtpriv->c2h_queue = rtw_cbuf_alloc(C2H_QUEUE_MAX_LEN+1);
 212        if (!pevtpriv->c2h_queue)
 213                return -ENOMEM;
 214
 215        return 0;
 216}
 217
 218void _rtw_free_evt_priv(struct  evt_priv *pevtpriv)
 219{
 220        _cancel_workitem_sync(&pevtpriv->c2h_wk);
 221        while (pevtpriv->c2h_wk_alive)
 222                msleep(10);
 223
 224        while (!rtw_cbuf_empty(pevtpriv->c2h_queue)) {
 225                void *c2h = rtw_cbuf_pop(pevtpriv->c2h_queue);
 226
 227                if (c2h && c2h != (void *)pevtpriv)
 228                        kfree(c2h);
 229        }
 230        kfree(pevtpriv->c2h_queue);
 231}
 232
 233void _rtw_free_cmd_priv(struct  cmd_priv *pcmdpriv)
 234{
 235        if (pcmdpriv) {
 236                kfree(pcmdpriv->cmd_allocated_buf);
 237
 238                kfree(pcmdpriv->rsp_allocated_buf);
 239
 240                mutex_destroy(&pcmdpriv->sctx_mutex);
 241        }
 242}
 243
 244/*
 245 * Calling Context:
 246 *
 247 * rtw_enqueue_cmd can only be called between kernel thread,
 248 * since only spin_lock is used.
 249 *
 250 * ISR/Call-Back functions can't call this sub-function.
 251 *
 252 */
 253
 254int _rtw_enqueue_cmd(struct __queue *queue, struct cmd_obj *obj)
 255{
 256        unsigned long irqL;
 257
 258        if (obj == NULL)
 259                goto exit;
 260
 261        /* spin_lock_bh(&queue->lock); */
 262        spin_lock_irqsave(&queue->lock, irqL);
 263
 264        list_add_tail(&obj->list, &queue->queue);
 265
 266        /* spin_unlock_bh(&queue->lock); */
 267        spin_unlock_irqrestore(&queue->lock, irqL);
 268
 269exit:
 270        return _SUCCESS;
 271}
 272
 273struct  cmd_obj *_rtw_dequeue_cmd(struct __queue *queue)
 274{
 275        unsigned long irqL;
 276        struct cmd_obj *obj;
 277
 278        /* spin_lock_bh(&(queue->lock)); */
 279        spin_lock_irqsave(&queue->lock, irqL);
 280        if (list_empty(&(queue->queue)))
 281                obj = NULL;
 282        else {
 283                obj = container_of(get_next(&(queue->queue)), struct cmd_obj, list);
 284                list_del_init(&obj->list);
 285        }
 286
 287        /* spin_unlock_bh(&(queue->lock)); */
 288        spin_unlock_irqrestore(&queue->lock, irqL);
 289
 290        return obj;
 291}
 292
 293void rtw_free_evt_priv(struct   evt_priv *pevtpriv)
 294{
 295        _rtw_free_evt_priv(pevtpriv);
 296}
 297
 298void rtw_free_cmd_priv(struct   cmd_priv *pcmdpriv)
 299{
 300        _rtw_free_cmd_priv(pcmdpriv);
 301}
 302
 303int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj);
 304int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
 305{
 306        u8 bAllow = false; /* set to true to allow enqueuing cmd when hw_init_completed is false */
 307
 308        if (cmd_obj->cmdcode == GEN_CMD_CODE(_SetChannelPlan))
 309                bAllow = true;
 310
 311        if ((pcmdpriv->padapter->hw_init_completed == false && bAllow == false)
 312                || atomic_read(&(pcmdpriv->cmdthd_running)) == false    /* com_thread not running */
 313        )
 314                return _FAIL;
 315
 316        return _SUCCESS;
 317}
 318
 319
 320
 321int rtw_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
 322{
 323        int res = _FAIL;
 324        struct adapter *padapter = pcmdpriv->padapter;
 325
 326        if (cmd_obj == NULL)
 327                goto exit;
 328
 329        cmd_obj->padapter = padapter;
 330
 331        res = rtw_cmd_filter(pcmdpriv, cmd_obj);
 332        if (res == _FAIL) {
 333                rtw_free_cmd_obj(cmd_obj);
 334                goto exit;
 335        }
 336
 337        res = _rtw_enqueue_cmd(&pcmdpriv->cmd_queue, cmd_obj);
 338
 339        if (res == _SUCCESS)
 340                complete(&pcmdpriv->cmd_queue_comp);
 341
 342exit:
 343        return res;
 344}
 345
 346struct  cmd_obj *rtw_dequeue_cmd(struct cmd_priv *pcmdpriv)
 347{
 348        return _rtw_dequeue_cmd(&pcmdpriv->cmd_queue);
 349}
 350
 351void rtw_free_cmd_obj(struct cmd_obj *pcmd)
 352{
 353        if ((pcmd->cmdcode != _JoinBss_CMD_) &&
 354            (pcmd->cmdcode != _CreateBss_CMD_)) {
 355                /* free parmbuf in cmd_obj */
 356                kfree(pcmd->parmbuf);
 357        }
 358
 359        if (pcmd->rsp) {
 360                if (pcmd->rspsz != 0) {
 361                        /* free rsp in cmd_obj */
 362                        kfree(pcmd->rsp);
 363                }
 364        }
 365
 366        /* free cmd_obj */
 367        kfree(pcmd);
 368}
 369
 370
 371void rtw_stop_cmd_thread(struct adapter *adapter)
 372{
 373        if (adapter->cmdThread &&
 374                atomic_read(&(adapter->cmdpriv.cmdthd_running)) == true &&
 375                adapter->cmdpriv.stop_req == 0) {
 376                adapter->cmdpriv.stop_req = 1;
 377                complete(&adapter->cmdpriv.cmd_queue_comp);
 378                wait_for_completion(&adapter->cmdpriv.terminate_cmdthread_comp);
 379        }
 380}
 381
 382int rtw_cmd_thread(void *context)
 383{
 384        u8 ret;
 385        struct cmd_obj *pcmd;
 386        u8 *pcmdbuf;
 387        u8 (*cmd_hdl)(struct adapter *padapter, u8 *pbuf);
 388        void (*pcmd_callback)(struct adapter *dev, struct cmd_obj *pcmd);
 389        struct adapter *padapter = context;
 390        struct cmd_priv *pcmdpriv = &(padapter->cmdpriv);
 391        struct drvextra_cmd_parm *extra_parm = NULL;
 392
 393        thread_enter("RTW_CMD_THREAD");
 394
 395        pcmdbuf = pcmdpriv->cmd_buf;
 396
 397        pcmdpriv->stop_req = 0;
 398        atomic_set(&(pcmdpriv->cmdthd_running), true);
 399        complete(&pcmdpriv->terminate_cmdthread_comp);
 400
 401        while (1) {
 402                if (wait_for_completion_interruptible(&pcmdpriv->cmd_queue_comp)) {
 403                        netdev_dbg(padapter->pnetdev,
 404                                   FUNC_ADPT_FMT " wait_for_completion_interruptible(&pcmdpriv->cmd_queue_comp) return != 0, break\n",
 405                                   FUNC_ADPT_ARG(padapter));
 406                        break;
 407                }
 408
 409                if ((padapter->bDriverStopped == true) || (padapter->bSurpriseRemoved == true)) {
 410                        netdev_dbg(padapter->pnetdev,
 411                                   "%s: DriverStopped(%d) SurpriseRemoved(%d) break at line %d\n",
 412                                   __func__, padapter->bDriverStopped,
 413                                   padapter->bSurpriseRemoved, __LINE__);
 414                        break;
 415                }
 416
 417                if (pcmdpriv->stop_req) {
 418                        netdev_dbg(padapter->pnetdev,
 419                                   FUNC_ADPT_FMT " stop_req:%u, break\n",
 420                                   FUNC_ADPT_ARG(padapter),
 421                                   pcmdpriv->stop_req);
 422                        break;
 423                }
 424
 425                if (list_empty(&pcmdpriv->cmd_queue.queue))
 426                        continue;
 427
 428                if (rtw_register_cmd_alive(padapter) != _SUCCESS)
 429                        continue;
 430
 431_next:
 432                if ((padapter->bDriverStopped == true) || (padapter->bSurpriseRemoved == true)) {
 433                        netdev_dbg(padapter->pnetdev,
 434                                   "%s: DriverStopped(%d) SurpriseRemoved(%d) break at line %d\n",
 435                                   __func__, padapter->bDriverStopped,
 436                                   padapter->bSurpriseRemoved, __LINE__);
 437                        break;
 438                }
 439
 440                pcmd = rtw_dequeue_cmd(pcmdpriv);
 441                if (!pcmd) {
 442                        rtw_unregister_cmd_alive(padapter);
 443                        continue;
 444                }
 445
 446                if (rtw_cmd_filter(pcmdpriv, pcmd) == _FAIL) {
 447                        pcmd->res = H2C_DROPPED;
 448                        goto post_process;
 449                }
 450
 451                pcmdpriv->cmd_issued_cnt++;
 452
 453                pcmd->cmdsz = round_up((pcmd->cmdsz), 4);
 454
 455                memcpy(pcmdbuf, pcmd->parmbuf, pcmd->cmdsz);
 456
 457                if (pcmd->cmdcode < ARRAY_SIZE(wlancmds)) {
 458                        cmd_hdl = wlancmds[pcmd->cmdcode].h2cfuns;
 459
 460                        if (cmd_hdl) {
 461                                ret = cmd_hdl(pcmd->padapter, pcmdbuf);
 462                                pcmd->res = ret;
 463                        }
 464
 465                        pcmdpriv->cmd_seq++;
 466                } else {
 467                        pcmd->res = H2C_PARAMETERS_ERROR;
 468                }
 469
 470                cmd_hdl = NULL;
 471
 472post_process:
 473
 474                if (mutex_lock_interruptible(&(pcmd->padapter->cmdpriv.sctx_mutex)) == 0) {
 475                        if (pcmd->sctx) {
 476                                netdev_dbg(padapter->pnetdev,
 477                                           FUNC_ADPT_FMT " pcmd->sctx\n",
 478                                           FUNC_ADPT_ARG(pcmd->padapter));
 479
 480                                if (pcmd->res == H2C_SUCCESS)
 481                                        rtw_sctx_done(&pcmd->sctx);
 482                                else
 483                                        rtw_sctx_done_err(&pcmd->sctx, RTW_SCTX_DONE_CMD_ERROR);
 484                        }
 485                        mutex_unlock(&(pcmd->padapter->cmdpriv.sctx_mutex));
 486                }
 487
 488                /* call callback function for post-processed */
 489                if (pcmd->cmdcode < ARRAY_SIZE(rtw_cmd_callback)) {
 490                        pcmd_callback = rtw_cmd_callback[pcmd->cmdcode].callback;
 491                        if (pcmd_callback == NULL) {
 492                                rtw_free_cmd_obj(pcmd);
 493                        } else {
 494                                /* todo: !!! fill rsp_buf to pcmd->rsp if (pcmd->rsp!= NULL) */
 495                                pcmd_callback(pcmd->padapter, pcmd);/* need consider that free cmd_obj in rtw_cmd_callback */
 496                        }
 497                } else {
 498                        rtw_free_cmd_obj(pcmd);
 499                }
 500
 501                flush_signals_thread();
 502
 503                goto _next;
 504
 505        }
 506
 507        /*  free all cmd_obj resources */
 508        do {
 509                pcmd = rtw_dequeue_cmd(pcmdpriv);
 510                if (pcmd == NULL) {
 511                        rtw_unregister_cmd_alive(padapter);
 512                        break;
 513                }
 514
 515                if (pcmd->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra)) {
 516                        extra_parm = (struct drvextra_cmd_parm *)pcmd->parmbuf;
 517                        if (extra_parm->pbuf && extra_parm->size > 0)
 518                                kfree(extra_parm->pbuf);
 519                }
 520
 521                rtw_free_cmd_obj(pcmd);
 522        } while (1);
 523
 524        complete(&pcmdpriv->terminate_cmdthread_comp);
 525        atomic_set(&(pcmdpriv->cmdthd_running), false);
 526
 527        thread_exit();
 528}
 529
 530/*
 531 * rtw_sitesurvey_cmd(~)
 532 *      ### NOTE:#### (!!!!)
 533 *      MUST TAKE CARE THAT BEFORE CALLING THIS FUNC, YOU SHOULD HAVE LOCKED pmlmepriv->lock
 534 */
 535
 536u8 rtw_sitesurvey_cmd(struct adapter  *padapter, struct ndis_802_11_ssid *ssid, int ssid_num,
 537        struct rtw_ieee80211_channel *ch, int ch_num)
 538{
 539        u8 res = _FAIL;
 540        struct cmd_obj          *ph2c;
 541        struct sitesurvey_parm  *psurveyPara;
 542        struct cmd_priv         *pcmdpriv = &padapter->cmdpriv;
 543        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
 544
 545        if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
 546                rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_SCAN, 1);
 547
 548        ph2c = rtw_zmalloc(sizeof(struct cmd_obj));
 549        if (ph2c == NULL)
 550                return _FAIL;
 551
 552        psurveyPara = rtw_zmalloc(sizeof(struct sitesurvey_parm));
 553        if (psurveyPara == NULL) {
 554                kfree(ph2c);
 555                return _FAIL;
 556        }
 557
 558        rtw_free_network_queue(padapter, false);
 559
 560        init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, GEN_CMD_CODE(_SiteSurvey));
 561
 562        /* psurveyPara->bsslimit = 48; */
 563        psurveyPara->scan_mode = pmlmepriv->scan_mode;
 564
 565        /* prepare ssid list */
 566        if (ssid) {
 567                int i;
 568
 569                for (i = 0; i < ssid_num && i < RTW_SSID_SCAN_AMOUNT; i++) {
 570                        if (ssid[i].SsidLength) {
 571                                memcpy(&psurveyPara->ssid[i], &ssid[i], sizeof(struct ndis_802_11_ssid));
 572                                psurveyPara->ssid_num++;
 573                        }
 574                }
 575        }
 576
 577        /* prepare channel list */
 578        if (ch) {
 579                int i;
 580
 581                for (i = 0; i < ch_num && i < RTW_CHANNEL_SCAN_AMOUNT; i++) {
 582                        if (ch[i].hw_value && !(ch[i].flags & RTW_IEEE80211_CHAN_DISABLED)) {
 583                                memcpy(&psurveyPara->ch[i], &ch[i], sizeof(struct rtw_ieee80211_channel));
 584                                psurveyPara->ch_num++;
 585                        }
 586                }
 587        }
 588
 589        set_fwstate(pmlmepriv, _FW_UNDER_SURVEY);
 590
 591        res = rtw_enqueue_cmd(pcmdpriv, ph2c);
 592
 593        if (res == _SUCCESS) {
 594
 595                pmlmepriv->scan_start_time = jiffies;
 596                _set_timer(&pmlmepriv->scan_to_timer, SCANNING_TIMEOUT);
 597        } else {
 598                _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
 599        }
 600        return res;
 601}
 602
 603u8 rtw_setdatarate_cmd(struct adapter *padapter, u8 *rateset)
 604{
 605        struct cmd_obj *ph2c;
 606        struct setdatarate_parm *pbsetdataratepara;
 607        struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
 608        u8 res = _SUCCESS;
 609
 610        ph2c = rtw_zmalloc(sizeof(struct cmd_obj));
 611        if (ph2c == NULL) {
 612                res = _FAIL;
 613                goto exit;
 614        }
 615
 616        pbsetdataratepara = rtw_zmalloc(sizeof(struct setdatarate_parm));
 617        if (pbsetdataratepara == NULL) {
 618                kfree(ph2c);
 619                res = _FAIL;
 620                goto exit;
 621        }
 622
 623        init_h2fwcmd_w_parm_no_rsp(ph2c, pbsetdataratepara, GEN_CMD_CODE(_SetDataRate));
 624        pbsetdataratepara->mac_id = 5;
 625        memcpy(pbsetdataratepara->datarates, rateset, NumRates);
 626
 627        res = rtw_enqueue_cmd(pcmdpriv, ph2c);
 628exit:
 629        return res;
 630}
 631
 632void rtw_getbbrfreg_cmdrsp_callback(struct adapter *padapter,  struct cmd_obj *pcmd)
 633{
 634        /* rtw_free_cmd_obj(pcmd); */
 635        kfree(pcmd->parmbuf);
 636        kfree(pcmd);
 637}
 638
 639u8 rtw_createbss_cmd(struct adapter  *padapter)
 640{
 641        struct cmd_obj *pcmd;
 642        struct cmd_priv                         *pcmdpriv = &padapter->cmdpriv;
 643        struct wlan_bssid_ex            *pdev_network = &padapter->registrypriv.dev_network;
 644        u8 res = _SUCCESS;
 645
 646        pcmd = rtw_zmalloc(sizeof(struct cmd_obj));
 647        if (pcmd == NULL) {
 648                res = _FAIL;
 649                goto exit;
 650        }
 651
 652        INIT_LIST_HEAD(&pcmd->list);
 653        pcmd->cmdcode = _CreateBss_CMD_;
 654        pcmd->parmbuf = (unsigned char *)pdev_network;
 655        pcmd->cmdsz = get_wlan_bssid_ex_sz((struct wlan_bssid_ex *)pdev_network);
 656        pcmd->rsp = NULL;
 657        pcmd->rspsz = 0;
 658
 659        pdev_network->Length = pcmd->cmdsz;
 660
 661        res = rtw_enqueue_cmd(pcmdpriv, pcmd);
 662
 663exit:
 664        return res;
 665}
 666
 667int rtw_startbss_cmd(struct adapter  *padapter, int flags)
 668{
 669        struct cmd_obj *pcmd;
 670        struct cmd_priv  *pcmdpriv = &padapter->cmdpriv;
 671        struct submit_ctx sctx;
 672        int res = _SUCCESS;
 673
 674        if (flags & RTW_CMDF_DIRECTLY) {
 675                /* no need to enqueue, do the cmd hdl directly and free cmd parameter */
 676                start_bss_network(padapter);
 677        } else {
 678                /* need enqueue, prepare cmd_obj and enqueue */
 679                pcmd = rtw_zmalloc(sizeof(struct cmd_obj));
 680                if (pcmd == NULL) {
 681                        res = _FAIL;
 682                        goto exit;
 683                }
 684
 685                INIT_LIST_HEAD(&pcmd->list);
 686                pcmd->cmdcode = GEN_CMD_CODE(_CreateBss);
 687                pcmd->parmbuf = NULL;
 688                pcmd->cmdsz =  0;
 689                pcmd->rsp = NULL;
 690                pcmd->rspsz = 0;
 691
 692                if (flags & RTW_CMDF_WAIT_ACK) {
 693                        pcmd->sctx = &sctx;
 694                        rtw_sctx_init(&sctx, 2000);
 695                }
 696
 697                res = rtw_enqueue_cmd(pcmdpriv, pcmd);
 698
 699                if (res == _SUCCESS && (flags & RTW_CMDF_WAIT_ACK)) {
 700                        rtw_sctx_wait(&sctx);
 701                        if (mutex_lock_interruptible(&pcmdpriv->sctx_mutex) == 0) {
 702                                if (sctx.status == RTW_SCTX_SUBMITTED)
 703                                        pcmd->sctx = NULL;
 704                                mutex_unlock(&pcmdpriv->sctx_mutex);
 705                        }
 706                }
 707        }
 708
 709exit:
 710        return res;
 711}
 712
 713u8 rtw_joinbss_cmd(struct adapter  *padapter, struct wlan_network *pnetwork)
 714{
 715        u8 res = _SUCCESS;
 716        uint    t_len = 0;
 717        struct wlan_bssid_ex            *psecnetwork;
 718        struct cmd_obj          *pcmd;
 719        struct cmd_priv         *pcmdpriv = &padapter->cmdpriv;
 720        struct mlme_priv        *pmlmepriv = &padapter->mlmepriv;
 721        struct qos_priv         *pqospriv = &pmlmepriv->qospriv;
 722        struct security_priv *psecuritypriv = &padapter->securitypriv;
 723        struct registry_priv *pregistrypriv = &padapter->registrypriv;
 724        struct ht_priv          *phtpriv = &pmlmepriv->htpriv;
 725        enum ndis_802_11_network_infrastructure ndis_network_mode = pnetwork->network.InfrastructureMode;
 726        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
 727        struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
 728        u32 tmp_len;
 729        u8 *ptmp = NULL;
 730
 731        pcmd = rtw_zmalloc(sizeof(struct cmd_obj));
 732        if (pcmd == NULL) {
 733                res = _FAIL;
 734                goto exit;
 735        }
 736        /* for IEs is fix buf size */
 737        t_len = sizeof(struct wlan_bssid_ex);
 738
 739
 740        /* for hidden ap to set fw_state here */
 741        if (check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE) != true) {
 742                switch (ndis_network_mode) {
 743                case Ndis802_11IBSS:
 744                        set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
 745                        break;
 746
 747                case Ndis802_11Infrastructure:
 748                        set_fwstate(pmlmepriv, WIFI_STATION_STATE);
 749                        break;
 750
 751                case Ndis802_11APMode:
 752                case Ndis802_11AutoUnknown:
 753                case Ndis802_11InfrastructureMax:
 754                        break;
 755
 756                }
 757        }
 758
 759        psecnetwork = (struct wlan_bssid_ex *)&psecuritypriv->sec_bss;
 760
 761        memset(psecnetwork, 0, t_len);
 762
 763        memcpy(psecnetwork, &pnetwork->network, get_wlan_bssid_ex_sz(&pnetwork->network));
 764
 765        psecuritypriv->authenticator_ie[0] = (unsigned char)psecnetwork->IELength;
 766
 767        if ((psecnetwork->IELength-12) < (256-1))
 768                memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], psecnetwork->IELength-12);
 769        else
 770                memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], (256-1));
 771
 772        psecnetwork->IELength = 0;
 773        /*  Added by Albert 2009/02/18 */
 774        /*  If the driver wants to use the bssid to create the connection. */
 775        /*  If not,  we have to copy the connecting AP's MAC address to it so that */
 776        /*  the driver just has the bssid information for PMKIDList searching. */
 777
 778        if (pmlmepriv->assoc_by_bssid == false)
 779                memcpy(&pmlmepriv->assoc_bssid[0], &pnetwork->network.MacAddress[0], ETH_ALEN);
 780
 781        psecnetwork->IELength = rtw_restruct_sec_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0], pnetwork->network.IELength);
 782
 783
 784        pqospriv->qos_option = 0;
 785
 786        if (pregistrypriv->wmm_enable) {
 787                tmp_len = rtw_restruct_wmm_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0], pnetwork->network.IELength, psecnetwork->IELength);
 788
 789                if (psecnetwork->IELength != tmp_len) {
 790                        psecnetwork->IELength = tmp_len;
 791                        pqospriv->qos_option = 1; /* There is WMM IE in this corresp. beacon */
 792                } else {
 793                        pqospriv->qos_option = 0;/* There is no WMM IE in this corresp. beacon */
 794                }
 795        }
 796
 797        phtpriv->ht_option = false;
 798        ptmp = rtw_get_ie(&pnetwork->network.IEs[12], WLAN_EID_HT_CAPABILITY, &tmp_len, pnetwork->network.IELength-12);
 799        if (pregistrypriv->ht_enable && ptmp && tmp_len > 0) {
 800                /*      Added by Albert 2010/06/23 */
 801                /*      For the WEP mode, we will use the bg mode to do the connection to avoid some IOT issue. */
 802                /*      Especially for Realtek 8192u SoftAP. */
 803                if ((padapter->securitypriv.dot11PrivacyAlgrthm != _WEP40_) &&
 804                        (padapter->securitypriv.dot11PrivacyAlgrthm != _WEP104_) &&
 805                        (padapter->securitypriv.dot11PrivacyAlgrthm != _TKIP_)) {
 806                        rtw_ht_use_default_setting(padapter);
 807
 808                        rtw_build_wmm_ie_ht(padapter, &psecnetwork->IEs[12], &psecnetwork->IELength);
 809
 810                        /* rtw_restructure_ht_ie */
 811                        rtw_restructure_ht_ie(padapter, &pnetwork->network.IEs[12], &psecnetwork->IEs[0],
 812                                                                        pnetwork->network.IELength-12, &psecnetwork->IELength,
 813                                                                        pnetwork->network.Configuration.DSConfig);
 814                }
 815        }
 816
 817        rtw_append_exented_cap(padapter, &psecnetwork->IEs[0], &psecnetwork->IELength);
 818
 819        pmlmeinfo->assoc_AP_vendor = check_assoc_AP(pnetwork->network.IEs, pnetwork->network.IELength);
 820
 821        pcmd->cmdsz = get_wlan_bssid_ex_sz(psecnetwork);/* get cmdsz before endian conversion */
 822
 823        INIT_LIST_HEAD(&pcmd->list);
 824        pcmd->cmdcode = _JoinBss_CMD_;/* GEN_CMD_CODE(_JoinBss) */
 825        pcmd->parmbuf = (unsigned char *)psecnetwork;
 826        pcmd->rsp = NULL;
 827        pcmd->rspsz = 0;
 828
 829        res = rtw_enqueue_cmd(pcmdpriv, pcmd);
 830
 831exit:
 832        return res;
 833}
 834
 835u8 rtw_disassoc_cmd(struct adapter *padapter, u32 deauth_timeout_ms, bool enqueue) /* for sta_mode */
 836{
 837        struct cmd_obj *cmdobj = NULL;
 838        struct disconnect_parm *param = NULL;
 839        struct cmd_priv *cmdpriv = &padapter->cmdpriv;
 840        u8 res = _SUCCESS;
 841
 842        /* prepare cmd parameter */
 843        param = rtw_zmalloc(sizeof(*param));
 844        if (param == NULL) {
 845                res = _FAIL;
 846                goto exit;
 847        }
 848        param->deauth_timeout_ms = deauth_timeout_ms;
 849
 850        if (enqueue) {
 851                /* need enqueue, prepare cmd_obj and enqueue */
 852                cmdobj = rtw_zmalloc(sizeof(*cmdobj));
 853                if (cmdobj == NULL) {
 854                        res = _FAIL;
 855                        kfree(param);
 856                        goto exit;
 857                }
 858                init_h2fwcmd_w_parm_no_rsp(cmdobj, param, _DisConnect_CMD_);
 859                res = rtw_enqueue_cmd(cmdpriv, cmdobj);
 860        } else {
 861                /* no need to enqueue, do the cmd hdl directly and free cmd parameter */
 862                if (disconnect_hdl(padapter, (u8 *)param) != H2C_SUCCESS)
 863                        res = _FAIL;
 864                kfree(param);
 865        }
 866
 867exit:
 868        return res;
 869}
 870
 871u8 rtw_setopmode_cmd(struct adapter  *padapter, enum ndis_802_11_network_infrastructure networktype, bool enqueue)
 872{
 873        struct  cmd_obj *ph2c;
 874        struct  setopmode_parm *psetop;
 875
 876        struct  cmd_priv   *pcmdpriv = &padapter->cmdpriv;
 877        u8 res = _SUCCESS;
 878
 879        psetop = rtw_zmalloc(sizeof(struct setopmode_parm));
 880
 881        if (psetop == NULL) {
 882                res = _FAIL;
 883                goto exit;
 884        }
 885        psetop->mode = (u8)networktype;
 886
 887        if (enqueue) {
 888                ph2c = rtw_zmalloc(sizeof(struct cmd_obj));
 889                if (ph2c == NULL) {
 890                        kfree(psetop);
 891                        res = _FAIL;
 892                        goto exit;
 893                }
 894
 895                init_h2fwcmd_w_parm_no_rsp(ph2c, psetop, _SetOpMode_CMD_);
 896                res = rtw_enqueue_cmd(pcmdpriv, ph2c);
 897        } else {
 898                setopmode_hdl(padapter, (u8 *)psetop);
 899                kfree(psetop);
 900        }
 901exit:
 902        return res;
 903}
 904
 905u8 rtw_setstakey_cmd(struct adapter *padapter, struct sta_info *sta, u8 unicast_key, bool enqueue)
 906{
 907        struct cmd_obj *ph2c;
 908        struct set_stakey_parm  *psetstakey_para;
 909        struct cmd_priv                         *pcmdpriv = &padapter->cmdpriv;
 910        struct set_stakey_rsp           *psetstakey_rsp = NULL;
 911
 912        struct mlme_priv                *pmlmepriv = &padapter->mlmepriv;
 913        struct security_priv    *psecuritypriv = &padapter->securitypriv;
 914        u8 res = _SUCCESS;
 915
 916        psetstakey_para = rtw_zmalloc(sizeof(struct set_stakey_parm));
 917        if (psetstakey_para == NULL) {
 918                res = _FAIL;
 919                goto exit;
 920        }
 921
 922        memcpy(psetstakey_para->addr, sta->hwaddr, ETH_ALEN);
 923
 924        if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
 925                psetstakey_para->algorithm = (unsigned char) psecuritypriv->dot11PrivacyAlgrthm;
 926        else
 927                GET_ENCRY_ALGO(psecuritypriv, sta, psetstakey_para->algorithm, false);
 928
 929        if (unicast_key == true)
 930                memcpy(&psetstakey_para->key, &sta->dot118021x_UncstKey, 16);
 931        else
 932                memcpy(&psetstakey_para->key, &psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey, 16);
 933
 934        /* jeff: set this because at least sw key is ready */
 935        padapter->securitypriv.busetkipkey = true;
 936
 937        if (enqueue) {
 938                ph2c = rtw_zmalloc(sizeof(struct cmd_obj));
 939                if (ph2c == NULL) {
 940                        kfree(psetstakey_para);
 941                        res = _FAIL;
 942                        goto exit;
 943                }
 944
 945                psetstakey_rsp = rtw_zmalloc(sizeof(struct set_stakey_rsp));
 946                if (psetstakey_rsp == NULL) {
 947                        kfree(ph2c);
 948                        kfree(psetstakey_para);
 949                        res = _FAIL;
 950                        goto exit;
 951                }
 952
 953                init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
 954                ph2c->rsp = (u8 *) psetstakey_rsp;
 955                ph2c->rspsz = sizeof(struct set_stakey_rsp);
 956                res = rtw_enqueue_cmd(pcmdpriv, ph2c);
 957        } else {
 958                set_stakey_hdl(padapter, (u8 *)psetstakey_para);
 959                kfree(psetstakey_para);
 960        }
 961exit:
 962        return res;
 963}
 964
 965u8 rtw_clearstakey_cmd(struct adapter *padapter, struct sta_info *sta, u8 enqueue)
 966{
 967        struct cmd_obj *ph2c;
 968        struct set_stakey_parm  *psetstakey_para;
 969        struct cmd_priv                         *pcmdpriv = &padapter->cmdpriv;
 970        struct set_stakey_rsp           *psetstakey_rsp = NULL;
 971        s16 cam_id = 0;
 972        u8 res = _SUCCESS;
 973
 974        if (!enqueue) {
 975                while ((cam_id = rtw_camid_search(padapter, sta->hwaddr, -1)) >= 0) {
 976                        netdev_dbg(padapter->pnetdev,
 977                                   "clear key for addr:%pM, camid:%d\n",
 978                                   MAC_ARG(sta->hwaddr), cam_id);
 979                        clear_cam_entry(padapter, cam_id);
 980                        rtw_camid_free(padapter, cam_id);
 981                }
 982        } else {
 983                ph2c = rtw_zmalloc(sizeof(struct cmd_obj));
 984                if (ph2c == NULL) {
 985                        res = _FAIL;
 986                        goto exit;
 987                }
 988
 989                psetstakey_para = rtw_zmalloc(sizeof(struct set_stakey_parm));
 990                if (psetstakey_para == NULL) {
 991                        kfree(ph2c);
 992                        res = _FAIL;
 993                        goto exit;
 994                }
 995
 996                psetstakey_rsp = rtw_zmalloc(sizeof(struct set_stakey_rsp));
 997                if (psetstakey_rsp == NULL) {
 998                        kfree(ph2c);
 999                        kfree(psetstakey_para);
1000                        res = _FAIL;
1001                        goto exit;
1002                }
1003
1004                init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
1005                ph2c->rsp = (u8 *) psetstakey_rsp;
1006                ph2c->rspsz = sizeof(struct set_stakey_rsp);
1007
1008                memcpy(psetstakey_para->addr, sta->hwaddr, ETH_ALEN);
1009
1010                psetstakey_para->algorithm = _NO_PRIVACY_;
1011
1012                res = rtw_enqueue_cmd(pcmdpriv, ph2c);
1013
1014        }
1015
1016exit:
1017        return res;
1018}
1019
1020u8 rtw_addbareq_cmd(struct adapter *padapter, u8 tid, u8 *addr)
1021{
1022        struct cmd_priv         *pcmdpriv = &padapter->cmdpriv;
1023        struct cmd_obj *ph2c;
1024        struct addBaReq_parm    *paddbareq_parm;
1025
1026        u8 res = _SUCCESS;
1027
1028        ph2c = rtw_zmalloc(sizeof(struct cmd_obj));
1029        if (ph2c == NULL) {
1030                res = _FAIL;
1031                goto exit;
1032        }
1033
1034        paddbareq_parm = rtw_zmalloc(sizeof(struct addBaReq_parm));
1035        if (paddbareq_parm == NULL) {
1036                kfree(ph2c);
1037                res = _FAIL;
1038                goto exit;
1039        }
1040
1041        paddbareq_parm->tid = tid;
1042        memcpy(paddbareq_parm->addr, addr, ETH_ALEN);
1043
1044        init_h2fwcmd_w_parm_no_rsp(ph2c, paddbareq_parm, GEN_CMD_CODE(_AddBAReq));
1045
1046        /* rtw_enqueue_cmd(pcmdpriv, ph2c); */
1047        res = rtw_enqueue_cmd(pcmdpriv, ph2c);
1048
1049exit:
1050        return res;
1051}
1052/* add for CONFIG_IEEE80211W, none 11w can use it */
1053u8 rtw_reset_securitypriv_cmd(struct adapter *padapter)
1054{
1055        struct cmd_obj *ph2c;
1056        struct drvextra_cmd_parm  *pdrvextra_cmd_parm;
1057        struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
1058        u8 res = _SUCCESS;
1059
1060        ph2c = rtw_zmalloc(sizeof(struct cmd_obj));
1061        if (ph2c == NULL) {
1062                res = _FAIL;
1063                goto exit;
1064        }
1065
1066        pdrvextra_cmd_parm = rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
1067        if (pdrvextra_cmd_parm == NULL) {
1068                kfree(ph2c);
1069                res = _FAIL;
1070                goto exit;
1071        }
1072
1073        pdrvextra_cmd_parm->ec_id = RESET_SECURITYPRIV;
1074        pdrvextra_cmd_parm->type = 0;
1075        pdrvextra_cmd_parm->size = 0;
1076        pdrvextra_cmd_parm->pbuf = NULL;
1077
1078        init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
1079
1080
1081        /* rtw_enqueue_cmd(pcmdpriv, ph2c); */
1082        res = rtw_enqueue_cmd(pcmdpriv, ph2c);
1083
1084exit:
1085        return res;
1086}
1087
1088u8 rtw_free_assoc_resources_cmd(struct adapter *padapter)
1089{
1090        struct cmd_obj *ph2c;
1091        struct drvextra_cmd_parm  *pdrvextra_cmd_parm;
1092        struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
1093        u8 res = _SUCCESS;
1094
1095        ph2c = rtw_zmalloc(sizeof(struct cmd_obj));
1096        if (ph2c == NULL) {
1097                res = _FAIL;
1098                goto exit;
1099        }
1100
1101        pdrvextra_cmd_parm = rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
1102        if (pdrvextra_cmd_parm == NULL) {
1103                kfree(ph2c);
1104                res = _FAIL;
1105                goto exit;
1106        }
1107
1108        pdrvextra_cmd_parm->ec_id = FREE_ASSOC_RESOURCES;
1109        pdrvextra_cmd_parm->type = 0;
1110        pdrvextra_cmd_parm->size = 0;
1111        pdrvextra_cmd_parm->pbuf = NULL;
1112
1113        init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
1114
1115
1116        /* rtw_enqueue_cmd(pcmdpriv, ph2c); */
1117        res = rtw_enqueue_cmd(pcmdpriv, ph2c);
1118
1119exit:
1120        return res;
1121}
1122
1123u8 rtw_dynamic_chk_wk_cmd(struct adapter *padapter)
1124{
1125        struct cmd_obj *ph2c;
1126        struct drvextra_cmd_parm  *pdrvextra_cmd_parm;
1127        struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
1128        u8 res = _SUCCESS;
1129
1130        /* only  primary padapter does this cmd */
1131        ph2c = rtw_zmalloc(sizeof(struct cmd_obj));
1132        if (ph2c == NULL) {
1133                res = _FAIL;
1134                goto exit;
1135        }
1136
1137        pdrvextra_cmd_parm = rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
1138        if (pdrvextra_cmd_parm == NULL) {
1139                kfree(ph2c);
1140                res = _FAIL;
1141                goto exit;
1142        }
1143
1144        pdrvextra_cmd_parm->ec_id = DYNAMIC_CHK_WK_CID;
1145        pdrvextra_cmd_parm->type = 0;
1146        pdrvextra_cmd_parm->size = 0;
1147        pdrvextra_cmd_parm->pbuf = NULL;
1148        init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
1149
1150
1151        /* rtw_enqueue_cmd(pcmdpriv, ph2c); */
1152        res = rtw_enqueue_cmd(pcmdpriv, ph2c);
1153
1154exit:
1155        return res;
1156}
1157
1158u8 rtw_set_chplan_cmd(struct adapter *padapter, u8 chplan, u8 enqueue, u8 swconfig)
1159{
1160        struct  cmd_obj *pcmdobj;
1161        struct  SetChannelPlan_param *setChannelPlan_param;
1162        struct  cmd_priv   *pcmdpriv = &padapter->cmdpriv;
1163
1164        u8 res = _SUCCESS;
1165
1166        /*  check if allow software config */
1167        if (swconfig && rtw_hal_is_disable_sw_channel_plan(padapter) == true) {
1168                res = _FAIL;
1169                goto exit;
1170        }
1171
1172        /* check input parameter */
1173        if (!rtw_is_channel_plan_valid(chplan)) {
1174                res = _FAIL;
1175                goto exit;
1176        }
1177
1178        /* prepare cmd parameter */
1179        setChannelPlan_param = rtw_zmalloc(sizeof(struct SetChannelPlan_param));
1180        if (setChannelPlan_param == NULL) {
1181                res = _FAIL;
1182                goto exit;
1183        }
1184        setChannelPlan_param->channel_plan = chplan;
1185
1186        if (enqueue) {
1187                /* need enqueue, prepare cmd_obj and enqueue */
1188                pcmdobj = rtw_zmalloc(sizeof(struct cmd_obj));
1189                if (pcmdobj == NULL) {
1190                        kfree(setChannelPlan_param);
1191                        res = _FAIL;
1192                        goto exit;
1193                }
1194
1195                init_h2fwcmd_w_parm_no_rsp(pcmdobj, setChannelPlan_param, GEN_CMD_CODE(_SetChannelPlan));
1196                res = rtw_enqueue_cmd(pcmdpriv, pcmdobj);
1197        } else {
1198                /* no need to enqueue, do the cmd hdl directly and free cmd parameter */
1199                if (set_chplan_hdl(padapter, (unsigned char *)setChannelPlan_param) != H2C_SUCCESS)
1200                        res = _FAIL;
1201
1202                kfree(setChannelPlan_param);
1203        }
1204
1205        /* do something based on res... */
1206        if (res == _SUCCESS)
1207                padapter->mlmepriv.ChannelPlan = chplan;
1208
1209exit:
1210        return res;
1211}
1212
1213static void collect_traffic_statistics(struct adapter *padapter)
1214{
1215        struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
1216
1217        /*  Tx */
1218        pdvobjpriv->traffic_stat.tx_bytes = padapter->xmitpriv.tx_bytes;
1219        pdvobjpriv->traffic_stat.tx_pkts = padapter->xmitpriv.tx_pkts;
1220        pdvobjpriv->traffic_stat.tx_drop = padapter->xmitpriv.tx_drop;
1221
1222        /*  Rx */
1223        pdvobjpriv->traffic_stat.rx_bytes = padapter->recvpriv.rx_bytes;
1224        pdvobjpriv->traffic_stat.rx_pkts = padapter->recvpriv.rx_pkts;
1225        pdvobjpriv->traffic_stat.rx_drop = padapter->recvpriv.rx_drop;
1226
1227        /*  Calculate throughput in last interval */
1228        pdvobjpriv->traffic_stat.cur_tx_bytes = pdvobjpriv->traffic_stat.tx_bytes - pdvobjpriv->traffic_stat.last_tx_bytes;
1229        pdvobjpriv->traffic_stat.cur_rx_bytes = pdvobjpriv->traffic_stat.rx_bytes - pdvobjpriv->traffic_stat.last_rx_bytes;
1230        pdvobjpriv->traffic_stat.last_tx_bytes = pdvobjpriv->traffic_stat.tx_bytes;
1231        pdvobjpriv->traffic_stat.last_rx_bytes = pdvobjpriv->traffic_stat.rx_bytes;
1232
1233        pdvobjpriv->traffic_stat.cur_tx_tp = (u32)(pdvobjpriv->traffic_stat.cur_tx_bytes * 8/2/1024/1024);
1234        pdvobjpriv->traffic_stat.cur_rx_tp = (u32)(pdvobjpriv->traffic_stat.cur_rx_bytes * 8/2/1024/1024);
1235}
1236
1237u8 traffic_status_watchdog(struct adapter *padapter, u8 from_timer)
1238{
1239        u8 bEnterPS = false;
1240        u16 BusyThresholdHigh = 25;
1241        u16 BusyThresholdLow = 10;
1242        u16 BusyThreshold = BusyThresholdHigh;
1243        u8 bBusyTraffic = false, bTxBusyTraffic = false, bRxBusyTraffic = false;
1244        u8 bHigherBusyTraffic = false, bHigherBusyRxTraffic = false, bHigherBusyTxTraffic = false;
1245
1246        struct mlme_priv        *pmlmepriv = &(padapter->mlmepriv);
1247
1248        collect_traffic_statistics(padapter);
1249
1250        /*  */
1251        /*  Determine if our traffic is busy now */
1252        /*  */
1253        if ((check_fwstate(pmlmepriv, _FW_LINKED) == true)
1254                /*&& !MgntInitAdapterInProgress(pMgntInfo)*/) {
1255                /*  if we raise bBusyTraffic in last watchdog, using lower threshold. */
1256                if (pmlmepriv->LinkDetectInfo.bBusyTraffic)
1257                                BusyThreshold = BusyThresholdLow;
1258
1259                if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > BusyThreshold ||
1260                        pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > BusyThreshold) {
1261                        bBusyTraffic = true;
1262
1263                        if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > pmlmepriv->LinkDetectInfo.NumTxOkInPeriod)
1264                                bRxBusyTraffic = true;
1265                        else
1266                                bTxBusyTraffic = true;
1267                }
1268
1269                /*  Higher Tx/Rx data. */
1270                if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > 4000 ||
1271                        pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > 4000) {
1272                        bHigherBusyTraffic = true;
1273
1274                        if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > pmlmepriv->LinkDetectInfo.NumTxOkInPeriod)
1275                                bHigherBusyRxTraffic = true;
1276                        else
1277                                bHigherBusyTxTraffic = true;
1278                }
1279
1280                /*  check traffic for  powersaving. */
1281                if (((pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod + pmlmepriv->LinkDetectInfo.NumTxOkInPeriod) > 8) ||
1282                        (pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod > 2)) {
1283                        bEnterPS = false;
1284
1285                        if (bBusyTraffic == true) {
1286                                if (pmlmepriv->LinkDetectInfo.TrafficTransitionCount <= 4)
1287                                        pmlmepriv->LinkDetectInfo.TrafficTransitionCount = 4;
1288
1289                                pmlmepriv->LinkDetectInfo.TrafficTransitionCount++;
1290
1291                                if (pmlmepriv->LinkDetectInfo.TrafficTransitionCount > 30/*TrafficTransitionLevel*/)
1292                                        pmlmepriv->LinkDetectInfo.TrafficTransitionCount = 30;
1293                        }
1294                } else {
1295                        if (pmlmepriv->LinkDetectInfo.TrafficTransitionCount >= 2)
1296                                pmlmepriv->LinkDetectInfo.TrafficTransitionCount -= 2;
1297                        else
1298                                pmlmepriv->LinkDetectInfo.TrafficTransitionCount = 0;
1299
1300                        if (pmlmepriv->LinkDetectInfo.TrafficTransitionCount == 0)
1301                                bEnterPS = true;
1302                }
1303
1304                /*  LeisurePS only work in infra mode. */
1305                if (bEnterPS) {
1306                        if (!from_timer)
1307                                LPS_Enter(padapter, "TRAFFIC_IDLE");
1308                } else {
1309                        if (!from_timer)
1310                                LPS_Leave(padapter, "TRAFFIC_BUSY");
1311                        else
1312                                rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_TRAFFIC_BUSY, 1);
1313                }
1314        } else {
1315                struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
1316                int n_assoc_iface = 0;
1317
1318                if (check_fwstate(&(dvobj->padapters->mlmepriv), WIFI_ASOC_STATE))
1319                        n_assoc_iface++;
1320
1321                if (!from_timer && n_assoc_iface == 0)
1322                        LPS_Leave(padapter, "NON_LINKED");
1323        }
1324
1325        pmlmepriv->LinkDetectInfo.NumRxOkInPeriod = 0;
1326        pmlmepriv->LinkDetectInfo.NumTxOkInPeriod = 0;
1327        pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod = 0;
1328        pmlmepriv->LinkDetectInfo.bBusyTraffic = bBusyTraffic;
1329        pmlmepriv->LinkDetectInfo.bTxBusyTraffic = bTxBusyTraffic;
1330        pmlmepriv->LinkDetectInfo.bRxBusyTraffic = bRxBusyTraffic;
1331        pmlmepriv->LinkDetectInfo.bHigherBusyTraffic = bHigherBusyTraffic;
1332        pmlmepriv->LinkDetectInfo.bHigherBusyRxTraffic = bHigherBusyRxTraffic;
1333        pmlmepriv->LinkDetectInfo.bHigherBusyTxTraffic = bHigherBusyTxTraffic;
1334
1335        return bEnterPS;
1336
1337}
1338
1339static void dynamic_chk_wk_hdl(struct adapter *padapter)
1340{
1341        struct mlme_priv *pmlmepriv;
1342
1343        pmlmepriv = &(padapter->mlmepriv);
1344
1345        if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true)
1346                expire_timeout_chk(padapter);
1347
1348        /* for debug purpose */
1349        _linked_info_dump(padapter);
1350
1351
1352        /* if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING|_FW_UNDER_SURVEY) ==false) */
1353        {
1354                linked_status_chk(padapter);
1355                traffic_status_watchdog(padapter, 0);
1356        }
1357
1358        rtw_hal_dm_watchdog(padapter);
1359
1360        /* check_hw_pbc(padapter, pdrvextra_cmd->pbuf, pdrvextra_cmd->type); */
1361
1362        /*  */
1363        /*  BT-Coexist */
1364        /*  */
1365        hal_btcoex_Handler(padapter);
1366
1367
1368        /* always call rtw_ps_processor() at last one. */
1369        if (is_primary_adapter(padapter))
1370                rtw_ps_processor(padapter);
1371}
1372
1373void lps_ctrl_wk_hdl(struct adapter *padapter, u8 lps_ctrl_type);
1374void lps_ctrl_wk_hdl(struct adapter *padapter, u8 lps_ctrl_type)
1375{
1376        struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
1377        struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
1378        u8 mstatus;
1379
1380        if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)
1381                || (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true)) {
1382                return;
1383        }
1384
1385        switch (lps_ctrl_type) {
1386        case LPS_CTRL_SCAN:
1387                hal_btcoex_ScanNotify(padapter, true);
1388
1389                if (check_fwstate(pmlmepriv, _FW_LINKED) == true) {
1390                        /*  connect */
1391                        LPS_Leave(padapter, "LPS_CTRL_SCAN");
1392                }
1393                break;
1394        case LPS_CTRL_JOINBSS:
1395                LPS_Leave(padapter, "LPS_CTRL_JOINBSS");
1396                break;
1397        case LPS_CTRL_CONNECT:
1398                mstatus = 1;/* connect */
1399                /*  Reset LPS Setting */
1400                pwrpriv->LpsIdleCount = 0;
1401                rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)(&mstatus));
1402                rtw_btcoex_MediaStatusNotify(padapter, mstatus);
1403                break;
1404        case LPS_CTRL_DISCONNECT:
1405                mstatus = 0;/* disconnect */
1406                rtw_btcoex_MediaStatusNotify(padapter, mstatus);
1407                LPS_Leave(padapter, "LPS_CTRL_DISCONNECT");
1408                rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)(&mstatus));
1409                break;
1410        case LPS_CTRL_SPECIAL_PACKET:
1411                pwrpriv->DelayLPSLastTimeStamp = jiffies;
1412                hal_btcoex_SpecialPacketNotify(padapter, PACKET_DHCP);
1413                LPS_Leave(padapter, "LPS_CTRL_SPECIAL_PACKET");
1414                break;
1415        case LPS_CTRL_LEAVE:
1416                LPS_Leave(padapter, "LPS_CTRL_LEAVE");
1417                break;
1418        case LPS_CTRL_TRAFFIC_BUSY:
1419                LPS_Leave(padapter, "LPS_CTRL_TRAFFIC_BUSY");
1420                break;
1421        default:
1422                break;
1423        }
1424}
1425
1426u8 rtw_lps_ctrl_wk_cmd(struct adapter *padapter, u8 lps_ctrl_type, u8 enqueue)
1427{
1428        struct cmd_obj  *ph2c;
1429        struct drvextra_cmd_parm        *pdrvextra_cmd_parm;
1430        struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
1431        /* struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter); */
1432        u8 res = _SUCCESS;
1433
1434        /* if (!pwrctrlpriv->bLeisurePs) */
1435        /*      return res; */
1436
1437        if (enqueue) {
1438                ph2c = rtw_zmalloc(sizeof(struct cmd_obj));
1439                if (ph2c == NULL) {
1440                        res = _FAIL;
1441                        goto exit;
1442                }
1443
1444                pdrvextra_cmd_parm = rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
1445                if (pdrvextra_cmd_parm == NULL) {
1446                        kfree(ph2c);
1447                        res = _FAIL;
1448                        goto exit;
1449                }
1450
1451                pdrvextra_cmd_parm->ec_id = LPS_CTRL_WK_CID;
1452                pdrvextra_cmd_parm->type = lps_ctrl_type;
1453                pdrvextra_cmd_parm->size = 0;
1454                pdrvextra_cmd_parm->pbuf = NULL;
1455
1456                init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
1457
1458                res = rtw_enqueue_cmd(pcmdpriv, ph2c);
1459        } else {
1460                lps_ctrl_wk_hdl(padapter, lps_ctrl_type);
1461        }
1462
1463exit:
1464        return res;
1465}
1466
1467static void rtw_dm_in_lps_hdl(struct adapter *padapter)
1468{
1469        rtw_hal_set_hwreg(padapter, HW_VAR_DM_IN_LPS, NULL);
1470}
1471
1472u8 rtw_dm_in_lps_wk_cmd(struct adapter *padapter)
1473{
1474        struct cmd_obj  *ph2c;
1475        struct drvextra_cmd_parm        *pdrvextra_cmd_parm;
1476        struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
1477        u8 res = _SUCCESS;
1478
1479
1480        ph2c = rtw_zmalloc(sizeof(struct cmd_obj));
1481        if (ph2c == NULL) {
1482                res = _FAIL;
1483                goto exit;
1484        }
1485
1486        pdrvextra_cmd_parm = rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
1487        if (pdrvextra_cmd_parm == NULL) {
1488                kfree(ph2c);
1489                res = _FAIL;
1490                goto exit;
1491        }
1492
1493        pdrvextra_cmd_parm->ec_id = DM_IN_LPS_WK_CID;
1494        pdrvextra_cmd_parm->type = 0;
1495        pdrvextra_cmd_parm->size = 0;
1496        pdrvextra_cmd_parm->pbuf = NULL;
1497
1498        init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
1499
1500        res = rtw_enqueue_cmd(pcmdpriv, ph2c);
1501
1502exit:
1503
1504        return res;
1505
1506}
1507
1508static void rtw_lps_change_dtim_hdl(struct adapter *padapter, u8 dtim)
1509{
1510        struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
1511
1512        if (dtim <= 0 || dtim > 16)
1513                return;
1514
1515        if (hal_btcoex_IsBtControlLps(padapter) == true)
1516                return;
1517
1518        mutex_lock(&pwrpriv->lock);
1519
1520        if (pwrpriv->dtim != dtim)
1521                pwrpriv->dtim = dtim;
1522
1523        if (pwrpriv->fw_current_in_ps_mode && (pwrpriv->pwr_mode > PS_MODE_ACTIVE)) {
1524                u8 ps_mode = pwrpriv->pwr_mode;
1525
1526                rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode));
1527        }
1528
1529        mutex_unlock(&pwrpriv->lock);
1530}
1531
1532static void rtw_dm_ra_mask_hdl(struct adapter *padapter, struct sta_info *psta)
1533{
1534        if (psta)
1535                set_sta_rate(padapter, psta);
1536}
1537
1538u8 rtw_dm_ra_mask_wk_cmd(struct adapter *padapter, u8 *psta)
1539{
1540        struct cmd_obj  *ph2c;
1541        struct drvextra_cmd_parm        *pdrvextra_cmd_parm;
1542        struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
1543        u8 res = _SUCCESS;
1544
1545
1546        ph2c = rtw_zmalloc(sizeof(struct cmd_obj));
1547        if (ph2c == NULL) {
1548                res = _FAIL;
1549                goto exit;
1550        }
1551
1552        pdrvextra_cmd_parm = rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
1553        if (pdrvextra_cmd_parm == NULL) {
1554                kfree(ph2c);
1555                res = _FAIL;
1556                goto exit;
1557        }
1558
1559        pdrvextra_cmd_parm->ec_id = DM_RA_MSK_WK_CID;
1560        pdrvextra_cmd_parm->type = 0;
1561        pdrvextra_cmd_parm->size = 0;
1562        pdrvextra_cmd_parm->pbuf = psta;
1563
1564        init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
1565
1566        res = rtw_enqueue_cmd(pcmdpriv, ph2c);
1567
1568exit:
1569
1570        return res;
1571
1572}
1573
1574u8 rtw_ps_cmd(struct adapter *padapter)
1575{
1576        struct cmd_obj          *ppscmd;
1577        struct drvextra_cmd_parm        *pdrvextra_cmd_parm;
1578        struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
1579        u8 res = _SUCCESS;
1580
1581        ppscmd = rtw_zmalloc(sizeof(struct cmd_obj));
1582        if (ppscmd == NULL) {
1583                res = _FAIL;
1584                goto exit;
1585        }
1586
1587        pdrvextra_cmd_parm = rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
1588        if (pdrvextra_cmd_parm == NULL) {
1589                kfree(ppscmd);
1590                res = _FAIL;
1591                goto exit;
1592        }
1593
1594        pdrvextra_cmd_parm->ec_id = POWER_SAVING_CTRL_WK_CID;
1595        pdrvextra_cmd_parm->type = 0;
1596        pdrvextra_cmd_parm->size = 0;
1597        pdrvextra_cmd_parm->pbuf = NULL;
1598        init_h2fwcmd_w_parm_no_rsp(ppscmd, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
1599
1600        res = rtw_enqueue_cmd(pcmdpriv, ppscmd);
1601
1602exit:
1603        return res;
1604}
1605
1606u32 g_wait_hiq_empty;
1607
1608static void rtw_chk_hi_queue_hdl(struct adapter *padapter)
1609{
1610        struct sta_info *psta_bmc;
1611        struct sta_priv *pstapriv = &padapter->stapriv;
1612        unsigned long start = jiffies;
1613        u8 empty = false;
1614
1615        psta_bmc = rtw_get_bcmc_stainfo(padapter);
1616        if (!psta_bmc)
1617                return;
1618
1619        rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &empty);
1620
1621        while (false == empty && jiffies_to_msecs(jiffies - start) < g_wait_hiq_empty) {
1622                msleep(100);
1623                rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &empty);
1624        }
1625
1626        if (psta_bmc->sleepq_len == 0) {
1627                if (empty == _SUCCESS) {
1628                        bool update_tim = false;
1629
1630                        if (pstapriv->tim_bitmap & BIT(0))
1631                                update_tim = true;
1632
1633                        pstapriv->tim_bitmap &= ~BIT(0);
1634                        pstapriv->sta_dz_bitmap &= ~BIT(0);
1635
1636                        if (update_tim)
1637                                update_beacon(padapter, WLAN_EID_TIM, NULL, true);
1638                } else {/* re check again */
1639                        rtw_chk_hi_queue_cmd(padapter);
1640                }
1641
1642        }
1643
1644}
1645
1646u8 rtw_chk_hi_queue_cmd(struct adapter *padapter)
1647{
1648        struct cmd_obj  *ph2c;
1649        struct drvextra_cmd_parm        *pdrvextra_cmd_parm;
1650        struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
1651        u8 res = _SUCCESS;
1652
1653        ph2c = rtw_zmalloc(sizeof(struct cmd_obj));
1654        if (ph2c == NULL) {
1655                res = _FAIL;
1656                goto exit;
1657        }
1658
1659        pdrvextra_cmd_parm = rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
1660        if (pdrvextra_cmd_parm == NULL) {
1661                kfree(ph2c);
1662                res = _FAIL;
1663                goto exit;
1664        }
1665
1666        pdrvextra_cmd_parm->ec_id = CHECK_HIQ_WK_CID;
1667        pdrvextra_cmd_parm->type = 0;
1668        pdrvextra_cmd_parm->size = 0;
1669        pdrvextra_cmd_parm->pbuf = NULL;
1670
1671        init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
1672
1673        res = rtw_enqueue_cmd(pcmdpriv, ph2c);
1674
1675exit:
1676
1677        return res;
1678
1679}
1680
1681struct btinfo {
1682        u8 cid;
1683        u8 len;
1684
1685        u8 bConnection:1;
1686        u8 bSCOeSCO:1;
1687        u8 bInQPage:1;
1688        u8 bACLBusy:1;
1689        u8 bSCOBusy:1;
1690        u8 bHID:1;
1691        u8 bA2DP:1;
1692        u8 bFTP:1;
1693
1694        u8 retry_cnt:4;
1695        u8 rsvd_34:1;
1696        u8 rsvd_35:1;
1697        u8 rsvd_36:1;
1698        u8 rsvd_37:1;
1699
1700        u8 rssi;
1701
1702        u8 rsvd_50:1;
1703        u8 rsvd_51:1;
1704        u8 rsvd_52:1;
1705        u8 rsvd_53:1;
1706        u8 rsvd_54:1;
1707        u8 rsvd_55:1;
1708        u8 eSCO_SCO:1;
1709        u8 Master_Slave:1;
1710
1711        u8 rsvd_6;
1712        u8 rsvd_7;
1713};
1714
1715static void rtw_btinfo_hdl(struct adapter *adapter, u8 *buf, u16 buf_len)
1716{
1717        #define BTINFO_WIFI_FETCH 0x23
1718        #define BTINFO_BT_AUTO_RPT 0x27
1719        struct btinfo *info = (struct btinfo *)buf;
1720        u8 cmd_idx;
1721        u8 len;
1722
1723        cmd_idx = info->cid;
1724
1725        if (info->len > buf_len-2) {
1726                rtw_warn_on(1);
1727                len = buf_len-2;
1728        } else {
1729                len = info->len;
1730        }
1731
1732        /* transform BT-FW btinfo to WiFI-FW C2H format and notify */
1733        if (cmd_idx == BTINFO_WIFI_FETCH)
1734                buf[1] = 0;
1735        else if (cmd_idx == BTINFO_BT_AUTO_RPT)
1736                buf[1] = 2;
1737        hal_btcoex_BtInfoNotify(adapter, len+1, &buf[1]);
1738}
1739
1740u8 rtw_c2h_packet_wk_cmd(struct adapter *padapter, u8 *pbuf, u16 length)
1741{
1742        struct cmd_obj *ph2c;
1743        struct drvextra_cmd_parm *pdrvextra_cmd_parm;
1744        struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
1745        u8 res = _SUCCESS;
1746
1747        ph2c = rtw_zmalloc(sizeof(struct cmd_obj));
1748        if (ph2c == NULL) {
1749                res = _FAIL;
1750                goto exit;
1751        }
1752
1753        pdrvextra_cmd_parm = rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
1754        if (pdrvextra_cmd_parm == NULL) {
1755                kfree(ph2c);
1756                res = _FAIL;
1757                goto exit;
1758        }
1759
1760        pdrvextra_cmd_parm->ec_id = C2H_WK_CID;
1761        pdrvextra_cmd_parm->type = 0;
1762        pdrvextra_cmd_parm->size = length;
1763        pdrvextra_cmd_parm->pbuf = pbuf;
1764
1765        init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
1766
1767        res = rtw_enqueue_cmd(pcmdpriv, ph2c);
1768
1769exit:
1770        return res;
1771}
1772
1773/* dont call R/W in this function, beucase SDIO interrupt have claim host */
1774/* or deadlock will happen and cause special-systemserver-died in android */
1775u8 rtw_c2h_wk_cmd(struct adapter *padapter, u8 *c2h_evt)
1776{
1777        struct cmd_obj *ph2c;
1778        struct drvextra_cmd_parm *pdrvextra_cmd_parm;
1779        struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
1780        u8 res = _SUCCESS;
1781
1782        ph2c = rtw_zmalloc(sizeof(struct cmd_obj));
1783        if (ph2c == NULL) {
1784                res = _FAIL;
1785                goto exit;
1786        }
1787
1788        pdrvextra_cmd_parm = rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
1789        if (pdrvextra_cmd_parm == NULL) {
1790                kfree(ph2c);
1791                res = _FAIL;
1792                goto exit;
1793        }
1794
1795        pdrvextra_cmd_parm->ec_id = C2H_WK_CID;
1796        pdrvextra_cmd_parm->type = 0;
1797        pdrvextra_cmd_parm->size =  c2h_evt?16:0;
1798        pdrvextra_cmd_parm->pbuf = c2h_evt;
1799
1800        init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
1801
1802        res = rtw_enqueue_cmd(pcmdpriv, ph2c);
1803
1804exit:
1805
1806        return res;
1807}
1808
1809static void c2h_wk_callback(struct work_struct *work)
1810{
1811        struct evt_priv *evtpriv = container_of(work, struct evt_priv, c2h_wk);
1812        struct adapter *adapter = container_of(evtpriv, struct adapter, evtpriv);
1813        u8 *c2h_evt;
1814        c2h_id_filter ccx_id_filter = rtw_hal_c2h_id_filter_ccx(adapter);
1815
1816        evtpriv->c2h_wk_alive = true;
1817
1818        while (!rtw_cbuf_empty(evtpriv->c2h_queue)) {
1819                c2h_evt = (u8 *)rtw_cbuf_pop(evtpriv->c2h_queue);
1820                if (c2h_evt) {
1821                        /* This C2H event is read, clear it */
1822                        c2h_evt_clear(adapter);
1823                } else {
1824                        c2h_evt = rtw_malloc(16);
1825                        if (c2h_evt) {
1826                                /* This C2H event is not read, read & clear now */
1827                                if (c2h_evt_read_88xx(adapter, c2h_evt) != _SUCCESS) {
1828                                        kfree(c2h_evt);
1829                                        continue;
1830                                }
1831                        }
1832                }
1833
1834                /* Special pointer to trigger c2h_evt_clear only */
1835                if ((void *)c2h_evt == (void *)evtpriv)
1836                        continue;
1837
1838                if (!rtw_hal_c2h_valid(adapter, c2h_evt)) {
1839                        kfree(c2h_evt);
1840                        continue;
1841                }
1842
1843                if (ccx_id_filter(c2h_evt) == true) {
1844                        /* Handle CCX report here */
1845                        rtw_hal_c2h_handler(adapter, c2h_evt);
1846                        kfree(c2h_evt);
1847                } else {
1848                        /* Enqueue into cmd_thread for others */
1849                        rtw_c2h_wk_cmd(adapter, c2h_evt);
1850                }
1851        }
1852
1853        evtpriv->c2h_wk_alive = false;
1854}
1855
1856u8 rtw_drvextra_cmd_hdl(struct adapter *padapter, unsigned char *pbuf)
1857{
1858        struct drvextra_cmd_parm *pdrvextra_cmd;
1859
1860        if (!pbuf)
1861                return H2C_PARAMETERS_ERROR;
1862
1863        pdrvextra_cmd = (struct drvextra_cmd_parm *)pbuf;
1864
1865        switch (pdrvextra_cmd->ec_id) {
1866        case DYNAMIC_CHK_WK_CID:/* only  primary padapter go to this cmd, but execute dynamic_chk_wk_hdl() for two interfaces */
1867                dynamic_chk_wk_hdl(padapter);
1868                break;
1869        case POWER_SAVING_CTRL_WK_CID:
1870                rtw_ps_processor(padapter);
1871                break;
1872        case LPS_CTRL_WK_CID:
1873                lps_ctrl_wk_hdl(padapter, (u8)pdrvextra_cmd->type);
1874                break;
1875        case DM_IN_LPS_WK_CID:
1876                rtw_dm_in_lps_hdl(padapter);
1877                break;
1878        case LPS_CHANGE_DTIM_CID:
1879                rtw_lps_change_dtim_hdl(padapter, (u8)pdrvextra_cmd->type);
1880                break;
1881        case CHECK_HIQ_WK_CID:
1882                rtw_chk_hi_queue_hdl(padapter);
1883                break;
1884        /* add for CONFIG_IEEE80211W, none 11w can use it */
1885        case RESET_SECURITYPRIV:
1886                rtw_reset_securitypriv(padapter);
1887                break;
1888        case FREE_ASSOC_RESOURCES:
1889                rtw_free_assoc_resources(padapter, 1);
1890                break;
1891        case C2H_WK_CID:
1892                rtw_hal_set_hwreg_with_buf(padapter, HW_VAR_C2H_HANDLE, pdrvextra_cmd->pbuf, pdrvextra_cmd->size);
1893                break;
1894        case DM_RA_MSK_WK_CID:
1895                rtw_dm_ra_mask_hdl(padapter, (struct sta_info *)pdrvextra_cmd->pbuf);
1896                break;
1897        case BTINFO_WK_CID:
1898                rtw_btinfo_hdl(padapter, pdrvextra_cmd->pbuf, pdrvextra_cmd->size);
1899                break;
1900        default:
1901                break;
1902        }
1903
1904        if (pdrvextra_cmd->pbuf && pdrvextra_cmd->size > 0)
1905                kfree(pdrvextra_cmd->pbuf);
1906
1907        return H2C_SUCCESS;
1908}
1909
1910void rtw_survey_cmd_callback(struct adapter *padapter,  struct cmd_obj *pcmd)
1911{
1912        struct  mlme_priv *pmlmepriv = &padapter->mlmepriv;
1913
1914        if (pcmd->res == H2C_DROPPED) {
1915                /* TODO: cancel timer and do timeout handler directly... */
1916                /* need to make timeout handlerOS independent */
1917                _set_timer(&pmlmepriv->scan_to_timer, 1);
1918        } else if (pcmd->res != H2C_SUCCESS) {
1919                _set_timer(&pmlmepriv->scan_to_timer, 1);
1920        }
1921
1922        /*  free cmd */
1923        rtw_free_cmd_obj(pcmd);
1924}
1925
1926void rtw_disassoc_cmd_callback(struct adapter *padapter,  struct cmd_obj *pcmd)
1927{
1928        struct  mlme_priv *pmlmepriv = &padapter->mlmepriv;
1929
1930        if (pcmd->res != H2C_SUCCESS) {
1931                spin_lock_bh(&pmlmepriv->lock);
1932                set_fwstate(pmlmepriv, _FW_LINKED);
1933                spin_unlock_bh(&pmlmepriv->lock);
1934
1935                return;
1936        }
1937        /*  free cmd */
1938        rtw_free_cmd_obj(pcmd);
1939}
1940
1941void rtw_joinbss_cmd_callback(struct adapter *padapter,  struct cmd_obj *pcmd)
1942{
1943        struct  mlme_priv *pmlmepriv = &padapter->mlmepriv;
1944
1945        if (pcmd->res == H2C_DROPPED) {
1946                /* TODO: cancel timer and do timeout handler directly... */
1947                /* need to make timeout handlerOS independent */
1948                _set_timer(&pmlmepriv->assoc_timer, 1);
1949        } else if (pcmd->res != H2C_SUCCESS) {
1950                _set_timer(&pmlmepriv->assoc_timer, 1);
1951        }
1952
1953        rtw_free_cmd_obj(pcmd);
1954}
1955
1956void rtw_createbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
1957{
1958        struct sta_info *psta = NULL;
1959        struct wlan_network *pwlan = NULL;
1960        struct  mlme_priv *pmlmepriv = &padapter->mlmepriv;
1961        struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)pcmd->parmbuf;
1962        struct wlan_network *tgt_network = &(pmlmepriv->cur_network);
1963
1964        if (pcmd->parmbuf == NULL)
1965                goto exit;
1966
1967        if (pcmd->res != H2C_SUCCESS)
1968                _set_timer(&pmlmepriv->assoc_timer, 1);
1969
1970        del_timer_sync(&pmlmepriv->assoc_timer);
1971
1972        spin_lock_bh(&pmlmepriv->lock);
1973
1974
1975        if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
1976                psta = rtw_get_stainfo(&padapter->stapriv, pnetwork->MacAddress);
1977                if (!psta) {
1978                        psta = rtw_alloc_stainfo(&padapter->stapriv, pnetwork->MacAddress);
1979                        if (!psta)
1980                                goto createbss_cmd_fail;
1981                }
1982
1983                rtw_indicate_connect(padapter);
1984        } else {
1985                pwlan = rtw_alloc_network(pmlmepriv);
1986                spin_lock_bh(&(pmlmepriv->scanned_queue.lock));
1987                if (pwlan == NULL) {
1988                        pwlan = rtw_get_oldest_wlan_network(&pmlmepriv->scanned_queue);
1989                        if (pwlan == NULL) {
1990                                spin_unlock_bh(&(pmlmepriv->scanned_queue.lock));
1991                                goto createbss_cmd_fail;
1992                        }
1993                        pwlan->last_scanned = jiffies;
1994                } else {
1995                        list_add_tail(&(pwlan->list), &pmlmepriv->scanned_queue.queue);
1996                }
1997
1998                pnetwork->Length = get_wlan_bssid_ex_sz(pnetwork);
1999                memcpy(&(pwlan->network), pnetwork, pnetwork->Length);
2000                /* pwlan->fixed = true; */
2001
2002                /* list_add_tail(&(pwlan->list), &pmlmepriv->scanned_queue.queue); */
2003
2004                /*  copy pdev_network information to    pmlmepriv->cur_network */
2005                memcpy(&tgt_network->network, pnetwork, (get_wlan_bssid_ex_sz(pnetwork)));
2006
2007                /*  reset DSConfig */
2008                /* tgt_network->network.Configuration.DSConfig = (u32)rtw_ch2freq(pnetwork->Configuration.DSConfig); */
2009
2010                _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
2011
2012                spin_unlock_bh(&(pmlmepriv->scanned_queue.lock));
2013                /*  we will set _FW_LINKED when there is one more sat to join us (rtw_stassoc_event_callback) */
2014
2015        }
2016
2017createbss_cmd_fail:
2018
2019        spin_unlock_bh(&pmlmepriv->lock);
2020exit:
2021        rtw_free_cmd_obj(pcmd);
2022}
2023
2024
2025
2026void rtw_setstaKey_cmdrsp_callback(struct adapter *padapter,  struct cmd_obj *pcmd)
2027{
2028
2029        struct sta_priv *pstapriv = &padapter->stapriv;
2030        struct set_stakey_rsp *psetstakey_rsp = (struct set_stakey_rsp *) (pcmd->rsp);
2031        struct sta_info *psta = rtw_get_stainfo(pstapriv, psetstakey_rsp->addr);
2032
2033        if (!psta)
2034                goto exit;
2035
2036exit:
2037        rtw_free_cmd_obj(pcmd);
2038}
2039
2040void rtw_setassocsta_cmdrsp_callback(struct adapter *padapter,  struct cmd_obj *pcmd)
2041{
2042        struct sta_priv *pstapriv = &padapter->stapriv;
2043        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
2044        struct set_assocsta_parm *passocsta_parm = (struct set_assocsta_parm *)(pcmd->parmbuf);
2045        struct set_assocsta_rsp *passocsta_rsp = (struct set_assocsta_rsp *) (pcmd->rsp);
2046        struct sta_info *psta = rtw_get_stainfo(pstapriv, passocsta_parm->addr);
2047
2048        if (!psta)
2049                goto exit;
2050
2051        psta->aid = passocsta_rsp->cam_id;
2052        psta->mac_id = passocsta_rsp->cam_id;
2053
2054        spin_lock_bh(&pmlmepriv->lock);
2055
2056        if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) && (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true))
2057                _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
2058
2059        set_fwstate(pmlmepriv, _FW_LINKED);
2060        spin_unlock_bh(&pmlmepriv->lock);
2061
2062exit:
2063        rtw_free_cmd_obj(pcmd);
2064}
2065