linux/drivers/staging/rtl8192u/r819xU_cmdpkt.c
<<
>>
Prefs
   1/******************************************************************************
   2 *
   3 *  (c) Copyright 2008, RealTEK Technologies Inc. All Rights Reserved.
   4 *
   5 *  Module:     r819xusb_cmdpkt.c
   6 *              (RTL8190 TX/RX command packet handler Source C File)
   7 *
   8 *  Note:       The module is responsible for handling TX and RX command packet.
   9 *              1. TX : Send set and query configuration command packet.
  10 *              2. RX : Receive tx feedback, beacon state, query configuration
  11 *                      command packet.
  12 *
  13 *  Function:
  14 *
  15 *  Export:
  16 *
  17 *  Abbrev:
  18 *
  19 *  History:
  20 *
  21 *      Date            Who             Remark
  22 *      05/06/2008      amy             Create initial version porting from
  23 *                                      windows driver.
  24 *
  25 ******************************************************************************/
  26#include "r8192U.h"
  27#include "r819xU_cmdpkt.h"
  28
  29rt_status SendTxCommandPacket(struct net_device *dev, void *pData, u32 DataLen)
  30{
  31        rt_status       rtStatus = RT_STATUS_SUCCESS;
  32        struct r8192_priv   *priv = ieee80211_priv(dev);
  33        struct sk_buff      *skb;
  34        cb_desc             *tcb_desc;
  35        unsigned char       *ptr_buf;
  36
  37        /* Get TCB and local buffer from common pool.
  38           (It is shared by CmdQ, MgntQ, and USB coalesce DataQ) */
  39        skb  = dev_alloc_skb(USB_HWDESC_HEADER_LEN + DataLen + 4);
  40        if (!skb)
  41                return RT_STATUS_FAILURE;
  42        memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev));
  43        tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
  44        tcb_desc->queue_index = TXCMD_QUEUE;
  45        tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_NORMAL;
  46        tcb_desc->bLastIniPkt = 0;
  47        skb_reserve(skb, USB_HWDESC_HEADER_LEN);
  48        ptr_buf = skb_put(skb, DataLen);
  49        memcpy(ptr_buf, pData, DataLen);
  50        tcb_desc->txbuf_size = (u16)DataLen;
  51
  52        if (!priv->ieee80211->check_nic_enough_desc(dev, tcb_desc->queue_index) ||
  53            (!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index])) ||
  54            (priv->ieee80211->queue_stop)) {
  55                RT_TRACE(COMP_FIRMWARE, "=== NULL packet ======> tx full!\n");
  56                skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb);
  57        } else {
  58                priv->ieee80211->softmac_hard_start_xmit(skb, dev);
  59        }
  60
  61        return rtStatus;
  62}
  63
  64/*-----------------------------------------------------------------------------
  65 * Function:    cmpk_message_handle_tx()
  66 *
  67 * Overview:    Driver internal module can call the API to send message to
  68 *              firmware side. For example, you can send a debug command packet.
  69 *              Or you can send a request for FW to modify RLX4181 LBUS HW bank.
  70 *              Otherwise, you can change MAC/PHT/RF register by firmware at
  71 *              run time. We do not support message more than one segment now.
  72 *
  73 * Input:       NONE
  74 *
  75 * Output:      NONE
  76 *
  77 * Return:      NONE
  78 *
  79 * Revised History:
  80 *      When            Who             Remark
  81 *      05/06/2008      amy             porting from windows code.
  82 *
  83 *---------------------------------------------------------------------------*/
  84extern rt_status cmpk_message_handle_tx(struct net_device *dev,
  85                                        u8 *codevirtualaddress,
  86                                        u32 packettype, u32 buffer_len)
  87{
  88
  89        bool        rt_status = true;
  90#ifdef RTL8192U
  91        return rt_status;
  92#else
  93        struct r8192_priv   *priv = ieee80211_priv(dev);
  94        u16                 frag_threshold;
  95        u16                 frag_length, frag_offset = 0;
  96
  97        rt_firmware         *pfirmware = priv->pFirmware;
  98        struct sk_buff      *skb;
  99        unsigned char       *seg_ptr;
 100        cb_desc             *tcb_desc;
 101        u8                  bLastIniPkt;
 102
 103        firmware_init_param(dev);
 104        /* Fragmentation might be required */
 105        frag_threshold = pfirmware->cmdpacket_frag_thresold;
 106        do {
 107                if ((buffer_len - frag_offset) > frag_threshold) {
 108                        frag_length = frag_threshold;
 109                        bLastIniPkt = 0;
 110
 111                } else {
 112                        frag_length = buffer_len - frag_offset;
 113                        bLastIniPkt = 1;
 114
 115                }
 116
 117                /* Allocate skb buffer to contain firmware info and tx
 118                   descriptor info add 4 to avoid packet appending overflow. */
 119#ifdef RTL8192U
 120                skb  = dev_alloc_skb(USB_HWDESC_HEADER_LEN + frag_length + 4);
 121#else
 122                skb  = dev_alloc_skb(frag_length + 4);
 123#endif
 124                memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev));
 125                tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
 126                tcb_desc->queue_index = TXCMD_QUEUE;
 127                tcb_desc->bCmdOrInit = packettype;
 128                tcb_desc->bLastIniPkt = bLastIniPkt;
 129
 130#ifdef RTL8192U
 131                skb_reserve(skb, USB_HWDESC_HEADER_LEN);
 132#endif
 133
 134                seg_ptr = skb_put(skb, buffer_len);
 135                /*
 136                 * Transform from little endian to big endian
 137                 * and pending zero
 138                 */
 139                memcpy(seg_ptr, codevirtualaddress, buffer_len);
 140                tcb_desc->txbuf_size = (u16)buffer_len;
 141
 142
 143                if (!priv->ieee80211->check_nic_enough_desc(dev, tcb_desc->queue_index) ||
 144                    (!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index])) ||
 145                    (priv->ieee80211->queue_stop)) {
 146                        RT_TRACE(COMP_FIRMWARE, "======> tx full!\n");
 147                        skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb);
 148                } else {
 149                        priv->ieee80211->softmac_hard_start_xmit(skb, dev);
 150                }
 151
 152                codevirtualaddress += frag_length;
 153                frag_offset += frag_length;
 154
 155        } while (frag_offset < buffer_len);
 156
 157        return rt_status;
 158
 159
 160#endif
 161}
 162
 163/*-----------------------------------------------------------------------------
 164 * Function:    cmpk_counttxstatistic()
 165 *
 166 * Overview:
 167 *
 168 * Input:       PADAPTER        pAdapter
 169 *              CMPK_TXFB_T     *psTx_FB
 170 *
 171 * Output:      NONE
 172 *
 173 * Return:      NONE
 174 *
 175 * Revised History:
 176 *  When                Who     Remark
 177 *  05/12/2008          amy     Create Version 0 porting from windows code.
 178 *
 179 *---------------------------------------------------------------------------*/
 180static void cmpk_count_txstatistic(struct net_device *dev, cmpk_txfb_t *pstx_fb)
 181{
 182        struct r8192_priv *priv = ieee80211_priv(dev);
 183#ifdef ENABLE_PS
 184        RT_RF_POWER_STATE       rtState;
 185
 186        pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
 187                                          (pu1Byte)(&rtState));
 188
 189        /* When RF is off, we should not count the packet for hw/sw synchronize
 190           reason, ie. there may be a duration while sw switch is changed and
 191           hw switch is being changed. */
 192        if (rtState == eRfOff)
 193                return;
 194#endif
 195
 196#ifdef TODO
 197        if (pAdapter->bInHctTest)
 198                return;
 199#endif
 200        /* We can not know the packet length and transmit type:
 201           broadcast or uni or multicast. So the relative statistics
 202           must be collected in tx feedback info. */
 203        if (pstx_fb->tok) {
 204                priv->stats.txfeedbackok++;
 205                priv->stats.txoktotal++;
 206                priv->stats.txokbytestotal += pstx_fb->pkt_length;
 207                priv->stats.txokinperiod++;
 208
 209                /* We can not make sure broadcast/multicast or unicast mode. */
 210                if (pstx_fb->pkt_type == PACKET_MULTICAST) {
 211                        priv->stats.txmulticast++;
 212                        priv->stats.txbytesmulticast += pstx_fb->pkt_length;
 213                } else if (pstx_fb->pkt_type == PACKET_BROADCAST) {
 214                        priv->stats.txbroadcast++;
 215                        priv->stats.txbytesbroadcast += pstx_fb->pkt_length;
 216                } else {
 217                        priv->stats.txunicast++;
 218                        priv->stats.txbytesunicast += pstx_fb->pkt_length;
 219                }
 220        } else {
 221                priv->stats.txfeedbackfail++;
 222                priv->stats.txerrtotal++;
 223                priv->stats.txerrbytestotal += pstx_fb->pkt_length;
 224
 225                /* We can not make sure broadcast/multicast or unicast mode. */
 226                if (pstx_fb->pkt_type == PACKET_MULTICAST)
 227                        priv->stats.txerrmulticast++;
 228                else if (pstx_fb->pkt_type == PACKET_BROADCAST)
 229                        priv->stats.txerrbroadcast++;
 230                else
 231                        priv->stats.txerrunicast++;
 232        }
 233
 234        priv->stats.txretrycount += pstx_fb->retry_cnt;
 235        priv->stats.txfeedbackretry += pstx_fb->retry_cnt;
 236
 237}
 238
 239
 240
 241/*-----------------------------------------------------------------------------
 242 * Function:    cmpk_handle_tx_feedback()
 243 *
 244 * Overview:    The function is responsible for extract the message inside TX
 245 *              feedbck message from firmware. It will contain dedicated info in
 246 *              ws-06-0063-rtl8190-command-packet-specification.
 247 *              Please refer to chapter "TX Feedback Element".
 248 *              We have to read 20 bytes in the command packet.
 249 *
 250 * Input:       struct net_device       *dev
 251 *              u8                      *pmsg   - Msg Ptr of the command packet.
 252 *
 253 * Output:      NONE
 254 *
 255 * Return:      NONE
 256 *
 257 * Revised History:
 258 *  When                Who     Remark
 259 *  05/08/2008          amy     Create Version 0 porting from windows code.
 260 *
 261 *---------------------------------------------------------------------------*/
 262static void cmpk_handle_tx_feedback(struct net_device *dev, u8 *pmsg)
 263{
 264        struct r8192_priv *priv = ieee80211_priv(dev);
 265        cmpk_txfb_t             rx_tx_fb;
 266
 267        priv->stats.txfeedback++;
 268
 269        /* 1. Extract TX feedback info from RFD to temp structure buffer. */
 270        /* It seems that FW use big endian(MIPS) and DRV use little endian in
 271           windows OS. So we have to read the content byte by byte or transfer
 272           endian type before copy the message copy. */
 273        /* Use pointer to transfer structure memory. */
 274        memcpy((u8 *)&rx_tx_fb, pmsg, sizeof(cmpk_txfb_t));
 275        /* 2. Use tx feedback info to count TX statistics. */
 276        cmpk_count_txstatistic(dev, &rx_tx_fb);
 277        /* Comment previous method for TX statistic function. */
 278        /* Collect info TX feedback packet to fill TCB. */
 279        /* We can not know the packet length and transmit type: broadcast or uni
 280           or multicast. */
 281
 282}
 283
 284void cmdpkt_beacontimerinterrupt_819xusb(struct net_device *dev)
 285{
 286        struct r8192_priv *priv = ieee80211_priv(dev);
 287        u16 tx_rate;
 288                /* 87B have to S/W beacon for DTM encryption_cmn. */
 289                if (priv->ieee80211->current_network.mode == IEEE_A ||
 290                        priv->ieee80211->current_network.mode == IEEE_N_5G ||
 291                        (priv->ieee80211->current_network.mode == IEEE_N_24G &&
 292                         (!priv->ieee80211->pHTInfo->bCurSuppCCK))) {
 293                        tx_rate = 60;
 294                        DMESG("send beacon frame  tx rate is 6Mbpm\n");
 295                } else {
 296                        tx_rate = 10;
 297                        DMESG("send beacon frame  tx rate is 1Mbpm\n");
 298                }
 299
 300                rtl819xusb_beacon_tx(dev, tx_rate); /* HW Beacon */
 301
 302
 303}
 304
 305
 306
 307
 308/*-----------------------------------------------------------------------------
 309 * Function:    cmpk_handle_interrupt_status()
 310 *
 311 * Overview:    The function is responsible for extract the message from
 312 *              firmware. It will contain dedicated info in
 313 *              ws-07-0063-v06-rtl819x-command-packet-specification-070315.doc.
 314 *              Please refer to chapter "Interrupt Status Element".
 315 *
 316 * Input:       struct net_device *dev
 317 *              u8 *pmsg                - Message Pointer of the command packet.
 318 *
 319 * Output:      NONE
 320 *
 321 * Return:      NONE
 322 *
 323 * Revised History:
 324 *  When                Who     Remark
 325 *  05/12/2008          amy     Add this for rtl8192 porting from windows code.
 326 *
 327 *---------------------------------------------------------------------------*/
 328static void cmpk_handle_interrupt_status(struct net_device *dev, u8 *pmsg)
 329{
 330        cmpk_intr_sta_t         rx_intr_status; /* */
 331        struct r8192_priv *priv = ieee80211_priv(dev);
 332
 333        DMESG("---> cmpk_Handle_Interrupt_Status()\n");
 334
 335        /* 1. Extract TX feedback info from RFD to temp structure buffer. */
 336        /* It seems that FW use big endian(MIPS) and DRV use little endian in
 337           windows OS. So we have to read the content byte by byte or transfer
 338           endian type before copy the message copy. */
 339        rx_intr_status.length = pmsg[1];
 340        if (rx_intr_status.length != (sizeof(cmpk_intr_sta_t) - 2)) {
 341                DMESG("cmpk_Handle_Interrupt_Status: wrong length!\n");
 342                return;
 343        }
 344
 345
 346        /* Statistics of beacon for ad-hoc mode. */
 347        if (priv->ieee80211->iw_mode == IW_MODE_ADHOC) {
 348                /* 2 maybe need endian transform? */
 349                rx_intr_status.interrupt_status = *((u32 *)(pmsg + 4));
 350
 351                DMESG("interrupt status = 0x%x\n",
 352                      rx_intr_status.interrupt_status);
 353
 354                if (rx_intr_status.interrupt_status & ISR_TxBcnOk) {
 355                        priv->ieee80211->bibsscoordinator = true;
 356                        priv->stats.txbeaconokint++;
 357                } else if (rx_intr_status.interrupt_status & ISR_TxBcnErr) {
 358                        priv->ieee80211->bibsscoordinator = false;
 359                        priv->stats.txbeaconerr++;
 360                }
 361
 362                if (rx_intr_status.interrupt_status & ISR_BcnTimerIntr)
 363                        cmdpkt_beacontimerinterrupt_819xusb(dev);
 364
 365        }
 366
 367        /* Other informations in interrupt status we need? */
 368
 369
 370        DMESG("<---- cmpk_handle_interrupt_status()\n");
 371
 372}
 373
 374
 375/*-----------------------------------------------------------------------------
 376 * Function:    cmpk_handle_query_config_rx()
 377 *
 378 * Overview:    The function is responsible for extract the message from
 379 *              firmware. It will contain dedicated info in
 380 *              ws-06-0063-rtl8190-command-packet-specification. Please
 381 *              refer to chapter "Beacon State Element".
 382 *
 383 * Input:       u8    *pmsg     -       Message Pointer of the command packet.
 384 *
 385 * Output:      NONE
 386 *
 387 * Return:      NONE
 388 *
 389 * Revised History:
 390 *  When                Who     Remark
 391 *  05/12/2008          amy     Create Version 0 porting from windows code.
 392 *
 393 *---------------------------------------------------------------------------*/
 394static void cmpk_handle_query_config_rx(struct net_device *dev, u8 *pmsg)
 395{
 396        cmpk_query_cfg_t        rx_query_cfg;
 397
 398
 399        /* 1. Extract TX feedback info from RFD to temp structure buffer. */
 400        /* It seems that FW use big endian(MIPS) and DRV use little endian in
 401           windows OS. So we have to read the content byte by byte or transfer
 402           endian type before copy the message copy. */
 403        rx_query_cfg.cfg_action         = (pmsg[4] & 0x80000000) >> 31;
 404        rx_query_cfg.cfg_type           = (pmsg[4] & 0x60) >> 5;
 405        rx_query_cfg.cfg_size           = (pmsg[4] & 0x18) >> 3;
 406        rx_query_cfg.cfg_page           = (pmsg[6] & 0x0F) >> 0;
 407        rx_query_cfg.cfg_offset         = pmsg[7];
 408        rx_query_cfg.value              = (pmsg[8]  << 24) | (pmsg[9]  << 16) |
 409                                          (pmsg[10] <<  8) | (pmsg[11] <<  0);
 410        rx_query_cfg.mask               = (pmsg[12] << 24) | (pmsg[13] << 16) |
 411                                          (pmsg[14] <<  8) | (pmsg[15] <<  0);
 412
 413}
 414
 415
 416/*-----------------------------------------------------------------------------
 417 * Function:    cmpk_count_tx_status()
 418 *
 419 * Overview:    Count aggregated tx status from firmwar of one type rx command
 420 *              packet element id = RX_TX_STATUS.
 421 *
 422 * Input:       NONE
 423 *
 424 * Output:      NONE
 425 *
 426 * Return:      NONE
 427 *
 428 * Revised History:
 429 *      When            Who     Remark
 430 *      05/12/2008      amy     Create Version 0 porting from windows code.
 431 *
 432 *---------------------------------------------------------------------------*/
 433static void cmpk_count_tx_status(struct net_device *dev,
 434                                 cmpk_tx_status_t *pstx_status)
 435{
 436        struct r8192_priv *priv = ieee80211_priv(dev);
 437
 438#ifdef ENABLE_PS
 439
 440        RT_RF_POWER_STATE       rtstate;
 441
 442        pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
 443                                          (pu1Byte)(&rtState));
 444
 445        /* When RF is off, we should not count the packet for hw/sw synchronize
 446           reason, ie. there may be a duration while sw switch is changed and
 447           hw switch is being changed. */
 448        if (rtState == eRfOff)
 449                return;
 450#endif
 451
 452        priv->stats.txfeedbackok        += pstx_status->txok;
 453        priv->stats.txoktotal           += pstx_status->txok;
 454
 455        priv->stats.txfeedbackfail      += pstx_status->txfail;
 456        priv->stats.txerrtotal          += pstx_status->txfail;
 457
 458        priv->stats.txretrycount        += pstx_status->txretry;
 459        priv->stats.txfeedbackretry     += pstx_status->txretry;
 460
 461
 462        priv->stats.txmulticast         += pstx_status->txmcok;
 463        priv->stats.txbroadcast         += pstx_status->txbcok;
 464        priv->stats.txunicast           += pstx_status->txucok;
 465
 466        priv->stats.txerrmulticast      += pstx_status->txmcfail;
 467        priv->stats.txerrbroadcast      += pstx_status->txbcfail;
 468        priv->stats.txerrunicast        += pstx_status->txucfail;
 469
 470        priv->stats.txbytesmulticast    += pstx_status->txmclength;
 471        priv->stats.txbytesbroadcast    += pstx_status->txbclength;
 472        priv->stats.txbytesunicast      += pstx_status->txuclength;
 473
 474        priv->stats.last_packet_rate    = pstx_status->rate;
 475}
 476
 477
 478
 479/*-----------------------------------------------------------------------------
 480 * Function:    cmpk_handle_tx_status()
 481 *
 482 * Overview:    Firmware add a new tx feedback status to reduce rx command
 483 *              packet buffer operation load.
 484 *
 485 * Input:               NONE
 486 *
 487 * Output:              NONE
 488 *
 489 * Return:              NONE
 490 *
 491 * Revised History:
 492 *      When            Who     Remark
 493 *      05/12/2008      amy     Create Version 0 porting from windows code.
 494 *
 495 *---------------------------------------------------------------------------*/
 496static void cmpk_handle_tx_status(struct net_device *dev, u8 *pmsg)
 497{
 498        cmpk_tx_status_t        rx_tx_sts;
 499
 500        memcpy((void *)&rx_tx_sts, (void *)pmsg, sizeof(cmpk_tx_status_t));
 501        /* 2. Use tx feedback info to count TX statistics. */
 502        cmpk_count_tx_status(dev, &rx_tx_sts);
 503
 504}
 505
 506
 507/*-----------------------------------------------------------------------------
 508 * Function:    cmpk_handle_tx_rate_history()
 509 *
 510 * Overview:    Firmware add a new tx rate history
 511 *
 512 * Input:               NONE
 513 *
 514 * Output:              NONE
 515 *
 516 * Return:              NONE
 517 *
 518 * Revised History:
 519 *      When            Who     Remark
 520 *      05/12/2008      amy     Create Version 0 porting from windows code.
 521 *
 522 *---------------------------------------------------------------------------*/
 523static void cmpk_handle_tx_rate_history(struct net_device *dev, u8 *pmsg)
 524{
 525        cmpk_tx_rahis_t *ptxrate;
 526        u8              i, j;
 527        u16             length = sizeof(cmpk_tx_rahis_t);
 528        u32             *ptemp;
 529        struct r8192_priv *priv = ieee80211_priv(dev);
 530
 531
 532#ifdef ENABLE_PS
 533        pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
 534                                          (pu1Byte)(&rtState));
 535
 536        /* When RF is off, we should not count the packet for hw/sw synchronize
 537           reason, ie. there may be a duration while sw switch is changed and
 538           hw switch is being changed. */
 539        if (rtState == eRfOff)
 540                return;
 541#endif
 542
 543        ptemp = (u32 *)pmsg;
 544
 545        /* Do endian transfer to word alignment(16 bits) for windows system.
 546           You must do different endian transfer for linux and MAC OS */
 547        for (i = 0; i < (length/4); i++) {
 548                u16      temp1, temp2;
 549
 550                temp1 = ptemp[i] & 0x0000FFFF;
 551                temp2 = ptemp[i] >> 16;
 552                ptemp[i] = (temp1 << 16) | temp2;
 553        }
 554
 555        ptxrate = (cmpk_tx_rahis_t *)pmsg;
 556
 557        if (ptxrate == NULL)
 558                return;
 559
 560        for (i = 0; i < 16; i++) {
 561                /* Collect CCK rate packet num */
 562                if (i < 4)
 563                        priv->stats.txrate.cck[i] += ptxrate->cck[i];
 564
 565                /* Collect OFDM rate packet num */
 566                if (i < 8)
 567                        priv->stats.txrate.ofdm[i] += ptxrate->ofdm[i];
 568
 569                for (j = 0; j < 4; j++)
 570                        priv->stats.txrate.ht_mcs[j][i] += ptxrate->ht_mcs[j][i];
 571        }
 572
 573}
 574
 575
 576/*-----------------------------------------------------------------------------
 577 * Function:    cmpk_message_handle_rx()
 578 *
 579 * Overview:    In the function, we will capture different RX command packet
 580 *              info. Every RX command packet element has different message
 581 *              length and meaning in content. We only support three type of RX
 582 *              command packet now. Please refer to document
 583 *              ws-06-0063-rtl8190-command-packet-specification.
 584 *
 585 * Input:       NONE
 586 *
 587 * Output:      NONE
 588 *
 589 * Return:      NONE
 590 *
 591 * Revised History:
 592 *  When                Who     Remark
 593 *  05/06/2008          amy     Create Version 0 porting from windows code.
 594 *
 595 *---------------------------------------------------------------------------*/
 596extern u32 cmpk_message_handle_rx(struct net_device *dev,
 597                                  struct ieee80211_rx_stats *pstats)
 598{
 599        int                     total_length;
 600        u8                      cmd_length, exe_cnt = 0;
 601        u8                      element_id;
 602        u8                      *pcmd_buff;
 603
 604        /* 0. Check inpt arguments. If is is a command queue message or
 605           pointer is null. */
 606        if (pstats == NULL)
 607                return 0;       /* This is not a command packet. */
 608
 609        /* 1. Read received command packet message length from RFD. */
 610        total_length = pstats->Length;
 611
 612        /* 2. Read virtual address from RFD. */
 613        pcmd_buff = pstats->virtual_address;
 614
 615        /* 3. Read command packet element id and length. */
 616        element_id = pcmd_buff[0];
 617
 618        /* 4. Check every received command packet content according to different
 619              element type. Because FW may aggregate RX command packet to
 620              minimize transmit time between DRV and FW.*/
 621        /* Add a counter to prevent the lock in the loop from being held too
 622           long */
 623        while (total_length > 0 && exe_cnt++ < 100) {
 624                /* We support aggregation of different cmd in the same packet */
 625                element_id = pcmd_buff[0];
 626
 627                switch (element_id) {
 628                case RX_TX_FEEDBACK:
 629                        cmpk_handle_tx_feedback(dev, pcmd_buff);
 630                        cmd_length = CMPK_RX_TX_FB_SIZE;
 631                        break;
 632
 633                case RX_INTERRUPT_STATUS:
 634                        cmpk_handle_interrupt_status(dev, pcmd_buff);
 635                        cmd_length = sizeof(cmpk_intr_sta_t);
 636                        break;
 637
 638                case BOTH_QUERY_CONFIG:
 639                        cmpk_handle_query_config_rx(dev, pcmd_buff);
 640                        cmd_length = CMPK_BOTH_QUERY_CONFIG_SIZE;
 641                        break;
 642
 643                case RX_TX_STATUS:
 644                        cmpk_handle_tx_status(dev, pcmd_buff);
 645                        cmd_length = CMPK_RX_TX_STS_SIZE;
 646                        break;
 647
 648                case RX_TX_PER_PKT_FEEDBACK:
 649                        /* You must at lease add a switch case element here,
 650                           Otherwise, we will jump to default case. */
 651                        cmd_length = CMPK_RX_TX_FB_SIZE;
 652                        break;
 653
 654                case RX_TX_RATE_HISTORY:
 655                        cmpk_handle_tx_rate_history(dev, pcmd_buff);
 656                        cmd_length = CMPK_TX_RAHIS_SIZE;
 657                        break;
 658
 659                default:
 660
 661                        RT_TRACE(COMP_ERR, "---->%s():unknown CMD Element\n",
 662                                 __func__);
 663                        return 1;       /* This is a command packet. */
 664                }
 665
 666                total_length -= cmd_length;
 667                pcmd_buff    += cmd_length;
 668        }
 669        return  1;      /* This is a command packet. */
 670
 671}
 672