Logo Search packages:      
Sourcecode: linux-fsl-imx51 version File versions  Download package

mlme.c

/*
 *************************************************************************
 * Ralink Tech Inc.
 * 5F., No.36, Taiyuan St., Jhubei City,
 * Hsinchu County 302,
 * Taiwan, R.O.C.
 *
 * (c) Copyright 2002-2007, Ralink Technology, Inc.
 *
 * This program is free software; you can redistribute it and/or modify  *
 * it under the terms of the GNU General Public License as published by  *
 * the Free Software Foundation; either version 2 of the License, or     *
 * (at your option) any later version.                                   *
 *                                                                       *
 * This program is distributed in the hope that it will be useful,       *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 * GNU General Public License for more details.                          *
 *                                                                       *
 * You should have received a copy of the GNU General Public License     *
 * along with this program; if not, write to the                         *
 * Free Software Foundation, Inc.,                                       *
 * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 *                                                                       *
 *************************************************************************

      Module Name:
      mlme.c

      Abstract:

      Revision History:
      Who               When              What
      --------    ----------        ----------------------------------------------
      John Chang  2004-08-25        Modify from RT2500 code base
      John Chang  2004-09-06        modified for RT2600
*/

#include "../rt_config.h"
#include <stdarg.h>

UCHAR CISCO_OUI[] = {0x00, 0x40, 0x96};

UCHAR WPA_OUI[] = {0x00, 0x50, 0xf2, 0x01};
UCHAR RSN_OUI[] = {0x00, 0x0f, 0xac};
UCHAR WAPI_OUI[] = {0x00, 0x14, 0x72};
UCHAR   WME_INFO_ELEM[]  = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01};
UCHAR   WME_PARM_ELEM[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01};
UCHAR Ccx2QosInfo[] = {0x00, 0x40, 0x96, 0x04};
UCHAR   RALINK_OUI[]  = {0x00, 0x0c, 0x43};
UCHAR   BROADCOM_OUI[]  = {0x00, 0x90, 0x4c};
UCHAR   WPS_OUI[] = {0x00, 0x50, 0xf2, 0x04};
UCHAR PRE_N_HT_OUI[]    = {0x00, 0x90, 0x4c};

UCHAR RateSwitchTable[] = {
// Item No.   Mode   Curr-MCS   TrainUp   TrainDown         // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF)
    0x11, 0x00,  0,  0,  0,                                 // Initial used item after association
    0x00, 0x00,  0, 40, 101,
    0x01, 0x00,  1, 40, 50,
    0x02, 0x00,  2, 35, 45,
    0x03, 0x00,  3, 20, 45,
    0x04, 0x21,  0, 30, 50,
    0x05, 0x21,  1, 20, 50,
    0x06, 0x21,  2, 20, 50,
    0x07, 0x21,  3, 15, 50,
    0x08, 0x21,  4, 15, 30,
    0x09, 0x21,  5, 10, 25,
    0x0a, 0x21,  6,  8, 25,
    0x0b, 0x21,  7,  8, 25,
    0x0c, 0x20, 12,  15, 30,
    0x0d, 0x20, 13,  8, 20,
    0x0e, 0x20, 14,  8, 20,
    0x0f, 0x20, 15,  8, 25,
    0x10, 0x22, 15,  8, 25,
    0x11, 0x00,  0,  0,  0,
    0x12, 0x00,  0,  0,  0,
    0x13, 0x00,  0,  0,  0,
    0x14, 0x00,  0,  0,  0,
    0x15, 0x00,  0,  0,  0,
    0x16, 0x00,  0,  0,  0,
    0x17, 0x00,  0,  0,  0,
    0x18, 0x00,  0,  0,  0,
    0x19, 0x00,  0,  0,  0,
    0x1a, 0x00,  0,  0,  0,
    0x1b, 0x00,  0,  0,  0,
    0x1c, 0x00,  0,  0,  0,
    0x1d, 0x00,  0,  0,  0,
    0x1e, 0x00,  0,  0,  0,
    0x1f, 0x00,  0,  0,  0,
};

UCHAR RateSwitchTable11B[] = {
// Item No.   Mode   Curr-MCS   TrainUp   TrainDown         // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF)
    0x04, 0x03,  0,  0,  0,                                 // Initial used item after association
    0x00, 0x00,  0, 40, 101,
    0x01, 0x00,  1, 40, 50,
    0x02, 0x00,  2, 35, 45,
    0x03, 0x00,  3, 20, 45,
};

UCHAR RateSwitchTable11BG[] = {
// Item No.   Mode   Curr-MCS   TrainUp   TrainDown         // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF)
    0x0a, 0x00,  0,  0,  0,                                 // Initial used item after association
    0x00, 0x00,  0, 40, 101,
    0x01, 0x00,  1, 40, 50,
    0x02, 0x00,  2, 35, 45,
    0x03, 0x00,  3, 20, 45,
    0x04, 0x10,  2, 20, 35,
    0x05, 0x10,  3, 16, 35,
    0x06, 0x10,  4, 10, 25,
    0x07, 0x10,  5, 16, 25,
    0x08, 0x10,  6, 10, 25,
    0x09, 0x10,  7, 10, 13,
};

UCHAR RateSwitchTable11G[] = {
// Item No.   Mode   Curr-MCS   TrainUp   TrainDown         // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF)
    0x08, 0x00,  0,  0,  0,                                 // Initial used item after association
    0x00, 0x10,  0, 20, 101,
    0x01, 0x10,  1, 20, 35,
    0x02, 0x10,  2, 20, 35,
    0x03, 0x10,  3, 16, 35,
    0x04, 0x10,  4, 10, 25,
    0x05, 0x10,  5, 16, 25,
    0x06, 0x10,  6, 10, 25,
    0x07, 0x10,  7, 10, 13,
};

UCHAR RateSwitchTable11N1S[] = {
// Item No.   Mode   Curr-MCS   TrainUp   TrainDown         // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF)
    0x09, 0x00,  0,  0,  0,                                 // Initial used item after association
    0x00, 0x21,  0, 30, 101,
    0x01, 0x21,  1, 20, 50,
    0x02, 0x21,  2, 20, 50,
    0x03, 0x21,  3, 15, 50,
    0x04, 0x21,  4, 15, 30,
    0x05, 0x21,  5, 10, 25,
    0x06, 0x21,  6,  8, 14,
    0x07, 0x21,  7,  8, 14,
    0x08, 0x23,  7,  8, 14,
};

UCHAR RateSwitchTable11N2S[] = {
// Item No.   Mode   Curr-MCS   TrainUp   TrainDown         // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF)
    0x0a, 0x00,  0,  0,  0,      // Initial used item after association
    0x00, 0x21,  0, 30, 101,
    0x01, 0x21,  1, 20, 50,
    0x02, 0x21,  2, 20, 50,
    0x03, 0x21,  3, 15, 50,
    0x04, 0x21,  4, 15, 30,
    0x05, 0x20, 12,  15, 30,
    0x06, 0x20, 13,  8, 20,
    0x07, 0x20, 14,  8, 20,
    0x08, 0x20, 15,  8, 25,
    0x09, 0x22, 15,  8, 25,
};

UCHAR RateSwitchTable11N3S[] = {
// Item No. Mode  Curr-MCS    TrainUp     TrainDown   // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF)
    0x0a, 0x00,  0,  0,  0,      // Initial used item after association
    0x00, 0x21,  0, 30, 101,
    0x01, 0x21,  1, 20, 50,
    0x02, 0x21,  2, 20, 50,
    0x03, 0x21,  3, 15, 50,
    0x04, 0x21,  4, 15, 30,
    0x05, 0x20, 12,  15, 30,
    0x06, 0x20, 13,  8, 20,
    0x07, 0x20, 14,  8, 20,
    0x08, 0x20, 15,  8, 25,
    0x09, 0x22, 15,  8, 25,
};

UCHAR RateSwitchTable11N2SForABand[] = {
// Item No.   Mode   Curr-MCS   TrainUp   TrainDown         // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF)
    0x0b, 0x09,  0,  0,  0,                                 // Initial used item after association
    0x00, 0x21,  0, 30, 101,
    0x01, 0x21,  1, 20, 50,
    0x02, 0x21,  2, 20, 50,
    0x03, 0x21,  3, 15, 50,
    0x04, 0x21,  4, 15, 30,
    0x05, 0x21,  5, 15, 30,
    0x06, 0x20, 12,  15, 30,
    0x07, 0x20, 13,  8, 20,
    0x08, 0x20, 14,  8, 20,
    0x09, 0x20, 15,  8, 25,
    0x0a, 0x22, 15,  8, 25,
};

UCHAR RateSwitchTable11N3SForABand[] = { // 3*3
// Item No.   Mode   Curr-MCS   TrainUp   TrainDown         // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF)
    0x0b, 0x09,  0,  0,  0,                                 // Initial used item after association
    0x00, 0x21,  0, 30, 101,
    0x01, 0x21,  1, 20, 50,
    0x02, 0x21,  2, 20, 50,
    0x03, 0x21,  3, 15, 50,
    0x04, 0x21,  4, 15, 30,
    0x05, 0x21,  5, 15, 30,
    0x06, 0x20, 12,  15, 30,
    0x07, 0x20, 13,  8, 20,
    0x08, 0x20, 14,  8, 20,
    0x09, 0x20, 15,  8, 25,
    0x0a, 0x22, 15,  8, 25,
};

UCHAR RateSwitchTable11BGN1S[] = {
// Item No.   Mode   Curr-MCS   TrainUp   TrainDown         // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF)
    0x0d, 0x00,  0,  0,  0,                                 // Initial used item after association
    0x00, 0x00,  0, 40, 101,
    0x01, 0x00,  1, 40, 50,
    0x02, 0x00,  2, 35, 45,
    0x03, 0x00,  3, 20, 45,
    0x04, 0x21,  0, 30,101,   //50
    0x05, 0x21,  1, 20, 50,
    0x06, 0x21,  2, 20, 50,
    0x07, 0x21,  3, 15, 50,
    0x08, 0x21,  4, 15, 30,
    0x09, 0x21,  5, 10, 25,
    0x0a, 0x21,  6,  8, 14,
    0x0b, 0x21,  7,  8, 14,
      0x0c, 0x23,  7,  8, 14,
};

UCHAR RateSwitchTable11BGN2S[] = {
// Item No.   Mode   Curr-MCS   TrainUp   TrainDown         // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF)
    0x0a, 0x00,  0,  0,  0,                                 // Initial used item after association
    0x00, 0x21,  0, 30,101,   //50
    0x01, 0x21,  1, 20, 50,
    0x02, 0x21,  2, 20, 50,
    0x03, 0x21,  3, 15, 50,
    0x04, 0x21,  4, 15, 30,
    0x05, 0x20, 12, 15, 30,
    0x06, 0x20, 13,  8, 20,
    0x07, 0x20, 14,  8, 20,
    0x08, 0x20, 15,  8, 25,
    0x09, 0x22, 15,  8, 25,
};

UCHAR RateSwitchTable11BGN3S[] = { // 3*3
// Item No.   Mode   Curr-MCS   TrainUp   TrainDown         // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF)
    0x0a, 0x00,  0,  0,  0,                                 // Initial used item after association
    0x00, 0x21,  0, 30,101,   //50
    0x01, 0x21,  1, 20, 50,
    0x02, 0x21,  2, 20, 50,
    0x03, 0x21,  3, 20, 50,
    0x04, 0x21,  4, 15, 50,
    0x05, 0x20, 20, 15, 30,
    0x06, 0x20, 21,  8, 20,
    0x07, 0x20, 22,  8, 20,
    0x08, 0x20, 23,  8, 25,
    0x09, 0x22, 23,  8, 25,
};

UCHAR RateSwitchTable11BGN2SForABand[] = {
// Item No.   Mode   Curr-MCS   TrainUp   TrainDown         // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF)
    0x0b, 0x09,  0,  0,  0,                                 // Initial used item after association
    0x00, 0x21,  0, 30,101,   //50
    0x01, 0x21,  1, 20, 50,
    0x02, 0x21,  2, 20, 50,
    0x03, 0x21,  3, 15, 50,
    0x04, 0x21,  4, 15, 30,
    0x05, 0x21,  5, 15, 30,
    0x06, 0x20, 12, 15, 30,
    0x07, 0x20, 13,  8, 20,
    0x08, 0x20, 14,  8, 20,
    0x09, 0x20, 15,  8, 25,
    0x0a, 0x22, 15,  8, 25,
};

UCHAR RateSwitchTable11BGN3SForABand[] = { // 3*3
// Item No.   Mode   Curr-MCS   TrainUp   TrainDown         // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF)
    0x0c, 0x09,  0,  0,  0,                                 // Initial used item after association
    0x00, 0x21,  0, 30,101,   //50
    0x01, 0x21,  1, 20, 50,
    0x02, 0x21,  2, 20, 50,
    0x03, 0x21,  3, 15, 50,
    0x04, 0x21,  4, 15, 30,
    0x05, 0x21,  5, 15, 30,
    0x06, 0x21, 12, 15, 30,
    0x07, 0x20, 20, 15, 30,
    0x08, 0x20, 21,  8, 20,
    0x09, 0x20, 22,  8, 20,
    0x0a, 0x20, 23,  8, 25,
    0x0b, 0x22, 23,  8, 25,
};

PUCHAR ReasonString[] = {
      /* 0  */     "Reserved",
      /* 1  */     "Unspecified Reason",
      /* 2  */     "Previous Auth no longer valid",
      /* 3  */     "STA is leaving / has left",
      /* 4  */     "DIS-ASSOC due to inactivity",
      /* 5  */     "AP unable to hanle all associations",
      /* 6  */     "class 2 error",
      /* 7  */     "class 3 error",
      /* 8  */     "STA is leaving / has left",
      /* 9  */     "require auth before assoc/re-assoc",
      /* 10 */     "Reserved",
      /* 11 */     "Reserved",
      /* 12 */     "Reserved",
      /* 13 */     "invalid IE",
      /* 14 */     "MIC error",
      /* 15 */     "4-way handshake timeout",
      /* 16 */     "2-way (group key) handshake timeout",
      /* 17 */     "4-way handshake IE diff among AssosReq/Rsp/Beacon",
      /* 18 */
};

extern UCHAR       OfdmRateToRxwiMCS[];
// since RT61 has better RX sensibility, we have to limit TX ACK rate not to exceed our normal data TX rate.
// otherwise the WLAN peer may not be able to receive the ACK thus downgrade its data TX rate
ULONG BasicRateMask[12]                   = {0xfffff001 /* 1-Mbps */, 0xfffff003 /* 2 Mbps */, 0xfffff007 /* 5.5 */, 0xfffff00f /* 11 */,
                                                        0xfffff01f /* 6 */     , 0xfffff03f /* 9 */     , 0xfffff07f /* 12 */ , 0xfffff0ff /* 18 */,
                                                        0xfffff1ff /* 24 */    , 0xfffff3ff /* 36 */    , 0xfffff7ff /* 48 */ , 0xffffffff /* 54 */};

UCHAR MULTICAST_ADDR[MAC_ADDR_LEN] = {0x1,  0x00, 0x00, 0x00, 0x00, 0x00};
UCHAR BROADCAST_ADDR[MAC_ADDR_LEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
UCHAR ZERO_MAC_ADDR[MAC_ADDR_LEN]  = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

// e.g. RssiSafeLevelForTxRate[RATE_36]" means if the current RSSI is greater than
//          this value, then it's quaranteed capable of operating in 36 mbps TX rate in
//          clean environment.
//                                                TxRate: 1   2   5.5   11     6      9    12   18     24   36   48     54     72  100
CHAR RssiSafeLevelForTxRate[] ={  -92, -91, -90, -87, -88, -86, -85, -83, -81, -78, -72, -71, -40, -40 };

UCHAR  RateIdToMbps[]    = { 1, 2, 5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 72, 100};
USHORT RateIdTo500Kbps[] = { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108, 144, 200};

UCHAR  SsidIe      = IE_SSID;
UCHAR  SupRateIe = IE_SUPP_RATES;
UCHAR  ExtRateIe = IE_EXT_SUPP_RATES;
UCHAR  HtCapIe = IE_HT_CAP;
UCHAR  AddHtInfoIe = IE_ADD_HT;
UCHAR  NewExtChanIe = IE_SECONDARY_CH_OFFSET;
UCHAR  ErpIe       = IE_ERP;
UCHAR  DsIe        = IE_DS_PARM;
UCHAR  TimIe       = IE_TIM;
UCHAR  WpaIe       = IE_WPA;
UCHAR  Wpa2Ie      = IE_WPA2;
UCHAR  IbssIe      = IE_IBSS_PARM;
UCHAR  Ccx2Ie      = IE_CCX_V2;
#ifdef RT2870
UCHAR  WapiIe      = IE_WAPI;
#endif

extern UCHAR      WPA_OUI[];

UCHAR SES_OUI[] = {0x00, 0x90, 0x4c};

UCHAR ZeroSsid[32] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};

// Reset the RFIC setting to new series
RTMP_RF_REGS RF2850RegTable[] = {
//          ch     R1          R2          R3(TX0~4=0) R4
            {1,  0x98402ecc, 0x984c0786, 0x9816b455, 0x9800510b},
            {2,  0x98402ecc, 0x984c0786, 0x98168a55, 0x9800519f},
            {3,  0x98402ecc, 0x984c078a, 0x98168a55, 0x9800518b},
            {4,  0x98402ecc, 0x984c078a, 0x98168a55, 0x9800519f},
            {5,  0x98402ecc, 0x984c078e, 0x98168a55, 0x9800518b},
            {6,  0x98402ecc, 0x984c078e, 0x98168a55, 0x9800519f},
            {7,  0x98402ecc, 0x984c0792, 0x98168a55, 0x9800518b},
            {8,  0x98402ecc, 0x984c0792, 0x98168a55, 0x9800519f},
            {9,  0x98402ecc, 0x984c0796, 0x98168a55, 0x9800518b},
            {10, 0x98402ecc, 0x984c0796, 0x98168a55, 0x9800519f},
            {11, 0x98402ecc, 0x984c079a, 0x98168a55, 0x9800518b},
            {12, 0x98402ecc, 0x984c079a, 0x98168a55, 0x9800519f},
            {13, 0x98402ecc, 0x984c079e, 0x98168a55, 0x9800518b},
            {14, 0x98402ecc, 0x984c07a2, 0x98168a55, 0x98005193},

            // 802.11 UNI / HyperLan 2
            {36, 0x98402ecc, 0x984c099a, 0x98158a55, 0x980ed1a3},
            {38, 0x98402ecc, 0x984c099e, 0x98158a55, 0x980ed193},
            {40, 0x98402ec8, 0x984c0682, 0x98158a55, 0x980ed183},
            {44, 0x98402ec8, 0x984c0682, 0x98158a55, 0x980ed1a3},
            {46, 0x98402ec8, 0x984c0686, 0x98158a55, 0x980ed18b},
            {48, 0x98402ec8, 0x984c0686, 0x98158a55, 0x980ed19b},
            {52, 0x98402ec8, 0x984c068a, 0x98158a55, 0x980ed193},
            {54, 0x98402ec8, 0x984c068a, 0x98158a55, 0x980ed1a3},
            {56, 0x98402ec8, 0x984c068e, 0x98158a55, 0x980ed18b},
            {60, 0x98402ec8, 0x984c0692, 0x98158a55, 0x980ed183},
            {62, 0x98402ec8, 0x984c0692, 0x98158a55, 0x980ed193},
            {64, 0x98402ec8, 0x984c0692, 0x98158a55, 0x980ed1a3}, // Plugfest#4, Day4, change RFR3 left4th 9->5.

            // 802.11 HyperLan 2
            {100, 0x98402ec8, 0x984c06b2, 0x98178a55, 0x980ed783},

            // 2008.04.30 modified
            // The system team has AN to improve the EVM value
            // for channel 102 to 108 for the RT2850/RT2750 dual band solution.
            {102, 0x98402ec8, 0x985c06b2, 0x98578a55, 0x980ed793},
            {104, 0x98402ec8, 0x985c06b2, 0x98578a55, 0x980ed1a3},
            {108, 0x98402ecc, 0x985c0a32, 0x98578a55, 0x980ed193},

            {110, 0x98402ecc, 0x984c0a36, 0x98178a55, 0x980ed183},
            {112, 0x98402ecc, 0x984c0a36, 0x98178a55, 0x980ed19b},
            {116, 0x98402ecc, 0x984c0a3a, 0x98178a55, 0x980ed1a3},
            {118, 0x98402ecc, 0x984c0a3e, 0x98178a55, 0x980ed193},
            {120, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed183},
            {124, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed193},
            {126, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed15b}, // 0x980ed1bb->0x980ed15b required by Rory 20070927
            {128, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed1a3},
            {132, 0x98402ec4, 0x984c0386, 0x98178a55, 0x980ed18b},
            {134, 0x98402ec4, 0x984c0386, 0x98178a55, 0x980ed193},
            {136, 0x98402ec4, 0x984c0386, 0x98178a55, 0x980ed19b},
            {140, 0x98402ec4, 0x984c038a, 0x98178a55, 0x980ed183},

            // 802.11 UNII
            {149, 0x98402ec4, 0x984c038a, 0x98178a55, 0x980ed1a7},
            {151, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed187},
            {153, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed18f},
            {157, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed19f},
            {159, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed1a7},
            {161, 0x98402ec4, 0x984c0392, 0x98178a55, 0x980ed187},
            {165, 0x98402ec4, 0x984c0392, 0x98178a55, 0x980ed197},

            // Japan
            {184, 0x95002ccc, 0x9500491e, 0x9509be55, 0x950c0a0b},
            {188, 0x95002ccc, 0x95004922, 0x9509be55, 0x950c0a13},
            {192, 0x95002ccc, 0x95004926, 0x9509be55, 0x950c0a1b},
            {196, 0x95002ccc, 0x9500492a, 0x9509be55, 0x950c0a23},
            {208, 0x95002ccc, 0x9500493a, 0x9509be55, 0x950c0a13},
            {212, 0x95002ccc, 0x9500493e, 0x9509be55, 0x950c0a1b},
            {216, 0x95002ccc, 0x95004982, 0x9509be55, 0x950c0a23},

            // still lack of MMAC(Japan) ch 34,38,42,46
};
UCHAR NUM_OF_2850_CHNL = (sizeof(RF2850RegTable) / sizeof(RTMP_RF_REGS));

FREQUENCY_ITEM FreqItems3020[] =
{
      /**************************************************/
      // ISM : 2.4 to 2.483 GHz                         //
      /**************************************************/
      // 11g
      /**************************************************/
      //-CH---N-------R---K-----------
      {1,    241,  2,  2},
      {2,    241,  2,  7},
      {3,    242,  2,  2},
      {4,    242,  2,  7},
      {5,    243,  2,  2},
      {6,    243,  2,  7},
      {7,    244,  2,  2},
      {8,    244,  2,  7},
      {9,    245,  2,  2},
      {10,   245,  2,  7},
      {11,   246,  2,  2},
      {12,   246,  2,  7},
      {13,   247,  2,  2},
      {14,   248,  2,  4},
};
#ifndef RT30xx
#define     NUM_OF_3020_CHNL  (sizeof(FreqItems3020) / sizeof(FREQUENCY_ITEM))
#endif
#ifdef RT30xx
//2008/07/10:KH Modified to share this variable
UCHAR NUM_OF_3020_CHNL=(sizeof(FreqItems3020) / sizeof(FREQUENCY_ITEM));
#endif

/*
      ==========================================================================
      Description:
            initialize the MLME task and its data structure (queue, spinlock,
            timer, state machines).

      IRQL = PASSIVE_LEVEL

      Return:
            always return NDIS_STATUS_SUCCESS

      ==========================================================================
*/
NDIS_STATUS MlmeInit(
      IN PRTMP_ADAPTER pAd)
{
      NDIS_STATUS Status = NDIS_STATUS_SUCCESS;

      DBGPRINT(RT_DEBUG_TRACE, ("--> MLME Initialize\n"));

      do
      {
            Status = MlmeQueueInit(&pAd->Mlme.Queue);
            if(Status != NDIS_STATUS_SUCCESS)
                  break;

            pAd->Mlme.bRunning = FALSE;
            NdisAllocateSpinLock(&pAd->Mlme.TaskLock);

            {
                  BssTableInit(&pAd->ScanTab);

                  // init STA state machines
                  AssocStateMachineInit(pAd, &pAd->Mlme.AssocMachine, pAd->Mlme.AssocFunc);
                  AuthStateMachineInit(pAd, &pAd->Mlme.AuthMachine, pAd->Mlme.AuthFunc);
                  AuthRspStateMachineInit(pAd, &pAd->Mlme.AuthRspMachine, pAd->Mlme.AuthRspFunc);
                  SyncStateMachineInit(pAd, &pAd->Mlme.SyncMachine, pAd->Mlme.SyncFunc);
                  WpaPskStateMachineInit(pAd, &pAd->Mlme.WpaPskMachine, pAd->Mlme.WpaPskFunc);
                  AironetStateMachineInit(pAd, &pAd->Mlme.AironetMachine, pAd->Mlme.AironetFunc);

                  // Since we are using switch/case to implement it, the init is different from the above
                  // state machine init
                  MlmeCntlInit(pAd, &pAd->Mlme.CntlMachine, NULL);
            }

            ActionStateMachineInit(pAd, &pAd->Mlme.ActMachine, pAd->Mlme.ActFunc);

            // Init mlme periodic timer
            RTMPInitTimer(pAd, &pAd->Mlme.PeriodicTimer, GET_TIMER_FUNCTION(MlmePeriodicExec), pAd, TRUE);

            // Set mlme periodic timer
            RTMPSetTimer(&pAd->Mlme.PeriodicTimer, MLME_TASK_EXEC_INTV);

            // software-based RX Antenna diversity
            RTMPInitTimer(pAd, &pAd->Mlme.RxAntEvalTimer, GET_TIMER_FUNCTION(AsicRxAntEvalTimeout), pAd, FALSE);

#ifdef RT2860
            {
              if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
              {
                  // only PCIe cards need these two timers
                  RTMPInitTimer(pAd, &pAd->Mlme.PsPollTimer, GET_TIMER_FUNCTION(PsPollWakeExec), pAd, FALSE);
                  RTMPInitTimer(pAd, &pAd->Mlme.RadioOnOffTimer, GET_TIMER_FUNCTION(RadioOnExec), pAd, FALSE);
              }
            }
#endif
      } while (FALSE);

      DBGPRINT(RT_DEBUG_TRACE, ("<-- MLME Initialize\n"));

      return Status;
}

/*
      ==========================================================================
      Description:
            main loop of the MLME
      Pre:
            Mlme has to be initialized, and there are something inside the queue
      Note:
            This function is invoked from MPSetInformation and MPReceive;
            This task guarantee only one MlmeHandler will run.

      IRQL = DISPATCH_LEVEL

      ==========================================================================
 */
VOID MlmeHandler(
      IN PRTMP_ADAPTER pAd)
{
      MLME_QUEUE_ELEM      *Elem = NULL;

      // Only accept MLME and Frame from peer side, no other (control/data) frame should
      // get into this state machine

      NdisAcquireSpinLock(&pAd->Mlme.TaskLock);
      if(pAd->Mlme.bRunning)
      {
            NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
            return;
      }
      else
      {
            pAd->Mlme.bRunning = TRUE;
      }
      NdisReleaseSpinLock(&pAd->Mlme.TaskLock);

      while (!MlmeQueueEmpty(&pAd->Mlme.Queue))
      {
            if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_MLME_RESET_IN_PROGRESS) ||
                  RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS) ||
                  RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))
            {
                  DBGPRINT(RT_DEBUG_TRACE, ("Device Halted or Removed or MlmeRest, exit MlmeHandler! (queue num = %ld)\n", pAd->Mlme.Queue.Num));
                  break;
            }

            //From message type, determine which state machine I should drive
            if (MlmeDequeue(&pAd->Mlme.Queue, &Elem))
            {
#ifdef RT2870
                  if (Elem->MsgType == MT2_RESET_CONF)
                  {
                        DBGPRINT_RAW(RT_DEBUG_TRACE, ("!!! reset MLME state machine !!!\n"));
                        MlmeRestartStateMachine(pAd);
                        Elem->Occupied = FALSE;
                        Elem->MsgLen = 0;
                        continue;
                  }
#endif // RT2870 //

                  // if dequeue success
                  switch (Elem->Machine)
                  {
                        // STA state machines
                        case ASSOC_STATE_MACHINE:
                              StateMachinePerformAction(pAd, &pAd->Mlme.AssocMachine, Elem);
                              break;
                        case AUTH_STATE_MACHINE:
                              StateMachinePerformAction(pAd, &pAd->Mlme.AuthMachine, Elem);
                              break;
                        case AUTH_RSP_STATE_MACHINE:
                              StateMachinePerformAction(pAd, &pAd->Mlme.AuthRspMachine, Elem);
                              break;
                        case SYNC_STATE_MACHINE:
                              StateMachinePerformAction(pAd, &pAd->Mlme.SyncMachine, Elem);
                              break;
                        case MLME_CNTL_STATE_MACHINE:
                              MlmeCntlMachinePerformAction(pAd, &pAd->Mlme.CntlMachine, Elem);
                              break;
                        case WPA_PSK_STATE_MACHINE:
                              StateMachinePerformAction(pAd, &pAd->Mlme.WpaPskMachine, Elem);
                              break;
                        case AIRONET_STATE_MACHINE:
                              StateMachinePerformAction(pAd, &pAd->Mlme.AironetMachine, Elem);
                              break;
                        case ACTION_STATE_MACHINE:
                              StateMachinePerformAction(pAd, &pAd->Mlme.ActMachine, Elem);
                              break;




                        default:
                              DBGPRINT(RT_DEBUG_TRACE, ("ERROR: Illegal machine %ld in MlmeHandler()\n", Elem->Machine));
                              break;
                  } // end of switch

                  // free MLME element
                  Elem->Occupied = FALSE;
                  Elem->MsgLen = 0;

            }
            else {
                  DBGPRINT_ERR(("MlmeHandler: MlmeQueue empty\n"));
            }
      }

      NdisAcquireSpinLock(&pAd->Mlme.TaskLock);
      pAd->Mlme.bRunning = FALSE;
      NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
}

/*
      ==========================================================================
      Description:
            Destructor of MLME (Destroy queue, state machine, spin lock and timer)
      Parameters:
            Adapter - NIC Adapter pointer
      Post:
            The MLME task will no longer work properly

      IRQL = PASSIVE_LEVEL

      ==========================================================================
 */
VOID MlmeHalt(
      IN PRTMP_ADAPTER pAd)
{
      BOOLEAN       Cancelled;
#ifdef RT3070
      UINT32            TxPinCfg = 0x00050F0F;
#endif // RT3070 //

      DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeHalt\n"));

      if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))
      {
            // disable BEACON generation and other BEACON related hardware timers
            AsicDisableSync(pAd);
      }

      {
            // Cancel pending timers
            RTMPCancelTimer(&pAd->MlmeAux.AssocTimer,       &Cancelled);
            RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer,           &Cancelled);
            RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer,    &Cancelled);
            RTMPCancelTimer(&pAd->MlmeAux.AuthTimer,        &Cancelled);
            RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer,            &Cancelled);
            RTMPCancelTimer(&pAd->MlmeAux.ScanTimer,        &Cancelled);
#ifdef RT2860
          if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
          {
                RTMPCancelTimer(&pAd->Mlme.PsPollTimer,           &Cancelled);
                RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer,       &Cancelled);
            }
#endif
      }

      RTMPCancelTimer(&pAd->Mlme.PeriodicTimer,       &Cancelled);
      RTMPCancelTimer(&pAd->Mlme.RxAntEvalTimer,            &Cancelled);



      if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))
      {
            // Set LED
            RTMPSetLED(pAd, LED_HALT);
        RTMPSetSignalLED(pAd, -100);      // Force signal strength Led to be turned off, firmware is not done it.
#ifdef RT2870
        {
            LED_CFG_STRUC LedCfg;
            RTMP_IO_READ32(pAd, LED_CFG, &LedCfg.word);
            LedCfg.field.LedPolar = 0;
            LedCfg.field.RLedMode = 0;
            LedCfg.field.GLedMode = 0;
            LedCfg.field.YLedMode = 0;
            RTMP_IO_WRITE32(pAd, LED_CFG, LedCfg.word);
        }
#endif // RT2870 //
#ifdef RT3070
            //
            // Turn off LNA_PE
            //
            if (IS_RT3070(pAd) || IS_RT3071(pAd))
            {
                  TxPinCfg &= 0xFFFFF0F0;
                  RTUSBWriteMACRegister(pAd, TX_PIN_CFG, TxPinCfg);
            }
#endif // RT3070 //
      }

      RTMPusecDelay(5000);    //  5 msec to gurantee Ant Diversity timer canceled

      MlmeQueueDestroy(&pAd->Mlme.Queue);
      NdisFreeSpinLock(&pAd->Mlme.TaskLock);

      DBGPRINT(RT_DEBUG_TRACE, ("<== MlmeHalt\n"));
}

VOID MlmeResetRalinkCounters(
      IN  PRTMP_ADAPTER   pAd)
{
      pAd->RalinkCounters.LastOneSecRxOkDataCnt = pAd->RalinkCounters.OneSecRxOkDataCnt;
      // clear all OneSecxxx counters.
      pAd->RalinkCounters.OneSecBeaconSentCnt = 0;
      pAd->RalinkCounters.OneSecFalseCCACnt = 0;
      pAd->RalinkCounters.OneSecRxFcsErrCnt = 0;
      pAd->RalinkCounters.OneSecRxOkCnt = 0;
      pAd->RalinkCounters.OneSecTxFailCount = 0;
      pAd->RalinkCounters.OneSecTxNoRetryOkCount = 0;
      pAd->RalinkCounters.OneSecTxRetryOkCount = 0;
      pAd->RalinkCounters.OneSecRxOkDataCnt = 0;

      // TODO: for debug only. to be removed
      pAd->RalinkCounters.OneSecOsTxCount[QID_AC_BE] = 0;
      pAd->RalinkCounters.OneSecOsTxCount[QID_AC_BK] = 0;
      pAd->RalinkCounters.OneSecOsTxCount[QID_AC_VI] = 0;
      pAd->RalinkCounters.OneSecOsTxCount[QID_AC_VO] = 0;
      pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_BE] = 0;
      pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_BK] = 0;
      pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_VI] = 0;
      pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_VO] = 0;
      pAd->RalinkCounters.OneSecTxDoneCount = 0;
      pAd->RalinkCounters.OneSecRxCount = 0;
      pAd->RalinkCounters.OneSecTxAggregationCount = 0;
      pAd->RalinkCounters.OneSecRxAggregationCount = 0;

      return;
}

unsigned long rx_AMSDU;
unsigned long rx_Total;

/*
      ==========================================================================
      Description:
            This routine is executed periodically to -
            1. Decide if it's a right time to turn on PwrMgmt bit of all
               outgoiing frames
            2. Calculate ChannelQuality based on statistics of the last
               period, so that TX rate won't toggling very frequently between a
               successful TX and a failed TX.
            3. If the calculated ChannelQuality indicated current connection not
               healthy, then a ROAMing attempt is tried here.

      IRQL = DISPATCH_LEVEL

      ==========================================================================
 */
#define ADHOC_BEACON_LOST_TIME            (8*OS_HZ)  // 8 sec
VOID MlmePeriodicExec(
      IN PVOID SystemSpecific1,
      IN PVOID FunctionContext,
      IN PVOID SystemSpecific2,
      IN PVOID SystemSpecific3)
{
      ULONG             TxTotalCnt;
      PRTMP_ADAPTER     pAd = (RTMP_ADAPTER *)FunctionContext;

#ifdef RT2860
      //Baron 2008/07/10
      //printk("Baron_Test:\t%s", RTMPGetRalinkEncryModeStr(pAd->StaCfg.WepStatus));
      //If the STA security setting is OPEN or WEP, pAd->StaCfg.WpaSupplicantUP = 0.
      //If the STA security setting is WPAPSK or WPA2PSK, pAd->StaCfg.WpaSupplicantUP = 1.
      if(pAd->StaCfg.WepStatus<2)
      {
            pAd->StaCfg.WpaSupplicantUP = 0;
      }
      else
      {
            pAd->StaCfg.WpaSupplicantUP = 1;
      }

      {
          // If Hardware controlled Radio enabled, we have to check GPIO pin2 every 2 second.
            // Move code to here, because following code will return when radio is off
            if ((pAd->Mlme.PeriodicRound % (MLME_TASK_EXEC_MULTIPLE * 2) == 0) &&
                  (pAd->StaCfg.bHardwareRadio == TRUE) &&
                  (RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_START_UP)) &&
                  (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) &&
                  (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)))
            {
                  UINT32                        data = 0;

                  // Read GPIO pin2 as Hardware controlled radio state
                  RTMP_IO_FORCE_READ32(pAd, GPIO_CTRL_CFG, &data);
                  if (data & 0x04)
                  {
                        pAd->StaCfg.bHwRadio = TRUE;
                  }
                  else
                  {
                        pAd->StaCfg.bHwRadio = FALSE;
                  }
                  if (pAd->StaCfg.bRadio != (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio))
                  {
                        pAd->StaCfg.bRadio = (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio);
                        if (pAd->StaCfg.bRadio == TRUE)
                        {
                              MlmeRadioOn(pAd);
                              // Update extra information
                              pAd->ExtraInfo = EXTRA_INFO_CLEAR;
                        }
                        else
                        {
                              MlmeRadioOff(pAd);
                              // Update extra information
                              pAd->ExtraInfo = HW_RADIO_OFF;
                        }
                  }
            }
      }
#endif /* RT2860 */

      // Do nothing if the driver is starting halt state.
      // This might happen when timer already been fired before cancel timer with mlmehalt
      if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_HALT_IN_PROGRESS |
                                                fRTMP_ADAPTER_RADIO_OFF |
                                                fRTMP_ADAPTER_RADIO_MEASUREMENT |
                                                fRTMP_ADAPTER_RESET_IN_PROGRESS))))
            return;

#ifdef RT2860
      {
            if ((pAd->RalinkCounters.LastReceivedByteCount == pAd->RalinkCounters.ReceivedByteCount) && (pAd->StaCfg.bRadio == TRUE))
            {
                  // If ReceiveByteCount doesn't change,  increase SameRxByteCount by 1.
                  pAd->SameRxByteCount++;
            }
            else
                  pAd->SameRxByteCount = 0;

            // If after BBP, still not work...need to check to reset PBF&MAC.
            if (pAd->SameRxByteCount == 702)
            {
                  pAd->SameRxByteCount = 0;
                  AsicResetPBF(pAd);
                  AsicResetMAC(pAd);
            }

            // If SameRxByteCount keeps happens for 2 second in infra mode, or for 60 seconds in idle mode.
            if (((INFRA_ON(pAd)) && (pAd->SameRxByteCount > 20)) || ((IDLE_ON(pAd)) && (pAd->SameRxByteCount > 600)))
            {
                  if ((pAd->StaCfg.bRadio == TRUE) && (pAd->SameRxByteCount < 700))
                  {
                        DBGPRINT(RT_DEBUG_TRACE, ("--->  SameRxByteCount = %lu !!!!!!!!!!!!!!! \n", pAd->SameRxByteCount));
                        pAd->SameRxByteCount = 700;
                        AsicResetBBP(pAd);
                  }
            }

            // Update lastReceiveByteCount.
            pAd->RalinkCounters.LastReceivedByteCount = pAd->RalinkCounters.ReceivedByteCount;

            if ((pAd->CheckDmaBusyCount > 3) && (IDLE_ON(pAd)))
            {
                  pAd->CheckDmaBusyCount = 0;
                  AsicResetFromDMABusy(pAd);
            }
      }
#endif /* RT2860 */
      RT28XX_MLME_PRE_SANITY_CHECK(pAd);

      {
            // Do nothing if monitor mode is on
            if (MONITOR_ON(pAd))
                  return;

            if (pAd->Mlme.PeriodicRound & 0x1)
            {
                  // This is the fix for wifi 11n extension channel overlapping test case.  for 2860D
                  if (((pAd->MACVersion & 0xffff) == 0x0101) &&
                        (STA_TGN_WIFI_ON(pAd)) &&
                        (pAd->CommonCfg.IOTestParm.bToggle == FALSE))

                        {
                              RTMP_IO_WRITE32(pAd, TXOP_CTRL_CFG, 0x24Bf);
                              pAd->CommonCfg.IOTestParm.bToggle = TRUE;
                        }
                        else if ((STA_TGN_WIFI_ON(pAd)) &&
                                    ((pAd->MACVersion & 0xffff) == 0x0101))
                        {
                              RTMP_IO_WRITE32(pAd, TXOP_CTRL_CFG, 0x243f);
                              pAd->CommonCfg.IOTestParm.bToggle = FALSE;
                        }
            }
      }

      pAd->bUpdateBcnCntDone = FALSE;

//    RECBATimerTimeout(SystemSpecific1,FunctionContext,SystemSpecific2,SystemSpecific3);
      pAd->Mlme.PeriodicRound ++;

#ifdef RT3070
      // execute every 100ms, update the Tx FIFO Cnt for update Tx Rate.
      NICUpdateFifoStaCounters(pAd);
#endif // RT3070 //
      // execute every 500ms
      if ((pAd->Mlme.PeriodicRound % 5 == 0) && RTMPAutoRateSwitchCheck(pAd)/*(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED))*/)
      {
            // perform dynamic tx rate switching based on past TX history
            {
                  if ((OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)
                              )
                        && (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)))
                        MlmeDynamicTxRateSwitching(pAd);
            }
      }

      // Normal 1 second Mlme PeriodicExec.
      if (pAd->Mlme.PeriodicRound %MLME_TASK_EXEC_MULTIPLE == 0)
      {
                pAd->Mlme.OneSecPeriodicRound ++;

            if (rx_Total)
            {

                  // reset counters
                  rx_AMSDU = 0;
                  rx_Total = 0;
            }

            // Media status changed, report to NDIS
            if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_MEDIA_STATE_CHANGE))
            {
                  RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_MEDIA_STATE_CHANGE);
                  if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED))
                  {
                        pAd->IndicateMediaState = NdisMediaStateConnected;
                        RTMP_IndicateMediaState(pAd);

                  }
                  else
                  {
                        pAd->IndicateMediaState = NdisMediaStateDisconnected;
                        RTMP_IndicateMediaState(pAd);
                  }
            }

            NdisGetSystemUpTime(&pAd->Mlme.Now32);

            // add the most up-to-date h/w raw counters into software variable, so that
            // the dynamic tuning mechanism below are based on most up-to-date information
            NICUpdateRawCounters(pAd);

#ifdef RT2870
            RT2870_WatchDog(pAd);
#endif // RT2870 //

            // Need statistics after read counter. So put after NICUpdateRawCounters
            ORIBATimerTimeout(pAd);

            // The time period for checking antenna is according to traffic
            if (pAd->Mlme.bEnableAutoAntennaCheck)
            {
                  TxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount +
                                           pAd->RalinkCounters.OneSecTxRetryOkCount +
                                           pAd->RalinkCounters.OneSecTxFailCount;

                  // dynamic adjust antenna evaluation period according to the traffic
                  if (TxTotalCnt > 50)
                  {
                        if (pAd->Mlme.OneSecPeriodicRound % 10 == 0)
                        {
                              AsicEvaluateRxAnt(pAd);
                        }
                  }
                  else
                  {
                        if (pAd->Mlme.OneSecPeriodicRound % 3 == 0)
                        {
                              AsicEvaluateRxAnt(pAd);
                        }
                  }
            }

            STAMlmePeriodicExec(pAd);

            MlmeResetRalinkCounters(pAd);

            {
#ifdef RT2860
                  if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST) && (pAd->bPCIclkOff == FALSE))
#endif
                  {
                        // When Adhoc beacon is enabled and RTS/CTS is enabled, there is a chance that hardware MAC FSM will run into a deadlock
                        // and sending CTS-to-self over and over.
                        // Software Patch Solution:
                        // 1. Polling debug state register 0x10F4 every one second.
                        // 2. If in 0x10F4 the ((bit29==1) && (bit7==1)) OR ((bit29==1) && (bit5==1)), it means the deadlock has occurred.
                        // 3. If the deadlock occurred, reset MAC/BBP by setting 0x1004 to 0x0001 for a while then setting it back to 0x000C again.

                        UINT32      MacReg = 0;

                        RTMP_IO_READ32(pAd, 0x10F4, &MacReg);
                        if (((MacReg & 0x20000000) && (MacReg & 0x80)) || ((MacReg & 0x20000000) && (MacReg & 0x20)))
                        {
                              RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x1);
                              RTMPusecDelay(1);
                              RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0xC);

                              DBGPRINT(RT_DEBUG_WARN,("Warning, MAC specific condition occurs \n"));
                        }
                  }
            }

            RT28XX_MLME_HANDLER(pAd);
      }

      pAd->bUpdateBcnCntDone = FALSE;
}

VOID STAMlmePeriodicExec(
      PRTMP_ADAPTER pAd)
{
#ifdef RT2860
      ULONG                 TxTotalCnt;
#endif
#ifdef RT2870
      ULONG TxTotalCnt;
      int   i;
#endif

    if (pAd->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_DISABLE)
    {
      // WPA MIC error should block association attempt for 60 seconds
      if (pAd->StaCfg.bBlockAssoc && (pAd->StaCfg.LastMicErrorTime + (60 * OS_HZ) < pAd->Mlme.Now32))
            pAd->StaCfg.bBlockAssoc = FALSE;
    }

#ifdef RT2860
      //Baron 2008/07/10
      //printk("Baron_Test:\t%s", RTMPGetRalinkEncryModeStr(pAd->StaCfg.WepStatus));
      //If the STA security setting is OPEN or WEP, pAd->StaCfg.WpaSupplicantUP = 0.
      //If the STA security setting is WPAPSK or WPA2PSK, pAd->StaCfg.WpaSupplicantUP = 1.
      if(pAd->StaCfg.WepStatus<2)
      {
            pAd->StaCfg.WpaSupplicantUP = 0;
      }
      else
      {
            pAd->StaCfg.WpaSupplicantUP = 1;
      }
#endif

    if ((pAd->PreMediaState != pAd->IndicateMediaState) && (pAd->CommonCfg.bWirelessEvent))
      {
            if (pAd->IndicateMediaState == NdisMediaStateConnected)
            {
                  RTMPSendWirelessEvent(pAd, IW_STA_LINKUP_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0);
            }
            pAd->PreMediaState = pAd->IndicateMediaState;
      }

#ifdef RT2860
      if ((pAd->OpMode == OPMODE_STA) && (IDLE_ON(pAd)) &&
        (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) &&
            (pAd->Mlme.SyncMachine.CurrState == SYNC_IDLE) &&
            (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) &&
            (RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_START_UP)) &&
            (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF)))
      {
            RT28xxPciAsicRadioOff(pAd, GUI_IDLE_POWER_SAVE, 0);
      }
#endif



      AsicStaBbpTuning(pAd);

      TxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount +
                               pAd->RalinkCounters.OneSecTxRetryOkCount +
                               pAd->RalinkCounters.OneSecTxFailCount;

      if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED))
      {
            // update channel quality for Roaming and UI LinkQuality display
            MlmeCalculateChannelQuality(pAd, pAd->Mlme.Now32);
      }

      // must be AFTER MlmeDynamicTxRateSwitching() because it needs to know if
      // Radio is currently in noisy environment
      if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
            AsicAdjustTxPower(pAd);

      if (INFRA_ON(pAd))
      {
            // Is PSM bit consistent with user power management policy?
            // This is the only place that will set PSM bit ON.
            if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))
            MlmeCheckPsmChange(pAd, pAd->Mlme.Now32);

            pAd->RalinkCounters.LastOneSecTotalTxCount = TxTotalCnt;

            if ((pAd->StaCfg.LastBeaconRxTime + 1*OS_HZ < pAd->Mlme.Now32) &&
                  (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) &&
                  ((TxTotalCnt + pAd->RalinkCounters.OneSecRxOkCnt < 600)))
            {
                  RTMPSetAGCInitValue(pAd, BW_20);
                  DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - No BEACON. restore R66 to the low bound(%d) \n", (0x2E + GET_LNA_GAIN(pAd))));
            }

        {
            if (pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable)
            {
                // When APSD is enabled, the period changes as 20 sec
                  if ((pAd->Mlme.OneSecPeriodicRound % 20) == 8)
                        RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE);
            }
            else
            {
                // Send out a NULL frame every 10 sec to inform AP that STA is still alive (Avoid being age out)
                  if ((pAd->Mlme.OneSecPeriodicRound % 10) == 8)
                {
                    if (pAd->CommonCfg.bWmmCapable)
                              RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE);
                    else
                                    RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, FALSE);
                }
            }
        }

            if (CQI_IS_DEAD(pAd->Mlme.ChannelQuality))
                  {
                  DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - No BEACON. Dead CQI. Auto Recovery attempt #%ld\n", pAd->RalinkCounters.BadCQIAutoRecoveryCount));
                  pAd->StaCfg.CCXAdjacentAPReportFlag = TRUE;
                  pAd->StaCfg.CCXAdjacentAPLinkDownTime = pAd->StaCfg.LastBeaconRxTime;

                  // Lost AP, send disconnect & link down event
                  LinkDown(pAd, FALSE);

            {
                union iwreq_data    wrqu;
                memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN);
                wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL);
            }

                  MlmeAutoReconnectLastSSID(pAd);
            }
            else if (CQI_IS_BAD(pAd->Mlme.ChannelQuality))
            {
                  pAd->RalinkCounters.BadCQIAutoRecoveryCount ++;
                  DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Bad CQI. Auto Recovery attempt #%ld\n", pAd->RalinkCounters.BadCQIAutoRecoveryCount));
                  MlmeAutoReconnectLastSSID(pAd);
            }

            // Add auto seamless roaming
            if (pAd->StaCfg.bFastRoaming)
            {
                  SHORT dBmToRoam = (SHORT)pAd->StaCfg.dBmToRoam;

                  DBGPRINT(RT_DEBUG_TRACE, ("Rssi=%d, dBmToRoam=%d\n", RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2), (CHAR)dBmToRoam));

                  if (RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2) <= (CHAR)dBmToRoam)
                  {
                        MlmeCheckForFastRoaming(pAd, pAd->Mlme.Now32);
                  }
            }
      }
      else if (ADHOC_ON(pAd))
      {
#ifdef RT2860
            // 2003-04-17 john. this is a patch that driver forces a BEACON out if ASIC fails
            // the "TX BEACON competition" for the entire past 1 sec.
            // So that even when ASIC's BEACONgen engine been blocked
            // by peer's BEACON due to slower system clock, this STA still can send out
            // minimum BEACON to tell the peer I'm alive.
            // drawback is that this BEACON won't be well aligned at TBTT boundary.
            // EnqueueBeaconFrame(pAd);                 // software send BEACON

            // if all 11b peers leave this BSS more than 5 seconds, update Tx rate,
            // restore outgoing BEACON to support B/G-mixed mode
            if ((pAd->CommonCfg.Channel <= 14)                 &&
                  (pAd->CommonCfg.MaxTxRate <= RATE_11)        &&
                  (pAd->CommonCfg.MaxDesiredRate > RATE_11)  &&
                  ((pAd->StaCfg.Last11bBeaconRxTime + 5*OS_HZ) < pAd->Mlme.Now32))
            {
                  DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - last 11B peer left, update Tx rates\n"));
                  NdisMoveMemory(pAd->StaActive.SupRate, pAd->CommonCfg.SupRate, MAX_LEN_OF_SUPPORTED_RATES);
                  pAd->StaActive.SupRateLen = pAd->CommonCfg.SupRateLen;
                  MlmeUpdateTxRates(pAd, FALSE, 0);
                  MakeIbssBeacon(pAd);          // re-build BEACON frame
                  AsicEnableIbssSync(pAd);      // copy to on-chip memory
                  pAd->StaCfg.AdhocBOnlyJoined = FALSE;
            }

            if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)
            {
                  if ((pAd->StaCfg.AdhocBGJoined) &&
                        ((pAd->StaCfg.Last11gBeaconRxTime + 5 * OS_HZ) < pAd->Mlme.Now32))
                  {
                        DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - last 11G peer left\n"));
                        pAd->StaCfg.AdhocBGJoined = FALSE;
                  }

                  if ((pAd->StaCfg.Adhoc20NJoined) &&
                        ((pAd->StaCfg.Last20NBeaconRxTime + 5 * OS_HZ) < pAd->Mlme.Now32))
                  {
                        DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - last 20MHz N peer left\n"));
                        pAd->StaCfg.Adhoc20NJoined = FALSE;
                  }
            }
#endif /* RT2860 */

            //radar detect
            if ((pAd->CommonCfg.Channel > 14)
                  && (pAd->CommonCfg.bIEEE80211H == 1)
                  && RadarChannelCheck(pAd, pAd->CommonCfg.Channel))
            {
                  RadarDetectPeriodic(pAd);
            }

            // If all peers leave, and this STA becomes the last one in this IBSS, then change MediaState
            // to DISCONNECTED. But still holding this IBSS (i.e. sending BEACON) so that other STAs can
            // join later.
            if ((pAd->StaCfg.LastBeaconRxTime + ADHOC_BEACON_LOST_TIME < pAd->Mlme.Now32) &&
                  OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED))
            {
                  MLME_START_REQ_STRUCT     StartReq;

                  DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - excessive BEACON lost, last STA in this IBSS, MediaState=Disconnected\n"));
                  LinkDown(pAd, FALSE);

                  StartParmFill(pAd, &StartReq, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen);
                  MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_START_REQ, sizeof(MLME_START_REQ_STRUCT), &StartReq);
                  pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_START;
            }

#ifdef RT2870
            for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++)
            {
                  MAC_TABLE_ENTRY *pEntry = &pAd->MacTab.Content[i];

                  if (pEntry->ValidAsCLI == FALSE)
                        continue;

                  if (pEntry->LastBeaconRxTime + ADHOC_BEACON_LOST_TIME < pAd->Mlme.Now32)
                        MacTableDeleteEntry(pAd, pEntry->Aid, pEntry->Addr);
            }
#endif
      }
      else // no INFRA nor ADHOC connection
      {

            if (pAd->StaCfg.bScanReqIsFromWebUI &&
            ((pAd->StaCfg.LastScanTime + 30 * OS_HZ) > pAd->Mlme.Now32))
                  goto SKIP_AUTO_SCAN_CONN;
        else
            pAd->StaCfg.bScanReqIsFromWebUI = FALSE;

            if ((pAd->StaCfg.bAutoReconnect == TRUE)
                  && RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP)
                  && (MlmeValidateSSID(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen) == TRUE))
            {
                  if ((pAd->ScanTab.BssNr==0) && (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE))
                  {
                        MLME_SCAN_REQ_STRUCT       ScanReq;

                        if ((pAd->StaCfg.LastScanTime + 10 * OS_HZ) < pAd->Mlme.Now32)
                        {
                              DBGPRINT(RT_DEBUG_TRACE, ("STAMlmePeriodicExec():CNTL - ScanTab.BssNr==0, start a new ACTIVE scan SSID[%s]\n", pAd->MlmeAux.AutoReconnectSsid));
                              ScanParmFill(pAd, &ScanReq, pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen, BSS_ANY, SCAN_ACTIVE);
                              MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq);
                              pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN;
                              // Reset Missed scan number
                              pAd->StaCfg.LastScanTime = pAd->Mlme.Now32;
                        }
                        else if (pAd->StaCfg.BssType == BSS_ADHOC)      // Quit the forever scan when in a very clean room
                              MlmeAutoReconnectLastSSID(pAd);
                  }
                  else if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)
                  {
                        if ((pAd->Mlme.OneSecPeriodicRound % 7) == 0)
                        {
                              MlmeAutoScan(pAd);
                              pAd->StaCfg.LastScanTime = pAd->Mlme.Now32;
                        }
                        else
                        {
                                    MlmeAutoReconnectLastSSID(pAd);
                        }
                  }
            }
      }

SKIP_AUTO_SCAN_CONN:

    if ((pAd->MacTab.Content[BSSID_WCID].TXBAbitmap !=0) && (pAd->MacTab.fAnyBASession == FALSE))
      {
            pAd->MacTab.fAnyBASession = TRUE;
            AsicUpdateProtect(pAd, HT_FORCERTSCTS,  ALLN_SETPROTECT, FALSE, FALSE);
      }
      else if ((pAd->MacTab.Content[BSSID_WCID].TXBAbitmap ==0) && (pAd->MacTab.fAnyBASession == TRUE))
      {
            pAd->MacTab.fAnyBASession = FALSE;
            AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode,  ALLN_SETPROTECT, FALSE, FALSE);
      }

      return;
}

// Link down report
VOID LinkDownExec(
      IN PVOID SystemSpecific1,
      IN PVOID FunctionContext,
      IN PVOID SystemSpecific2,
      IN PVOID SystemSpecific3)
{

      RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;

      pAd->IndicateMediaState = NdisMediaStateDisconnected;
      RTMP_IndicateMediaState(pAd);
    pAd->ExtraInfo = GENERAL_LINK_DOWN;
}

// IRQL = DISPATCH_LEVEL
VOID MlmeAutoScan(
      IN PRTMP_ADAPTER pAd)
{
      // check CntlMachine.CurrState to avoid collision with NDIS SetOID request
      if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)
      {
            DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Driver auto scan\n"));
            MlmeEnqueue(pAd,
                              MLME_CNTL_STATE_MACHINE,
                              OID_802_11_BSSID_LIST_SCAN,
                              0,
                              NULL);
            RT28XX_MLME_HANDLER(pAd);
      }
}

// IRQL = DISPATCH_LEVEL
VOID MlmeAutoReconnectLastSSID(
      IN PRTMP_ADAPTER pAd)
{


      // check CntlMachine.CurrState to avoid collision with NDIS SetOID request
      if ((pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) &&
            (MlmeValidateSSID(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen) == TRUE))
      {
            NDIS_802_11_SSID OidSsid;
            OidSsid.SsidLength = pAd->MlmeAux.AutoReconnectSsidLen;
            NdisMoveMemory(OidSsid.Ssid, pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen);

            DBGPRINT(RT_DEBUG_TRACE, ("Driver auto reconnect to last OID_802_11_SSID setting - %s, len - %d\n", pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen));
            MlmeEnqueue(pAd,
                              MLME_CNTL_STATE_MACHINE,
                              OID_802_11_SSID,
                              sizeof(NDIS_802_11_SSID),
                              &OidSsid);
            RT28XX_MLME_HANDLER(pAd);
      }
}

/*
      ==========================================================================
      Validate SSID for connection try and rescan purpose
      Valid SSID will have visible chars only.
      The valid length is from 0 to 32.
      IRQL = DISPATCH_LEVEL
      ==========================================================================
 */
BOOLEAN MlmeValidateSSID(
      IN PUCHAR   pSsid,
      IN UCHAR    SsidLen)
{
      int   index;

      if (SsidLen > MAX_LEN_OF_SSID)
            return (FALSE);

      // Check each character value
      for (index = 0; index < SsidLen; index++)
      {
            if (pSsid[index] < 0x20)
                  return (FALSE);
      }

      // All checked
      return (TRUE);
}

VOID MlmeSelectTxRateTable(
      IN PRTMP_ADAPTER        pAd,
      IN PMAC_TABLE_ENTRY           pEntry,
      IN PUCHAR                     *ppTable,
      IN PUCHAR                     pTableSize,
      IN PUCHAR                     pInitTxRateIdx)
{
      do
      {
            // decide the rate table for tuning
            if (pAd->CommonCfg.TxRateTableSize > 0)
            {
                  *ppTable = RateSwitchTable;
                  *pTableSize = RateSwitchTable[0];
                  *pInitTxRateIdx = RateSwitchTable[1];

                  break;
            }

            if ((pAd->OpMode == OPMODE_STA) && ADHOC_ON(pAd))
            {
                  if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) &&
#ifdef RT2860
                        !pAd->StaCfg.AdhocBOnlyJoined &&
                        !pAd->StaCfg.AdhocBGJoined &&
                        (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) &&
                        ((pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0x00) || (pAd->Antenna.field.TxPath == 1)))
#endif
#ifdef RT2870
                        (pEntry->HTCapability.MCSSet[0] == 0xff) &&
                        ((pEntry->HTCapability.MCSSet[1] == 0x00) || (pAd->Antenna.field.TxPath == 1)))
#endif
                  {// 11N 1S Adhoc
                        *ppTable = RateSwitchTable11N1S;
                        *pTableSize = RateSwitchTable11N1S[0];
                        *pInitTxRateIdx = RateSwitchTable11N1S[1];

                  }
                  else if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) &&
#ifdef RT2860
                              !pAd->StaCfg.AdhocBOnlyJoined &&
                              !pAd->StaCfg.AdhocBGJoined &&
                              (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) &&
                              (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0xff) &&
#endif
#ifdef RT2870
                              (pEntry->HTCapability.MCSSet[0] == 0xff) &&
                              (pEntry->HTCapability.MCSSet[1] == 0xff) &&
#endif
                              (pAd->Antenna.field.TxPath == 2))
                  {// 11N 2S Adhoc
                        if (pAd->LatchRfRegs.Channel <= 14)
                        {
                              *ppTable = RateSwitchTable11N2S;
                              *pTableSize = RateSwitchTable11N2S[0];
                              *pInitTxRateIdx = RateSwitchTable11N2S[1];
                        }
                        else
                        {
                              *ppTable = RateSwitchTable11N2SForABand;
                              *pTableSize = RateSwitchTable11N2SForABand[0];
                              *pInitTxRateIdx = RateSwitchTable11N2SForABand[1];
                        }

                  }
                  else
#ifdef RT2860
                        if (pAd->CommonCfg.PhyMode == PHY_11B)
                  {
                        *ppTable = RateSwitchTable11B;
                        *pTableSize = RateSwitchTable11B[0];
                        *pInitTxRateIdx = RateSwitchTable11B[1];

                  }
              else if((pAd->LatchRfRegs.Channel <= 14) && (pAd->StaCfg.AdhocBOnlyJoined == TRUE))
#endif
#ifdef RT2870
                        if ((pEntry->RateLen == 4)
                              && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0)
                              )
#endif
                  {
                        // USe B Table when Only b-only Station in my IBSS .
                        *ppTable = RateSwitchTable11B;
                        *pTableSize = RateSwitchTable11B[0];
                        *pInitTxRateIdx = RateSwitchTable11B[1];

                  }
                  else if (pAd->LatchRfRegs.Channel <= 14)
                  {
                        *ppTable = RateSwitchTable11BG;
                        *pTableSize = RateSwitchTable11BG[0];
                        *pInitTxRateIdx = RateSwitchTable11BG[1];

                  }
                  else
                  {
                        *ppTable = RateSwitchTable11G;
                        *pTableSize = RateSwitchTable11G[0];
                        *pInitTxRateIdx = RateSwitchTable11G[1];

                  }
                  break;
            }

            if ((pEntry->RateLen == 12) && (pEntry->HTCapability.MCSSet[0] == 0xff) &&
                  ((pEntry->HTCapability.MCSSet[1] == 0x00) || (pAd->CommonCfg.TxStream == 1)))
            {// 11BGN 1S AP
                  *ppTable = RateSwitchTable11BGN1S;
                  *pTableSize = RateSwitchTable11BGN1S[0];
                  *pInitTxRateIdx = RateSwitchTable11BGN1S[1];

                  break;
            }

            if ((pEntry->RateLen == 12) && (pEntry->HTCapability.MCSSet[0] == 0xff) &&
                  (pEntry->HTCapability.MCSSet[1] == 0xff) && (pAd->CommonCfg.TxStream == 2))
            {// 11BGN 2S AP
                  if (pAd->LatchRfRegs.Channel <= 14)
                  {
                        *ppTable = RateSwitchTable11BGN2S;
                        *pTableSize = RateSwitchTable11BGN2S[0];
                        *pInitTxRateIdx = RateSwitchTable11BGN2S[1];

                  }
                  else
                  {
                        *ppTable = RateSwitchTable11BGN2SForABand;
                        *pTableSize = RateSwitchTable11BGN2SForABand[0];
                        *pInitTxRateIdx = RateSwitchTable11BGN2SForABand[1];

                  }
                  break;
            }

            if ((pEntry->HTCapability.MCSSet[0] == 0xff) && ((pEntry->HTCapability.MCSSet[1] == 0x00) || (pAd->CommonCfg.TxStream == 1)))
            {// 11N 1S AP
                  *ppTable = RateSwitchTable11N1S;
                  *pTableSize = RateSwitchTable11N1S[0];
                  *pInitTxRateIdx = RateSwitchTable11N1S[1];

                  break;
            }

            if ((pEntry->HTCapability.MCSSet[0] == 0xff) && (pEntry->HTCapability.MCSSet[1] == 0xff) && (pAd->CommonCfg.TxStream == 2))
            {// 11N 2S AP
                  if (pAd->LatchRfRegs.Channel <= 14)
                  {
                  *ppTable = RateSwitchTable11N2S;
                  *pTableSize = RateSwitchTable11N2S[0];
                  *pInitTxRateIdx = RateSwitchTable11N2S[1];
            }
                  else
                  {
                        *ppTable = RateSwitchTable11N2SForABand;
                        *pTableSize = RateSwitchTable11N2SForABand[0];
                        *pInitTxRateIdx = RateSwitchTable11N2SForABand[1];
                  }

                  break;
            }

            //else if ((pAd->StaActive.SupRateLen == 4) && (pAd->StaActive.ExtRateLen == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0))
            if ((pEntry->RateLen == 4)
#ifndef RT30xx
//Iverson mark for Adhoc b mode,sta will use rate 54  Mbps when connect with sta b/g/n mode
                  && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0)
#endif
                  )
            {// B only AP
                  *ppTable = RateSwitchTable11B;
                  *pTableSize = RateSwitchTable11B[0];
                  *pInitTxRateIdx = RateSwitchTable11B[1];

                  break;
            }

            //else if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen > 8) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0))
            if ((pEntry->RateLen > 8)
                  && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0)
                  )
            {// B/G  mixed AP
                  *ppTable = RateSwitchTable11BG;
                  *pTableSize = RateSwitchTable11BG[0];
                  *pInitTxRateIdx = RateSwitchTable11BG[1];

                  break;
            }

            //else if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen == 8) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0))
            if ((pEntry->RateLen == 8)
                  && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0)
                  )
            {// G only AP
                  *ppTable = RateSwitchTable11G;
                  *pTableSize = RateSwitchTable11G[0];
                  *pInitTxRateIdx = RateSwitchTable11G[1];

                  break;
            }

            {
                  //else if ((pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0))
                  if ((pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0))
                  {     // Legacy mode
                        if (pAd->CommonCfg.MaxTxRate <= RATE_11)
                        {
                              *ppTable = RateSwitchTable11B;
                              *pTableSize = RateSwitchTable11B[0];
                              *pInitTxRateIdx = RateSwitchTable11B[1];
                        }
                        else if ((pAd->CommonCfg.MaxTxRate > RATE_11) && (pAd->CommonCfg.MinTxRate > RATE_11))
                        {
                              *ppTable = RateSwitchTable11G;
                              *pTableSize = RateSwitchTable11G[0];
                              *pInitTxRateIdx = RateSwitchTable11G[1];

                        }
                        else
                        {
                              *ppTable = RateSwitchTable11BG;
                              *pTableSize = RateSwitchTable11BG[0];
                              *pInitTxRateIdx = RateSwitchTable11BG[1];
                        }
                        break;
                  }

                  if (pAd->LatchRfRegs.Channel <= 14)
                  {
                        if (pAd->CommonCfg.TxStream == 1)
                        {
                              *ppTable = RateSwitchTable11N1S;
                              *pTableSize = RateSwitchTable11N1S[0];
                              *pInitTxRateIdx = RateSwitchTable11N1S[1];
                              DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode,default use 11N 1S AP \n"));
                        }
                        else
                        {
                              *ppTable = RateSwitchTable11N2S;
                              *pTableSize = RateSwitchTable11N2S[0];
                              *pInitTxRateIdx = RateSwitchTable11N2S[1];
                              DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode,default use 11N 2S AP \n"));
                        }
                  }
                  else
                  {
                        if (pAd->CommonCfg.TxStream == 1)
                        {
                              *ppTable = RateSwitchTable11N1S;
                              *pTableSize = RateSwitchTable11N1S[0];
                              *pInitTxRateIdx = RateSwitchTable11N1S[1];
                              DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode,default use 11N 1S AP \n"));
                        }
                        else
                        {
                              *ppTable = RateSwitchTable11N2SForABand;
                              *pTableSize = RateSwitchTable11N2SForABand[0];
                              *pInitTxRateIdx = RateSwitchTable11N2SForABand[1];
                              DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode,default use 11N 2S AP \n"));
                        }
                  }

                  DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode (SupRateLen=%d, ExtRateLen=%d, MCSSet[0]=0x%x, MCSSet[1]=0x%x)\n",
                        pAd->StaActive.SupRateLen, pAd->StaActive.ExtRateLen, pAd->StaActive.SupportedPhyInfo.MCSSet[0], pAd->StaActive.SupportedPhyInfo.MCSSet[1]));
            }
      } while(FALSE);
}

/*
      ==========================================================================
      Description:
            This routine checks if there're other APs out there capable for
            roaming. Caller should call this routine only when Link up in INFRA mode
            and channel quality is below CQI_GOOD_THRESHOLD.

      IRQL = DISPATCH_LEVEL

      Output:
      ==========================================================================
 */
VOID MlmeCheckForRoaming(
      IN PRTMP_ADAPTER pAd,
      IN ULONG    Now32)
{
      USHORT         i;
      BSS_TABLE  *pRoamTab = &pAd->MlmeAux.RoamTab;
      BSS_ENTRY  *pBss;

      DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeCheckForRoaming\n"));
      // put all roaming candidates into RoamTab, and sort in RSSI order
      BssTableInit(pRoamTab);
      for (i = 0; i < pAd->ScanTab.BssNr; i++)
      {
            pBss = &pAd->ScanTab.BssEntry[i];

            if ((pBss->LastBeaconRxTime + BEACON_LOST_TIME) < Now32)
                  continue;    // AP disappear
            if (pBss->Rssi <= RSSI_THRESHOLD_FOR_ROAMING)
                  continue;    // RSSI too weak. forget it.
            if (MAC_ADDR_EQUAL(pBss->Bssid, pAd->CommonCfg.Bssid))
                  continue;    // skip current AP
            if (pBss->Rssi < (pAd->StaCfg.RssiSample.LastRssi0 + RSSI_DELTA))
                  continue;    // only AP with stronger RSSI is eligible for roaming

            // AP passing all above rules is put into roaming candidate table
            NdisMoveMemory(&pRoamTab->BssEntry[pRoamTab->BssNr], pBss, sizeof(BSS_ENTRY));
            pRoamTab->BssNr += 1;
      }

      if (pRoamTab->BssNr > 0)
      {
            // check CntlMachine.CurrState to avoid collision with NDIS SetOID request
            if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)
            {
                  pAd->RalinkCounters.PoorCQIRoamingCount ++;
                  DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Roaming attempt #%ld\n", pAd->RalinkCounters.PoorCQIRoamingCount));
                  MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_MLME_ROAMING_REQ, 0, NULL);
                  RT28XX_MLME_HANDLER(pAd);
            }
      }
      DBGPRINT(RT_DEBUG_TRACE, ("<== MlmeCheckForRoaming(# of candidate= %d)\n",pRoamTab->BssNr));
}

/*
      ==========================================================================
      Description:
            This routine checks if there're other APs out there capable for
            roaming. Caller should call this routine only when link up in INFRA mode
            and channel quality is below CQI_GOOD_THRESHOLD.

      IRQL = DISPATCH_LEVEL

      Output:
      ==========================================================================
 */
VOID MlmeCheckForFastRoaming(
      IN    PRTMP_ADAPTER     pAd,
      IN    ULONG             Now)
{
      USHORT            i;
      BSS_TABLE   *pRoamTab = &pAd->MlmeAux.RoamTab;
      BSS_ENTRY   *pBss;

      DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeCheckForFastRoaming\n"));
      // put all roaming candidates into RoamTab, and sort in RSSI order
      BssTableInit(pRoamTab);
      for (i = 0; i < pAd->ScanTab.BssNr; i++)
      {
            pBss = &pAd->ScanTab.BssEntry[i];

        if ((pBss->Rssi <= -50) && (pBss->Channel == pAd->CommonCfg.Channel))
                  continue;    // RSSI too weak. forget it.
            if (MAC_ADDR_EQUAL(pBss->Bssid, pAd->CommonCfg.Bssid))
                  continue;    // skip current AP
            if (!SSID_EQUAL(pBss->Ssid, pBss->SsidLen, pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen))
                  continue;    // skip different SSID
        if (pBss->Rssi < (RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2) + RSSI_DELTA))
                  continue;    // skip AP without better RSSI

        DBGPRINT(RT_DEBUG_TRACE, ("LastRssi0 = %d, pBss->Rssi = %d\n", RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2), pBss->Rssi));
            // AP passing all above rules is put into roaming candidate table
            NdisMoveMemory(&pRoamTab->BssEntry[pRoamTab->BssNr], pBss, sizeof(BSS_ENTRY));
            pRoamTab->BssNr += 1;
      }

      if (pRoamTab->BssNr > 0)
      {
            // check CntlMachine.CurrState to avoid collision with NDIS SetOID request
            if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)
            {
                  pAd->RalinkCounters.PoorCQIRoamingCount ++;
                  DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Roaming attempt #%ld\n", pAd->RalinkCounters.PoorCQIRoamingCount));
                  MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_MLME_ROAMING_REQ, 0, NULL);
                  RT28XX_MLME_HANDLER(pAd);
            }
      }
      // Maybe site survey required
      else
      {
            if ((pAd->StaCfg.LastScanTime + 10 * 1000) < Now)
            {
                  // check CntlMachine.CurrState to avoid collision with NDIS SetOID request
                  DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Roaming, No eligable entry, try new scan!\n"));
                  pAd->StaCfg.ScanCnt = 2;
                  pAd->StaCfg.LastScanTime = Now;
                  MlmeAutoScan(pAd);
            }
      }

    DBGPRINT(RT_DEBUG_TRACE, ("<== MlmeCheckForFastRoaming (BssNr=%d)\n", pRoamTab->BssNr));
}

/*
      ==========================================================================
      Description:
            This routine calculates TxPER, RxPER of the past N-sec period. And
            according to the calculation result, ChannelQuality is calculated here
            to decide if current AP is still doing the job.

            If ChannelQuality is not good, a ROAMing attempt may be tried later.
      Output:
            StaCfg.ChannelQuality - 0..100

      IRQL = DISPATCH_LEVEL

      NOTE: This routine decide channle quality based on RX CRC error ratio.
            Caller should make sure a function call to NICUpdateRawCounters(pAd)
            is performed right before this routine, so that this routine can decide
            channel quality based on the most up-to-date information
      ==========================================================================
 */
VOID MlmeCalculateChannelQuality(
      IN PRTMP_ADAPTER pAd,
      IN ULONG Now32)
{
      ULONG TxOkCnt, TxCnt, TxPER, TxPRR;
      ULONG RxCnt, RxPER;
      UCHAR NorRssi;
      CHAR  MaxRssi;
      ULONG BeaconLostTime = BEACON_LOST_TIME;

      MaxRssi = RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2);

      //
      // calculate TX packet error ratio and TX retry ratio - if too few TX samples, skip TX related statistics
      //
      TxOkCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + pAd->RalinkCounters.OneSecTxRetryOkCount;
      TxCnt = TxOkCnt + pAd->RalinkCounters.OneSecTxFailCount;
      if (TxCnt < 5)
      {
            TxPER = 0;
            TxPRR = 0;
      }
      else
      {
            TxPER = (pAd->RalinkCounters.OneSecTxFailCount * 100) / TxCnt;
            TxPRR = ((TxCnt - pAd->RalinkCounters.OneSecTxNoRetryOkCount) * 100) / TxCnt;
      }

      //
      // calculate RX PER - don't take RxPER into consideration if too few sample
      //
      RxCnt = pAd->RalinkCounters.OneSecRxOkCnt + pAd->RalinkCounters.OneSecRxFcsErrCnt;
      if (RxCnt < 5)
            RxPER = 0;
      else
            RxPER = (pAd->RalinkCounters.OneSecRxFcsErrCnt * 100) / RxCnt;

      //
      // decide ChannelQuality based on: 1)last BEACON received time, 2)last RSSI, 3)TxPER, and 4)RxPER
      //
      if (INFRA_ON(pAd) &&
            (pAd->RalinkCounters.OneSecTxNoRetryOkCount < 2) && // no heavy traffic
            (pAd->StaCfg.LastBeaconRxTime + BeaconLostTime < Now32))
      {
            DBGPRINT(RT_DEBUG_TRACE, ("BEACON lost > %ld msec with TxOkCnt=%ld -> CQI=0\n", BeaconLostTime, TxOkCnt));
            pAd->Mlme.ChannelQuality = 0;
      }
      else
      {
            // Normalize Rssi
            if (MaxRssi > -40)
                  NorRssi = 100;
            else if (MaxRssi < -90)
                  NorRssi = 0;
            else
                  NorRssi = (MaxRssi + 90) * 2;

            // ChannelQuality = W1*RSSI + W2*TxPRR + W3*RxPER      (RSSI 0..100), (TxPER 100..0), (RxPER 100..0)
            pAd->Mlme.ChannelQuality = (RSSI_WEIGHTING * NorRssi +
                                                   TX_WEIGHTING * (100 - TxPRR) +
                                                   RX_WEIGHTING* (100 - RxPER)) / 100;
            if (pAd->Mlme.ChannelQuality >= 100)
                  pAd->Mlme.ChannelQuality = 100;
      }

}

VOID MlmeSetTxRate(
      IN PRTMP_ADAPTER        pAd,
      IN PMAC_TABLE_ENTRY           pEntry,
      IN PRTMP_TX_RATE_SWITCH pTxRate)
{
      UCHAR MaxMode = MODE_OFDM;

      MaxMode = MODE_HTGREENFIELD;

      if (pTxRate->STBC && (pAd->StaCfg.MaxHTPhyMode.field.STBC) && (pAd->Antenna.field.TxPath == 2))
            pAd->StaCfg.HTPhyMode.field.STBC = STBC_USE;
      else
            pAd->StaCfg.HTPhyMode.field.STBC = STBC_NONE;

      if (pTxRate->CurrMCS < MCS_AUTO)
            pAd->StaCfg.HTPhyMode.field.MCS = pTxRate->CurrMCS;

      if (pAd->StaCfg.HTPhyMode.field.MCS > 7)
            pAd->StaCfg.HTPhyMode.field.STBC = STBC_NONE;

      if (ADHOC_ON(pAd))
      {
            // If peer adhoc is b-only mode, we can't send 11g rate.
            pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800;
            pEntry->HTPhyMode.field.STBC  = STBC_NONE;

            //
            // For Adhoc MODE_CCK, driver will use AdhocBOnlyJoined flag to roll back to B only if necessary
            //
            pEntry->HTPhyMode.field.MODE  = pTxRate->Mode;
            pEntry->HTPhyMode.field.ShortGI     = pAd->StaCfg.HTPhyMode.field.ShortGI;
            pEntry->HTPhyMode.field.MCS         = pAd->StaCfg.HTPhyMode.field.MCS;

            // Patch speed error in status page
            pAd->StaCfg.HTPhyMode.field.MODE = pEntry->HTPhyMode.field.MODE;
      }
      else
      {
            if (pTxRate->Mode <= MaxMode)
                  pAd->StaCfg.HTPhyMode.field.MODE = pTxRate->Mode;

            if (pTxRate->ShortGI && (pAd->StaCfg.MaxHTPhyMode.field.ShortGI))
                  pAd->StaCfg.HTPhyMode.field.ShortGI = GI_400;
            else
                  pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800;

            // Reexam each bandwidth's SGI support.
            if (pAd->StaCfg.HTPhyMode.field.ShortGI == GI_400)
            {
                  if ((pEntry->HTPhyMode.field.BW == BW_20) && (!CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_SGI20_CAPABLE)))
                        pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800;
                  if ((pEntry->HTPhyMode.field.BW == BW_40) && (!CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_SGI40_CAPABLE)))
                        pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800;
            }

            // Turn RTS/CTS rate to 6Mbps.
            if ((pEntry->HTPhyMode.field.MCS == 0) && (pAd->StaCfg.HTPhyMode.field.MCS != 0))
            {
                  pEntry->HTPhyMode.field.MCS         = pAd->StaCfg.HTPhyMode.field.MCS;
                  if (pAd->MacTab.fAnyBASession)
                  {
                        AsicUpdateProtect(pAd, HT_FORCERTSCTS, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent);
                  }
                  else
                  {
                        AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent);
                  }
            }
            else if ((pEntry->HTPhyMode.field.MCS == 8) && (pAd->StaCfg.HTPhyMode.field.MCS != 8))
            {
                  pEntry->HTPhyMode.field.MCS         = pAd->StaCfg.HTPhyMode.field.MCS;
                  if (pAd->MacTab.fAnyBASession)
                  {
                        AsicUpdateProtect(pAd, HT_FORCERTSCTS, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent);
                  }
                  else
                  {
                        AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent);
                  }
            }
            else if ((pEntry->HTPhyMode.field.MCS != 0) && (pAd->StaCfg.HTPhyMode.field.MCS == 0))
            {
                  AsicUpdateProtect(pAd, HT_RTSCTS_6M, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent);

            }
            else if ((pEntry->HTPhyMode.field.MCS != 8) && (pAd->StaCfg.HTPhyMode.field.MCS == 8))
            {
                  AsicUpdateProtect(pAd, HT_RTSCTS_6M, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent);
            }

            pEntry->HTPhyMode.field.STBC  = pAd->StaCfg.HTPhyMode.field.STBC;
            pEntry->HTPhyMode.field.ShortGI     = pAd->StaCfg.HTPhyMode.field.ShortGI;
            pEntry->HTPhyMode.field.MCS         = pAd->StaCfg.HTPhyMode.field.MCS;
            pEntry->HTPhyMode.field.MODE  = pAd->StaCfg.HTPhyMode.field.MODE;

            if ((pAd->StaCfg.MaxHTPhyMode.field.MODE == MODE_HTGREENFIELD) &&
                pAd->WIFItestbed.bGreenField)
                pEntry->HTPhyMode.field.MODE = MODE_HTGREENFIELD;
      }

      pAd->LastTxRate = (USHORT)(pEntry->HTPhyMode.word);
}

/*
      ==========================================================================
      Description:
            This routine calculates the acumulated TxPER of eaxh TxRate. And
            according to the calculation result, change CommonCfg.TxRate which
            is the stable TX Rate we expect the Radio situation could sustained.

            CommonCfg.TxRate will change dynamically within {RATE_1/RATE_6, MaxTxRate}
      Output:
            CommonCfg.TxRate -

      IRQL = DISPATCH_LEVEL

      NOTE:
            call this routine every second
      ==========================================================================
 */
VOID MlmeDynamicTxRateSwitching(
      IN PRTMP_ADAPTER pAd)
{
      UCHAR                         UpRateIdx = 0, DownRateIdx = 0, CurrRateIdx;
      ULONG                         i, AccuTxTotalCnt = 0, TxTotalCnt;
      ULONG                         TxErrorRatio = 0;
      BOOLEAN                             bTxRateChanged, bUpgradeQuality = FALSE;
      PRTMP_TX_RATE_SWITCH    pCurrTxRate, pNextTxRate = NULL;
      PUCHAR                              pTable;
      UCHAR                         TableSize = 0;
      UCHAR                         InitTxRateIdx = 0, TrainUp, TrainDown;
      CHAR                          Rssi, RssiOffset = 0;
      TX_STA_CNT1_STRUC       StaTx1;
      TX_STA_CNT0_STRUC       TxStaCnt0;
      ULONG                         TxRetransmit = 0, TxSuccess = 0, TxFailCount = 0;
      MAC_TABLE_ENTRY               *pEntry;

      //
      // walk through MAC table, see if need to change AP's TX rate toward each entry
      //
      for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++)
      {
            pEntry = &pAd->MacTab.Content[i];

            // check if this entry need to switch rate automatically
            if (RTMPCheckEntryEnableAutoRateSwitch(pAd, pEntry) == FALSE)
                  continue;

            if ((pAd->MacTab.Size == 1) || (pEntry->ValidAsDls))
            {
#ifdef RT2860
                  Rssi = RTMPMaxRssi(pAd, (CHAR)pAd->StaCfg.RssiSample.AvgRssi0, (CHAR)pAd->StaCfg.RssiSample.AvgRssi1, (CHAR)pAd->StaCfg.RssiSample.AvgRssi2);
#endif
#ifdef RT2870
                  Rssi = RTMPMaxRssi(pAd,
                                             pAd->StaCfg.RssiSample.AvgRssi0,
                                             pAd->StaCfg.RssiSample.AvgRssi1,
                                             pAd->StaCfg.RssiSample.AvgRssi2);
#endif

                  // Update statistic counter
                  RTMP_IO_READ32(pAd, TX_STA_CNT0, &TxStaCnt0.word);
                  RTMP_IO_READ32(pAd, TX_STA_CNT1, &StaTx1.word);
                  pAd->bUpdateBcnCntDone = TRUE;
                  TxRetransmit = StaTx1.field.TxRetransmit;
                  TxSuccess = StaTx1.field.TxSuccess;
                  TxFailCount = TxStaCnt0.field.TxFailCount;
                  TxTotalCnt = TxRetransmit + TxSuccess + TxFailCount;

                  pAd->RalinkCounters.OneSecTxRetryOkCount += StaTx1.field.TxRetransmit;
                  pAd->RalinkCounters.OneSecTxNoRetryOkCount += StaTx1.field.TxSuccess;
                  pAd->RalinkCounters.OneSecTxFailCount += TxStaCnt0.field.TxFailCount;
                  pAd->WlanCounters.TransmittedFragmentCount.u.LowPart += StaTx1.field.TxSuccess;
                  pAd->WlanCounters.RetryCount.u.LowPart += StaTx1.field.TxRetransmit;
                  pAd->WlanCounters.FailedCount.u.LowPart += TxStaCnt0.field.TxFailCount;

                  // if no traffic in the past 1-sec period, don't change TX rate,
                  // but clear all bad history. because the bad history may affect the next
                  // Chariot throughput test
                  AccuTxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount +
                                     pAd->RalinkCounters.OneSecTxRetryOkCount +
                                     pAd->RalinkCounters.OneSecTxFailCount;

                  if (TxTotalCnt)
                        TxErrorRatio = ((TxRetransmit + TxFailCount) * 100) / TxTotalCnt;
            }
            else
            {
#ifdef RT2860
                  Rssi = RTMPMaxRssi(pAd, (CHAR)pEntry->RssiSample.AvgRssi0, (CHAR)pEntry->RssiSample.AvgRssi1, (CHAR)pEntry->RssiSample.AvgRssi2);
#endif
#ifdef RT2870
                  if (INFRA_ON(pAd) && (i == 1))
                        Rssi = RTMPMaxRssi(pAd,
                                                   pAd->StaCfg.RssiSample.AvgRssi0,
                                                   pAd->StaCfg.RssiSample.AvgRssi1,
                                                   pAd->StaCfg.RssiSample.AvgRssi2);
                  else
                        Rssi = RTMPMaxRssi(pAd,
                                                   pEntry->RssiSample.AvgRssi0,
                                                   pEntry->RssiSample.AvgRssi1,
                                                   pEntry->RssiSample.AvgRssi2);
#endif

                  TxTotalCnt = pEntry->OneSecTxNoRetryOkCount +
                         pEntry->OneSecTxRetryOkCount +
                         pEntry->OneSecTxFailCount;

                  if (TxTotalCnt)
                        TxErrorRatio = ((pEntry->OneSecTxRetryOkCount + pEntry->OneSecTxFailCount) * 100) / TxTotalCnt;
            }

            CurrRateIdx = pEntry->CurrTxRateIndex;

            MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &InitTxRateIdx);

            if (CurrRateIdx >= TableSize)
            {
                  CurrRateIdx = TableSize - 1;
            }

            // When switch from Fixed rate -> auto rate, the REAL TX rate might be different from pAd->CommonCfg.TxRateIndex.
            // So need to sync here.
            pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(CurrRateIdx+1)*5];
            if ((pEntry->HTPhyMode.field.MCS != pCurrTxRate->CurrMCS)
                  //&& (pAd->StaCfg.bAutoTxRateSwitch == TRUE)
                  )
            {

                  // Need to sync Real Tx rate and our record.
                  // Then return for next DRS.
                  pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(InitTxRateIdx+1)*5];
                  pEntry->CurrTxRateIndex = InitTxRateIdx;
                  MlmeSetTxRate(pAd, pEntry, pCurrTxRate);

                  // reset all OneSecTx counters
                  RESET_ONE_SEC_TX_CNT(pEntry);
                  continue;
            }

            // decide the next upgrade rate and downgrade rate, if any
            if ((CurrRateIdx > 0) && (CurrRateIdx < (TableSize - 1)))
            {
                  UpRateIdx = CurrRateIdx + 1;
                  DownRateIdx = CurrRateIdx -1;
            }
            else if (CurrRateIdx == 0)
            {
                  UpRateIdx = CurrRateIdx + 1;
                  DownRateIdx = CurrRateIdx;
            }
            else if (CurrRateIdx == (TableSize - 1))
            {
                  UpRateIdx = CurrRateIdx;
                  DownRateIdx = CurrRateIdx - 1;
            }

            pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(CurrRateIdx+1)*5];

            if ((Rssi > -65) && (pCurrTxRate->Mode >= MODE_HTMIX))
            {
                  TrainUp           = (pCurrTxRate->TrainUp + (pCurrTxRate->TrainUp >> 1));
                  TrainDown   = (pCurrTxRate->TrainDown + (pCurrTxRate->TrainDown >> 1));
            }
            else
            {
                  TrainUp           = pCurrTxRate->TrainUp;
                  TrainDown   = pCurrTxRate->TrainDown;
            }

            //pAd->DrsCounters.LastTimeTxRateChangeAction = pAd->DrsCounters.LastSecTxRateChangeAction;

            //
            // Keep the last time TxRateChangeAction status.
            //
            pEntry->LastTimeTxRateChangeAction = pEntry->LastSecTxRateChangeAction;



            //
            // CASE 1. when TX samples are fewer than 15, then decide TX rate solely on RSSI
            //         (criteria copied from RT2500 for Netopia case)
            //
            if (TxTotalCnt <= 15)
            {
                  CHAR  idx = 0;
                  UCHAR TxRateIdx;
                  //UCHAR     MCS0 = 0, MCS1 = 0, MCS2 = 0, MCS3 = 0, MCS4 = 0, MCS7 = 0, MCS12 = 0, MCS13 = 0, MCS14 = 0, MCS15 = 0;
                  UCHAR MCS0 = 0, MCS1 = 0, MCS2 = 0, MCS3 = 0, MCS4 = 0,  MCS5 =0, MCS6 = 0, MCS7 = 0;
              UCHAR     MCS12 = 0, MCS13 = 0, MCS14 = 0, MCS15 = 0;
                  UCHAR MCS20 = 0, MCS21 = 0, MCS22 = 0, MCS23 = 0; // 3*3

                  // check the existence and index of each needed MCS
                  while (idx < pTable[0])
                  {
                        pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(idx+1)*5];

                        if (pCurrTxRate->CurrMCS == MCS_0)
                        {
                              MCS0 = idx;
                        }
                        else if (pCurrTxRate->CurrMCS == MCS_1)
                        {
                              MCS1 = idx;
                        }
                        else if (pCurrTxRate->CurrMCS == MCS_2)
                        {
                              MCS2 = idx;
                        }
                        else if (pCurrTxRate->CurrMCS == MCS_3)
                        {
                              MCS3 = idx;
                        }
                        else if (pCurrTxRate->CurrMCS == MCS_4)
                        {
                              MCS4 = idx;
                        }
                  else if (pCurrTxRate->CurrMCS == MCS_5)
                  {
                      MCS5 = idx;
                  }
                  else if (pCurrTxRate->CurrMCS == MCS_6)
                  {
                      MCS6 = idx;
                  }
                        //else if (pCurrTxRate->CurrMCS == MCS_7)
                        else if ((pCurrTxRate->CurrMCS == MCS_7) && (pCurrTxRate->ShortGI == GI_800)) // prevent the highest MCS using short GI when 1T and low throughput
                        {
                              MCS7 = idx;
                        }
                        else if (pCurrTxRate->CurrMCS == MCS_12)
                        {
                              MCS12 = idx;
                        }
                        else if (pCurrTxRate->CurrMCS == MCS_13)
                        {
                              MCS13 = idx;
                        }
                        else if (pCurrTxRate->CurrMCS == MCS_14)
                        {
                              MCS14 = idx;
                        }
                        else if ((pCurrTxRate->CurrMCS == MCS_15) && (pCurrTxRate->ShortGI == GI_800))      //we hope to use ShortGI as initial rate, however Atheros's chip has bugs when short GI
                        {
                              MCS15 = idx;
                        }
                        else if (pCurrTxRate->CurrMCS == MCS_20) // 3*3
                        {
                              MCS20 = idx;
                        }
                        else if (pCurrTxRate->CurrMCS == MCS_21)
                        {
                              MCS21 = idx;
                        }
                        else if (pCurrTxRate->CurrMCS == MCS_22)
                        {
                              MCS22 = idx;
                        }
                        else if (pCurrTxRate->CurrMCS == MCS_23)
                        {
                              MCS23 = idx;
                        }
                        idx ++;
                  }

                  if (pAd->LatchRfRegs.Channel <= 14)
                  {
                        if (pAd->NicConfig2.field.ExternalLNAForG)
                        {
                              RssiOffset = 2;
                        }
                        else
                        {
                              RssiOffset = 5;
                        }
                  }
                  else
                  {
                        if (pAd->NicConfig2.field.ExternalLNAForA)
                        {
                              RssiOffset = 5;
                        }
                        else
                        {
                              RssiOffset = 8;
                        }
                  }

                  /*if (MCS15)*/
                  if ((pTable == RateSwitchTable11BGN3S) ||
                        (pTable == RateSwitchTable11N3S) ||
                        (pTable == RateSwitchTable))
                  {// N mode with 3 stream // 3*3
                        if (MCS23 && (Rssi >= -70))
                              TxRateIdx = MCS15;
                        else if (MCS22 && (Rssi >= -72))
                              TxRateIdx = MCS14;
                else if (MCS21 && (Rssi >= -76))
                              TxRateIdx = MCS13;
                        else if (MCS20 && (Rssi >= -78))
                              TxRateIdx = MCS12;
                  else if (MCS4 && (Rssi >= -82))
                        TxRateIdx = MCS4;
                  else if (MCS3 && (Rssi >= -84))
                        TxRateIdx = MCS3;
                  else if (MCS2 && (Rssi >= -86))
                        TxRateIdx = MCS2;
                  else if (MCS1 && (Rssi >= -88))
                        TxRateIdx = MCS1;
                  else
                        TxRateIdx = MCS0;
            }
            else if ((pTable == RateSwitchTable11BGN2S) || (pTable == RateSwitchTable11BGN2SForABand) ||(pTable == RateSwitchTable11N2S) ||(pTable == RateSwitchTable11N2SForABand)) // 3*3
                  {// N mode with 2 stream
                        if (MCS15 && (Rssi >= (-70+RssiOffset)))
                              TxRateIdx = MCS15;
                        else if (MCS14 && (Rssi >= (-72+RssiOffset)))
                              TxRateIdx = MCS14;
                        else if (MCS13 && (Rssi >= (-76+RssiOffset)))
                              TxRateIdx = MCS13;
                        else if (MCS12 && (Rssi >= (-78+RssiOffset)))
                              TxRateIdx = MCS12;
                        else if (MCS4 && (Rssi >= (-82+RssiOffset)))
                              TxRateIdx = MCS4;
                        else if (MCS3 && (Rssi >= (-84+RssiOffset)))
                              TxRateIdx = MCS3;
                        else if (MCS2 && (Rssi >= (-86+RssiOffset)))
                              TxRateIdx = MCS2;
                        else if (MCS1 && (Rssi >= (-88+RssiOffset)))
                              TxRateIdx = MCS1;
                        else
                              TxRateIdx = MCS0;
                  }
                  else if ((pTable == RateSwitchTable11BGN1S) || (pTable == RateSwitchTable11N1S))
                  {// N mode with 1 stream
                        if (MCS7 && (Rssi > (-72+RssiOffset)))
                              TxRateIdx = MCS7;
                        else if (MCS6 && (Rssi > (-74+RssiOffset)))
                              TxRateIdx = MCS6;
                        else if (MCS5 && (Rssi > (-77+RssiOffset)))
                              TxRateIdx = MCS5;
                        else if (MCS4 && (Rssi > (-79+RssiOffset)))
                              TxRateIdx = MCS4;
                        else if (MCS3 && (Rssi > (-81+RssiOffset)))
                              TxRateIdx = MCS3;
                        else if (MCS2 && (Rssi > (-83+RssiOffset)))
                              TxRateIdx = MCS2;
                        else if (MCS1 && (Rssi > (-86+RssiOffset)))
                              TxRateIdx = MCS1;
                        else
                              TxRateIdx = MCS0;
                  }
                  else
                  {// Legacy mode
                        if (MCS7 && (Rssi > -70))
                              TxRateIdx = MCS7;
                        else if (MCS6 && (Rssi > -74))
                              TxRateIdx = MCS6;
                        else if (MCS5 && (Rssi > -78))
                              TxRateIdx = MCS5;
                        else if (MCS4 && (Rssi > -82))
                              TxRateIdx = MCS4;
                        else if (MCS4 == 0)     // for B-only mode
                              TxRateIdx = MCS3;
                        else if (MCS3 && (Rssi > -85))
                              TxRateIdx = MCS3;
                        else if (MCS2 && (Rssi > -87))
                              TxRateIdx = MCS2;
                        else if (MCS1 && (Rssi > -90))
                              TxRateIdx = MCS1;
                        else
                              TxRateIdx = MCS0;
                  }

                  {
                        pEntry->CurrTxRateIndex = TxRateIdx;
                        pNextTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(pEntry->CurrTxRateIndex+1)*5];
                        MlmeSetTxRate(pAd, pEntry, pNextTxRate);
                  }

                  NdisZeroMemory(pEntry->TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH);
                  NdisZeroMemory(pEntry->PER, sizeof(UCHAR) * MAX_STEP_OF_TX_RATE_SWITCH);
                  pEntry->fLastSecAccordingRSSI = TRUE;
                  // reset all OneSecTx counters
                  RESET_ONE_SEC_TX_CNT(pEntry);

                  continue;
            }

            if (pEntry->fLastSecAccordingRSSI == TRUE)
            {
                  pEntry->fLastSecAccordingRSSI = FALSE;
                  pEntry->LastSecTxRateChangeAction = 0;
                  // reset all OneSecTx counters
                  RESET_ONE_SEC_TX_CNT(pEntry);

                  continue;
            }

            do
            {
                  BOOLEAN     bTrainUpDown = FALSE;

                  pEntry->CurrTxRateStableTime ++;

                  // downgrade TX quality if PER >= Rate-Down threshold
                  if (TxErrorRatio >= TrainDown)
                  {
                        bTrainUpDown = TRUE;
                        pEntry->TxQuality[CurrRateIdx] = DRS_TX_QUALITY_WORST_BOUND;
                  }
                  // upgrade TX quality if PER <= Rate-Up threshold
                  else if (TxErrorRatio <= TrainUp)
                  {
                        bTrainUpDown = TRUE;
                        bUpgradeQuality = TRUE;
                        if (pEntry->TxQuality[CurrRateIdx])
                              pEntry->TxQuality[CurrRateIdx] --;  // quality very good in CurrRate

                        if (pEntry->TxRateUpPenalty)
                              pEntry->TxRateUpPenalty --;
                        else if (pEntry->TxQuality[UpRateIdx])
                              pEntry->TxQuality[UpRateIdx] --;    // may improve next UP rate's quality
                  }

                  pEntry->PER[CurrRateIdx] = (UCHAR)TxErrorRatio;

                  if (bTrainUpDown)
                  {
                        // perform DRS - consider TxRate Down first, then rate up.
                        if ((CurrRateIdx != DownRateIdx) && (pEntry->TxQuality[CurrRateIdx] >= DRS_TX_QUALITY_WORST_BOUND))
                        {
                              pEntry->CurrTxRateIndex = DownRateIdx;
                        }
                        else if ((CurrRateIdx != UpRateIdx) && (pEntry->TxQuality[UpRateIdx] <= 0))
                        {
                              pEntry->CurrTxRateIndex = UpRateIdx;
                        }
                  }
            } while (FALSE);

            // if rate-up happen, clear all bad history of all TX rates
            if (pEntry->CurrTxRateIndex > CurrRateIdx)
            {
                  pEntry->CurrTxRateStableTime = 0;
                  pEntry->TxRateUpPenalty = 0;
                  pEntry->LastSecTxRateChangeAction = 1; // rate UP
                  NdisZeroMemory(pEntry->TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH);
                  NdisZeroMemory(pEntry->PER, sizeof(UCHAR) * MAX_STEP_OF_TX_RATE_SWITCH);

                  //
                  // For TxRate fast train up
                  //
                  if (!pAd->StaCfg.StaQuickResponeForRateUpTimerRunning)
                  {
                        RTMPSetTimer(&pAd->StaCfg.StaQuickResponeForRateUpTimer, 100);

                        pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = TRUE;
                  }
                  bTxRateChanged = TRUE;
            }
            // if rate-down happen, only clear DownRate's bad history
            else if (pEntry->CurrTxRateIndex < CurrRateIdx)
            {
                  pEntry->CurrTxRateStableTime = 0;
                  pEntry->TxRateUpPenalty = 0;           // no penalty
                  pEntry->LastSecTxRateChangeAction = 2; // rate DOWN
                  pEntry->TxQuality[pEntry->CurrTxRateIndex] = 0;
                  pEntry->PER[pEntry->CurrTxRateIndex] = 0;

                  //
                  // For TxRate fast train down
                  //
                  if (!pAd->StaCfg.StaQuickResponeForRateUpTimerRunning)
                  {
                        RTMPSetTimer(&pAd->StaCfg.StaQuickResponeForRateUpTimer, 100);

                        pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = TRUE;
                  }
                  bTxRateChanged = TRUE;
            }
            else
            {
                  pEntry->LastSecTxRateChangeAction = 0; // rate no change
                  bTxRateChanged = FALSE;
            }

            pEntry->LastTxOkCount = TxSuccess;

            // reset all OneSecTx counters
            RESET_ONE_SEC_TX_CNT(pEntry);

            pNextTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(pEntry->CurrTxRateIndex+1)*5];
            if (bTxRateChanged && pNextTxRate)
            {
                  MlmeSetTxRate(pAd, pEntry, pNextTxRate);
            }
      }
}

/*
      ========================================================================
      Routine Description:
            Station side, Auto TxRate faster train up timer call back function.

      Arguments:
            SystemSpecific1               - Not used.
            FunctionContext               - Pointer to our Adapter context.
            SystemSpecific2               - Not used.
            SystemSpecific3               - Not used.

      Return Value:
            None

      ========================================================================
*/
VOID StaQuickResponeForRateUpExec(
      IN PVOID SystemSpecific1,
      IN PVOID FunctionContext,
      IN PVOID SystemSpecific2,
      IN PVOID SystemSpecific3)
{
      PRTMP_ADAPTER                 pAd = (PRTMP_ADAPTER)FunctionContext;
      UCHAR                         UpRateIdx = 0, DownRateIdx = 0, CurrRateIdx = 0;
      ULONG                         TxTotalCnt;
      ULONG                         TxErrorRatio = 0;
#ifdef RT2860
      BOOLEAN                             bTxRateChanged = TRUE; //, bUpgradeQuality = FALSE;
#endif
#ifdef RT2870
      BOOLEAN                             bTxRateChanged; //, bUpgradeQuality = FALSE;
#endif
      PRTMP_TX_RATE_SWITCH    pCurrTxRate, pNextTxRate = NULL;
      PUCHAR                              pTable;
      UCHAR                         TableSize = 0;
      UCHAR                         InitTxRateIdx = 0, TrainUp, TrainDown;
      TX_STA_CNT1_STRUC       StaTx1;
      TX_STA_CNT0_STRUC       TxStaCnt0;
      CHAR                          Rssi, ratio;
      ULONG                         TxRetransmit = 0, TxSuccess = 0, TxFailCount = 0;
      MAC_TABLE_ENTRY               *pEntry;
      ULONG                         i;

      pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = FALSE;

    //
    // walk through MAC table, see if need to change AP's TX rate toward each entry
    //
      for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++)
      {
            pEntry = &pAd->MacTab.Content[i];

            // check if this entry need to switch rate automatically
            if (RTMPCheckEntryEnableAutoRateSwitch(pAd, pEntry) == FALSE)
                  continue;

#ifdef RT2860
            //Rssi = RTMPMaxRssi(pAd, (CHAR)pAd->StaCfg.AvgRssi0, (CHAR)pAd->StaCfg.AvgRssi1, (CHAR)pAd->StaCfg.AvgRssi2);
          if (pAd->Antenna.field.TxPath > 1)
                  Rssi = (pAd->StaCfg.RssiSample.AvgRssi0 + pAd->StaCfg.RssiSample.AvgRssi1) >> 1;
            else
                  Rssi = pAd->StaCfg.RssiSample.AvgRssi0;
#endif
#ifdef RT2870
            if (INFRA_ON(pAd) && (i == 1))
                  Rssi = RTMPMaxRssi(pAd,
                                             pAd->StaCfg.RssiSample.AvgRssi0,
                                             pAd->StaCfg.RssiSample.AvgRssi1,
                                             pAd->StaCfg.RssiSample.AvgRssi2);
            else
                  Rssi = RTMPMaxRssi(pAd,
                                             pEntry->RssiSample.AvgRssi0,
                                             pEntry->RssiSample.AvgRssi1,
                                             pEntry->RssiSample.AvgRssi2);
#endif

            CurrRateIdx = pAd->CommonCfg.TxRateIndex;

                  MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &InitTxRateIdx);

            // decide the next upgrade rate and downgrade rate, if any
            if ((CurrRateIdx > 0) && (CurrRateIdx < (TableSize - 1)))
            {
                  UpRateIdx = CurrRateIdx + 1;
                  DownRateIdx = CurrRateIdx -1;
            }
            else if (CurrRateIdx == 0)
            {
                  UpRateIdx = CurrRateIdx + 1;
                  DownRateIdx = CurrRateIdx;
            }
            else if (CurrRateIdx == (TableSize - 1))
            {
                  UpRateIdx = CurrRateIdx;
                  DownRateIdx = CurrRateIdx - 1;
            }

            pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(CurrRateIdx+1)*5];

            if ((Rssi > -65) && (pCurrTxRate->Mode >= MODE_HTMIX))
            {
                  TrainUp           = (pCurrTxRate->TrainUp + (pCurrTxRate->TrainUp >> 1));
                  TrainDown   = (pCurrTxRate->TrainDown + (pCurrTxRate->TrainDown >> 1));
            }
            else
            {
                  TrainUp           = pCurrTxRate->TrainUp;
                  TrainDown   = pCurrTxRate->TrainDown;
            }

            if (pAd->MacTab.Size == 1)
            {
                  // Update statistic counter
                  RTMP_IO_READ32(pAd, TX_STA_CNT0, &TxStaCnt0.word);
                  RTMP_IO_READ32(pAd, TX_STA_CNT1, &StaTx1.word);

                  TxRetransmit = StaTx1.field.TxRetransmit;
                  TxSuccess = StaTx1.field.TxSuccess;
                  TxFailCount = TxStaCnt0.field.TxFailCount;
                  TxTotalCnt = TxRetransmit + TxSuccess + TxFailCount;

                  pAd->RalinkCounters.OneSecTxRetryOkCount += StaTx1.field.TxRetransmit;
                  pAd->RalinkCounters.OneSecTxNoRetryOkCount += StaTx1.field.TxSuccess;
                  pAd->RalinkCounters.OneSecTxFailCount += TxStaCnt0.field.TxFailCount;
                  pAd->WlanCounters.TransmittedFragmentCount.u.LowPart += StaTx1.field.TxSuccess;
                  pAd->WlanCounters.RetryCount.u.LowPart += StaTx1.field.TxRetransmit;
                  pAd->WlanCounters.FailedCount.u.LowPart += TxStaCnt0.field.TxFailCount;

                  if (TxTotalCnt)
                        TxErrorRatio = ((TxRetransmit + TxFailCount) * 100) / TxTotalCnt;
            }
            else
            {
                  TxTotalCnt = pEntry->OneSecTxNoRetryOkCount +
                         pEntry->OneSecTxRetryOkCount +
                         pEntry->OneSecTxFailCount;

                  if (TxTotalCnt)
                        TxErrorRatio = ((pEntry->OneSecTxRetryOkCount + pEntry->OneSecTxFailCount) * 100) / TxTotalCnt;
            }


            //
            // CASE 1. when TX samples are fewer than 15, then decide TX rate solely on RSSI
            //         (criteria copied from RT2500 for Netopia case)
            //
            if (TxTotalCnt <= 12)
            {
                  NdisZeroMemory(pAd->DrsCounters.TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH);
                  NdisZeroMemory(pAd->DrsCounters.PER, sizeof(UCHAR) * MAX_STEP_OF_TX_RATE_SWITCH);

                  if ((pAd->DrsCounters.LastSecTxRateChangeAction == 1) && (CurrRateIdx != DownRateIdx))
                  {
                        pAd->CommonCfg.TxRateIndex = DownRateIdx;
                        pAd->DrsCounters.TxQuality[CurrRateIdx] = DRS_TX_QUALITY_WORST_BOUND;
                  }
                  else if ((pAd->DrsCounters.LastSecTxRateChangeAction == 2) && (CurrRateIdx != UpRateIdx))
                  {
                        pAd->CommonCfg.TxRateIndex = UpRateIdx;
                  }

                  DBGPRINT_RAW(RT_DEBUG_TRACE,("QuickDRS: TxTotalCnt <= 15, train back to original rate \n"));
                  return;
            }

            do
            {
                  ULONG OneSecTxNoRetryOKRationCount;

                  if (pAd->DrsCounters.LastTimeTxRateChangeAction == 0)
                        ratio = 5;
                  else
                        ratio = 4;

                  // downgrade TX quality if PER >= Rate-Down threshold
                  if (TxErrorRatio >= TrainDown)
                  {
                        pAd->DrsCounters.TxQuality[CurrRateIdx] = DRS_TX_QUALITY_WORST_BOUND;
                  }

                  pAd->DrsCounters.PER[CurrRateIdx] = (UCHAR)TxErrorRatio;

                  OneSecTxNoRetryOKRationCount = (TxSuccess * ratio);

                  // perform DRS - consider TxRate Down first, then rate up.
                  if ((pAd->DrsCounters.LastSecTxRateChangeAction == 1) && (CurrRateIdx != DownRateIdx))
                  {
                        if ((pAd->DrsCounters.LastTxOkCount + 2) >= OneSecTxNoRetryOKRationCount)
                        {
                              pAd->CommonCfg.TxRateIndex = DownRateIdx;
                              pAd->DrsCounters.TxQuality[CurrRateIdx] = DRS_TX_QUALITY_WORST_BOUND;

                        }

                  }
                  else if ((pAd->DrsCounters.LastSecTxRateChangeAction == 2) && (CurrRateIdx != UpRateIdx))
                  {
                        if ((TxErrorRatio >= 50) || (TxErrorRatio >= TrainDown))
                        {

                        }
                        else if ((pAd->DrsCounters.LastTxOkCount + 2) >= OneSecTxNoRetryOKRationCount)
                        {
                              pAd->CommonCfg.TxRateIndex = UpRateIdx;
                        }
                  }
            }while (FALSE);

            // if rate-up happen, clear all bad history of all TX rates
            if (pAd->CommonCfg.TxRateIndex > CurrRateIdx)
            {
                  pAd->DrsCounters.TxRateUpPenalty = 0;
                  NdisZeroMemory(pAd->DrsCounters.TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH);
                  NdisZeroMemory(pAd->DrsCounters.PER, sizeof(UCHAR) * MAX_STEP_OF_TX_RATE_SWITCH);
#ifdef RT2870
                  bTxRateChanged = TRUE;
#endif
            }
            // if rate-down happen, only clear DownRate's bad history
            else if (pAd->CommonCfg.TxRateIndex < CurrRateIdx)
            {
                  DBGPRINT_RAW(RT_DEBUG_TRACE,("QuickDRS: --TX rate from %d to %d \n", CurrRateIdx, pAd->CommonCfg.TxRateIndex));

                  pAd->DrsCounters.TxRateUpPenalty = 0;           // no penalty
                  pAd->DrsCounters.TxQuality[pAd->CommonCfg.TxRateIndex] = 0;
                  pAd->DrsCounters.PER[pAd->CommonCfg.TxRateIndex] = 0;
#ifdef RT2870
                  bTxRateChanged = TRUE;
#endif
            }
            else
            {
                  bTxRateChanged = FALSE;
            }

            pNextTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(pAd->CommonCfg.TxRateIndex+1)*5];
            if (bTxRateChanged && pNextTxRate)
            {
                  MlmeSetTxRate(pAd, pEntry, pNextTxRate);
            }
      }
}

/*
      ==========================================================================
      Description:
            This routine is executed periodically inside MlmePeriodicExec() after
            association with an AP.
            It checks if StaCfg.Psm is consistent with user policy (recorded in
            StaCfg.WindowsPowerMode). If not, enforce user policy. However,
            there're some conditions to consider:
            1. we don't support power-saving in ADHOC mode, so Psm=PWR_ACTIVE all
               the time when Mibss==TRUE
            2. When link up in INFRA mode, Psm should not be switch to PWR_SAVE
               if outgoing traffic available in TxRing or MgmtRing.
      Output:
            1. change pAd->StaCfg.Psm to PWR_SAVE or leave it untouched

      IRQL = DISPATCH_LEVEL

      ==========================================================================
 */
VOID MlmeCheckPsmChange(
      IN PRTMP_ADAPTER pAd,
      IN ULONG    Now32)
{
      ULONG PowerMode;

      // condition -
      // 1. Psm maybe ON only happen in INFRASTRUCTURE mode
      // 2. user wants either MAX_PSP or FAST_PSP
      // 3. but current psm is not in PWR_SAVE
      // 4. CNTL state machine is not doing SCANning
      // 5. no TX SUCCESS event for the past 1-sec period
#ifdef NDIS51_MINIPORT
      if (pAd->StaCfg.WindowsPowerProfile == NdisPowerProfileBattery)
            PowerMode = pAd->StaCfg.WindowsBatteryPowerMode;
      else
#endif
            PowerMode = pAd->StaCfg.WindowsPowerMode;

      if (INFRA_ON(pAd) &&
            (PowerMode != Ndis802_11PowerModeCAM) &&
            (pAd->StaCfg.Psm == PWR_ACTIVE) &&
#ifdef RT2860
            RTMP_TEST_PSFLAG(pAd, fRTMP_PS_CAN_GO_SLEEP))
#endif
#if !defined(RT2860) && !defined(RT30xx)
            (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE))
#endif
#ifndef RT30xx
      {
            NdisGetSystemUpTime(&pAd->Mlme.LastSendNULLpsmTime);
            pAd->RalinkCounters.RxCountSinceLastNULL = 0;
            MlmeSetPsmBit(pAd, PWR_SAVE);
            if (!(pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable))
            {
                  RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, FALSE);
            }
            else
            {
                  RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE);
            }
      }
#endif
#ifdef RT30xx
//          (! RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
            (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) /*&&
            (pAd->RalinkCounters.OneSecTxNoRetryOkCount == 0) &&
            (pAd->RalinkCounters.OneSecTxRetryOkCount == 0)*/)
      {
            // add by johnli, use Rx OK data count per second to calculate throughput
            // If Ttraffic is too high ( > 400 Rx per second), don't go to sleep mode. If tx rate is low, use low criteria
            // Mode=CCK/MCS=3 => 11 Mbps, Mode=OFDM/MCS=3 => 18 Mbps
            if (((pAd->StaCfg.HTPhyMode.field.MCS <= 3) &&
/* Iverson mark
                        (pAd->StaCfg.HTPhyMode.field.MODE <= MODE_OFDM) &&
*/
                        (pAd->RalinkCounters.OneSecRxOkDataCnt < (ULONG)100)) ||
                  ((pAd->StaCfg.HTPhyMode.field.MCS > 3) &&
/* Iverson mark
                  (pAd->StaCfg.HTPhyMode.field.MODE > MODE_OFDM) &&
*/
                  (pAd->RalinkCounters.OneSecRxOkDataCnt < (ULONG)400)))
            {
                        // Get this time
                  NdisGetSystemUpTime(&pAd->Mlme.LastSendNULLpsmTime);
                  pAd->RalinkCounters.RxCountSinceLastNULL = 0;
                  MlmeSetPsmBit(pAd, PWR_SAVE);
                  if (!(pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable))
                  {
                        RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, FALSE);
                  }
                  else
                  {
                        RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE);
                  }
            }
      }
#endif
}

// IRQL = PASSIVE_LEVEL
// IRQL = DISPATCH_LEVEL
VOID MlmeSetPsmBit(
      IN PRTMP_ADAPTER pAd,
      IN USHORT psm)
{
      AUTO_RSP_CFG_STRUC csr4;

      pAd->StaCfg.Psm = psm;
      RTMP_IO_READ32(pAd, AUTO_RSP_CFG, &csr4.word);
      csr4.field.AckCtsPsmBit = (psm == PWR_SAVE)? 1:0;
      RTMP_IO_WRITE32(pAd, AUTO_RSP_CFG, csr4.word);
#ifndef RT30xx
      DBGPRINT(RT_DEBUG_TRACE, ("MlmeSetPsmBit = %d\n", psm));
#endif
}

// IRQL = DISPATCH_LEVEL
VOID MlmeSetTxPreamble(
      IN PRTMP_ADAPTER pAd,
      IN USHORT TxPreamble)
{
      AUTO_RSP_CFG_STRUC csr4;

      //
      // Always use Long preamble before verifiation short preamble functionality works well.
      // Todo: remove the following line if short preamble functionality works
      //
      //TxPreamble = Rt802_11PreambleLong;

      RTMP_IO_READ32(pAd, AUTO_RSP_CFG, &csr4.word);
      if (TxPreamble == Rt802_11PreambleLong)
      {
            DBGPRINT(RT_DEBUG_TRACE, ("MlmeSetTxPreamble (= LONG PREAMBLE)\n"));
            OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED);
            csr4.field.AutoResponderPreamble = 0;
      }
      else
      {
            // NOTE: 1Mbps should always use long preamble
            DBGPRINT(RT_DEBUG_TRACE, ("MlmeSetTxPreamble (= SHORT PREAMBLE)\n"));
            OPSTATUS_SET_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED);
            csr4.field.AutoResponderPreamble = 1;
      }

      RTMP_IO_WRITE32(pAd, AUTO_RSP_CFG, csr4.word);
}

/*
    ==========================================================================
    Description:
        Update basic rate bitmap
    ==========================================================================
 */

VOID UpdateBasicRateBitmap(
    IN  PRTMP_ADAPTER   pAdapter)
{
    INT  i, j;
                  /* 1  2  5.5, 11,  6,  9, 12, 18, 24, 36, 48,  54 */
    UCHAR rate[] = { 2, 4,  11, 22, 12, 18, 24, 36, 48, 72, 96, 108 };
    UCHAR *sup_p = pAdapter->CommonCfg.SupRate;
    UCHAR *ext_p = pAdapter->CommonCfg.ExtRate;
    ULONG bitmap = pAdapter->CommonCfg.BasicRateBitmap;


    /* if A mode, always use fix BasicRateBitMap */
    //if (pAdapter->CommonCfg.Channel == PHY_11A)
      if (pAdapter->CommonCfg.Channel > 14)
        pAdapter->CommonCfg.BasicRateBitmap = 0x150; /* 6, 12, 24M */
    /* End of if */

    if (pAdapter->CommonCfg.BasicRateBitmap > 4095)
    {
        /* (2 ^ MAX_LEN_OF_SUPPORTED_RATES) -1 */
        return;
    } /* End of if */

    for(i=0; i<MAX_LEN_OF_SUPPORTED_RATES; i++)
    {
        sup_p[i] &= 0x7f;
        ext_p[i] &= 0x7f;
    } /* End of for */

    for(i=0; i<MAX_LEN_OF_SUPPORTED_RATES; i++)
    {
        if (bitmap & (1 << i))
        {
            for(j=0; j<MAX_LEN_OF_SUPPORTED_RATES; j++)
            {
                if (sup_p[j] == rate[i])
                    sup_p[j] |= 0x80;
                /* End of if */
            } /* End of for */

            for(j=0; j<MAX_LEN_OF_SUPPORTED_RATES; j++)
            {
                if (ext_p[j] == rate[i])
                    ext_p[j] |= 0x80;
                /* End of if */
            } /* End of for */
        } /* End of if */
    } /* End of for */
} /* End of UpdateBasicRateBitmap */

// IRQL = PASSIVE_LEVEL
// IRQL = DISPATCH_LEVEL
// bLinkUp is to identify the inital link speed.
// TRUE indicates the rate update at linkup, we should not try to set the rate at 54Mbps.
VOID MlmeUpdateTxRates(
      IN PRTMP_ADAPTER        pAd,
      IN    BOOLEAN                       bLinkUp,
      IN    UCHAR                   apidx)
{
      int i, num;
      UCHAR Rate = RATE_6, MaxDesire = RATE_1, MaxSupport = RATE_1;
      UCHAR MinSupport = RATE_54;
      ULONG BasicRateBitmap = 0;
      UCHAR CurrBasicRate = RATE_1;
      UCHAR *pSupRate, SupRateLen, *pExtRate, ExtRateLen;
      PHTTRANSMIT_SETTING           pHtPhy = NULL;
      PHTTRANSMIT_SETTING           pMaxHtPhy = NULL;
      PHTTRANSMIT_SETTING           pMinHtPhy = NULL;
      BOOLEAN                       *auto_rate_cur_p;
      UCHAR                         HtMcs = MCS_AUTO;

      // find max desired rate
      UpdateBasicRateBitmap(pAd);

      num = 0;
      auto_rate_cur_p = NULL;
      for (i=0; i<MAX_LEN_OF_SUPPORTED_RATES; i++)
      {
            switch (pAd->CommonCfg.DesireRate[i] & 0x7f)
            {
                  case 2:  Rate = RATE_1;   num++;   break;
                  case 4:  Rate = RATE_2;   num++;   break;
                  case 11: Rate = RATE_5_5; num++;   break;
                  case 22: Rate = RATE_11;  num++;   break;
                  case 12: Rate = RATE_6;   num++;   break;
                  case 18: Rate = RATE_9;   num++;   break;
                  case 24: Rate = RATE_12;  num++;   break;
                  case 36: Rate = RATE_18;  num++;   break;
                  case 48: Rate = RATE_24;  num++;   break;
                  case 72: Rate = RATE_36;  num++;   break;
                  case 96: Rate = RATE_48;  num++;   break;
                  case 108: Rate = RATE_54; num++;   break;
                  //default: Rate = RATE_1;   break;
            }
            if (MaxDesire < Rate)  MaxDesire = Rate;
      }

//===========================================================================
//===========================================================================
      {
            pHtPhy            = &pAd->StaCfg.HTPhyMode;
            pMaxHtPhy   = &pAd->StaCfg.MaxHTPhyMode;
            pMinHtPhy   = &pAd->StaCfg.MinHTPhyMode;

            auto_rate_cur_p = &pAd->StaCfg.bAutoTxRateSwitch;
            HtMcs             = pAd->StaCfg.DesiredTransmitSetting.field.MCS;

            if ((pAd->StaCfg.BssType == BSS_ADHOC) &&
                  (pAd->CommonCfg.PhyMode == PHY_11B) &&
                  (MaxDesire > RATE_11))
            {
                  MaxDesire = RATE_11;
            }
      }

      pAd->CommonCfg.MaxDesiredRate = MaxDesire;
      pMinHtPhy->word = 0;
      pMaxHtPhy->word = 0;
      pHtPhy->word = 0;

      // Auto rate switching is enabled only if more than one DESIRED RATES are
      // specified; otherwise disabled
      if (num <= 1)
      {
            *auto_rate_cur_p = FALSE;
      }
      else
      {
            *auto_rate_cur_p = TRUE;
      }

#if 1
      if (HtMcs != MCS_AUTO)
      {
            *auto_rate_cur_p = FALSE;
      }
      else
      {
            *auto_rate_cur_p = TRUE;
      }
#endif

      if ((ADHOC_ON(pAd) || INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA))
      {
            pSupRate = &pAd->StaActive.SupRate[0];
            pExtRate = &pAd->StaActive.ExtRate[0];
            SupRateLen = pAd->StaActive.SupRateLen;
            ExtRateLen = pAd->StaActive.ExtRateLen;
      }
      else
      {
            pSupRate = &pAd->CommonCfg.SupRate[0];
            pExtRate = &pAd->CommonCfg.ExtRate[0];
            SupRateLen = pAd->CommonCfg.SupRateLen;
            ExtRateLen = pAd->CommonCfg.ExtRateLen;
      }

      // find max supported rate
      for (i=0; i<SupRateLen; i++)
      {
            switch (pSupRate[i] & 0x7f)
            {
                  case 2:   Rate = RATE_1;      if (pSupRate[i] & 0x80) BasicRateBitmap |= 0x0001;     break;
                  case 4:   Rate = RATE_2;      if (pSupRate[i] & 0x80) BasicRateBitmap |= 0x0002;     break;
                  case 11:  Rate = RATE_5_5;    if (pSupRate[i] & 0x80) BasicRateBitmap |= 0x0004;     break;
                  case 22:  Rate = RATE_11;     if (pSupRate[i] & 0x80) BasicRateBitmap |= 0x0008;     break;
                  case 12:  Rate = RATE_6;      /*if (pSupRate[i] & 0x80)*/  BasicRateBitmap |= 0x0010;  break;
                  case 18:  Rate = RATE_9;      if (pSupRate[i] & 0x80) BasicRateBitmap |= 0x0020;     break;
                  case 24:  Rate = RATE_12;     /*if (pSupRate[i] & 0x80)*/  BasicRateBitmap |= 0x0040;  break;
                  case 36:  Rate = RATE_18;     if (pSupRate[i] & 0x80) BasicRateBitmap |= 0x0080;     break;
                  case 48:  Rate = RATE_24;     /*if (pSupRate[i] & 0x80)*/  BasicRateBitmap |= 0x0100;  break;
                  case 72:  Rate = RATE_36;     if (pSupRate[i] & 0x80) BasicRateBitmap |= 0x0200;     break;
                  case 96:  Rate = RATE_48;     if (pSupRate[i] & 0x80) BasicRateBitmap |= 0x0400;     break;
                  case 108: Rate = RATE_54;     if (pSupRate[i] & 0x80) BasicRateBitmap |= 0x0800;     break;
                  default:  Rate = RATE_1;      break;
            }
            if (MaxSupport < Rate)  MaxSupport = Rate;

            if (MinSupport > Rate) MinSupport = Rate;
      }

      for (i=0; i<ExtRateLen; i++)
      {
            switch (pExtRate[i] & 0x7f)
            {
                  case 2:   Rate = RATE_1;      if (pExtRate[i] & 0x80) BasicRateBitmap |= 0x0001;     break;
                  case 4:   Rate = RATE_2;      if (pExtRate[i] & 0x80) BasicRateBitmap |= 0x0002;     break;
                  case 11:  Rate = RATE_5_5;    if (pExtRate[i] & 0x80) BasicRateBitmap |= 0x0004;     break;
                  case 22:  Rate = RATE_11;     if (pExtRate[i] & 0x80) BasicRateBitmap |= 0x0008;     break;
                  case 12:  Rate = RATE_6;      /*if (pExtRate[i] & 0x80)*/  BasicRateBitmap |= 0x0010;  break;
                  case 18:  Rate = RATE_9;      if (pExtRate[i] & 0x80) BasicRateBitmap |= 0x0020;     break;
                  case 24:  Rate = RATE_12;     /*if (pExtRate[i] & 0x80)*/  BasicRateBitmap |= 0x0040;  break;
                  case 36:  Rate = RATE_18;     if (pExtRate[i] & 0x80) BasicRateBitmap |= 0x0080;     break;
                  case 48:  Rate = RATE_24;     /*if (pExtRate[i] & 0x80)*/  BasicRateBitmap |= 0x0100;  break;
                  case 72:  Rate = RATE_36;     if (pExtRate[i] & 0x80) BasicRateBitmap |= 0x0200;     break;
                  case 96:  Rate = RATE_48;     if (pExtRate[i] & 0x80) BasicRateBitmap |= 0x0400;     break;
                  case 108: Rate = RATE_54;     if (pExtRate[i] & 0x80) BasicRateBitmap |= 0x0800;     break;
                  default:  Rate = RATE_1;      break;
            }
            if (MaxSupport < Rate)  MaxSupport = Rate;

            if (MinSupport > Rate) MinSupport = Rate;
      }

      RTMP_IO_WRITE32(pAd, LEGACY_BASIC_RATE, BasicRateBitmap);

      // calculate the exptected ACK rate for each TX rate. This info is used to caculate
      // the DURATION field of outgoing uniicast DATA/MGMT frame
      for (i=0; i<MAX_LEN_OF_SUPPORTED_RATES; i++)
      {
            if (BasicRateBitmap & (0x01 << i))
                  CurrBasicRate = (UCHAR)i;
            pAd->CommonCfg.ExpectedACKRate[i] = CurrBasicRate;
      }

      DBGPRINT(RT_DEBUG_TRACE,("MlmeUpdateTxRates[MaxSupport = %d] = MaxDesire %d Mbps\n", RateIdToMbps[MaxSupport], RateIdToMbps[MaxDesire]));
      // max tx rate = min {max desire rate, max supported rate}
      if (MaxSupport < MaxDesire)
            pAd->CommonCfg.MaxTxRate = MaxSupport;
      else
            pAd->CommonCfg.MaxTxRate = MaxDesire;

      pAd->CommonCfg.MinTxRate = MinSupport;
      if (*auto_rate_cur_p)
      {
            short dbm = 0;

            dbm = pAd->StaCfg.RssiSample.AvgRssi0 - pAd->BbpRssiToDbmDelta;

            if (bLinkUp == TRUE)
                  pAd->CommonCfg.TxRate = RATE_24;
            else
                  pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate;

            if (dbm < -75)
                  pAd->CommonCfg.TxRate = RATE_11;
            else if (dbm < -70)
                  pAd->CommonCfg.TxRate = RATE_24;

            // should never exceed MaxTxRate (consider 11B-only mode)
            if (pAd->CommonCfg.TxRate > pAd->CommonCfg.MaxTxRate)
                  pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate;

            pAd->CommonCfg.TxRateIndex = 0;
      }
      else
      {
            pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate;
            pHtPhy->field.MCS = (pAd->CommonCfg.MaxTxRate > 3) ? (pAd->CommonCfg.MaxTxRate - 4) : pAd->CommonCfg.MaxTxRate;
            pHtPhy->field.MODE      = (pAd->CommonCfg.MaxTxRate > 3) ? MODE_OFDM : MODE_CCK;

            pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.STBC  = pHtPhy->field.STBC;
            pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.ShortGI     = pHtPhy->field.ShortGI;
            pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MCS         = pHtPhy->field.MCS;
            pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE  = pHtPhy->field.MODE;
      }

      if (pAd->CommonCfg.TxRate <= RATE_11)
      {
            pMaxHtPhy->field.MODE = MODE_CCK;
            pMaxHtPhy->field.MCS = pAd->CommonCfg.TxRate;
            pMinHtPhy->field.MCS = pAd->CommonCfg.MinTxRate;
      }
      else
      {
            pMaxHtPhy->field.MODE = MODE_OFDM;
            pMaxHtPhy->field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.TxRate];
            if (pAd->CommonCfg.MinTxRate >= RATE_6 && (pAd->CommonCfg.MinTxRate <= RATE_54))
                  {pMinHtPhy->field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MinTxRate];}
            else
                  {pMinHtPhy->field.MCS = pAd->CommonCfg.MinTxRate;}
      }

      pHtPhy->word = (pMaxHtPhy->word);
      if (bLinkUp && (pAd->OpMode == OPMODE_STA))
      {
                  pAd->MacTab.Content[BSSID_WCID].HTPhyMode.word = pHtPhy->word;
                  pAd->MacTab.Content[BSSID_WCID].MaxHTPhyMode.word = pMaxHtPhy->word;
                  pAd->MacTab.Content[BSSID_WCID].MinHTPhyMode.word = pMinHtPhy->word;
      }
      else
      {
            switch (pAd->CommonCfg.PhyMode)
            {
                  case PHY_11BG_MIXED:
                  case PHY_11B:
                  case PHY_11BGN_MIXED:
                        pAd->CommonCfg.MlmeRate = RATE_1;
                        pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK;
                        pAd->CommonCfg.MlmeTransmit.field.MCS = RATE_1;
                        pAd->CommonCfg.RtsRate = RATE_11;
                        break;
                  case PHY_11G:
                  case PHY_11A:
                  case PHY_11AGN_MIXED:
                  case PHY_11GN_MIXED:
                  case PHY_11N_2_4G:
                  case PHY_11AN_MIXED:
                  case PHY_11N_5G:
                        pAd->CommonCfg.MlmeRate = RATE_6;
                        pAd->CommonCfg.RtsRate = RATE_6;
                        pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM;
                        pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate];
                        break;
                  case PHY_11ABG_MIXED:
                  case PHY_11ABGN_MIXED:
                        if (pAd->CommonCfg.Channel <= 14)
                        {
                              pAd->CommonCfg.MlmeRate = RATE_1;
                              pAd->CommonCfg.RtsRate = RATE_1;
                              pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK;
                              pAd->CommonCfg.MlmeTransmit.field.MCS = RATE_1;
                        }
                        else
                        {
                              pAd->CommonCfg.MlmeRate = RATE_6;
                              pAd->CommonCfg.RtsRate = RATE_6;
                              pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM;
                              pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate];
                        }
                        break;
                  default: // error
                        pAd->CommonCfg.MlmeRate = RATE_6;
                              pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM;
                        pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate];
                        pAd->CommonCfg.RtsRate = RATE_1;
                        break;
            }
            //
            // Keep Basic Mlme Rate.
            //
            pAd->MacTab.Content[MCAST_WCID].HTPhyMode.word = pAd->CommonCfg.MlmeTransmit.word;
            if (pAd->CommonCfg.MlmeTransmit.field.MODE == MODE_OFDM)
                  pAd->MacTab.Content[MCAST_WCID].HTPhyMode.field.MCS = OfdmRateToRxwiMCS[RATE_24];
            else
                  pAd->MacTab.Content[MCAST_WCID].HTPhyMode.field.MCS = RATE_1;
            pAd->CommonCfg.BasicMlmeRate = pAd->CommonCfg.MlmeRate;
      }

      DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (MaxDesire=%d, MaxSupport=%d, MaxTxRate=%d, MinRate=%d, Rate Switching =%d)\n",
                   RateIdToMbps[MaxDesire], RateIdToMbps[MaxSupport], RateIdToMbps[pAd->CommonCfg.MaxTxRate], RateIdToMbps[pAd->CommonCfg.MinTxRate],
                   /*OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED)*/*auto_rate_cur_p));
      DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (TxRate=%d, RtsRate=%d, BasicRateBitmap=0x%04lx)\n",
                   RateIdToMbps[pAd->CommonCfg.TxRate], RateIdToMbps[pAd->CommonCfg.RtsRate], BasicRateBitmap));
      DBGPRINT(RT_DEBUG_TRACE, ("MlmeUpdateTxRates (MlmeTransmit=0x%x, MinHTPhyMode=%x, MaxHTPhyMode=0x%x, HTPhyMode=0x%x)\n",
                   pAd->CommonCfg.MlmeTransmit.word, pAd->MacTab.Content[BSSID_WCID].MinHTPhyMode.word ,pAd->MacTab.Content[BSSID_WCID].MaxHTPhyMode.word ,pAd->MacTab.Content[BSSID_WCID].HTPhyMode.word ));
}

/*
      ==========================================================================
      Description:
            This function update HT Rate setting.
            Input Wcid value is valid for 2 case :
            1. it's used for Station in infra mode that copy AP rate to Mactable.
            2. OR Station     in adhoc mode to copy peer's HT rate to Mactable.

      IRQL = DISPATCH_LEVEL

      ==========================================================================
 */
VOID MlmeUpdateHtTxRates(
      IN PRTMP_ADAPTER        pAd,
      IN    UCHAR                   apidx)
{
      UCHAR StbcMcs; //j, StbcMcs, bitmask;
      CHAR  i; // 3*3
      RT_HT_CAPABILITY  *pRtHtCap = NULL;
      RT_HT_PHY_INFO          *pActiveHtPhy = NULL;
      ULONG       BasicMCS;
      UCHAR j, bitmask;
      PRT_HT_PHY_INFO               pDesireHtPhy = NULL;
      PHTTRANSMIT_SETTING           pHtPhy = NULL;
      PHTTRANSMIT_SETTING           pMaxHtPhy = NULL;
      PHTTRANSMIT_SETTING           pMinHtPhy = NULL;
      BOOLEAN                       *auto_rate_cur_p;

      DBGPRINT(RT_DEBUG_TRACE,("MlmeUpdateHtTxRates===> \n"));

      auto_rate_cur_p = NULL;

      {
            pDesireHtPhy      = &pAd->StaCfg.DesiredHtPhyInfo;
            pActiveHtPhy      = &pAd->StaCfg.DesiredHtPhyInfo;
            pHtPhy            = &pAd->StaCfg.HTPhyMode;
            pMaxHtPhy   = &pAd->StaCfg.MaxHTPhyMode;
            pMinHtPhy   = &pAd->StaCfg.MinHTPhyMode;

            auto_rate_cur_p = &pAd->StaCfg.bAutoTxRateSwitch;
      }

      if ((ADHOC_ON(pAd) || INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA))
      {
            if (pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE)
                  return;

            pRtHtCap = &pAd->StaActive.SupportedHtPhy;
            pActiveHtPhy = &pAd->StaActive.SupportedPhyInfo;
            StbcMcs = (UCHAR)pAd->MlmeAux.AddHtInfo.AddHtInfo3.StbcMcs;
            BasicMCS =pAd->MlmeAux.AddHtInfo.MCSSet[0]+(pAd->MlmeAux.AddHtInfo.MCSSet[1]<<8)+(StbcMcs<<16);
            if ((pAd->CommonCfg.DesiredHtPhy.TxSTBC) && (pRtHtCap->RxSTBC) && (pAd->Antenna.field.TxPath == 2))
                  pMaxHtPhy->field.STBC = STBC_USE;
            else
                  pMaxHtPhy->field.STBC = STBC_NONE;
      }
      else
      {
            if (pDesireHtPhy->bHtEnable == FALSE)
                  return;

            pRtHtCap = &pAd->CommonCfg.DesiredHtPhy;
            StbcMcs = (UCHAR)pAd->CommonCfg.AddHTInfo.AddHtInfo3.StbcMcs;
            BasicMCS = pAd->CommonCfg.AddHTInfo.MCSSet[0]+(pAd->CommonCfg.AddHTInfo.MCSSet[1]<<8)+(StbcMcs<<16);
            if ((pAd->CommonCfg.DesiredHtPhy.TxSTBC) && (pRtHtCap->RxSTBC) && (pAd->Antenna.field.TxPath == 2))
                  pMaxHtPhy->field.STBC = STBC_USE;
            else
                  pMaxHtPhy->field.STBC = STBC_NONE;
      }

      // Decide MAX ht rate.
      if ((pRtHtCap->GF) && (pAd->CommonCfg.DesiredHtPhy.GF))
            pMaxHtPhy->field.MODE = MODE_HTGREENFIELD;
      else
            pMaxHtPhy->field.MODE = MODE_HTMIX;

    if ((pAd->CommonCfg.DesiredHtPhy.ChannelWidth) && (pRtHtCap->ChannelWidth))
            pMaxHtPhy->field.BW = BW_40;
      else
            pMaxHtPhy->field.BW = BW_20;

    if (pMaxHtPhy->field.BW == BW_20)
            pMaxHtPhy->field.ShortGI = (pAd->CommonCfg.DesiredHtPhy.ShortGIfor20 & pRtHtCap->ShortGIfor20);
      else
            pMaxHtPhy->field.ShortGI = (pAd->CommonCfg.DesiredHtPhy.ShortGIfor40 & pRtHtCap->ShortGIfor40);

      for (i=23; i>=0; i--) // 3*3
      {
            j = i/8;
            bitmask = (1<<(i-(j*8)));

            if ((pActiveHtPhy->MCSSet[j] & bitmask) && (pDesireHtPhy->MCSSet[j] & bitmask))
            {
                  pMaxHtPhy->field.MCS = i;
                  break;
            }

            if (i==0)
                  break;
      }

      // Copy MIN ht rate.  rt2860???
      pMinHtPhy->field.BW = BW_20;
      pMinHtPhy->field.MCS = 0;
      pMinHtPhy->field.STBC = 0;
      pMinHtPhy->field.ShortGI = 0;
      //If STA assigns fixed rate. update to fixed here.
      if ( (pAd->OpMode == OPMODE_STA) && (pDesireHtPhy->MCSSet[0] != 0xff))
      {
            if (pDesireHtPhy->MCSSet[4] != 0)
            {
                  pMaxHtPhy->field.MCS = 32;
                  pMinHtPhy->field.MCS = 32;
                  DBGPRINT(RT_DEBUG_TRACE,("MlmeUpdateHtTxRates<=== Use Fixed MCS = %d\n",pMinHtPhy->field.MCS));
            }

            for (i=23; (CHAR)i >= 0; i--) // 3*3
            {
                  j = i/8;
                  bitmask = (1<<(i-(j*8)));
                  if ( (pDesireHtPhy->MCSSet[j] & bitmask) && (pActiveHtPhy->MCSSet[j] & bitmask))
                  {
                        pMaxHtPhy->field.MCS = i;
                        pMinHtPhy->field.MCS = i;
                        break;
                  }
                  if (i==0)
                        break;
            }
      }

      // Decide ht rate
      pHtPhy->field.STBC = pMaxHtPhy->field.STBC;
      pHtPhy->field.BW = pMaxHtPhy->field.BW;
      pHtPhy->field.MODE = pMaxHtPhy->field.MODE;
      pHtPhy->field.MCS = pMaxHtPhy->field.MCS;
      pHtPhy->field.ShortGI = pMaxHtPhy->field.ShortGI;

      // use default now. rt2860
      if (pDesireHtPhy->MCSSet[0] != 0xff)
            *auto_rate_cur_p = FALSE;
      else
            *auto_rate_cur_p = TRUE;

      DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateHtTxRates<---.AMsduSize = %d  \n", pAd->CommonCfg.DesiredHtPhy.AmsduSize ));
      DBGPRINT(RT_DEBUG_TRACE,("TX: MCS[0] = %x (choose %d), BW = %d, ShortGI = %d, MODE = %d,  \n", pActiveHtPhy->MCSSet[0],pHtPhy->field.MCS,
            pHtPhy->field.BW, pHtPhy->field.ShortGI, pHtPhy->field.MODE));
      DBGPRINT(RT_DEBUG_TRACE,("MlmeUpdateHtTxRates<=== \n"));
}

// IRQL = DISPATCH_LEVEL
VOID MlmeRadioOff(
      IN PRTMP_ADAPTER pAd)
{
      RT28XX_MLME_RADIO_OFF(pAd);
}

// IRQL = DISPATCH_LEVEL
VOID MlmeRadioOn(
      IN PRTMP_ADAPTER pAd)
{
      RT28XX_MLME_RADIO_ON(pAd);
}

// ===========================================================================================
// bss_table.c
// ===========================================================================================


/*! \brief initialize BSS table
 *    \param p_tab pointer to the table
 *    \return none
 *    \pre
 *    \post

 IRQL = PASSIVE_LEVEL
 IRQL = DISPATCH_LEVEL

 */
VOID BssTableInit(
      IN BSS_TABLE *Tab)
{
      int i;

      Tab->BssNr = 0;
    Tab->BssOverlapNr = 0;
      for (i = 0; i < MAX_LEN_OF_BSS_TABLE; i++)
      {
            NdisZeroMemory(&Tab->BssEntry[i], sizeof(BSS_ENTRY));
            Tab->BssEntry[i].Rssi = -127; // initial the rssi as a minimum value
      }
}

VOID BATableInit(
      IN PRTMP_ADAPTER pAd,
    IN BA_TABLE *Tab)
{
      int i;

      Tab->numAsOriginator = 0;
      Tab->numAsRecipient = 0;
      NdisAllocateSpinLock(&pAd->BATabLock);
      for (i = 0; i < MAX_LEN_OF_BA_REC_TABLE; i++)
      {
            Tab->BARecEntry[i].REC_BA_Status = Recipient_NONE;
            NdisAllocateSpinLock(&(Tab->BARecEntry[i].RxReRingLock));
      }
      for (i = 0; i < MAX_LEN_OF_BA_ORI_TABLE; i++)
      {
            Tab->BAOriEntry[i].ORI_BA_Status = Originator_NONE;
      }
}

/*! \brief search the BSS table by SSID
 *    \param p_tab pointer to the bss table
 *    \param ssid SSID string
 *    \return index of the table, BSS_NOT_FOUND if not in the table
 *    \pre
 *    \post
 *    \note search by sequential search

 IRQL = DISPATCH_LEVEL

 */
ULONG BssTableSearch(
      IN BSS_TABLE *Tab,
      IN PUCHAR    pBssid,
      IN UCHAR     Channel)
{
      UCHAR i;

      for (i = 0; i < Tab->BssNr; i++)
      {
            //
            // Some AP that support A/B/G mode that may used the same BSSID on 11A and 11B/G.
            // We should distinguish this case.
            //
            if ((((Tab->BssEntry[i].Channel <= 14) && (Channel <= 14)) ||
                   ((Tab->BssEntry[i].Channel > 14) && (Channel > 14))) &&
                  MAC_ADDR_EQUAL(Tab->BssEntry[i].Bssid, pBssid))
            {
                  return i;
            }
      }
      return (ULONG)BSS_NOT_FOUND;
}

ULONG BssSsidTableSearch(
      IN BSS_TABLE *Tab,
      IN PUCHAR    pBssid,
      IN PUCHAR    pSsid,
      IN UCHAR     SsidLen,
      IN UCHAR     Channel)
{
      UCHAR i;

      for (i = 0; i < Tab->BssNr; i++)
      {
            //
            // Some AP that support A/B/G mode that may used the same BSSID on 11A and 11B/G.
            // We should distinguish this case.
            //
            if ((((Tab->BssEntry[i].Channel <= 14) && (Channel <= 14)) ||
                   ((Tab->BssEntry[i].Channel > 14) && (Channel > 14))) &&
                  MAC_ADDR_EQUAL(Tab->BssEntry[i].Bssid, pBssid) &&
                  SSID_EQUAL(pSsid, SsidLen, Tab->BssEntry[i].Ssid, Tab->BssEntry[i].SsidLen))
            {
                  return i;
            }
      }
      return (ULONG)BSS_NOT_FOUND;
}

ULONG BssTableSearchWithSSID(
      IN BSS_TABLE *Tab,
      IN PUCHAR    Bssid,
      IN PUCHAR    pSsid,
      IN UCHAR     SsidLen,
      IN UCHAR     Channel)
{
      UCHAR i;

      for (i = 0; i < Tab->BssNr; i++)
      {
            if ((((Tab->BssEntry[i].Channel <= 14) && (Channel <= 14)) ||
                  ((Tab->BssEntry[i].Channel > 14) && (Channel > 14))) &&
                  MAC_ADDR_EQUAL(&(Tab->BssEntry[i].Bssid), Bssid) &&
                  (SSID_EQUAL(pSsid, SsidLen, Tab->BssEntry[i].Ssid, Tab->BssEntry[i].SsidLen) ||
                  (NdisEqualMemory(pSsid, ZeroSsid, SsidLen)) ||
                  (NdisEqualMemory(Tab->BssEntry[i].Ssid, ZeroSsid, Tab->BssEntry[i].SsidLen))))
            {
                  return i;
            }
      }
      return (ULONG)BSS_NOT_FOUND;
}

// IRQL = DISPATCH_LEVEL
VOID BssTableDeleteEntry(
      IN OUT      BSS_TABLE *Tab,
      IN          PUCHAR        pBssid,
      IN          UCHAR   Channel)
{
      UCHAR i, j;

      for (i = 0; i < Tab->BssNr; i++)
      {
            if ((Tab->BssEntry[i].Channel == Channel) &&
                  (MAC_ADDR_EQUAL(Tab->BssEntry[i].Bssid, pBssid)))
            {
                  for (j = i; j < Tab->BssNr - 1; j++)
                  {
                        NdisMoveMemory(&(Tab->BssEntry[j]), &(Tab->BssEntry[j + 1]), sizeof(BSS_ENTRY));
                  }
                  NdisZeroMemory(&(Tab->BssEntry[Tab->BssNr - 1]), sizeof(BSS_ENTRY));
                  Tab->BssNr -= 1;
                  return;
            }
      }
}

/*
      ========================================================================
      Routine Description:
            Delete the Originator Entry in BAtable. Or decrease numAs Originator by 1 if needed.

      Arguments:
      // IRQL = DISPATCH_LEVEL
      ========================================================================
*/
VOID BATableDeleteORIEntry(
      IN OUT      PRTMP_ADAPTER pAd,
      IN          BA_ORI_ENTRY      *pBAORIEntry)
{

      if (pBAORIEntry->ORI_BA_Status != Originator_NONE)
      {
            NdisAcquireSpinLock(&pAd->BATabLock);
            if (pBAORIEntry->ORI_BA_Status == Originator_Done)
            {
                  pAd->BATable.numAsOriginator -= 1;
                  DBGPRINT(RT_DEBUG_TRACE, ("BATableDeleteORIEntry numAsOriginator= %ld\n", pAd->BATable.numAsRecipient));
                  // Erase Bitmap flag.
            }
            pAd->MacTab.Content[pBAORIEntry->Wcid].TXBAbitmap &= (~(1<<(pBAORIEntry->TID) ));   // If STA mode,  erase flag here
            pAd->MacTab.Content[pBAORIEntry->Wcid].BAOriWcidArray[pBAORIEntry->TID] = 0;  // If STA mode,  erase flag here
            pBAORIEntry->ORI_BA_Status = Originator_NONE;
            pBAORIEntry->Token = 1;
            // Not clear Sequence here.
            NdisReleaseSpinLock(&pAd->BATabLock);
      }
}

/*! \brief
 *    \param
 *    \return
 *    \pre
 *    \post

 IRQL = DISPATCH_LEVEL

 */
VOID BssEntrySet(
      IN PRTMP_ADAPTER  pAd,
      OUT BSS_ENTRY *pBss,
      IN PUCHAR pBssid,
      IN CHAR Ssid[],
      IN UCHAR SsidLen,
      IN UCHAR BssType,
      IN USHORT BeaconPeriod,
      IN PCF_PARM pCfParm,
      IN USHORT AtimWin,
      IN USHORT CapabilityInfo,
      IN UCHAR SupRate[],
      IN UCHAR SupRateLen,
      IN UCHAR ExtRate[],
      IN UCHAR ExtRateLen,
      IN HT_CAPABILITY_IE *pHtCapability,
      IN ADD_HT_INFO_IE *pAddHtInfo,      // AP might use this additional ht info IE
      IN UCHAR                HtCapabilityLen,
      IN UCHAR                AddHtInfoLen,
      IN UCHAR                NewExtChanOffset,
      IN UCHAR Channel,
      IN CHAR Rssi,
      IN LARGE_INTEGER TimeStamp,
      IN UCHAR CkipFlag,
      IN PEDCA_PARM pEdcaParm,
      IN PQOS_CAPABILITY_PARM pQosCapability,
      IN PQBSS_LOAD_PARM pQbssLoad,
      IN USHORT LengthVIE,
      IN PNDIS_802_11_VARIABLE_IEs pVIE)
{
      COPY_MAC_ADDR(pBss->Bssid, pBssid);
      // Default Hidden SSID to be TRUE, it will be turned to FALSE after coping SSID
      pBss->Hidden = 1;
      if (SsidLen > 0)
      {
            // For hidden SSID AP, it might send beacon with SSID len equal to 0
            // Or send beacon /probe response with SSID len matching real SSID length,
            // but SSID is all zero. such as "00-00-00-00" with length 4.
            // We have to prevent this case overwrite correct table
            if (NdisEqualMemory(Ssid, ZeroSsid, SsidLen) == 0)
            {
                NdisZeroMemory(pBss->Ssid, MAX_LEN_OF_SSID);
                  NdisMoveMemory(pBss->Ssid, Ssid, SsidLen);
                  pBss->SsidLen = SsidLen;
                  pBss->Hidden = 0;
            }
      }
      else
            pBss->SsidLen = 0;
      pBss->BssType = BssType;
      pBss->BeaconPeriod = BeaconPeriod;
      if (BssType == BSS_INFRA)
      {
            if (pCfParm->bValid)
            {
                  pBss->CfpCount = pCfParm->CfpCount;
                  pBss->CfpPeriod = pCfParm->CfpPeriod;
                  pBss->CfpMaxDuration = pCfParm->CfpMaxDuration;
                  pBss->CfpDurRemaining = pCfParm->CfpDurRemaining;
            }
      }
      else
      {
            pBss->AtimWin = AtimWin;
      }

      pBss->CapabilityInfo = CapabilityInfo;
      // The privacy bit indicate security is ON, it maight be WEP, TKIP or AES
      // Combine with AuthMode, they will decide the connection methods.
      pBss->Privacy = CAP_IS_PRIVACY_ON(pBss->CapabilityInfo);
      ASSERT(SupRateLen <= MAX_LEN_OF_SUPPORTED_RATES);
      if (SupRateLen <= MAX_LEN_OF_SUPPORTED_RATES)
            NdisMoveMemory(pBss->SupRate, SupRate, SupRateLen);
      else
            NdisMoveMemory(pBss->SupRate, SupRate, MAX_LEN_OF_SUPPORTED_RATES);
      pBss->SupRateLen = SupRateLen;
      ASSERT(ExtRateLen <= MAX_LEN_OF_SUPPORTED_RATES);
      NdisMoveMemory(pBss->ExtRate, ExtRate, ExtRateLen);
      NdisMoveMemory(&pBss->HtCapability, pHtCapability, HtCapabilityLen);
      NdisMoveMemory(&pBss->AddHtInfo, pAddHtInfo, AddHtInfoLen);
      pBss->NewExtChanOffset = NewExtChanOffset;
      pBss->ExtRateLen = ExtRateLen;
      pBss->Channel = Channel;
      pBss->CentralChannel = Channel;
      pBss->Rssi = Rssi;
      // Update CkipFlag. if not exists, the value is 0x0
      pBss->CkipFlag = CkipFlag;

      // New for microsoft Fixed IEs
      NdisMoveMemory(pBss->FixIEs.Timestamp, &TimeStamp, 8);
      pBss->FixIEs.BeaconInterval = BeaconPeriod;
      pBss->FixIEs.Capabilities = CapabilityInfo;

      // New for microsoft Variable IEs
      if (LengthVIE != 0)
      {
            pBss->VarIELen = LengthVIE;
            NdisMoveMemory(pBss->VarIEs, pVIE, pBss->VarIELen);
      }
      else
      {
            pBss->VarIELen = 0;
      }

      pBss->AddHtInfoLen = 0;
      pBss->HtCapabilityLen = 0;

      if (HtCapabilityLen> 0)
      {
            pBss->HtCapabilityLen = HtCapabilityLen;
            NdisMoveMemory(&pBss->HtCapability, pHtCapability, HtCapabilityLen);
            if (AddHtInfoLen > 0)
            {
                  pBss->AddHtInfoLen = AddHtInfoLen;
                  NdisMoveMemory(&pBss->AddHtInfo, pAddHtInfo, AddHtInfoLen);

                        if ((pAddHtInfo->ControlChan > 2)&& (pAddHtInfo->AddHtInfo.ExtChanOffset == EXTCHA_BELOW) && (pHtCapability->HtCapInfo.ChannelWidth == BW_40))
                        {
                              pBss->CentralChannel = pAddHtInfo->ControlChan - 2;
                        }
                        else if ((pAddHtInfo->AddHtInfo.ExtChanOffset == EXTCHA_ABOVE) && (pHtCapability->HtCapInfo.ChannelWidth == BW_40))
                        {
                                    pBss->CentralChannel = pAddHtInfo->ControlChan + 2;
                        }
            }
      }

      BssCipherParse(pBss);

      // new for QOS
      if (pEdcaParm)
            NdisMoveMemory(&pBss->EdcaParm, pEdcaParm, sizeof(EDCA_PARM));
      else
            pBss->EdcaParm.bValid = FALSE;
      if (pQosCapability)
            NdisMoveMemory(&pBss->QosCapability, pQosCapability, sizeof(QOS_CAPABILITY_PARM));
      else
            pBss->QosCapability.bValid = FALSE;
      if (pQbssLoad)
            NdisMoveMemory(&pBss->QbssLoad, pQbssLoad, sizeof(QBSS_LOAD_PARM));
      else
            pBss->QbssLoad.bValid = FALSE;

      {
            PEID_STRUCT     pEid;
            USHORT          Length = 0;


            NdisZeroMemory(&pBss->WpaIE.IE[0], MAX_CUSTOM_LEN);
            NdisZeroMemory(&pBss->RsnIE.IE[0], MAX_CUSTOM_LEN);

            pEid = (PEID_STRUCT) pVIE;

            while ((Length + 2 + (USHORT)pEid->Len) <= LengthVIE)
            {
                  switch(pEid->Eid)
                  {
                        case IE_WPA:
                              if (NdisEqualMemory(pEid->Octet, WPA_OUI, 4))
                              {
                                    if ((pEid->Len + 2) > MAX_CUSTOM_LEN)
                                    {
                                          pBss->WpaIE.IELen = 0;
                                          break;
                                    }
                                    pBss->WpaIE.IELen = pEid->Len + 2;
                                    NdisMoveMemory(pBss->WpaIE.IE, pEid, pBss->WpaIE.IELen);
                              }
                              break;
                case IE_RSN:
                    if (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3))
                              {
                                    if ((pEid->Len + 2) > MAX_CUSTOM_LEN)
                                    {
                                          pBss->RsnIE.IELen = 0;
                                          break;
                                    }
                                    pBss->RsnIE.IELen = pEid->Len + 2;
                                    NdisMoveMemory(pBss->RsnIE.IE, pEid, pBss->RsnIE.IELen);
                  }
                        break;
            }
                  Length = Length + 2 + (USHORT)pEid->Len;  // Eid[1] + Len[1]+ content[Len]
                  pEid = (PEID_STRUCT)((UCHAR*)pEid + 2 + pEid->Len);
            }
      }
}

/*!
 *    \brief insert an entry into the bss table
 *    \param p_tab The BSS table
 *    \param Bssid BSSID
 *    \param ssid SSID
 *    \param ssid_len Length of SSID
 *    \param bss_type
 *    \param beacon_period
 *    \param timestamp
 *    \param p_cf
 *    \param atim_win
 *    \param cap
 *    \param rates
 *    \param rates_len
 *    \param channel_idx
 *    \return none
 *    \pre
 *    \post
 *    \note If SSID is identical, the old entry will be replaced by the new one

 IRQL = DISPATCH_LEVEL

 */
ULONG BssTableSetEntry(
      IN    PRTMP_ADAPTER     pAd,
      OUT BSS_TABLE *Tab,
      IN PUCHAR pBssid,
      IN CHAR Ssid[],
      IN UCHAR SsidLen,
      IN UCHAR BssType,
      IN USHORT BeaconPeriod,
      IN CF_PARM *CfParm,
      IN USHORT AtimWin,
      IN USHORT CapabilityInfo,
      IN UCHAR SupRate[],
      IN UCHAR SupRateLen,
      IN UCHAR ExtRate[],
      IN UCHAR ExtRateLen,
      IN HT_CAPABILITY_IE *pHtCapability,
      IN ADD_HT_INFO_IE *pAddHtInfo,      // AP might use this additional ht info IE
      IN UCHAR                HtCapabilityLen,
      IN UCHAR                AddHtInfoLen,
      IN UCHAR                NewExtChanOffset,
      IN UCHAR ChannelNo,
      IN CHAR Rssi,
      IN LARGE_INTEGER TimeStamp,
      IN UCHAR CkipFlag,
      IN PEDCA_PARM pEdcaParm,
      IN PQOS_CAPABILITY_PARM pQosCapability,
      IN PQBSS_LOAD_PARM pQbssLoad,
      IN USHORT LengthVIE,
      IN PNDIS_802_11_VARIABLE_IEs pVIE)
{
      ULONG Idx;

      Idx = BssTableSearchWithSSID(Tab, pBssid,  Ssid, SsidLen, ChannelNo);
      if (Idx == BSS_NOT_FOUND)
      {
            if (Tab->BssNr >= MAX_LEN_OF_BSS_TABLE)
          {
                  //
                  // It may happen when BSS Table was full.
                  // The desired AP will not be added into BSS Table
                  // In this case, if we found the desired AP then overwrite BSS Table.
                  //
                  if(!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED))
                  {
                        if (MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, pBssid) ||
                              SSID_EQUAL(pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen, Ssid, SsidLen))
                        {
                              Idx = Tab->BssOverlapNr;
                              BssEntrySet(pAd, &Tab->BssEntry[Idx], pBssid, Ssid, SsidLen, BssType, BeaconPeriod, CfParm, AtimWin,
                                    CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen,pHtCapability, pAddHtInfo,HtCapabilityLen, AddHtInfoLen,
                                    NewExtChanOffset, ChannelNo, Rssi, TimeStamp, CkipFlag, pEdcaParm, pQosCapability, pQbssLoad, LengthVIE, pVIE);
                    Tab->BssOverlapNr = (Tab->BssOverlapNr++) % MAX_LEN_OF_BSS_TABLE;
                        }
                        return Idx;
                  }
                  else
                  {
                  return BSS_NOT_FOUND;
                  }
            }
            Idx = Tab->BssNr;
            BssEntrySet(pAd, &Tab->BssEntry[Idx], pBssid, Ssid, SsidLen, BssType, BeaconPeriod, CfParm, AtimWin,
                              CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen,pHtCapability, pAddHtInfo,HtCapabilityLen, AddHtInfoLen,
                              NewExtChanOffset, ChannelNo, Rssi, TimeStamp, CkipFlag, pEdcaParm, pQosCapability, pQbssLoad, LengthVIE, pVIE);
            Tab->BssNr++;
      }
      else
      {
#ifdef RT30xx
            /* avoid  Hidden SSID form beacon to overwirite correct SSID from probe response */
            if ((SSID_EQUAL(Ssid, SsidLen, Tab->BssEntry[Idx].Ssid, Tab->BssEntry[Idx].SsidLen)) ||
                  (NdisEqualMemory(Tab->BssEntry[Idx].Ssid, ZeroSsid, Tab->BssEntry[Idx].SsidLen)))
            {
#endif
            BssEntrySet(pAd, &Tab->BssEntry[Idx], pBssid, Ssid, SsidLen, BssType, BeaconPeriod,CfParm, AtimWin,
                              CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen,pHtCapability, pAddHtInfo,HtCapabilityLen, AddHtInfoLen,
                              NewExtChanOffset, ChannelNo, Rssi, TimeStamp, CkipFlag, pEdcaParm, pQosCapability, pQbssLoad, LengthVIE, pVIE);
#ifdef RT30xx
            }
#endif
      }

      return Idx;
}

// IRQL = DISPATCH_LEVEL
VOID BssTableSsidSort(
      IN    PRTMP_ADAPTER     pAd,
      OUT BSS_TABLE *OutTab,
      IN    CHAR Ssid[],
      IN    UCHAR SsidLen)
{
      INT i;
      BssTableInit(OutTab);

      for (i = 0; i < pAd->ScanTab.BssNr; i++)
      {
            BSS_ENTRY *pInBss = &pAd->ScanTab.BssEntry[i];
            BOOLEAN     bIsHiddenApIncluded = FALSE;

            if (((pAd->CommonCfg.bIEEE80211H == 1) &&
            (pAd->MlmeAux.Channel > 14) &&
             RadarChannelCheck(pAd, pInBss->Channel))
            )
            {
                  if (pInBss->Hidden)
                        bIsHiddenApIncluded = TRUE;
            }

            if ((pInBss->BssType == pAd->StaCfg.BssType) &&
                  (SSID_EQUAL(Ssid, SsidLen, pInBss->Ssid, pInBss->SsidLen) || bIsHiddenApIncluded))
            {
                  BSS_ENTRY *pOutBss = &OutTab->BssEntry[OutTab->BssNr];

                  // 2.4G/5G N only mode
                  if ((pInBss->HtCapabilityLen == 0) &&
                        ((pAd->CommonCfg.PhyMode == PHY_11N_2_4G) || (pAd->CommonCfg.PhyMode == PHY_11N_5G)))
                  {
                        DBGPRINT(RT_DEBUG_TRACE,("STA is in N-only Mode, this AP don't have Ht capability in Beacon.\n"));
                        continue;
                  }

                  // New for WPA2
                  // Check the Authmode first
                  if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA)
                  {
                        // Check AuthMode and AuthModeAux for matching, in case AP support dual-mode
                        if ((pAd->StaCfg.AuthMode != pInBss->AuthMode) && (pAd->StaCfg.AuthMode != pInBss->AuthModeAux))
                              // None matched
                              continue;

                        // Check cipher suite, AP must have more secured cipher than station setting
                        if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK))
                        {
                              // If it's not mixed mode, we should only let BSS pass with the same encryption
                              if (pInBss->WPA.bMixMode == FALSE)
                                    if (pAd->StaCfg.WepStatus != pInBss->WPA.GroupCipher)
                                          continue;

                              // check group cipher
#ifndef RT30xx
                              if ((pAd->StaCfg.WepStatus < pInBss->WPA.GroupCipher) &&
                                    (pInBss->WPA.GroupCipher != Ndis802_11GroupWEP40Enabled) &&
                                    (pInBss->WPA.GroupCipher != Ndis802_11GroupWEP104Enabled))
#endif
#ifdef RT30xx
                              if (pAd->StaCfg.WepStatus < pInBss->WPA.GroupCipher)
#endif
                                    continue;

                              // check pairwise cipher, skip if none matched
                              // If profile set to AES, let it pass without question.
                              // If profile set to TKIP, we must find one mateched
                              if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) &&
                                    (pAd->StaCfg.WepStatus != pInBss->WPA.PairCipher) &&
                                    (pAd->StaCfg.WepStatus != pInBss->WPA.PairCipherAux))
                                    continue;
                        }
                        else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK))
                        {
                              // If it's not mixed mode, we should only let BSS pass with the same encryption
                              if (pInBss->WPA2.bMixMode == FALSE)
                                    if (pAd->StaCfg.WepStatus != pInBss->WPA2.GroupCipher)
                                          continue;

                              // check group cipher
#ifndef RT30xx
                              if ((pAd->StaCfg.WepStatus < pInBss->WPA.GroupCipher) &&
                                    (pInBss->WPA2.GroupCipher != Ndis802_11GroupWEP40Enabled) &&
                                    (pInBss->WPA2.GroupCipher != Ndis802_11GroupWEP104Enabled))
#endif
#ifdef RT30xx
                              if (pAd->StaCfg.WepStatus < pInBss->WPA2.GroupCipher)
#endif
                                    continue;

                              // check pairwise cipher, skip if none matched
                              // If profile set to AES, let it pass without question.
                              // If profile set to TKIP, we must find one mateched
                              if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) &&
                                    (pAd->StaCfg.WepStatus != pInBss->WPA2.PairCipher) &&
                                    (pAd->StaCfg.WepStatus != pInBss->WPA2.PairCipherAux))
                                    continue;
                        }
                  }
                  // Bss Type matched, SSID matched.
                  // We will check wepstatus for qualification Bss
                  else if (pAd->StaCfg.WepStatus != pInBss->WepStatus)
                  {
                        DBGPRINT(RT_DEBUG_TRACE,("StaCfg.WepStatus=%d, while pInBss->WepStatus=%d\n", pAd->StaCfg.WepStatus, pInBss->WepStatus));
                        //
                        // For the SESv2 case, we will not qualify WepStatus.
                        //
                        if (!pInBss->bSES)
                              continue;
                  }

                  // Since the AP is using hidden SSID, and we are trying to connect to ANY
                  // It definitely will fail. So, skip it.
                  // CCX also require not even try to connect it!!
                  if (SsidLen == 0)
                        continue;

                  // If both station and AP use 40MHz, still need to check if the 40MHZ band's legality in my country region
                  // If this 40MHz wideband is not allowed in my country list, use bandwidth 20MHZ instead,
                  if ((pInBss->CentralChannel != pInBss->Channel) &&
                        (pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40))
                  {
                        if (RTMPCheckChannel(pAd, pInBss->CentralChannel, pInBss->Channel) == FALSE)
                        {
                              pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20;
                              SetCommonHT(pAd);
                              pAd->CommonCfg.RegTransmitSetting.field.BW = BW_40;
                        }
                        else
                        {
                              if (pAd->CommonCfg.DesiredHtPhy.ChannelWidth == BAND_WIDTH_20)
                              {
                                    SetCommonHT(pAd);
                              }
                        }
                  }

                  // copy matching BSS from InTab to OutTab
                  NdisMoveMemory(pOutBss, pInBss, sizeof(BSS_ENTRY));

                  OutTab->BssNr++;
            }
            else if ((pInBss->BssType == pAd->StaCfg.BssType) && (SsidLen == 0))
            {
                  BSS_ENTRY *pOutBss = &OutTab->BssEntry[OutTab->BssNr];

                  // 2.4G/5G N only mode
                  if ((pInBss->HtCapabilityLen == 0) &&
                        ((pAd->CommonCfg.PhyMode == PHY_11N_2_4G) || (pAd->CommonCfg.PhyMode == PHY_11N_5G)))
                  {
                        DBGPRINT(RT_DEBUG_TRACE,("STA is in N-only Mode, this AP don't have Ht capability in Beacon.\n"));
                        continue;
                  }

                  // New for WPA2
                  // Check the Authmode first
                  if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA)
                  {
                        // Check AuthMode and AuthModeAux for matching, in case AP support dual-mode
                        if ((pAd->StaCfg.AuthMode != pInBss->AuthMode) && (pAd->StaCfg.AuthMode != pInBss->AuthModeAux))
                              // None matched
                              continue;

                        // Check cipher suite, AP must have more secured cipher than station setting
                        if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK))
                        {
                              // If it's not mixed mode, we should only let BSS pass with the same encryption
                              if (pInBss->WPA.bMixMode == FALSE)
                                    if (pAd->StaCfg.WepStatus != pInBss->WPA.GroupCipher)
                                          continue;

                              // check group cipher
                              if (pAd->StaCfg.WepStatus < pInBss->WPA.GroupCipher)
                                    continue;

                              // check pairwise cipher, skip if none matched
                              // If profile set to AES, let it pass without question.
                              // If profile set to TKIP, we must find one mateched
                              if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) &&
                                    (pAd->StaCfg.WepStatus != pInBss->WPA.PairCipher) &&
                                    (pAd->StaCfg.WepStatus != pInBss->WPA.PairCipherAux))
                                    continue;
                        }
                        else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK))
                        {
                              // If it's not mixed mode, we should only let BSS pass with the same encryption
                              if (pInBss->WPA2.bMixMode == FALSE)
                                    if (pAd->StaCfg.WepStatus != pInBss->WPA2.GroupCipher)
                                          continue;

                              // check group cipher
                              if (pAd->StaCfg.WepStatus < pInBss->WPA2.GroupCipher)
                                    continue;

                              // check pairwise cipher, skip if none matched
                              // If profile set to AES, let it pass without question.
                              // If profile set to TKIP, we must find one mateched
                              if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) &&
                                    (pAd->StaCfg.WepStatus != pInBss->WPA2.PairCipher) &&
                                    (pAd->StaCfg.WepStatus != pInBss->WPA2.PairCipherAux))
                                    continue;
                        }
                  }
                  // Bss Type matched, SSID matched.
                  // We will check wepstatus for qualification Bss
                  else if (pAd->StaCfg.WepStatus != pInBss->WepStatus)
                              continue;

                  // If both station and AP use 40MHz, still need to check if the 40MHZ band's legality in my country region
                  // If this 40MHz wideband is not allowed in my country list, use bandwidth 20MHZ instead,
                  if ((pInBss->CentralChannel != pInBss->Channel) &&
                        (pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40))
                  {
                        if (RTMPCheckChannel(pAd, pInBss->CentralChannel, pInBss->Channel) == FALSE)
                        {
                              pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20;
                              SetCommonHT(pAd);
                              pAd->CommonCfg.RegTransmitSetting.field.BW = BW_40;
                        }
                  }

                  // copy matching BSS from InTab to OutTab
                  NdisMoveMemory(pOutBss, pInBss, sizeof(BSS_ENTRY));

                  OutTab->BssNr++;
            }

            if (OutTab->BssNr >= MAX_LEN_OF_BSS_TABLE)
                  break;
      }

      BssTableSortByRssi(OutTab);
}


// IRQL = DISPATCH_LEVEL
VOID BssTableSortByRssi(
      IN OUT BSS_TABLE *OutTab)
{
      INT     i, j;
      BSS_ENTRY TmpBss;

      for (i = 0; i < OutTab->BssNr - 1; i++)
      {
            for (j = i+1; j < OutTab->BssNr; j++)
            {
                  if (OutTab->BssEntry[j].Rssi > OutTab->BssEntry[i].Rssi)
                  {
                        NdisMoveMemory(&TmpBss, &OutTab->BssEntry[j], sizeof(BSS_ENTRY));
                        NdisMoveMemory(&OutTab->BssEntry[j], &OutTab->BssEntry[i], sizeof(BSS_ENTRY));
                        NdisMoveMemory(&OutTab->BssEntry[i], &TmpBss, sizeof(BSS_ENTRY));
                  }
            }
      }
}

VOID BssCipherParse(
      IN OUT      PBSS_ENTRY  pBss)
{
      PEID_STRUCT              pEid;
      PUCHAR                        pTmp;
      PRSN_IE_HEADER_STRUCT               pRsnHeader;
      PCIPHER_SUITE_STRUCT                pCipher;
      PAKM_SUITE_STRUCT                   pAKM;
      USHORT                                          Count;
      INT                                             Length;
      NDIS_802_11_ENCRYPTION_STATUS TmpCipher;

      //
      // WepStatus will be reset later, if AP announce TKIP or AES on the beacon frame.
      //
      if (pBss->Privacy)
      {
            pBss->WepStatus   = Ndis802_11WEPEnabled;
      }
      else
      {
            pBss->WepStatus   = Ndis802_11WEPDisabled;
      }
      // Set default to disable & open authentication before parsing variable IE
      pBss->AuthMode          = Ndis802_11AuthModeOpen;
      pBss->AuthModeAux = Ndis802_11AuthModeOpen;

      // Init WPA setting
      pBss->WPA.PairCipher    = Ndis802_11WEPDisabled;
      pBss->WPA.PairCipherAux = Ndis802_11WEPDisabled;
      pBss->WPA.GroupCipher   = Ndis802_11WEPDisabled;
      pBss->WPA.RsnCapability = 0;
      pBss->WPA.bMixMode            = FALSE;

      // Init WPA2 setting
      pBss->WPA2.PairCipher    = Ndis802_11WEPDisabled;
      pBss->WPA2.PairCipherAux = Ndis802_11WEPDisabled;
      pBss->WPA2.GroupCipher   = Ndis802_11WEPDisabled;
      pBss->WPA2.RsnCapability = 0;
      pBss->WPA2.bMixMode      = FALSE;


      Length = (INT) pBss->VarIELen;

      while (Length > 0)
      {
            // Parse cipher suite base on WPA1 & WPA2, they should be parsed differently
            pTmp = ((PUCHAR) pBss->VarIEs) + pBss->VarIELen - Length;
            pEid = (PEID_STRUCT) pTmp;
            switch (pEid->Eid)
            {
                  case IE_WPA:
                        //Parse Cisco IE_WPA (LEAP, CCKM, etc.)
                        if ( NdisEqualMemory((pTmp+8), CISCO_OUI, 3))
                        {
                              pTmp   += 11;
                              switch (*pTmp)
                              {
                                    case 1:
                                    case 5:     // Although WEP is not allowed in WPA related auth mode, we parse it anyway
                                          pBss->WepStatus = Ndis802_11Encryption1Enabled;
                                          pBss->WPA.PairCipher = Ndis802_11Encryption1Enabled;
                                          pBss->WPA.GroupCipher = Ndis802_11Encryption1Enabled;
                                          break;
                                    case 2:
                                          pBss->WepStatus = Ndis802_11Encryption2Enabled;
                                          pBss->WPA.PairCipher = Ndis802_11Encryption1Enabled;
                                          pBss->WPA.GroupCipher = Ndis802_11Encryption1Enabled;
                                          break;
                                    case 4:
                                          pBss->WepStatus = Ndis802_11Encryption3Enabled;
                                          pBss->WPA.PairCipher = Ndis802_11Encryption1Enabled;
                                          pBss->WPA.GroupCipher = Ndis802_11Encryption1Enabled;
                                          break;
                                    default:
                                          break;
                              }

                              // if Cisco IE_WPA, break
                              break;
                        }
                        else if (NdisEqualMemory(pEid->Octet, SES_OUI, 3) && (pEid->Len == 7))
                        {
                              pBss->bSES = TRUE;
                              break;
                        }
                        else if (NdisEqualMemory(pEid->Octet, WPA_OUI, 4) != 1)
                        {
                              // if unsupported vendor specific IE
                              break;
                        }
                        // Skip OUI, version, and multicast suite
                        // This part should be improved in the future when AP supported multiple cipher suite.
                        // For now, it's OK since almost all APs have fixed cipher suite supported.
                        // pTmp = (PUCHAR) pEid->Octet;
                        pTmp   += 11;

                        // Cipher Suite Selectors from Spec P802.11i/D3.2 P26.
                        //    Value    Meaning
                        //    0                 None
                        //    1                 WEP-40
                        //    2                 Tkip
                        //    3                 WRAP
                        //    4                 AES
                        //    5                 WEP-104
                        // Parse group cipher
                        switch (*pTmp)
                        {
                              case 1:
#ifndef RT30xx
                                    pBss->WPA.GroupCipher = Ndis802_11GroupWEP40Enabled;
                                    break;
                              case 5:
                                    pBss->WPA.GroupCipher = Ndis802_11GroupWEP104Enabled;
#endif
#ifdef RT30xx
                              case 5:     // Although WEP is not allowed in WPA related auth mode, we parse it anyway
                                    pBss->WPA.GroupCipher = Ndis802_11Encryption1Enabled;
#endif
                                    break;
                              case 2:
                                    pBss->WPA.GroupCipher = Ndis802_11Encryption2Enabled;
                                    break;
                              case 4:
                                    pBss->WPA.GroupCipher = Ndis802_11Encryption3Enabled;
                                    break;
                              default:
                                    break;
                        }
                        // number of unicast suite
                        pTmp   += 1;

                        // skip all unicast cipher suites
                        //Count = *(PUSHORT) pTmp;
                        Count = (pTmp[1]<<8) + pTmp[0];
                        pTmp   += sizeof(USHORT);

                        // Parsing all unicast cipher suite
                        while (Count > 0)
                        {
                              // Skip OUI
                              pTmp += 3;
                              TmpCipher = Ndis802_11WEPDisabled;
                              switch (*pTmp)
                              {
                                    case 1:
                                    case 5: // Although WEP is not allowed in WPA related auth mode, we parse it anyway
                                          TmpCipher = Ndis802_11Encryption1Enabled;
                                          break;
                                    case 2:
                                          TmpCipher = Ndis802_11Encryption2Enabled;
                                          break;
                                    case 4:
                                          TmpCipher = Ndis802_11Encryption3Enabled;
                                          break;
                                    default:
                                          break;
                              }
                              if (TmpCipher > pBss->WPA.PairCipher)
                              {
                                    // Move the lower cipher suite to PairCipherAux
                                    pBss->WPA.PairCipherAux = pBss->WPA.PairCipher;
                                    pBss->WPA.PairCipher    = TmpCipher;
                              }
                              else
                              {
                                    pBss->WPA.PairCipherAux = TmpCipher;
                              }
                              pTmp++;
                              Count--;
                        }

                        // 4. get AKM suite counts
                        //Count     = *(PUSHORT) pTmp;
                        Count = (pTmp[1]<<8) + pTmp[0];
                        pTmp   += sizeof(USHORT);
                        pTmp   += 3;

                        switch (*pTmp)
                        {
                              case 1:
                                    // Set AP support WPA mode
                                    if (pBss->AuthMode == Ndis802_11AuthModeOpen)
                                          pBss->AuthMode = Ndis802_11AuthModeWPA;
                                    else
                                          pBss->AuthModeAux = Ndis802_11AuthModeWPA;
                                    break;
                              case 2:
                                    // Set AP support WPA mode
                                    if (pBss->AuthMode == Ndis802_11AuthModeOpen)
                                          pBss->AuthMode = Ndis802_11AuthModeWPAPSK;
                                    else
                                          pBss->AuthModeAux = Ndis802_11AuthModeWPAPSK;
                                    break;
                              default:
                                    break;
                        }
                        pTmp   += 1;

                        // Fixed for WPA-None
                        if (pBss->BssType == BSS_ADHOC)
                        {
                              pBss->AuthMode      = Ndis802_11AuthModeWPANone;
                              pBss->AuthModeAux = Ndis802_11AuthModeWPANone;
                              pBss->WepStatus   = pBss->WPA.GroupCipher;
                              if (pBss->WPA.PairCipherAux == Ndis802_11WEPDisabled)
                                    pBss->WPA.PairCipherAux = pBss->WPA.GroupCipher;
                        }
                        else
                              pBss->WepStatus   = pBss->WPA.PairCipher;

                        // Check the Pair & Group, if different, turn on mixed mode flag
                        if (pBss->WPA.GroupCipher != pBss->WPA.PairCipher)
                              pBss->WPA.bMixMode = TRUE;

                        break;

                  case IE_RSN:
                        pRsnHeader = (PRSN_IE_HEADER_STRUCT) pTmp;

                        // 0. Version must be 1
                        if (le2cpu16(pRsnHeader->Version) != 1)
                              break;
                        pTmp   += sizeof(RSN_IE_HEADER_STRUCT);

                        // 1. Check group cipher
                        pCipher = (PCIPHER_SUITE_STRUCT) pTmp;
                        if (!RTMPEqualMemory(pTmp, RSN_OUI, 3))
                              break;

                        // Parse group cipher
                        switch (pCipher->Type)
                        {
                              case 1:
#ifndef RT30xx
                                    pBss->WPA2.GroupCipher = Ndis802_11GroupWEP40Enabled;
                                    break;
                              case 5:
                                    pBss->WPA2.GroupCipher = Ndis802_11GroupWEP104Enabled;
#endif
#ifdef RT30xx
                              case 5:     // Although WEP is not allowed in WPA related auth mode, we parse it anyway
                                    pBss->WPA2.GroupCipher = Ndis802_11Encryption1Enabled;
#endif
                                    break;
                              case 2:
                                    pBss->WPA2.GroupCipher = Ndis802_11Encryption2Enabled;
                                    break;
                              case 4:
                                    pBss->WPA2.GroupCipher = Ndis802_11Encryption3Enabled;
                                    break;
                              default:
                                    break;
                        }
                        // set to correct offset for next parsing
                        pTmp   += sizeof(CIPHER_SUITE_STRUCT);

                        // 2. Get pairwise cipher counts
                        //Count = *(PUSHORT) pTmp;
                        Count = (pTmp[1]<<8) + pTmp[0];
                        pTmp   += sizeof(USHORT);

                        // 3. Get pairwise cipher
                        // Parsing all unicast cipher suite
                        while (Count > 0)
                        {
                              // Skip OUI
                              pCipher = (PCIPHER_SUITE_STRUCT) pTmp;
                              TmpCipher = Ndis802_11WEPDisabled;
                              switch (pCipher->Type)
                              {
                                    case 1:
                                    case 5: // Although WEP is not allowed in WPA related auth mode, we parse it anyway
                                          TmpCipher = Ndis802_11Encryption1Enabled;
                                          break;
                                    case 2:
                                          TmpCipher = Ndis802_11Encryption2Enabled;
                                          break;
                                    case 4:
                                          TmpCipher = Ndis802_11Encryption3Enabled;
                                          break;
                                    default:
                                          break;
                              }
                              if (TmpCipher > pBss->WPA2.PairCipher)
                              {
                                    // Move the lower cipher suite to PairCipherAux
                                    pBss->WPA2.PairCipherAux = pBss->WPA2.PairCipher;
                                    pBss->WPA2.PairCipher    = TmpCipher;
                              }
                              else
                              {
                                    pBss->WPA2.PairCipherAux = TmpCipher;
                              }
                              pTmp += sizeof(CIPHER_SUITE_STRUCT);
                              Count--;
                        }

                        // 4. get AKM suite counts
                        //Count     = *(PUSHORT) pTmp;
                        Count = (pTmp[1]<<8) + pTmp[0];
                        pTmp   += sizeof(USHORT);

                        // 5. Get AKM ciphers
                        pAKM = (PAKM_SUITE_STRUCT) pTmp;
                        if (!RTMPEqualMemory(pTmp, RSN_OUI, 3))
                              break;

                        switch (pAKM->Type)
                        {
                              case 1:
                                    // Set AP support WPA mode
                                    if (pBss->AuthMode == Ndis802_11AuthModeOpen)
                                          pBss->AuthMode = Ndis802_11AuthModeWPA2;
                                    else
                                          pBss->AuthModeAux = Ndis802_11AuthModeWPA2;
                                    break;
                              case 2:
                                    // Set AP support WPA mode
                                    if (pBss->AuthMode == Ndis802_11AuthModeOpen)
                                          pBss->AuthMode = Ndis802_11AuthModeWPA2PSK;
                                    else
                                          pBss->AuthModeAux = Ndis802_11AuthModeWPA2PSK;
                                    break;
                              default:
                                    break;
                        }
                        pTmp   += (Count * sizeof(AKM_SUITE_STRUCT));

                        // Fixed for WPA-None
                        if (pBss->BssType == BSS_ADHOC)
                        {
                              pBss->AuthMode = Ndis802_11AuthModeWPANone;
                              pBss->AuthModeAux = Ndis802_11AuthModeWPANone;
                              pBss->WPA.PairCipherAux = pBss->WPA2.PairCipherAux;
                              pBss->WPA.GroupCipher   = pBss->WPA2.GroupCipher;
                              pBss->WepStatus         = pBss->WPA.GroupCipher;
                              if (pBss->WPA.PairCipherAux == Ndis802_11WEPDisabled)
                                    pBss->WPA.PairCipherAux = pBss->WPA.GroupCipher;
                        }
                        pBss->WepStatus   = pBss->WPA2.PairCipher;

                        // 6. Get RSN capability
                        //pBss->WPA2.RsnCapability = *(PUSHORT) pTmp;
                        pBss->WPA2.RsnCapability = (pTmp[1]<<8) + pTmp[0];
                        pTmp += sizeof(USHORT);

                        // Check the Pair & Group, if different, turn on mixed mode flag
                        if (pBss->WPA2.GroupCipher != pBss->WPA2.PairCipher)
                              pBss->WPA2.bMixMode = TRUE;

                        break;
                  default:
                        break;
            }
            Length -= (pEid->Len + 2);
      }
}

// ===========================================================================================
// mac_table.c
// ===========================================================================================

/*! \brief generates a random mac address value for IBSS BSSID
 *    \param Addr the bssid location
 *    \return none
 *    \pre
 *    \post
 */
VOID MacAddrRandomBssid(
      IN PRTMP_ADAPTER pAd,
      OUT PUCHAR pAddr)
{
      INT i;

      for (i = 0; i < MAC_ADDR_LEN; i++)
      {
            pAddr[i] = RandomByte(pAd);
      }

      pAddr[0] = (pAddr[0] & 0xfe) | 0x02;  // the first 2 bits must be 01xxxxxxxx
}

/*! \brief init the management mac frame header
 *    \param p_hdr mac header
 *    \param subtype subtype of the frame
 *    \param p_ds destination address, don't care if it is a broadcast address
 *    \return none
 *    \pre the station has the following information in the pAd->StaCfg
 *     - bssid
 *     - station address
 *    \post
 *    \note this function initializes the following field

 IRQL = PASSIVE_LEVEL
 IRQL = DISPATCH_LEVEL

 */
VOID MgtMacHeaderInit(
      IN    PRTMP_ADAPTER     pAd,
      IN OUT PHEADER_802_11 pHdr80211,
      IN UCHAR SubType,
      IN UCHAR ToDs,
      IN PUCHAR pDA,
      IN PUCHAR pBssid)
{
      NdisZeroMemory(pHdr80211, sizeof(HEADER_802_11));

      pHdr80211->FC.Type = BTYPE_MGMT;
      pHdr80211->FC.SubType = SubType;
      pHdr80211->FC.ToDs = ToDs;
      COPY_MAC_ADDR(pHdr80211->Addr1, pDA);

      COPY_MAC_ADDR(pHdr80211->Addr2, pAd->CurrentAddress);

      COPY_MAC_ADDR(pHdr80211->Addr3, pBssid);
}

// ===========================================================================================
// mem_mgmt.c
// ===========================================================================================

/*!***************************************************************************
 * This routine build an outgoing frame, and fill all information specified
 * in argument list to the frame body. The actual frame size is the summation
 * of all arguments.
 * input params:
 *          Buffer - pointer to a pre-allocated memory segment
 *          args - a list of <int arg_size, arg> pairs.
 *          NOTE NOTE NOTE!!!! the last argument must be NULL, otherwise this
 *                                     function will FAIL!!!
 * return:
 *          Size of the buffer
 * usage:
 *          MakeOutgoingFrame(Buffer, output_length, 2, &fc, 2, &dur, 6, p_addr1, 6,p_addr2, END_OF_ARGS);

 IRQL = PASSIVE_LEVEL
 IRQL = DISPATCH_LEVEL

 ****************************************************************************/
ULONG MakeOutgoingFrame(
      OUT CHAR *Buffer,
      OUT ULONG *FrameLen, ...)
{
      CHAR   *p;
      int   leng;
      ULONG TotLeng;
      va_list Args;

      // calculates the total length
      TotLeng = 0;
      va_start(Args, FrameLen);
      do
      {
            leng = va_arg(Args, int);
            if (leng == END_OF_ARGS)
            {
                  break;
            }
            p = va_arg(Args, PVOID);
            NdisMoveMemory(&Buffer[TotLeng], p, leng);
            TotLeng = TotLeng + leng;
      } while(TRUE);

      va_end(Args); /* clean up */
      *FrameLen = TotLeng;
      return TotLeng;
}

// ===========================================================================================
// mlme_queue.c
// ===========================================================================================

/*! \brief  Initialize The MLME Queue, used by MLME Functions
 *    \param      *Queue         The MLME Queue
 *    \return Always       Return NDIS_STATE_SUCCESS in this implementation
 *    \pre
 *    \post
 *    \note Because this is done only once (at the init stage), no need to be locked

 IRQL = PASSIVE_LEVEL

 */
NDIS_STATUS MlmeQueueInit(
      IN MLME_QUEUE *Queue)
{
      INT i;

      NdisAllocateSpinLock(&Queue->Lock);

      Queue->Num  = 0;
      Queue->Head = 0;
      Queue->Tail = 0;

      for (i = 0; i < MAX_LEN_OF_MLME_QUEUE; i++)
      {
            Queue->Entry[i].Occupied = FALSE;
            Queue->Entry[i].MsgLen = 0;
            NdisZeroMemory(Queue->Entry[i].Msg, MGMT_DMA_BUFFER_SIZE);
      }

      return NDIS_STATUS_SUCCESS;
}

/*! \brief   Enqueue a message for other threads, if they want to send messages to MLME thread
 *    \param      *Queue        The MLME Queue
 *    \param       Machine  The State Machine Id
 *    \param       MsgType  The Message Type
 *    \param       MsgLen   The Message length
 *    \param      *Msg    The message pointer
 *    \return  TRUE if enqueue is successful, FALSE if the queue is full
 *    \pre
 *    \post
 *    \note  The message has to be initialized

 IRQL = PASSIVE_LEVEL
 IRQL = DISPATCH_LEVEL

 */
BOOLEAN MlmeEnqueue(
      IN    PRTMP_ADAPTER     pAd,
      IN ULONG Machine,
      IN ULONG MsgType,
      IN ULONG MsgLen,
      IN VOID *Msg)
{
      INT Tail;
      MLME_QUEUE  *Queue = (MLME_QUEUE *)&pAd->Mlme.Queue;

      // Do nothing if the driver is starting halt state.
      // This might happen when timer already been fired before cancel timer with mlmehalt
      if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST))
            return FALSE;

      // First check the size, it MUST not exceed the mlme queue size
      if (MsgLen > MGMT_DMA_BUFFER_SIZE)
      {
            DBGPRINT_ERR(("MlmeEnqueue: msg too large, size = %ld \n", MsgLen));
            return FALSE;
      }

      if (MlmeQueueFull(Queue))
      {
            return FALSE;
      }

      NdisAcquireSpinLock(&(Queue->Lock));
      Tail = Queue->Tail;
      Queue->Tail++;
      Queue->Num++;
      if (Queue->Tail == MAX_LEN_OF_MLME_QUEUE)
      {
            Queue->Tail = 0;
      }

      Queue->Entry[Tail].Wcid = RESERVED_WCID;
      Queue->Entry[Tail].Occupied = TRUE;
      Queue->Entry[Tail].Machine = Machine;
      Queue->Entry[Tail].MsgType = MsgType;
      Queue->Entry[Tail].MsgLen  = MsgLen;

      if (Msg != NULL)
      {
            NdisMoveMemory(Queue->Entry[Tail].Msg, Msg, MsgLen);
      }

      NdisReleaseSpinLock(&(Queue->Lock));
      return TRUE;
}

/*! \brief   This function is used when Recv gets a MLME message
 *    \param      *Queue                   The MLME Queue
 *    \param       TimeStampHigh     The upper 32 bit of timestamp
 *    \param       TimeStampLow      The lower 32 bit of timestamp
 *    \param       Rssi              The receiving RSSI strength
 *    \param       MsgLen            The length of the message
 *    \param      *Msg               The message pointer
 *    \return  TRUE if everything ok, FALSE otherwise (like Queue Full)
 *    \pre
 *    \post

 IRQL = DISPATCH_LEVEL

 */
BOOLEAN MlmeEnqueueForRecv(
      IN    PRTMP_ADAPTER     pAd,
      IN ULONG Wcid,
      IN ULONG TimeStampHigh,
      IN ULONG TimeStampLow,
      IN UCHAR Rssi0,
      IN UCHAR Rssi1,
      IN UCHAR Rssi2,
      IN ULONG MsgLen,
      IN VOID *Msg,
      IN UCHAR Signal)
{
      INT          Tail, Machine;
      PFRAME_802_11 pFrame = (PFRAME_802_11)Msg;
      INT          MsgType;
      MLME_QUEUE  *Queue = (MLME_QUEUE *)&pAd->Mlme.Queue;

      // Do nothing if the driver is starting halt state.
      // This might happen when timer already been fired before cancel timer with mlmehalt
      if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST))
      {
            DBGPRINT_ERR(("MlmeEnqueueForRecv: fRTMP_ADAPTER_HALT_IN_PROGRESS\n"));
            return FALSE;
      }

      // First check the size, it MUST not exceed the mlme queue size
      if (MsgLen > MGMT_DMA_BUFFER_SIZE)
      {
            DBGPRINT_ERR(("MlmeEnqueueForRecv: frame too large, size = %ld \n", MsgLen));
            return FALSE;
      }

      if (MlmeQueueFull(Queue))
      {
            return FALSE;
      }

      {
            if (!MsgTypeSubst(pAd, pFrame, &Machine, &MsgType))
            {
                  DBGPRINT_ERR(("MlmeEnqueueForRecv: un-recongnized mgmt->subtype=%d\n",pFrame->Hdr.FC.SubType));
                  return FALSE;
            }
      }

      // OK, we got all the informations, it is time to put things into queue
      NdisAcquireSpinLock(&(Queue->Lock));
      Tail = Queue->Tail;
      Queue->Tail++;
      Queue->Num++;
      if (Queue->Tail == MAX_LEN_OF_MLME_QUEUE)
      {
            Queue->Tail = 0;
      }
      Queue->Entry[Tail].Occupied = TRUE;
      Queue->Entry[Tail].Machine = Machine;
      Queue->Entry[Tail].MsgType = MsgType;
      Queue->Entry[Tail].MsgLen  = MsgLen;
      Queue->Entry[Tail].TimeStamp.u.LowPart = TimeStampLow;
      Queue->Entry[Tail].TimeStamp.u.HighPart = TimeStampHigh;
      Queue->Entry[Tail].Rssi0 = Rssi0;
      Queue->Entry[Tail].Rssi1 = Rssi1;
      Queue->Entry[Tail].Rssi2 = Rssi2;
      Queue->Entry[Tail].Signal = Signal;
      Queue->Entry[Tail].Wcid = (UCHAR)Wcid;

      Queue->Entry[Tail].Channel = pAd->LatchRfRegs.Channel;

      if (Msg != NULL)
      {
            NdisMoveMemory(Queue->Entry[Tail].Msg, Msg, MsgLen);
      }

      NdisReleaseSpinLock(&(Queue->Lock));

      RT28XX_MLME_HANDLER(pAd);

      return TRUE;
}


/*! \brief   Dequeue a message from the MLME Queue
 *    \param      *Queue        The MLME Queue
 *    \param      *Elem   The message dequeued from MLME Queue
 *    \return  TRUE if the Elem contains something, FALSE otherwise
 *    \pre
 *    \post

 IRQL = DISPATCH_LEVEL

 */
BOOLEAN MlmeDequeue(
      IN MLME_QUEUE *Queue,
      OUT MLME_QUEUE_ELEM **Elem)
{
      NdisAcquireSpinLock(&(Queue->Lock));
      *Elem = &(Queue->Entry[Queue->Head]);
      Queue->Num--;
      Queue->Head++;
      if (Queue->Head == MAX_LEN_OF_MLME_QUEUE)
      {
            Queue->Head = 0;
      }
      NdisReleaseSpinLock(&(Queue->Lock));
      return TRUE;
}

// IRQL = DISPATCH_LEVEL
VOID  MlmeRestartStateMachine(
      IN    PRTMP_ADAPTER     pAd)
{
#ifdef RT2860
      MLME_QUEUE_ELEM         *Elem = NULL;
#endif
      BOOLEAN                       Cancelled;

      DBGPRINT(RT_DEBUG_TRACE, ("MlmeRestartStateMachine \n"));

#ifdef RT2860
      NdisAcquireSpinLock(&pAd->Mlme.TaskLock);
      if(pAd->Mlme.bRunning)
      {
            NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
            return;
      }
      else
      {
            pAd->Mlme.bRunning = TRUE;
      }
      NdisReleaseSpinLock(&pAd->Mlme.TaskLock);

      // Remove all Mlme queues elements
      while (!MlmeQueueEmpty(&pAd->Mlme.Queue))
      {
            //From message type, determine which state machine I should drive
            if (MlmeDequeue(&pAd->Mlme.Queue, &Elem))
            {
                  // free MLME element
                  Elem->Occupied = FALSE;
                  Elem->MsgLen = 0;

            }
            else {
                  DBGPRINT_ERR(("MlmeRestartStateMachine: MlmeQueue empty\n"));
            }
      }
#endif /* RT2860 */

      {
            // Cancel all timer events
            // Be careful to cancel new added timer
            RTMPCancelTimer(&pAd->MlmeAux.AssocTimer,   &Cancelled);
            RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer,   &Cancelled);
            RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer,  &Cancelled);
            RTMPCancelTimer(&pAd->MlmeAux.AuthTimer,     &Cancelled);
            RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer,         &Cancelled);
            RTMPCancelTimer(&pAd->MlmeAux.ScanTimer,     &Cancelled);
      }

      // Change back to original channel in case of doing scan
      AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
      AsicLockChannel(pAd, pAd->CommonCfg.Channel);

      // Resume MSDU which is turned off durning scan
      RTMPResumeMsduTransmission(pAd);

      {
            // Set all state machines back IDLE
            pAd->Mlme.CntlMachine.CurrState    = CNTL_IDLE;
            pAd->Mlme.AssocMachine.CurrState   = ASSOC_IDLE;
            pAd->Mlme.AuthMachine.CurrState    = AUTH_REQ_IDLE;
            pAd->Mlme.AuthRspMachine.CurrState = AUTH_RSP_IDLE;
            pAd->Mlme.SyncMachine.CurrState    = SYNC_IDLE;
            pAd->Mlme.ActMachine.CurrState    = ACT_IDLE;
      }

#ifdef RT2860
      // Remove running state
      NdisAcquireSpinLock(&pAd->Mlme.TaskLock);
      pAd->Mlme.bRunning = FALSE;
      NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
#endif
}

/*! \brief  test if the MLME Queue is empty
 *    \param      *Queue        The MLME Queue
 *    \return TRUE if the Queue is empty, FALSE otherwise
 *    \pre
 *    \post

 IRQL = DISPATCH_LEVEL

 */
BOOLEAN MlmeQueueEmpty(
      IN MLME_QUEUE *Queue)
{
      BOOLEAN Ans;

      NdisAcquireSpinLock(&(Queue->Lock));
      Ans = (Queue->Num == 0);
      NdisReleaseSpinLock(&(Queue->Lock));

      return Ans;
}

/*! \brief   test if the MLME Queue is full
 *    \param       *Queue      The MLME Queue
 *    \return  TRUE if the Queue is empty, FALSE otherwise
 *    \pre
 *    \post

 IRQL = PASSIVE_LEVEL
 IRQL = DISPATCH_LEVEL

 */
BOOLEAN MlmeQueueFull(
      IN MLME_QUEUE *Queue)
{
      BOOLEAN Ans;

      NdisAcquireSpinLock(&(Queue->Lock));
      Ans = (Queue->Num == MAX_LEN_OF_MLME_QUEUE || Queue->Entry[Queue->Tail].Occupied);
      NdisReleaseSpinLock(&(Queue->Lock));

      return Ans;
}

/*! \brief   The destructor of MLME Queue
 *    \param
 *    \return
 *    \pre
 *    \post
 *    \note Clear Mlme Queue, Set Queue->Num to Zero.

 IRQL = PASSIVE_LEVEL

 */
VOID MlmeQueueDestroy(
      IN MLME_QUEUE *pQueue)
{
      NdisAcquireSpinLock(&(pQueue->Lock));
      pQueue->Num  = 0;
      pQueue->Head = 0;
      pQueue->Tail = 0;
      NdisReleaseSpinLock(&(pQueue->Lock));
      NdisFreeSpinLock(&(pQueue->Lock));
}

/*! \brief   To substitute the message type if the message is coming from external
 *    \param      pFrame               The frame received
 *    \param      *Machine       The state machine
 *    \param      *MsgType       the message type for the state machine
 *    \return TRUE if the substitution is successful, FALSE otherwise
 *    \pre
 *    \post

 IRQL = DISPATCH_LEVEL

 */
BOOLEAN MsgTypeSubst(
      IN PRTMP_ADAPTER  pAd,
      IN PFRAME_802_11 pFrame,
      OUT INT *Machine,
      OUT INT *MsgType)
{
      USHORT      Seq;
      UCHAR EAPType;
      PUCHAR      pData;

      // Pointer to start of data frames including SNAP header
      pData = (PUCHAR) pFrame + LENGTH_802_11;

      // The only data type will pass to this function is EAPOL frame
      if (pFrame->Hdr.FC.Type == BTYPE_DATA)
      {
            if (NdisEqualMemory(SNAP_AIRONET, pData, LENGTH_802_1_H))
            {
                  // Cisco Aironet SNAP header
                  *Machine = AIRONET_STATE_MACHINE;
                  *MsgType = MT2_AIRONET_MSG;
                  return (TRUE);
            }
            {
                  *Machine = WPA_PSK_STATE_MACHINE;
                  EAPType = *((UCHAR*)pFrame + LENGTH_802_11 + LENGTH_802_1_H + 1);
                  return(WpaMsgTypeSubst(EAPType, MsgType));
            }
      }

      switch (pFrame->Hdr.FC.SubType)
      {
            case SUBTYPE_ASSOC_REQ:
                  *Machine = ASSOC_STATE_MACHINE;
                  *MsgType = MT2_PEER_ASSOC_REQ;
                  break;
            case SUBTYPE_ASSOC_RSP:
                  *Machine = ASSOC_STATE_MACHINE;
                  *MsgType = MT2_PEER_ASSOC_RSP;
                  break;
            case SUBTYPE_REASSOC_REQ:
                  *Machine = ASSOC_STATE_MACHINE;
                  *MsgType = MT2_PEER_REASSOC_REQ;
                  break;
            case SUBTYPE_REASSOC_RSP:
                  *Machine = ASSOC_STATE_MACHINE;
                  *MsgType = MT2_PEER_REASSOC_RSP;
                  break;
            case SUBTYPE_PROBE_REQ:
                  *Machine = SYNC_STATE_MACHINE;
                  *MsgType = MT2_PEER_PROBE_REQ;
                  break;
            case SUBTYPE_PROBE_RSP:
                  *Machine = SYNC_STATE_MACHINE;
                  *MsgType = MT2_PEER_PROBE_RSP;
                  break;
            case SUBTYPE_BEACON:
                  *Machine = SYNC_STATE_MACHINE;
                  *MsgType = MT2_PEER_BEACON;
                  break;
            case SUBTYPE_ATIM:
                  *Machine = SYNC_STATE_MACHINE;
                  *MsgType = MT2_PEER_ATIM;
                  break;
            case SUBTYPE_DISASSOC:
                  *Machine = ASSOC_STATE_MACHINE;
                  *MsgType = MT2_PEER_DISASSOC_REQ;
                  break;
            case SUBTYPE_AUTH:
                  // get the sequence number from payload 24 Mac Header + 2 bytes algorithm
                  NdisMoveMemory(&Seq, &pFrame->Octet[2], sizeof(USHORT));
                  if (Seq == 1 || Seq == 3)
                  {
                        *Machine = AUTH_RSP_STATE_MACHINE;
                        *MsgType = MT2_PEER_AUTH_ODD;
                  }
                  else if (Seq == 2 || Seq == 4)
                  {
                        *Machine = AUTH_STATE_MACHINE;
                        *MsgType = MT2_PEER_AUTH_EVEN;
                  }
                  else
                  {
                        return FALSE;
                  }
                  break;
            case SUBTYPE_DEAUTH:
                  *Machine = AUTH_RSP_STATE_MACHINE;
                  *MsgType = MT2_PEER_DEAUTH;
                  break;
            case SUBTYPE_ACTION:
                  *Machine = ACTION_STATE_MACHINE;
                  //  Sometimes Sta will return with category bytes with MSB = 1, if they receive catogory out of their support
                  if ((pFrame->Octet[0]&0x7F) > MAX_PEER_CATE_MSG)
                  {
                        *MsgType = MT2_ACT_INVALID;
                  }
                  else
                  {
                        *MsgType = (pFrame->Octet[0]&0x7F);
                  }
                  break;
            default:
                  return FALSE;
                  break;
      }

      return TRUE;
}

// ===========================================================================================
// state_machine.c
// ===========================================================================================

/*! \brief Initialize the state machine.
 *    \param *S               pointer to the state machine
 *    \param      Trans       State machine transition function
 *    \param      StNr        number of states
 *    \param      MsgNr       number of messages
 *    \param      DefFunc     default function, when there is invalid state/message combination
 *    \param      InitState   initial state of the state machine
 *    \param      Base        StateMachine base, internal use only
 *    \pre p_sm should be a legal pointer
 *    \post

 IRQL = PASSIVE_LEVEL

 */
VOID StateMachineInit(
      IN STATE_MACHINE *S,
      IN STATE_MACHINE_FUNC Trans[],
      IN ULONG StNr,
      IN ULONG MsgNr,
      IN STATE_MACHINE_FUNC DefFunc,
      IN ULONG InitState,
      IN ULONG Base)
{
      ULONG i, j;

      // set number of states and messages
      S->NrState = StNr;
      S->NrMsg   = MsgNr;
      S->Base    = Base;

      S->TransFunc  = Trans;

      // init all state transition to default function
      for (i = 0; i < StNr; i++)
      {
            for (j = 0; j < MsgNr; j++)
            {
                  S->TransFunc[i * MsgNr + j] = DefFunc;
            }
      }

      // set the starting state
      S->CurrState = InitState;
}

/*! \brief This function fills in the function pointer into the cell in the state machine
 *    \param *S   pointer to the state machine
 *    \param St   state
 *    \param Msg  incoming message
 *    \param f    the function to be executed when (state, message) combination occurs at the state machine
 *    \pre *S should be a legal pointer to the state machine, st, msg, should be all within the range, Base should be set in the initial state
 *    \post

 IRQL = PASSIVE_LEVEL

 */
VOID StateMachineSetAction(
      IN STATE_MACHINE *S,
      IN ULONG St,
      IN ULONG Msg,
      IN STATE_MACHINE_FUNC Func)
{
      ULONG MsgIdx;

      MsgIdx = Msg - S->Base;

      if (St < S->NrState && MsgIdx < S->NrMsg)
      {
            // boundary checking before setting the action
            S->TransFunc[St * S->NrMsg + MsgIdx] = Func;
      }
}

/*! \brief   This function does the state transition
 *    \param       *Adapter the NIC adapter pointer
 *    \param       *S     the state machine
 *    \param       *Elem        the message to be executed
 *    \return   None

 IRQL = DISPATCH_LEVEL

 */
VOID StateMachinePerformAction(
      IN    PRTMP_ADAPTER     pAd,
      IN STATE_MACHINE *S,
      IN MLME_QUEUE_ELEM *Elem)
{
      (*(S->TransFunc[S->CurrState * S->NrMsg + Elem->MsgType - S->Base]))(pAd, Elem);
}

/*
      ==========================================================================
      Description:
            The drop function, when machine executes this, the message is simply
            ignored. This function does nothing, the message is freed in
            StateMachinePerformAction()
      ==========================================================================
 */
VOID Drop(
      IN PRTMP_ADAPTER pAd,
      IN MLME_QUEUE_ELEM *Elem)
{
}

// ===========================================================================================
// lfsr.c
// ===========================================================================================

/*
      ==========================================================================
      Description:

      IRQL = PASSIVE_LEVEL

      ==========================================================================
 */
VOID LfsrInit(
      IN PRTMP_ADAPTER pAd,
      IN ULONG Seed)
{
      if (Seed == 0)
            pAd->Mlme.ShiftReg = 1;
      else
            pAd->Mlme.ShiftReg = Seed;
}

/*
      ==========================================================================
      Description:
      ==========================================================================
 */
UCHAR RandomByte(
      IN PRTMP_ADAPTER pAd)
{
      ULONG i;
      UCHAR R, Result;

      R = 0;

      if (pAd->Mlme.ShiftReg == 0)
      NdisGetSystemUpTime((ULONG *)&pAd->Mlme.ShiftReg);

      for (i = 0; i < 8; i++)
      {
            if (pAd->Mlme.ShiftReg & 0x00000001)
            {
                  pAd->Mlme.ShiftReg = ((pAd->Mlme.ShiftReg ^ LFSR_MASK) >> 1) | 0x80000000;
                  Result = 1;
            }
            else
            {
                  pAd->Mlme.ShiftReg = pAd->Mlme.ShiftReg >> 1;
                  Result = 0;
            }
            R = (R << 1) | Result;
      }

      return R;
}

VOID AsicUpdateAutoFallBackTable(
      IN    PRTMP_ADAPTER     pAd,
      IN    PUCHAR                  pRateTable)
{
      UCHAR                         i;
      HT_FBK_CFG0_STRUC       HtCfg0;
      HT_FBK_CFG1_STRUC       HtCfg1;
      LG_FBK_CFG0_STRUC       LgCfg0;
      LG_FBK_CFG1_STRUC       LgCfg1;
      PRTMP_TX_RATE_SWITCH    pCurrTxRate, pNextTxRate;

      // set to initial value
      HtCfg0.word = 0x65432100;
      HtCfg1.word = 0xedcba988;
      LgCfg0.word = 0xedcba988;
      LgCfg1.word = 0x00002100;

      pNextTxRate = (PRTMP_TX_RATE_SWITCH)pRateTable+1;
      for (i = 1; i < *((PUCHAR) pRateTable); i++)
      {
            pCurrTxRate = (PRTMP_TX_RATE_SWITCH)pRateTable+1+i;
            switch (pCurrTxRate->Mode)
            {
                  case 0:           //CCK
                        break;
                  case 1:           //OFDM
                        {
                              switch(pCurrTxRate->CurrMCS)
                              {
                                    case 0:
                                          LgCfg0.field.OFDMMCS0FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS;
                                          break;
                                    case 1:
                                          LgCfg0.field.OFDMMCS1FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS;
                                          break;
                                    case 2:
                                          LgCfg0.field.OFDMMCS2FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS;
                                          break;
                                    case 3:
                                          LgCfg0.field.OFDMMCS3FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS;
                                          break;
                                    case 4:
                                          LgCfg0.field.OFDMMCS4FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS;
                                          break;
                                    case 5:
                                          LgCfg0.field.OFDMMCS5FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS;
                                          break;
                                    case 6:
                                          LgCfg0.field.OFDMMCS6FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS;
                                          break;
                                    case 7:
                                          LgCfg0.field.OFDMMCS7FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS;
                                          break;
                              }
                        }
                        break;
                  case 2:           //HT-MIX
                  case 3:           //HT-GF
                        {
                              if ((pNextTxRate->Mode >= MODE_HTMIX) && (pCurrTxRate->CurrMCS != pNextTxRate->CurrMCS))
                              {
                                    switch(pCurrTxRate->CurrMCS)
                                    {
                                          case 0:
                                                HtCfg0.field.HTMCS0FBK = pNextTxRate->CurrMCS;
                                                break;
                                          case 1:
                                                HtCfg0.field.HTMCS1FBK = pNextTxRate->CurrMCS;
                                                break;
                                          case 2:
                                                HtCfg0.field.HTMCS2FBK = pNextTxRate->CurrMCS;
                                                break;
                                          case 3:
                                                HtCfg0.field.HTMCS3FBK = pNextTxRate->CurrMCS;
                                                break;
                                          case 4:
                                                HtCfg0.field.HTMCS4FBK = pNextTxRate->CurrMCS;
                                                break;
                                          case 5:
                                                HtCfg0.field.HTMCS5FBK = pNextTxRate->CurrMCS;
                                                break;
                                          case 6:
                                                HtCfg0.field.HTMCS6FBK = pNextTxRate->CurrMCS;
                                                break;
                                          case 7:
                                                HtCfg0.field.HTMCS7FBK = pNextTxRate->CurrMCS;
                                                break;
                                          case 8:
                                                HtCfg1.field.HTMCS8FBK = pNextTxRate->CurrMCS;
                                                break;
                                          case 9:
                                                HtCfg1.field.HTMCS9FBK = pNextTxRate->CurrMCS;
                                                break;
                                          case 10:
                                                HtCfg1.field.HTMCS10FBK = pNextTxRate->CurrMCS;
                                                break;
                                          case 11:
                                                HtCfg1.field.HTMCS11FBK = pNextTxRate->CurrMCS;
                                                break;
                                          case 12:
                                                HtCfg1.field.HTMCS12FBK = pNextTxRate->CurrMCS;
                                                break;
                                          case 13:
                                                HtCfg1.field.HTMCS13FBK = pNextTxRate->CurrMCS;
                                                break;
                                          case 14:
                                                HtCfg1.field.HTMCS14FBK = pNextTxRate->CurrMCS;
                                                break;
                                          case 15:
                                                HtCfg1.field.HTMCS15FBK = pNextTxRate->CurrMCS;
                                                break;
                                          default:
                                                DBGPRINT(RT_DEBUG_ERROR, ("AsicUpdateAutoFallBackTable: not support CurrMCS=%d\n", pCurrTxRate->CurrMCS));
                                    }
                              }
                        }
                        break;
            }

            pNextTxRate = pCurrTxRate;
      }

      RTMP_IO_WRITE32(pAd, HT_FBK_CFG0, HtCfg0.word);
      RTMP_IO_WRITE32(pAd, HT_FBK_CFG1, HtCfg1.word);
      RTMP_IO_WRITE32(pAd, LG_FBK_CFG0, LgCfg0.word);
      RTMP_IO_WRITE32(pAd, LG_FBK_CFG1, LgCfg1.word);
}

/*
      ========================================================================

      Routine Description:
            Set MAC register value according operation mode.
            OperationMode AND bNonGFExist are for MM and GF Proteciton.
            If MM or GF mask is not set, those passing argument doesn't not take effect.

            Operation mode meaning:
            = 0 : Pure HT, no preotection.
            = 0x01; there may be non-HT devices in both the control and extension channel, protection is optional in BSS.
            = 0x10: No Transmission in 40M is protected.
            = 0x11: Transmission in both 40M and 20M shall be protected
            if (bNonGFExist)
                  we should choose not to use GF. But still set correct ASIC registers.
      ========================================================================
*/
VOID  AsicUpdateProtect(
      IN          PRTMP_ADAPTER     pAd,
      IN          USHORT                  OperationMode,
      IN          UCHAR             SetMask,
      IN          BOOLEAN                 bDisableBGProtect,
      IN          BOOLEAN                 bNonGFExist)
{
      PROT_CFG_STRUC    ProtCfg, ProtCfg4;
      UINT32 Protect[6];
      USHORT                  offset;
      UCHAR             i;
      UINT32 MacReg = 0;

      if (!(pAd->CommonCfg.bHTProtect) && (OperationMode != 8))
      {
            return;
      }

      if (pAd->BATable.numAsOriginator)
      {
            //
            // enable the RTS/CTS to avoid channel collision
            //
            SetMask = ALLN_SETPROTECT;
            OperationMode = 8;
      }

      // Config ASIC RTS threshold register
      RTMP_IO_READ32(pAd, TX_RTS_CFG, &MacReg);
      MacReg &= 0xFF0000FF;

      // If the user want disable RtsThreshold and enable Amsdu/Ralink-Aggregation, set the RtsThreshold as 4096
        if ((
                  (pAd->CommonCfg.BACapability.field.AmsduEnable) ||
                  (pAd->CommonCfg.bAggregationCapable == TRUE))
            && pAd->CommonCfg.RtsThreshold == MAX_RTS_THRESHOLD)
        {
                  MacReg |= (0x1000 << 8);
        }
        else
        {
                  MacReg |= (pAd->CommonCfg.RtsThreshold << 8);
        }

      RTMP_IO_WRITE32(pAd, TX_RTS_CFG, MacReg);

      // Initial common protection settings
      RTMPZeroMemory(Protect, sizeof(Protect));
      ProtCfg4.word = 0;
      ProtCfg.word = 0;
      ProtCfg.field.TxopAllowGF40 = 1;
      ProtCfg.field.TxopAllowGF20 = 1;
      ProtCfg.field.TxopAllowMM40 = 1;
      ProtCfg.field.TxopAllowMM20 = 1;
      ProtCfg.field.TxopAllowOfdm = 1;
      ProtCfg.field.TxopAllowCck = 1;
      ProtCfg.field.RTSThEn = 1;
      ProtCfg.field.ProtectNav = ASIC_SHORTNAV;

      // update PHY mode and rate
      if (pAd->CommonCfg.Channel > 14)
            ProtCfg.field.ProtectRate = 0x4000;
      ProtCfg.field.ProtectRate |= pAd->CommonCfg.RtsRate;

      // Handle legacy(B/G) protection
      if (bDisableBGProtect)
      {
            //ProtCfg.field.ProtectRate = pAd->CommonCfg.RtsRate;
            ProtCfg.field.ProtectCtrl = 0;
            Protect[0] = ProtCfg.word;
            Protect[1] = ProtCfg.word;
      }
      else
      {
            //ProtCfg.field.ProtectRate = pAd->CommonCfg.RtsRate;
            ProtCfg.field.ProtectCtrl = 0;                  // CCK do not need to be protected
            Protect[0] = ProtCfg.word;
            ProtCfg.field.ProtectCtrl = ASIC_CTS;     // OFDM needs using CCK to protect
            Protect[1] = ProtCfg.word;
      }

      // Decide HT frame protection.
      if ((SetMask & ALLN_SETPROTECT) != 0)
      {
            switch(OperationMode)
            {
                  case 0x0:
                        // NO PROTECT
                        // 1.All STAs in the BSS are 20/40 MHz HT
                        // 2. in ai 20/40MHz BSS
                        // 3. all STAs are 20MHz in a 20MHz BSS
                        // Pure HT. no protection.

                        // MM20_PROT_CFG
                        //    Reserved (31:27)
                        //    PROT_TXOP(25:20) -- 010111
                        //    PROT_NAV(19:18)  -- 01 (Short NAV protection)
                        //  PROT_CTRL(17:16) -- 00 (None)
                        //    PROT_RATE(15:0)  -- 0x4004 (OFDM 24M)
                        Protect[2] = 0x01744004;

                        // MM40_PROT_CFG
                        //    Reserved (31:27)
                        //    PROT_TXOP(25:20) -- 111111
                        //    PROT_NAV(19:18)  -- 01 (Short NAV protection)
                        //  PROT_CTRL(17:16) -- 00 (None)
                        //    PROT_RATE(15:0)  -- 0x4084 (duplicate OFDM 24M)
                        Protect[3] = 0x03f44084;

                        // CF20_PROT_CFG
                        //    Reserved (31:27)
                        //    PROT_TXOP(25:20) -- 010111
                        //    PROT_NAV(19:18)  -- 01 (Short NAV protection)
                        //  PROT_CTRL(17:16) -- 00 (None)
                        //    PROT_RATE(15:0)  -- 0x4004 (OFDM 24M)
                        Protect[4] = 0x01744004;

                        // CF40_PROT_CFG
                        //    Reserved (31:27)
                        //    PROT_TXOP(25:20) -- 111111
                        //    PROT_NAV(19:18)  -- 01 (Short NAV protection)
                        //  PROT_CTRL(17:16) -- 00 (None)
                        //    PROT_RATE(15:0)  -- 0x4084 (duplicate OFDM 24M)
                        Protect[5] = 0x03f44084;

                        if (bNonGFExist)
                        {
                              // PROT_NAV(19:18)  -- 01 (Short NAV protectiion)
                              // PROT_CTRL(17:16) -- 01 (RTS/CTS)
                              Protect[4] = 0x01754004;
                              Protect[5] = 0x03f54084;
                        }
                        pAd->CommonCfg.IOTestParm.bRTSLongProtOn = FALSE;
                        break;

                  case 1:
                        // This is "HT non-member protection mode."
                        // If there may be non-HT STAs my BSS
                        ProtCfg.word = 0x01744004;    // PROT_CTRL(17:16) : 0 (None)
                        ProtCfg4.word = 0x03f44084; // duplicaet legacy 24M. BW set 1.
                        if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED))
                        {
                              ProtCfg.word = 0x01740003;    //ERP use Protection bit is set, use protection rate at Clause 18..
                              ProtCfg4.word = 0x03f40003; // Don't duplicate RTS/CTS in CCK mode. 0x03f40083;
                        }
                        //Assign Protection method for 20&40 MHz packets
                        ProtCfg.field.ProtectCtrl = ASIC_RTS;
                        ProtCfg.field.ProtectNav = ASIC_SHORTNAV;
                        ProtCfg4.field.ProtectCtrl = ASIC_RTS;
                        ProtCfg4.field.ProtectNav = ASIC_SHORTNAV;
                        Protect[2] = ProtCfg.word;
                        Protect[3] = ProtCfg4.word;
                        Protect[4] = ProtCfg.word;
                        Protect[5] = ProtCfg4.word;
                        pAd->CommonCfg.IOTestParm.bRTSLongProtOn = TRUE;
                        break;

                  case 2:
                        // If only HT STAs are in BSS. at least one is 20MHz. Only protect 40MHz packets
                        ProtCfg.word = 0x01744004;  // PROT_CTRL(17:16) : 0 (None)
                        ProtCfg4.word = 0x03f44084; // duplicaet legacy 24M. BW set 1.

                        //Assign Protection method for 40MHz packets
                        ProtCfg4.field.ProtectCtrl = ASIC_RTS;
                        ProtCfg4.field.ProtectNav = ASIC_SHORTNAV;
                        Protect[2] = ProtCfg.word;
                        Protect[3] = ProtCfg4.word;
                        if (bNonGFExist)
                        {
                              ProtCfg.field.ProtectCtrl = ASIC_RTS;
                              ProtCfg.field.ProtectNav = ASIC_SHORTNAV;
                        }
                        Protect[4] = ProtCfg.word;
                        Protect[5] = ProtCfg4.word;

                        pAd->CommonCfg.IOTestParm.bRTSLongProtOn = FALSE;
                        break;

                  case 3:
                        // HT mixed mode.  PROTECT ALL!
                        // Assign Rate
                        ProtCfg.word = 0x01744004;    //duplicaet legacy 24M. BW set 1.
                        ProtCfg4.word = 0x03f44084;
                        // both 20MHz and 40MHz are protected. Whether use RTS or CTS-to-self depends on the
                        if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED))
                        {
                              ProtCfg.word = 0x01740003;    //ERP use Protection bit is set, use protection rate at Clause 18..
                              ProtCfg4.word = 0x03f40003; // Don't duplicate RTS/CTS in CCK mode. 0x03f40083
                        }
                        //Assign Protection method for 20&40 MHz packets
                        ProtCfg.field.ProtectCtrl = ASIC_RTS;
                        ProtCfg.field.ProtectNav = ASIC_SHORTNAV;
                        ProtCfg4.field.ProtectCtrl = ASIC_RTS;
                        ProtCfg4.field.ProtectNav = ASIC_SHORTNAV;
                        Protect[2] = ProtCfg.word;
                        Protect[3] = ProtCfg4.word;
                        Protect[4] = ProtCfg.word;
                        Protect[5] = ProtCfg4.word;
                        pAd->CommonCfg.IOTestParm.bRTSLongProtOn = TRUE;
                        break;

                  case 8:
                        // Special on for Atheros problem n chip.
                        Protect[2] = 0x01754004;
                        Protect[3] = 0x03f54084;
                        Protect[4] = 0x01754004;
                        Protect[5] = 0x03f54084;
                        pAd->CommonCfg.IOTestParm.bRTSLongProtOn = TRUE;
                        break;
            }
      }

      offset = CCK_PROT_CFG;
      for (i = 0;i < 6;i++)
      {
            if ((SetMask & (1<< i)))
            {
                  RTMP_IO_WRITE32(pAd, offset + i*4, Protect[i]);
            }
      }
}

#ifdef RT30xx
/*
      ========================================================================

      Routine Description: Write RT30xx RF register through MAC

      Arguments:

      Return Value:

      IRQL =

      Note:

      ========================================================================
*/
NTSTATUS RT30xxWriteRFRegister(
      IN    PRTMP_ADAPTER     pAd,
      IN    UCHAR             RegID,
      IN    UCHAR             Value)
{
      RF_CSR_CFG_STRUC  rfcsr;
      UINT                    i = 0;

      do
      {
            RTMP_IO_READ32(pAd, RF_CSR_CFG, &rfcsr.word);

            if (!rfcsr.field.RF_CSR_KICK)
                  break;
            i++;
      }
      while ((i < RETRY_LIMIT) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)));

      if ((i == RETRY_LIMIT) || (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)))
      {
            DBGPRINT_RAW(RT_DEBUG_ERROR, ("Retry count exhausted or device removed!!!\n"));
            return STATUS_UNSUCCESSFUL;
      }

      rfcsr.field.RF_CSR_WR = 1;
      rfcsr.field.RF_CSR_KICK = 1;
      rfcsr.field.TESTCSR_RFACC_REGNUM = RegID;
      rfcsr.field.RF_CSR_DATA = Value;

      RTMP_IO_WRITE32(pAd, RF_CSR_CFG, rfcsr.word);

      return STATUS_SUCCESS;
}


/*
      ========================================================================

      Routine Description: Read RT30xx RF register through MAC

      Arguments:

      Return Value:

      IRQL =

      Note:

      ========================================================================
*/
NTSTATUS RT30xxReadRFRegister(
      IN    PRTMP_ADAPTER     pAd,
      IN    UCHAR             RegID,
      IN    PUCHAR                  pValue)
{
      RF_CSR_CFG_STRUC  rfcsr;
      UINT                    i=0, k=0;

      for (i=0; i<MAX_BUSY_COUNT; i++)
      {
            RTMP_IO_READ32(pAd, RF_CSR_CFG, &rfcsr.word);

            if (rfcsr.field.RF_CSR_KICK == BUSY)
            {
                  continue;
            }
            rfcsr.word = 0;
            rfcsr.field.RF_CSR_WR = 0;
            rfcsr.field.RF_CSR_KICK = 1;
            rfcsr.field.TESTCSR_RFACC_REGNUM = RegID;
            RTMP_IO_WRITE32(pAd, RF_CSR_CFG, rfcsr.word);
            for (k=0; k<MAX_BUSY_COUNT; k++)
            {
                  RTMP_IO_READ32(pAd, RF_CSR_CFG, &rfcsr.word);

                  if (rfcsr.field.RF_CSR_KICK == IDLE)
                        break;
            }
            if ((rfcsr.field.RF_CSR_KICK == IDLE) &&
                  (rfcsr.field.TESTCSR_RFACC_REGNUM == RegID))
            {
                  *pValue = (UCHAR)rfcsr.field.RF_CSR_DATA;
                  break;
            }
      }
      if (rfcsr.field.RF_CSR_KICK == BUSY)
      {
            DBGPRINT_ERR(("RF read R%d=0x%x fail, i[%d], k[%d]\n", RegID, rfcsr.word,i,k));
            return STATUS_UNSUCCESSFUL;
      }

      return STATUS_SUCCESS;
}
#endif // RT30xx //

#ifdef RT30xx
// add by johnli, RF power sequence setup
/*
      ==========================================================================
      Description:

      Load RF normal operation-mode setup

      ==========================================================================
 */
VOID RT30xxLoadRFNormalModeSetup(
      IN PRTMP_ADAPTER  pAd)
{
      UCHAR RFValue;

      // RX0_PD & TX0_PD, RF R1 register Bit 2 & Bit 3 to 0 and RF_BLOCK_en,RX1_PD & TX1_PD, Bit0, Bit 4 & Bit5 to 1
      RT30xxReadRFRegister(pAd, RF_R01, &RFValue);
      RFValue = (RFValue & (~0x0C)) | 0x31;
      RT30xxWriteRFRegister(pAd, RF_R01, RFValue);

      // TX_LO2_en, RF R15 register Bit 3 to 0
      RT30xxReadRFRegister(pAd, RF_R15, &RFValue);
      RFValue &= (~0x08);
      RT30xxWriteRFRegister(pAd, RF_R15, RFValue);

      // TX_LO1_en, RF R17 register Bit 3 to 0
      RT30xxReadRFRegister(pAd, RF_R17, &RFValue);
      RFValue &= (~0x08);
      // to fix rx long range issue
      if (((pAd->MACVersion & 0xffff) >= 0x0211) && (pAd->NicConfig2.field.ExternalLNAForG == 0))
      {
            RFValue |= 0x20;
      }
      RT30xxWriteRFRegister(pAd, RF_R17, RFValue);

      // RX_LO1_en, RF R20 register Bit 3 to 0
      RT30xxReadRFRegister(pAd, RF_R20, &RFValue);
      RFValue &= (~0x08);
      RT30xxWriteRFRegister(pAd, RF_R20, RFValue);

      // RX_LO2_en, RF R21 register Bit 3 to 0
      RT30xxReadRFRegister(pAd, RF_R21, &RFValue);
      RFValue &= (~0x08);
      RT30xxWriteRFRegister(pAd, RF_R21, RFValue);

      // LDORF_VC, RF R27 register Bit 2 to 0
      RT30xxReadRFRegister(pAd, RF_R27, &RFValue);
      if ((pAd->MACVersion & 0xffff) < 0x0211)
            RFValue = (RFValue & (~0x77)) | 0x3;
      else
            RFValue = (RFValue & (~0x77));
      RT30xxWriteRFRegister(pAd, RF_R27, RFValue);
      /* end johnli */
}

/*
      ==========================================================================
      Description:

      Load RF sleep-mode setup

      ==========================================================================
 */
VOID RT30xxLoadRFSleepModeSetup(
      IN PRTMP_ADAPTER  pAd)
{
      UCHAR RFValue;
      UINT32 MACValue;

      // RF_BLOCK_en. RF R1 register Bit 0 to 0
      RT30xxReadRFRegister(pAd, RF_R01, &RFValue);
      RFValue &= (~0x01);
      RT30xxWriteRFRegister(pAd, RF_R01, RFValue);

      // VCO_IC, RF R7 register Bit 4 & Bit 5 to 0
      RT30xxReadRFRegister(pAd, RF_R07, &RFValue);
      RFValue &= (~0x30);
      RT30xxWriteRFRegister(pAd, RF_R07, RFValue);

      // Idoh, RF R9 register Bit 1, Bit 2 & Bit 3 to 0
      RT30xxReadRFRegister(pAd, RF_R09, &RFValue);
      RFValue &= (~0x0E);
      RT30xxWriteRFRegister(pAd, RF_R09, RFValue);

      // RX_CTB_en, RF R21 register Bit 7 to 0
      RT30xxReadRFRegister(pAd, RF_R21, &RFValue);
      RFValue &= (~0x80);
      RT30xxWriteRFRegister(pAd, RF_R21, RFValue);

      // LDORF_VC, RF R27 register Bit 0, Bit 1 & Bit 2 to 1
      RT30xxReadRFRegister(pAd, RF_R27, &RFValue);
      RFValue |= 0x77;
      RT30xxWriteRFRegister(pAd, RF_R27, RFValue);

      RTMP_IO_READ32(pAd, LDO_CFG0, &MACValue);
      MACValue |= 0x1D000000;
      RTMP_IO_WRITE32(pAd, LDO_CFG0, MACValue);
}

/*
      ==========================================================================
      Description:

      Reverse RF sleep-mode setup

      ==========================================================================
 */
VOID RT30xxReverseRFSleepModeSetup(
      IN PRTMP_ADAPTER  pAd)
{
      UCHAR RFValue;
      UINT32 MACValue;

      // RF_BLOCK_en, RF R1 register Bit 0 to 1
      RT30xxReadRFRegister(pAd, RF_R01, &RFValue);
      RFValue |= 0x01;
      RT30xxWriteRFRegister(pAd, RF_R01, RFValue);

      // VCO_IC, RF R7 register Bit 4 & Bit 5 to 1
      RT30xxReadRFRegister(pAd, RF_R07, &RFValue);
      RFValue |= 0x30;
      RT30xxWriteRFRegister(pAd, RF_R07, RFValue);

      // Idoh, RF R9 register Bit 1, Bit 2 & Bit 3 to 1
      RT30xxReadRFRegister(pAd, RF_R09, &RFValue);
      RFValue |= 0x0E;
      RT30xxWriteRFRegister(pAd, RF_R09, RFValue);

      // RX_CTB_en, RF R21 register Bit 7 to 1
      RT30xxReadRFRegister(pAd, RF_R21, &RFValue);
      RFValue |= 0x80;
      RT30xxWriteRFRegister(pAd, RF_R21, RFValue);

      // LDORF_VC, RF R27 register Bit 2 to 0
      RT30xxReadRFRegister(pAd, RF_R27, &RFValue);
      if ((pAd->MACVersion & 0xffff) < 0x0211)
            RFValue = (RFValue & (~0x77)) | 0x3;
      else
            RFValue = (RFValue & (~0x77));
      RT30xxWriteRFRegister(pAd, RF_R27, RFValue);

      // RT3071 version E has fixed this issue
      if ((pAd->NicConfig2.field.DACTestBit == 1) && ((pAd->MACVersion & 0xffff) < 0x0211))
      {
            // patch tx EVM issue temporarily
            RTMP_IO_READ32(pAd, LDO_CFG0, &MACValue);
            MACValue = ((MACValue & 0xE0FFFFFF) | 0x0D000000);
            RTMP_IO_WRITE32(pAd, LDO_CFG0, MACValue);
      }
      else
      {
            RTMP_IO_READ32(pAd, LDO_CFG0, &MACValue);
            MACValue = ((MACValue & 0xE0FFFFFF) | 0x01000000);
            RTMP_IO_WRITE32(pAd, LDO_CFG0, MACValue);
      }
}
// end johnli
#endif // RT30xx //

/*
      ==========================================================================
      Description:

      IRQL = PASSIVE_LEVEL
      IRQL = DISPATCH_LEVEL

      ==========================================================================
 */
VOID AsicSwitchChannel(
                                IN PRTMP_ADAPTER pAd,
      IN    UCHAR             Channel,
      IN    BOOLEAN                 bScan)
{
      ULONG             R2 = 0, R3 = DEFAULT_RF_TX_POWER, R4 = 0;
      CHAR    TxPwer = 0, TxPwer2 = DEFAULT_RF_TX_POWER; //Bbp94 = BBPR94_DEFAULT, TxPwer2 = DEFAULT_RF_TX_POWER;
      UCHAR index;
      UINT32      Value = 0; //BbpReg, Value;
      RTMP_RF_REGS *RFRegTable;

      // Search Tx power value
#ifdef RT30xx
      // We can't use ChannelList to search channel, since some central channl's txpowr doesn't list
      // in ChannelList, so use TxPower array instead.
      //
      for (index = 0; index < MAX_NUM_OF_CHANNELS; index++)
      {
            if (Channel == pAd->TxPower[index].Channel)
      {
                  TxPwer = pAd->TxPower[index].Power;
                  TxPwer2 = pAd->TxPower[index].Power2;
                  break;
            }
      }
#endif
#ifndef RT30xx
      for (index = 0; index < pAd->ChannelListNum; index++)
      {
            if (Channel == pAd->ChannelList[index].Channel)
            {
                  TxPwer = pAd->ChannelList[index].Power;
                  TxPwer2 = pAd->ChannelList[index].Power2;
                  break;
            }
      }
#endif

      if (index == MAX_NUM_OF_CHANNELS)
      {
#ifndef RT30xx
            DBGPRINT(RT_DEBUG_ERROR, ("AsicSwitchChannel: Cant find the Channel#%d \n", Channel));
#endif
#ifdef RT30xx
            DBGPRINT(RT_DEBUG_ERROR, ("AsicSwitchChannel: Can't find the Channel#%d \n", Channel));
#endif
      }

#ifdef RT2870
      // The RF programming sequence is difference between 3xxx and 2xxx
#ifdef RT30xx
      if ((IS_RT3070(pAd) || IS_RT3090(pAd)) && ((pAd->RfIcType == RFIC_3020) || (pAd->RfIcType == RFIC_2020) ||
            (pAd->RfIcType == RFIC_3021) || (pAd->RfIcType == RFIC_3022)))
#endif
#ifndef RT30xx
      if (IS_RT3070(pAd) && ((pAd->RfIcType == RFIC_3020) || (pAd->RfIcType == RFIC_2020)))
#endif
      {
            /* modify by WY for Read RF Reg. error */
            UCHAR RFValue;

            for (index = 0; index < NUM_OF_3020_CHNL; index++)
            {
                  if (Channel == FreqItems3020[index].Channel)
                  {
                        // Programming channel parameters
                        RT30xxWriteRFRegister(pAd, RF_R02, FreqItems3020[index].N);
                        RT30xxWriteRFRegister(pAd, RF_R03, FreqItems3020[index].K);

#ifndef RT30xx
                        RT30xxReadRFRegister(pAd, RF_R06, (PUCHAR)&RFValue);
                        RFValue = (RFValue & 0xFC) | FreqItems3020[index].R;
                        RT30xxWriteRFRegister(pAd, RF_R06, (UCHAR)RFValue);

                        // Set Tx Power
                        RT30xxReadRFRegister(pAd, RF_R12, (PUCHAR)&RFValue);
                        RFValue = (RFValue & 0xE0) | TxPwer;
                        RT30xxWriteRFRegister(pAd, RF_R12, (UCHAR)RFValue);

                        // Set RF offset
                        RT30xxReadRFRegister(pAd, RF_R23, (PUCHAR)&RFValue);
                        RFValue = (RFValue & 0x80) | pAd->RfFreqOffset;
                        RT30xxWriteRFRegister(pAd, RF_R23, (UCHAR)RFValue);
#endif
#ifdef RT30xx
                        RT30xxReadRFRegister(pAd, RF_R06, &RFValue);
                        RFValue = (RFValue & 0xFC) | FreqItems3020[index].R;
                        RT30xxWriteRFRegister(pAd, RF_R06, RFValue);

                        // Set Tx0 Power
                        RT30xxReadRFRegister(pAd, RF_R12, &RFValue);
                        RFValue = (RFValue & 0xE0) | TxPwer;
                        RT30xxWriteRFRegister(pAd, RF_R12, RFValue);

                        // Set Tx1 Power
                        RT30xxReadRFRegister(pAd, RF_R13, &RFValue);
                        RFValue = (RFValue & 0xE0) | TxPwer2;
                        RT30xxWriteRFRegister(pAd, RF_R13, RFValue);

                        // Tx/Rx Stream setting
                        RT30xxReadRFRegister(pAd, RF_R01, &RFValue);
                        //if (IS_RT3090(pAd))
                        //    RFValue |= 0x01; // Enable RF block.
                        RFValue &= 0x03;  //clear bit[7~2]
                        if (pAd->Antenna.field.TxPath == 1)
                              RFValue |= 0xA0;
                        else if (pAd->Antenna.field.TxPath == 2)
                              RFValue |= 0x80;
                        if (pAd->Antenna.field.RxPath == 1)
                              RFValue |= 0x50;
                        else if (pAd->Antenna.field.RxPath == 2)
                              RFValue |= 0x40;
                        RT30xxWriteRFRegister(pAd, RF_R01, RFValue);

                        // Set RF offset
                        RT30xxReadRFRegister(pAd, RF_R23, &RFValue);
                        RFValue = (RFValue & 0x80) | pAd->RfFreqOffset;
                        RT30xxWriteRFRegister(pAd, RF_R23, RFValue);
#endif

                        // Set BW
                        if (!bScan && (pAd->CommonCfg.BBPCurrentBW == BW_40))
                        {
                              RFValue = pAd->Mlme.CaliBW40RfR24;
                              //DISABLE_11N_CHECK(pAd);
                        }
                        else
                        {
                              RFValue = pAd->Mlme.CaliBW20RfR24;
                        }
#ifndef RT30xx
                        RT30xxWriteRFRegister(pAd, RF_R24, (UCHAR)RFValue);

                        // Enable RF tuning
                        RT30xxReadRFRegister(pAd, RF_R07, (PUCHAR)&RFValue);
                        RFValue = RFValue | 0x1;
                        RT30xxWriteRFRegister(pAd, RF_R07, (UCHAR)RFValue);

                        // latch channel for future usage.
                        pAd->LatchRfRegs.Channel = Channel;
#endif
#ifdef RT30xx
                        RT30xxWriteRFRegister(pAd, RF_R24, RFValue);
                        RT30xxWriteRFRegister(pAd, RF_R31, RFValue);

                        // Enable RF tuning
                        RT30xxReadRFRegister(pAd, RF_R07, &RFValue);
                        RFValue = RFValue | 0x1;
                        RT30xxWriteRFRegister(pAd, RF_R07, RFValue);

                        // latch channel for future usage.
                        pAd->LatchRfRegs.Channel = Channel;

                        DBGPRINT(RT_DEBUG_TRACE, ("SwitchChannel#%d(RF=%d, Pwr0=%d, Pwr1=%d, %dT), N=0x%02X, K=0x%02X, R=0x%02X\n",
                              Channel,
                              pAd->RfIcType,
                              TxPwer,
                              TxPwer2,
                              pAd->Antenna.field.TxPath,
                              FreqItems3020[index].N,
                              FreqItems3020[index].K,
                              FreqItems3020[index].R));
#endif

                        break;
                  }
            }

#ifndef RT30xx
            DBGPRINT(RT_DEBUG_TRACE, ("SwitchChannel#%d(RF=%d, Pwr0=%d, Pwr1=%d, %dT), N=0x%02X, K=0x%02X, R=0x%02X\n",
                  Channel,
                  pAd->RfIcType,
                  TxPwer,
                  TxPwer2,
                  pAd->Antenna.field.TxPath,
                  FreqItems3020[index].N,
                  FreqItems3020[index].K,
                  FreqItems3020[index].R));
#endif
      }
      else
#endif // RT2870 //
      {
            RFRegTable = RF2850RegTable;

            switch (pAd->RfIcType)
            {
                  case RFIC_2820:
                  case RFIC_2850:
                  case RFIC_2720:
                  case RFIC_2750:

                  for (index = 0; index < NUM_OF_2850_CHNL; index++)
                  {
                        if (Channel == RFRegTable[index].Channel)
                        {
                              R2 = RFRegTable[index].R2;
                              if (pAd->Antenna.field.TxPath == 1)
                              {
                                    R2 |= 0x4000;     // If TXpath is 1, bit 14 = 1;
                              }

                              if (pAd->Antenna.field.RxPath == 2)
                              {
                                    R2 |= 0x40; // write 1 to off Rxpath.
                              }
                              else if (pAd->Antenna.field.RxPath == 1)
                              {
                                    R2 |= 0x20040;    // write 1 to off RxPath
                              }

                              if (Channel > 14)
                              {
                                    // initialize R3, R4
                                    R3 = (RFRegTable[index].R3 & 0xffffc1ff);
                                    R4 = (RFRegTable[index].R4 & (~0x001f87c0)) | (pAd->RfFreqOffset << 15);

                                    // 5G band power range: 0xF9~0X0F, TX0 Reg3 bit9/TX1 Reg4 bit6="0" means the TX power reduce 7dB
                                    // R3
                                    if ((TxPwer >= -7) && (TxPwer < 0))
                                    {
                                          TxPwer = (7+TxPwer);
                                          TxPwer = (TxPwer > 0xF) ? (0xF) : (TxPwer);
                                          R3 |= (TxPwer << 10);
                                          DBGPRINT(RT_DEBUG_ERROR, ("AsicSwitchChannel: TxPwer=%d \n", TxPwer));
                                    }
                                    else
                                    {
                                          TxPwer = (TxPwer > 0xF) ? (0xF) : (TxPwer);
                                          R3 |= (TxPwer << 10) | (1 << 9);
                                    }

                                    // R4
                                    if ((TxPwer2 >= -7) && (TxPwer2 < 0))
                                    {
                                          TxPwer2 = (7+TxPwer2);
                                          TxPwer2 = (TxPwer2 > 0xF) ? (0xF) : (TxPwer2);
                                          R4 |= (TxPwer2 << 7);
                                          DBGPRINT(RT_DEBUG_ERROR, ("AsicSwitchChannel: TxPwer2=%d \n", TxPwer2));
                                    }
                                    else
                                    {
                                          TxPwer2 = (TxPwer2 > 0xF) ? (0xF) : (TxPwer2);
                                          R4 |= (TxPwer2 << 7) | (1 << 6);
                                    }
                              }
                              else
                              {
                                    R3 = (RFRegTable[index].R3 & 0xffffc1ff) | (TxPwer << 9); // set TX power0
                              R4 = (RFRegTable[index].R4 & (~0x001f87c0)) | (pAd->RfFreqOffset << 15) | (TxPwer2 <<6);// Set freq Offset & TxPwr1
                              }

                              // Based on BBP current mode before changing RF channel.
                              if (!bScan && (pAd->CommonCfg.BBPCurrentBW == BW_40))
                              {
                                    R4 |=0x200000;
                              }

                              // Update variables
                              pAd->LatchRfRegs.Channel = Channel;
                              pAd->LatchRfRegs.R1 = RFRegTable[index].R1;
                              pAd->LatchRfRegs.R2 = R2;
                              pAd->LatchRfRegs.R3 = R3;
                              pAd->LatchRfRegs.R4 = R4;

                              // Set RF value 1's set R3[bit2] = [0]
                              RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1);
                              RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2);
                              RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 & (~0x04)));
                              RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4);

                              RTMPusecDelay(200);

                              // Set RF value 2's set R3[bit2] = [1]
                              RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1);
                              RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2);
                              RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 | 0x04));
                              RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4);

                              RTMPusecDelay(200);

                              // Set RF value 3's set R3[bit2] = [0]
                              RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1);
                              RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2);
                              RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 & (~0x04)));
                              RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4);

                              break;
                        }
                  }
                  break;

                  default:
                  break;
            }
      }

      // Change BBP setting during siwtch from a->g, g->a
      if (Channel <= 14)
      {
          ULONG   TxPinCfg = 0x00050F0A;//Gary 2007/08/09 0x050A0A

            RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R62, (0x37 - GET_LNA_GAIN(pAd)));
            RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R63, (0x37 - GET_LNA_GAIN(pAd)));
            RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R64, (0x37 - GET_LNA_GAIN(pAd)));
            RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R86, 0);//(0x44 - GET_LNA_GAIN(pAd)));  // According the Rory's suggestion to solve the middle range issue.
            //RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0x62);

            // Rx High power VGA offset for LNA select
          if (pAd->NicConfig2.field.ExternalLNAForG)
          {
              RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0x62);
                  RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R75, 0x46);
          }
          else
          {
              RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0x84);
                  RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R75, 0x50);
          }

            // 5G band selection PIN, bit1 and bit2 are complement
            RTMP_IO_READ32(pAd, TX_BAND_CFG, &Value);
            Value &= (~0x6);
            Value |= (0x04);
            RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value);

        // Turn off unused PA or LNA when only 1T or 1R
            if (pAd->Antenna.field.TxPath == 1)
            {
                  TxPinCfg &= 0xFFFFFFF3;
            }
            if (pAd->Antenna.field.RxPath == 1)
            {
                  TxPinCfg &= 0xFFFFF3FF;
            }

            RTMP_IO_WRITE32(pAd, TX_PIN_CFG, TxPinCfg);
      }
      else
      {
          ULONG   TxPinCfg = 0x00050F05;//Gary 2007/8/9 0x050505

            RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R62, (0x37 - GET_LNA_GAIN(pAd)));
            RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R63, (0x37 - GET_LNA_GAIN(pAd)));
            RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R64, (0x37 - GET_LNA_GAIN(pAd)));
            RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R86, 0);//(0x44 - GET_LNA_GAIN(pAd)));   // According the Rory's suggestion to solve the middle range issue.
            RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0xF2);

            // Rx High power VGA offset for LNA select
            if (pAd->NicConfig2.field.ExternalLNAForA)
            {
                  RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R75, 0x46);
            }
            else
            {
                  RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R75, 0x50);
            }

            // 5G band selection PIN, bit1 and bit2 are complement
            RTMP_IO_READ32(pAd, TX_BAND_CFG, &Value);
            Value &= (~0x6);
            Value |= (0x02);
            RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value);

        // Turn off unused PA or LNA when only 1T or 1R
            if (pAd->Antenna.field.TxPath == 1)
            {
                  TxPinCfg &= 0xFFFFFFF3;
      }
            if (pAd->Antenna.field.RxPath == 1)
            {
                  TxPinCfg &= 0xFFFFF3FF;
      }

            RTMP_IO_WRITE32(pAd, TX_PIN_CFG, TxPinCfg);
      }

    // R66 should be set according to Channel and use 20MHz when scanning
      //RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, (0x2E + GET_LNA_GAIN(pAd)));
      if (bScan)
            RTMPSetAGCInitValue(pAd, BW_20);
      else
            RTMPSetAGCInitValue(pAd, pAd->CommonCfg.BBPCurrentBW);

      //
      // On 11A, We should delay and wait RF/BBP to be stable
      // and the appropriate time should be 1000 micro seconds
      // 2005/06/05 - On 11G, We also need this delay time. Otherwise it's difficult to pass the WHQL.
      //
      RTMPusecDelay(1000);

      DBGPRINT(RT_DEBUG_TRACE, ("SwitchChannel#%d(RF=%d, Pwr0=%lu, Pwr1=%lu, %dT) to , R1=0x%08lx, R2=0x%08lx, R3=0x%08lx, R4=0x%08lx\n",
                                            Channel,
                                            pAd->RfIcType,
                                            (R3 & 0x00003e00) >> 9,
                                            (R4 & 0x000007c0) >> 6,
                                            pAd->Antenna.field.TxPath,
                                            pAd->LatchRfRegs.R1,
                                            pAd->LatchRfRegs.R2,
                                            pAd->LatchRfRegs.R3,
                                            pAd->LatchRfRegs.R4));
}

/*
      ==========================================================================
      Description:
            This function is required for 2421 only, and should not be used during
            site survey. It's only required after NIC decided to stay at a channel
            for a longer period.
            When this function is called, it's always after AsicSwitchChannel().

      IRQL = PASSIVE_LEVEL
      IRQL = DISPATCH_LEVEL

      ==========================================================================
 */
VOID AsicLockChannel(
      IN PRTMP_ADAPTER pAd,
      IN UCHAR Channel)
{
}

/*
      ==========================================================================
      Description:

      IRQL = PASSIVE_LEVEL
      IRQL = DISPATCH_LEVEL

      ==========================================================================
 */
VOID  AsicAntennaSelect(
      IN    PRTMP_ADAPTER     pAd,
      IN    UCHAR             Channel)
{
#ifdef RT30xx
                  if (pAd->Mlme.OneSecPeriodicRound % 2 == 1)
                  {
                        // patch for AsicSetRxAnt failed
                        pAd->RxAnt.EvaluatePeriod = 0;

                        // check every 2 second. If rcv-beacon less than 5 in the past 2 second, then AvgRSSI is no longer a
                        // valid indication of the distance between this AP and its clients.
                        if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED))
                        {
                              SHORT realavgrssi1;

                              // if no traffic then reset average rssi to trigger evaluation
                              if (pAd->StaCfg.NumOfAvgRssiSample < 5)
                              {
                                    pAd->RxAnt.Pair1LastAvgRssi = (-99);
                                    pAd->RxAnt.Pair2LastAvgRssi = (-99);
                                    DBGPRINT(RT_DEBUG_TRACE, ("MlmePeriodicExec: no traffic/beacon, reset RSSI\n"));
                              }

                              pAd->StaCfg.NumOfAvgRssiSample = 0;
                              realavgrssi1 = (pAd->RxAnt.Pair1AvgRssi[pAd->RxAnt.Pair1PrimaryRxAnt] >> 3);

                              DBGPRINT(RT_DEBUG_TRACE,("Ant-realrssi0(%d), Lastrssi0(%d), EvaluateStableCnt=%d\n", realavgrssi1, pAd->RxAnt.Pair1LastAvgRssi, pAd->RxAnt.EvaluateStableCnt));

                              // if the difference between two rssi is larger or less than 5, then evaluate the other antenna
                              if ((pAd->RxAnt.EvaluateStableCnt < 2) || (realavgrssi1 > (pAd->RxAnt.Pair1LastAvgRssi + 5)) || (realavgrssi1 < (pAd->RxAnt.Pair1LastAvgRssi - 5)))
                              {
                                    pAd->RxAnt.Pair1LastAvgRssi = realavgrssi1;
                                    AsicEvaluateRxAnt(pAd);
                              }
                        }
                        else
                        {
                              // if not connected, always switch antenna to try to connect
                              UCHAR temp;

                              temp = pAd->RxAnt.Pair1PrimaryRxAnt;
                              pAd->RxAnt.Pair1PrimaryRxAnt = pAd->RxAnt.Pair1SecondaryRxAnt;
                              pAd->RxAnt.Pair1SecondaryRxAnt = temp;

                              DBGPRINT(RT_DEBUG_TRACE, ("MlmePeriodicExec: no connect, switch to another one to try connection\n"));

                              AsicSetRxAnt(pAd, pAd->RxAnt.Pair1PrimaryRxAnt);
                        }
                  }
#endif /* RT30xx */
}

/*
      ========================================================================

      Routine Description:
            Antenna miscellaneous setting.

      Arguments:
            pAd                                 Pointer to our adapter
            BandState                     Indicate current Band State.

      Return Value:
            None

      IRQL <= DISPATCH_LEVEL

      Note:
            1.) Frame End type control
                  only valid for G only (RF_2527 & RF_2529)
                  0: means DPDT, set BBP R4 bit 5 to 1
                  1: means SPDT, set BBP R4 bit 5 to 0


      ========================================================================
*/
VOID  AsicAntennaSetting(
      IN    PRTMP_ADAPTER     pAd,
      IN    ABGBAND_STATE     BandState)
{
}

VOID AsicRfTuningExec(
      IN PVOID SystemSpecific1,
      IN PVOID FunctionContext,
      IN PVOID SystemSpecific2,
      IN PVOID SystemSpecific3)
{
}

/*
      ==========================================================================
      Description:
            Gives CCK TX rate 2 more dB TX power.
            This routine works only in LINK UP in INFRASTRUCTURE mode.

            calculate desired Tx power in RF R3.Tx0~5,      should consider -
            0. if current radio is a noisy environment (pAd->DrsCounters.fNoisyEnvironment)
            1. TxPowerPercentage
            2. auto calibration based on TSSI feedback
            3. extra 2 db for CCK
            4. -10 db upon very-short distance (AvgRSSI >= -40db) to AP

      NOTE: Since this routine requires the value of (pAd->DrsCounters.fNoisyEnvironment),
            it should be called AFTER MlmeDynamicTxRatSwitching()
      ==========================================================================
 */
VOID AsicAdjustTxPower(
      IN PRTMP_ADAPTER pAd)
{
      INT               i, j;
      CHAR        DeltaPwr = 0;
      BOOLEAN           bAutoTxAgc = FALSE;
      UCHAR       TssiRef, *pTssiMinusBoundary, *pTssiPlusBoundary, TxAgcStep;
      UCHAR       BbpR1 = 0, BbpR49 = 0, idx;
      PCHAR       pTxAgcCompensate;
      ULONG       TxPwr[5];
      CHAR        Value;

#ifdef RT2860
      if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)
            || (pAd->bPCIclkOff == TRUE)
            || RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF)
            || RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
            return;
#endif

      if (pAd->CommonCfg.BBPCurrentBW == BW_40)
      {
            if (pAd->CommonCfg.CentralChannel > 14)
            {
                  TxPwr[0] = pAd->Tx40MPwrCfgABand[0];
                  TxPwr[1] = pAd->Tx40MPwrCfgABand[1];
                  TxPwr[2] = pAd->Tx40MPwrCfgABand[2];
                  TxPwr[3] = pAd->Tx40MPwrCfgABand[3];
                  TxPwr[4] = pAd->Tx40MPwrCfgABand[4];
            }
            else
            {
                  TxPwr[0] = pAd->Tx40MPwrCfgGBand[0];
                  TxPwr[1] = pAd->Tx40MPwrCfgGBand[1];
                  TxPwr[2] = pAd->Tx40MPwrCfgGBand[2];
                  TxPwr[3] = pAd->Tx40MPwrCfgGBand[3];
                  TxPwr[4] = pAd->Tx40MPwrCfgGBand[4];
            }
      }
      else
      {
            if (pAd->CommonCfg.Channel > 14)
            {
                  TxPwr[0] = pAd->Tx20MPwrCfgABand[0];
                  TxPwr[1] = pAd->Tx20MPwrCfgABand[1];
                  TxPwr[2] = pAd->Tx20MPwrCfgABand[2];
                  TxPwr[3] = pAd->Tx20MPwrCfgABand[3];
                  TxPwr[4] = pAd->Tx20MPwrCfgABand[4];
            }
            else
            {
                  TxPwr[0] = pAd->Tx20MPwrCfgGBand[0];
                  TxPwr[1] = pAd->Tx20MPwrCfgGBand[1];
                  TxPwr[2] = pAd->Tx20MPwrCfgGBand[2];
                  TxPwr[3] = pAd->Tx20MPwrCfgGBand[3];
                  TxPwr[4] = pAd->Tx20MPwrCfgGBand[4];
            }
      }

      // TX power compensation for temperature variation based on TSSI. try every 4 second
      if (pAd->Mlme.OneSecPeriodicRound % 4 == 0)
      {
            if (pAd->CommonCfg.Channel <= 14)
            {
                  /* bg channel */
                  bAutoTxAgc         = pAd->bAutoTxAgcG;
                  TssiRef            = pAd->TssiRefG;
                  pTssiMinusBoundary = &pAd->TssiMinusBoundaryG[0];
                  pTssiPlusBoundary  = &pAd->TssiPlusBoundaryG[0];
                  TxAgcStep          = pAd->TxAgcStepG;
                  pTxAgcCompensate   = &pAd->TxAgcCompensateG;
            }
            else
            {
                  /* a channel */
                  bAutoTxAgc         = pAd->bAutoTxAgcA;
                  TssiRef            = pAd->TssiRefA;
                  pTssiMinusBoundary = &pAd->TssiMinusBoundaryA[0];
                  pTssiPlusBoundary  = &pAd->TssiPlusBoundaryA[0];
                  TxAgcStep          = pAd->TxAgcStepA;
                  pTxAgcCompensate   = &pAd->TxAgcCompensateA;
            }

            if (bAutoTxAgc)
            {
                  /* BbpR1 is unsigned char */
                  RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R49, &BbpR49);

                  /* (p) TssiPlusBoundaryG[0] = 0 = (m) TssiMinusBoundaryG[0] */
                  /* compensate: +4     +3   +2   +1    0   -1   -2   -3   -4 * steps */
                  /* step value is defined in pAd->TxAgcStepG for tx power value */

                  /* [4]+1+[4]   p4     p3   p2   p1   o1   m1   m2   m3   m4 */
                  /* ex:         0x00 0x15 0x25 0x45 0x88 0xA0 0xB5 0xD0 0xF0
                     above value are examined in mass factory production */
                  /*             [4]    [3]  [2]  [1]  [0]  [1]  [2]  [3]  [4] */

                  /* plus (+) is 0x00 ~ 0x45, minus (-) is 0xa0 ~ 0xf0 */
                  /* if value is between p1 ~ o1 or o1 ~ s1, no need to adjust tx power */
                  /* if value is 0xa5, tx power will be -= TxAgcStep*(2-1) */

                  if (BbpR49 > pTssiMinusBoundary[1])
                  {
                        // Reading is larger than the reference value
                        // check for how large we need to decrease the Tx power
                        for (idx = 1; idx < 5; idx++)
                        {
                              if (BbpR49 <= pTssiMinusBoundary[idx])  // Found the range
                                    break;
                        }
                        // The index is the step we should decrease, idx = 0 means there is nothing to compensate
                        *pTxAgcCompensate = -(TxAgcStep * (idx-1));

                        DeltaPwr += (*pTxAgcCompensate);
                        DBGPRINT(RT_DEBUG_TRACE, ("-- Tx Power, BBP R1=%x, TssiRef=%x, TxAgcStep=%x, step = -%d\n",
                              BbpR49, TssiRef, TxAgcStep, idx-1));
                  }
                  else if (BbpR49 < pTssiPlusBoundary[1])
                  {
                        // Reading is smaller than the reference value
                        // check for how large we need to increase the Tx power
                        for (idx = 1; idx < 5; idx++)
                        {
                              if (BbpR49 >= pTssiPlusBoundary[idx])   // Found the range
                                    break;
                        }
                        // The index is the step we should increase, idx = 0 means there is nothing to compensate
                        *pTxAgcCompensate = TxAgcStep * (idx-1);
                        DeltaPwr += (*pTxAgcCompensate);
                        DBGPRINT(RT_DEBUG_TRACE, ("++ Tx Power, BBP R1=%x, TssiRef=%x, TxAgcStep=%x, step = +%d\n",
                              BbpR49, TssiRef, TxAgcStep, idx-1));
                  }
                  else
                  {
                        *pTxAgcCompensate = 0;
                        DBGPRINT(RT_DEBUG_TRACE, ("   Tx Power, BBP R49=%x, TssiRef=%x, TxAgcStep=%x, step = +%d\n",
                              BbpR49, TssiRef, TxAgcStep, 0));
                  }
            }
      }
      else
      {
            if (pAd->CommonCfg.Channel <= 14)
            {
                  bAutoTxAgc         = pAd->bAutoTxAgcG;
                  pTxAgcCompensate   = &pAd->TxAgcCompensateG;
            }
            else
            {
                  bAutoTxAgc         = pAd->bAutoTxAgcA;
                  pTxAgcCompensate   = &pAd->TxAgcCompensateA;
            }

            if (bAutoTxAgc)
                  DeltaPwr += (*pTxAgcCompensate);
      }

      RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &BbpR1);
      BbpR1 &= 0xFC;

      /* calculate delta power based on the percentage specified from UI */
      // E2PROM setting is calibrated for maximum TX power (i.e. 100%)
      // We lower TX power here according to the percentage specified from UI
      if (pAd->CommonCfg.TxPowerPercentage == 0xffffffff)       // AUTO TX POWER control
            ;
      else if (pAd->CommonCfg.TxPowerPercentage > 90)  // 91 ~ 100% & AUTO, treat as 100% in terms of mW
            ;
      else if (pAd->CommonCfg.TxPowerPercentage > 60)  // 61 ~ 90%, treat as 75% in terms of mW       // DeltaPwr -= 1;
      {
            DeltaPwr -= 1;
      }
      else if (pAd->CommonCfg.TxPowerPercentage > 30)  // 31 ~ 60%, treat as 50% in terms of mW       // DeltaPwr -= 3;
      {
            DeltaPwr -= 3;
      }
      else if (pAd->CommonCfg.TxPowerPercentage > 15)  // 16 ~ 30%, treat as 25% in terms of mW       // DeltaPwr -= 6;
      {
            BbpR1 |= 0x01;
      }
      else if (pAd->CommonCfg.TxPowerPercentage > 9)   // 10 ~ 15%, treat as 12.5% in terms of mW           // DeltaPwr -= 9;
      {
            BbpR1 |= 0x01;
            DeltaPwr -= 3;
      }
      else                                           // 0 ~ 9 %, treat as MIN(~3%) in terms of mW           // DeltaPwr -= 12;
      {
            BbpR1 |= 0x02;
      }

      RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, BbpR1);

      /* reset different new tx power for different TX rate */
      for(i=0; i<5; i++)
      {
            if (TxPwr[i] != 0xffffffff)
            {
                  for (j=0; j<8; j++)
                  {
                        Value = (CHAR)((TxPwr[i] >> j*4) & 0x0F); /* 0 ~ 15 */

                        if ((Value + DeltaPwr) < 0)
                        {
                              Value = 0; /* min */
                        }
                        else if ((Value + DeltaPwr) > 0xF)
                        {
                              Value = 0xF; /* max */
                        }
                        else
                        {
                              Value += DeltaPwr; /* temperature compensation */
                        }

                        /* fill new value to CSR offset */
                        TxPwr[i] = (TxPwr[i] & ~(0x0000000F << j*4)) | (Value << j*4);
                  }

                  /* write tx power value to CSR */
                  /* TX_PWR_CFG_0 (8 tx rate) for     TX power for OFDM 12M/18M
                                                                  TX power for OFDM 6M/9M
                                                                  TX power for CCK5.5M/11M
                                                                  TX power for CCK1M/2M */
                  /* TX_PWR_CFG_1 ~ TX_PWR_CFG_4 */
                  RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, TxPwr[i]);
            }
      }

}

/*
      ==========================================================================
      Description:
            put PHY to sleep here, and set next wakeup timer. PHY doesn't not wakeup
            automatically. Instead, MCU will issue a TwakeUpInterrupt to host after
            the wakeup timer timeout. Driver has to issue a separate command to wake
            PHY up.

      IRQL = DISPATCH_LEVEL

      ==========================================================================
 */
VOID AsicSleepThenAutoWakeup(
      IN PRTMP_ADAPTER pAd,
      IN USHORT TbttNumToNextWakeUp)
{
    RT28XX_STA_SLEEP_THEN_AUTO_WAKEUP(pAd, TbttNumToNextWakeUp);
}

/*
      ==========================================================================
      Description:
            AsicForceWakeup() is used whenever manual wakeup is required
            AsicForceSleep() should only be used when not in INFRA BSS. When
            in INFRA BSS, we should use AsicSleepThenAutoWakeup() instead.
      ==========================================================================
 */
VOID AsicForceSleep(
      IN PRTMP_ADAPTER pAd)
{

}

/*
      ==========================================================================
      Description:
            AsicForceWakeup() is used whenever Twakeup timer (set via AsicSleepThenAutoWakeup)
            expired.

      IRQL = PASSIVE_LEVEL
      IRQL = DISPATCH_LEVEL
      ==========================================================================
 */
VOID AsicForceWakeup(
      IN PRTMP_ADAPTER pAd,
#ifdef RT2860
      IN UCHAR           Level)
#endif
#ifdef RT2870
      IN BOOLEAN    bFromTx)
#endif
{
    DBGPRINT(RT_DEBUG_TRACE, ("--> AsicForceWakeup \n"));
#ifdef RT2860
    RT28XX_STA_FORCE_WAKEUP(pAd, Level);
#endif
#ifdef RT2870
    RT28XX_STA_FORCE_WAKEUP(pAd, bFromTx);
#endif
}

/*
      ==========================================================================
      Description:
            Set My BSSID

      IRQL = DISPATCH_LEVEL

      ==========================================================================
 */
VOID AsicSetBssid(
      IN PRTMP_ADAPTER pAd,
      IN PUCHAR pBssid)
{
      ULONG         Addr4;
      DBGPRINT(RT_DEBUG_TRACE, ("==============> AsicSetBssid %x:%x:%x:%x:%x:%x\n",
            pBssid[0],pBssid[1],pBssid[2],pBssid[3], pBssid[4],pBssid[5]));

      Addr4 = (ULONG)(pBssid[0])           |
                  (ULONG)(pBssid[1] << 8)  |
                  (ULONG)(pBssid[2] << 16) |
                  (ULONG)(pBssid[3] << 24);
      RTMP_IO_WRITE32(pAd, MAC_BSSID_DW0, Addr4);

      Addr4 = 0;
      // always one BSSID in STA mode
      Addr4 = (ULONG)(pBssid[4]) | (ULONG)(pBssid[5] << 8);

      RTMP_IO_WRITE32(pAd, MAC_BSSID_DW1, Addr4);
}

VOID AsicSetMcastWC(
      IN PRTMP_ADAPTER pAd)
{
      MAC_TABLE_ENTRY *pEntry = &pAd->MacTab.Content[MCAST_WCID];
      USHORT            offset;

      pEntry->Sst        = SST_ASSOC;
      pEntry->Aid        = MCAST_WCID;    // Softap supports 1 BSSID and use WCID=0 as multicast Wcid index
      pEntry->PsMode     = PWR_ACTIVE;
      pEntry->CurrTxRate = pAd->CommonCfg.MlmeRate;
      offset = MAC_WCID_BASE + BSS0Mcast_WCID * HW_WCID_ENTRY_SIZE;
}

/*
      ==========================================================================
      Description:

      IRQL = DISPATCH_LEVEL

      ==========================================================================
 */
VOID AsicDelWcidTab(
      IN PRTMP_ADAPTER pAd,
      IN UCHAR    Wcid)
{
      ULONG         Addr0 = 0x0, Addr1 = 0x0;
      ULONG             offset;

      DBGPRINT(RT_DEBUG_TRACE, ("AsicDelWcidTab==>Wcid = 0x%x\n",Wcid));
      offset = MAC_WCID_BASE + Wcid * HW_WCID_ENTRY_SIZE;
      RTMP_IO_WRITE32(pAd, offset, Addr0);
      offset += 4;
      RTMP_IO_WRITE32(pAd, offset, Addr1);
}

/*
      ==========================================================================
      Description:

      IRQL = DISPATCH_LEVEL

      ==========================================================================
 */
VOID AsicEnableRDG(
      IN PRTMP_ADAPTER pAd)
{
      TX_LINK_CFG_STRUC TxLinkCfg;
      UINT32                        Data = 0;

      RTMP_IO_READ32(pAd, TX_LINK_CFG, &TxLinkCfg.word);
      TxLinkCfg.field.TxRDGEn = 1;
      RTMP_IO_WRITE32(pAd, TX_LINK_CFG, TxLinkCfg.word);

      RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &Data);
      Data  &= 0xFFFFFF00;
      Data  |= 0x80;
      RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Data);

      //OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED);
}

/*
      ==========================================================================
      Description:

      IRQL = DISPATCH_LEVEL

      ==========================================================================
 */
VOID AsicDisableRDG(
      IN PRTMP_ADAPTER pAd)
{
      TX_LINK_CFG_STRUC TxLinkCfg;
      UINT32                        Data = 0;


      RTMP_IO_READ32(pAd, TX_LINK_CFG, &TxLinkCfg.word);
      TxLinkCfg.field.TxRDGEn = 0;
      RTMP_IO_WRITE32(pAd, TX_LINK_CFG, TxLinkCfg.word);

      RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &Data);

      Data  &= 0xFFFFFF00;
      if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_DYNAMIC_BE_TXOP_ACTIVE)
            && (pAd->MacTab.fAnyStationMIMOPSDynamic == FALSE)
      )
      {
            // For CWC test, change txop from 0x30 to 0x20 in TxBurst mode
            if (pAd->CommonCfg.bEnableTxBurst)
                  Data |= 0x20;
      }
      RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Data);
}

/*
      ==========================================================================
      Description:

      IRQL = PASSIVE_LEVEL
      IRQL = DISPATCH_LEVEL

      ==========================================================================
 */
VOID AsicDisableSync(
      IN PRTMP_ADAPTER pAd)
{
      BCN_TIME_CFG_STRUC csr;

      DBGPRINT(RT_DEBUG_TRACE, ("--->Disable TSF synchronization\n"));

      // 2003-12-20 disable TSF and TBTT while NIC in power-saving have side effect
      //                  that NIC will never wakes up because TSF stops and no more
      //                  TBTT interrupts
      pAd->TbttTickCount = 0;
      RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr.word);
      csr.field.bBeaconGen = 0;
      csr.field.bTBTTEnable = 0;
      csr.field.TsfSyncMode = 0;
      csr.field.bTsfTicking = 0;
      RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr.word);

}

/*
      ==========================================================================
      Description:

      IRQL = DISPATCH_LEVEL

      ==========================================================================
 */
VOID AsicEnableBssSync(
      IN PRTMP_ADAPTER pAd)
{
      BCN_TIME_CFG_STRUC csr;

      DBGPRINT(RT_DEBUG_TRACE, ("--->AsicEnableBssSync(INFRA mode)\n"));

      RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr.word);

      {
            csr.field.BeaconInterval = pAd->CommonCfg.BeaconPeriod << 4; // ASIC register in units of 1/16 TU
            csr.field.bTsfTicking = 1;
            csr.field.TsfSyncMode = 1; // sync TSF in INFRASTRUCTURE mode
            csr.field.bBeaconGen  = 0; // do NOT generate BEACON
            csr.field.bTBTTEnable = 1;
      }

      RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr.word);
}

/*
      ==========================================================================
      Description:
      Note:
            BEACON frame in shared memory should be built ok before this routine
            can be called. Otherwise, a garbage frame maybe transmitted out every
            Beacon period.

      IRQL = DISPATCH_LEVEL

      ==========================================================================
 */
VOID AsicEnableIbssSync(
      IN PRTMP_ADAPTER pAd)
{
      BCN_TIME_CFG_STRUC csr9;
      PUCHAR                  ptr;
      UINT i;

      DBGPRINT(RT_DEBUG_TRACE, ("--->AsicEnableIbssSync(ADHOC mode. MPDUtotalByteCount = %d)\n", pAd->BeaconTxWI.MPDUtotalByteCount));

      RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr9.word);
      csr9.field.bBeaconGen = 0;
      csr9.field.bTBTTEnable = 0;
      csr9.field.bTsfTicking = 0;
      RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr9.word);

#ifdef RT2860
      // move BEACON TXD and frame content to on-chip memory
      ptr = (PUCHAR)&pAd->BeaconTxWI;
      for (i=0; i<TXWI_SIZE; i+=4)  // 16-byte TXWI field
      {
            UINT32 longptr =  *ptr + (*(ptr+1)<<8) + (*(ptr+2)<<16) + (*(ptr+3)<<24);
            RTMP_IO_WRITE32(pAd, HW_BEACON_BASE0 + i, longptr);
            ptr += 4;
      }

      // start right after the 16-byte TXWI field
      ptr = pAd->BeaconBuf;
      for (i=0; i< pAd->BeaconTxWI.MPDUtotalByteCount; i+=4)
      {
            UINT32 longptr =  *ptr + (*(ptr+1)<<8) + (*(ptr+2)<<16) + (*(ptr+3)<<24);
            RTMP_IO_WRITE32(pAd, HW_BEACON_BASE0 + TXWI_SIZE + i, longptr);
            ptr +=4;
      }
#endif
#ifdef RT2870
      // move BEACON TXD and frame content to on-chip memory
      ptr = (PUCHAR)&pAd->BeaconTxWI;
      for (i=0; i<TXWI_SIZE; i+=2)  // 16-byte TXWI field
      {
            RTUSBMultiWrite(pAd, HW_BEACON_BASE0 + i, ptr, 2);
            ptr += 2;
      }

      // start right after the 16-byte TXWI field
      ptr = pAd->BeaconBuf;
      for (i=0; i< pAd->BeaconTxWI.MPDUtotalByteCount; i+=2)
      {
            RTUSBMultiWrite(pAd, HW_BEACON_BASE0 + TXWI_SIZE + i, ptr, 2);
            ptr +=2;
      }
#endif // RT2870 //

      // start sending BEACON
      csr9.field.BeaconInterval = pAd->CommonCfg.BeaconPeriod << 4; // ASIC register in units of 1/16 TU
      csr9.field.bTsfTicking = 1;
      csr9.field.TsfSyncMode = 2; // sync TSF in IBSS mode
      csr9.field.bTBTTEnable = 1;
      csr9.field.bBeaconGen = 1;
      RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr9.word);
}

/*
      ==========================================================================
      Description:

      IRQL = PASSIVE_LEVEL
      IRQL = DISPATCH_LEVEL

      ==========================================================================
 */
VOID AsicSetEdcaParm(
      IN PRTMP_ADAPTER pAd,
      IN PEDCA_PARM      pEdcaParm)
{
      EDCA_AC_CFG_STRUC   Ac0Cfg, Ac1Cfg, Ac2Cfg, Ac3Cfg;
      AC_TXOP_CSR0_STRUC csr0;
      AC_TXOP_CSR1_STRUC csr1;
      AIFSN_CSR_STRUC    AifsnCsr;
      CWMIN_CSR_STRUC    CwminCsr;
      CWMAX_CSR_STRUC    CwmaxCsr;
      int i;

      Ac0Cfg.word = 0;
      Ac1Cfg.word = 0;
      Ac2Cfg.word = 0;
      Ac3Cfg.word = 0;
      if ((pEdcaParm == NULL) || (pEdcaParm->bValid == FALSE))
      {
            DBGPRINT(RT_DEBUG_TRACE,("AsicSetEdcaParm\n"));
            OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_WMM_INUSED);
            for (i=0; i<MAX_LEN_OF_MAC_TABLE; i++)
            {
                  if (pAd->MacTab.Content[i].ValidAsCLI || pAd->MacTab.Content[i].ValidAsApCli)
                        CLIENT_STATUS_CLEAR_FLAG(&pAd->MacTab.Content[i], fCLIENT_STATUS_WMM_CAPABLE);
            }

            //========================================================
            //      MAC Register has a copy .
            //========================================================
            if( pAd->CommonCfg.bEnableTxBurst )
            {
                  // For CWC test, change txop from 0x30 to 0x20 in TxBurst mode
                  Ac0Cfg.field.AcTxop = 0x20; // Suggest by John for TxBurst in HT Mode
            }
            else
                  Ac0Cfg.field.AcTxop = 0;      // QID_AC_BE
            Ac0Cfg.field.Cwmin = CW_MIN_IN_BITS;
            Ac0Cfg.field.Cwmax = CW_MAX_IN_BITS;
            Ac0Cfg.field.Aifsn = 2;
            RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Ac0Cfg.word);

            Ac1Cfg.field.AcTxop = 0;      // QID_AC_BK
            Ac1Cfg.field.Cwmin = CW_MIN_IN_BITS;
            Ac1Cfg.field.Cwmax = CW_MAX_IN_BITS;
            Ac1Cfg.field.Aifsn = 2;
            RTMP_IO_WRITE32(pAd, EDCA_AC1_CFG, Ac1Cfg.word);

            if (pAd->CommonCfg.PhyMode == PHY_11B)
            {
                  Ac2Cfg.field.AcTxop = 192;    // AC_VI: 192*32us ~= 6ms
                  Ac3Cfg.field.AcTxop = 96;     // AC_VO: 96*32us  ~= 3ms
            }
            else
            {
                  Ac2Cfg.field.AcTxop = 96;     // AC_VI: 96*32us ~= 3ms
                  Ac3Cfg.field.AcTxop = 48;     // AC_VO: 48*32us ~= 1.5ms
            }
            Ac2Cfg.field.Cwmin = CW_MIN_IN_BITS;
            Ac2Cfg.field.Cwmax = CW_MAX_IN_BITS;
            Ac2Cfg.field.Aifsn = 2;
            RTMP_IO_WRITE32(pAd, EDCA_AC2_CFG, Ac2Cfg.word);
            Ac3Cfg.field.Cwmin = CW_MIN_IN_BITS;
            Ac3Cfg.field.Cwmax = CW_MAX_IN_BITS;
            Ac3Cfg.field.Aifsn = 2;
            RTMP_IO_WRITE32(pAd, EDCA_AC3_CFG, Ac3Cfg.word);

            //========================================================
            //      DMA Register has a copy too.
            //========================================================
            csr0.field.Ac0Txop = 0;       // QID_AC_BE
            csr0.field.Ac1Txop = 0;       // QID_AC_BK
            RTMP_IO_WRITE32(pAd, WMM_TXOP0_CFG, csr0.word);
            if (pAd->CommonCfg.PhyMode == PHY_11B)
            {
                  csr1.field.Ac2Txop = 192;           // AC_VI: 192*32us ~= 6ms
                  csr1.field.Ac3Txop = 96;            // AC_VO: 96*32us  ~= 3ms
            }
            else
            {
                  csr1.field.Ac2Txop = 96;            // AC_VI: 96*32us ~= 3ms
                  csr1.field.Ac3Txop = 48;            // AC_VO: 48*32us ~= 1.5ms
            }
            RTMP_IO_WRITE32(pAd, WMM_TXOP1_CFG, csr1.word);

            CwminCsr.word = 0;
            CwminCsr.field.Cwmin0 = CW_MIN_IN_BITS;
            CwminCsr.field.Cwmin1 = CW_MIN_IN_BITS;
            CwminCsr.field.Cwmin2 = CW_MIN_IN_BITS;
            CwminCsr.field.Cwmin3 = CW_MIN_IN_BITS;
            RTMP_IO_WRITE32(pAd, WMM_CWMIN_CFG, CwminCsr.word);

            CwmaxCsr.word = 0;
            CwmaxCsr.field.Cwmax0 = CW_MAX_IN_BITS;
            CwmaxCsr.field.Cwmax1 = CW_MAX_IN_BITS;
            CwmaxCsr.field.Cwmax2 = CW_MAX_IN_BITS;
            CwmaxCsr.field.Cwmax3 = CW_MAX_IN_BITS;
            RTMP_IO_WRITE32(pAd, WMM_CWMAX_CFG, CwmaxCsr.word);

            RTMP_IO_WRITE32(pAd, WMM_AIFSN_CFG, 0x00002222);

            NdisZeroMemory(&pAd->CommonCfg.APEdcaParm, sizeof(EDCA_PARM));
      }
      else
      {
            OPSTATUS_SET_FLAG(pAd, fOP_STATUS_WMM_INUSED);
            //========================================================
            //      MAC Register has a copy.
            //========================================================
            //
            // Modify Cwmin/Cwmax/Txop on queue[QID_AC_VI], Recommend by Jerry 2005/07/27
            // To degrade our VIDO Queue's throughput for WiFi WMM S3T07 Issue.
            //
            //pEdcaParm->Txop[QID_AC_VI] = pEdcaParm->Txop[QID_AC_VI] * 7 / 10; // rt2860c need this

            Ac0Cfg.field.AcTxop =  pEdcaParm->Txop[QID_AC_BE];
            Ac0Cfg.field.Cwmin= pEdcaParm->Cwmin[QID_AC_BE];
            Ac0Cfg.field.Cwmax = pEdcaParm->Cwmax[QID_AC_BE];
            Ac0Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_BE]; //+1;

            Ac1Cfg.field.AcTxop =  pEdcaParm->Txop[QID_AC_BK];
            Ac1Cfg.field.Cwmin = pEdcaParm->Cwmin[QID_AC_BK]; //+2;
            Ac1Cfg.field.Cwmax = pEdcaParm->Cwmax[QID_AC_BK];
            Ac1Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_BK]; //+1;

            Ac2Cfg.field.AcTxop = (pEdcaParm->Txop[QID_AC_VI] * 6) / 10;
            Ac2Cfg.field.Cwmin = pEdcaParm->Cwmin[QID_AC_VI];
            Ac2Cfg.field.Cwmax = pEdcaParm->Cwmax[QID_AC_VI];
            Ac2Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_VI];

            {
                  // Tuning for Wi-Fi WMM S06
                  if (pAd->CommonCfg.bWiFiTest &&
                        pEdcaParm->Aifsn[QID_AC_VI] == 10)
                        Ac2Cfg.field.Aifsn -= 1;

                  // Tuning for TGn Wi-Fi 5.2.32
                  // STA TestBed changes in this item: connexant legacy sta ==> broadcom 11n sta
                  if (STA_TGN_WIFI_ON(pAd) &&
                        pEdcaParm->Aifsn[QID_AC_VI] == 10)
                  {
                        Ac0Cfg.field.Aifsn = 3;
                        Ac2Cfg.field.AcTxop = 5;
                  }

#ifdef RT30xx
                  if (pAd->RfIcType == RFIC_3020 || pAd->RfIcType == RFIC_2020)
                  {
                        // Tuning for WiFi WMM S3-T07: connexant legacy sta ==> broadcom 11n sta.
                        Ac2Cfg.field.Aifsn = 5;
                  }
#endif // RT30xx //
            }

            Ac3Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_VO];
            Ac3Cfg.field.Cwmin = pEdcaParm->Cwmin[QID_AC_VO];
            Ac3Cfg.field.Cwmax = pEdcaParm->Cwmax[QID_AC_VO];
            Ac3Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_VO];

//#ifdef WIFI_TEST
            if (pAd->CommonCfg.bWiFiTest)
            {
                  if (Ac3Cfg.field.AcTxop == 102)
                  {
                  Ac0Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_BE] ? pEdcaParm->Txop[QID_AC_BE] : 10;
                        Ac0Cfg.field.Aifsn  = pEdcaParm->Aifsn[QID_AC_BE]-1; /* AIFSN must >= 1 */
                  Ac1Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_BK];
                        Ac1Cfg.field.Aifsn  = pEdcaParm->Aifsn[QID_AC_BK];
                  Ac2Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_VI];
                  } /* End of if */
            }
//#endif // WIFI_TEST //

            RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Ac0Cfg.word);
            RTMP_IO_WRITE32(pAd, EDCA_AC1_CFG, Ac1Cfg.word);
            RTMP_IO_WRITE32(pAd, EDCA_AC2_CFG, Ac2Cfg.word);
            RTMP_IO_WRITE32(pAd, EDCA_AC3_CFG, Ac3Cfg.word);


            //========================================================
            //      DMA Register has a copy too.
            //========================================================
            csr0.field.Ac0Txop = Ac0Cfg.field.AcTxop;
            csr0.field.Ac1Txop = Ac1Cfg.field.AcTxop;
            RTMP_IO_WRITE32(pAd, WMM_TXOP0_CFG, csr0.word);

            csr1.field.Ac2Txop = Ac2Cfg.field.AcTxop;
            csr1.field.Ac3Txop = Ac3Cfg.field.AcTxop;
            RTMP_IO_WRITE32(pAd, WMM_TXOP1_CFG, csr1.word);

            CwminCsr.word = 0;
            CwminCsr.field.Cwmin0 = pEdcaParm->Cwmin[QID_AC_BE];
            CwminCsr.field.Cwmin1 = pEdcaParm->Cwmin[QID_AC_BK];
            CwminCsr.field.Cwmin2 = pEdcaParm->Cwmin[QID_AC_VI];

            CwminCsr.field.Cwmin3 = pEdcaParm->Cwmin[QID_AC_VO] - 1; //for TGn wifi test

            RTMP_IO_WRITE32(pAd, WMM_CWMIN_CFG, CwminCsr.word);

            CwmaxCsr.word = 0;
            CwmaxCsr.field.Cwmax0 = pEdcaParm->Cwmax[QID_AC_BE];
            CwmaxCsr.field.Cwmax1 = pEdcaParm->Cwmax[QID_AC_BK];
            CwmaxCsr.field.Cwmax2 = pEdcaParm->Cwmax[QID_AC_VI];
            CwmaxCsr.field.Cwmax3 = pEdcaParm->Cwmax[QID_AC_VO];
            RTMP_IO_WRITE32(pAd, WMM_CWMAX_CFG, CwmaxCsr.word);

            AifsnCsr.word = 0;
            AifsnCsr.field.Aifsn0 = Ac0Cfg.field.Aifsn; //pEdcaParm->Aifsn[QID_AC_BE];
            AifsnCsr.field.Aifsn1 = Ac1Cfg.field.Aifsn; //pEdcaParm->Aifsn[QID_AC_BK];
            AifsnCsr.field.Aifsn2 = Ac2Cfg.field.Aifsn; //pEdcaParm->Aifsn[QID_AC_VI];

            {
                  // Tuning for Wi-Fi WMM S06
                  if (pAd->CommonCfg.bWiFiTest &&
                        pEdcaParm->Aifsn[QID_AC_VI] == 10)
                        AifsnCsr.field.Aifsn2 = Ac2Cfg.field.Aifsn - 4;

                  // Tuning for TGn Wi-Fi 5.2.32
                  // STA TestBed changes in this item: connexant legacy sta ==> broadcom 11n sta
                  if (STA_TGN_WIFI_ON(pAd) &&
                        pEdcaParm->Aifsn[QID_AC_VI] == 10)
                  {
                        AifsnCsr.field.Aifsn0 = 3;
                        AifsnCsr.field.Aifsn2 = 7;
                  }
#ifdef RT2870
                  if (INFRA_ON(pAd))
                        CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[BSSID_WCID], fCLIENT_STATUS_WMM_CAPABLE);
#endif
            }

            AifsnCsr.field.Aifsn3 = Ac3Cfg.field.Aifsn - 1; //pEdcaParm->Aifsn[QID_AC_VO]; //for TGn wifi test
#ifdef RT30xx
            if (pAd->RfIcType == RFIC_3020 || pAd->RfIcType == RFIC_2020)
                  AifsnCsr.field.Aifsn2 = 0x2; //pEdcaParm->Aifsn[QID_AC_VI]; //for WiFi WMM S4-T04.
#endif // RT30xx //

            RTMP_IO_WRITE32(pAd, WMM_AIFSN_CFG, AifsnCsr.word);

            NdisMoveMemory(&pAd->CommonCfg.APEdcaParm, pEdcaParm, sizeof(EDCA_PARM));
            if (!ADHOC_ON(pAd))
            {
                  DBGPRINT(RT_DEBUG_TRACE,("EDCA [#%d]: AIFSN CWmin CWmax  TXOP(us)  ACM\n", pEdcaParm->EdcaUpdateCount));
                  DBGPRINT(RT_DEBUG_TRACE,("     AC_BE      %2d     %2d     %2d      %4d     %d\n",
                                                       pEdcaParm->Aifsn[0],
                                                       pEdcaParm->Cwmin[0],
                                                       pEdcaParm->Cwmax[0],
                                                       pEdcaParm->Txop[0]<<5,
                                                       pEdcaParm->bACM[0]));
                  DBGPRINT(RT_DEBUG_TRACE,("     AC_BK      %2d     %2d     %2d      %4d     %d\n",
                                                       pEdcaParm->Aifsn[1],
                                                       pEdcaParm->Cwmin[1],
                                                       pEdcaParm->Cwmax[1],
                                                       pEdcaParm->Txop[1]<<5,
                                                       pEdcaParm->bACM[1]));
                  DBGPRINT(RT_DEBUG_TRACE,("     AC_VI      %2d     %2d     %2d      %4d     %d\n",
                                                       pEdcaParm->Aifsn[2],
                                                       pEdcaParm->Cwmin[2],
                                                       pEdcaParm->Cwmax[2],
                                                       pEdcaParm->Txop[2]<<5,
                                                       pEdcaParm->bACM[2]));
                  DBGPRINT(RT_DEBUG_TRACE,("     AC_VO      %2d     %2d     %2d      %4d     %d\n",
                                                       pEdcaParm->Aifsn[3],
                                                       pEdcaParm->Cwmin[3],
                                                       pEdcaParm->Cwmax[3],
                                                       pEdcaParm->Txop[3]<<5,
                                                       pEdcaParm->bACM[3]));
            }
      }
}

/*
      ==========================================================================
      Description:

      IRQL = PASSIVE_LEVEL
      IRQL = DISPATCH_LEVEL

      ==========================================================================
 */
VOID  AsicSetSlotTime(
      IN PRTMP_ADAPTER pAd,
      IN BOOLEAN bUseShortSlotTime)
{
      ULONG SlotTime;
      UINT32      RegValue = 0;

      if (pAd->CommonCfg.Channel > 14)
            bUseShortSlotTime = TRUE;

      if (bUseShortSlotTime)
            OPSTATUS_SET_FLAG(pAd, fOP_STATUS_SHORT_SLOT_INUSED);
      else
            OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_SLOT_INUSED);

      SlotTime = (bUseShortSlotTime)? 9 : 20;

      {
#ifndef RT30xx
            // force using short SLOT time for FAE to demo performance when TxBurst is ON
            if (((pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE) && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED)))
                  || ((pAd->StaActive.SupportedPhyInfo.bHtEnable == TRUE) && (pAd->CommonCfg.BACapability.field.Policy == BA_NOTUSE))
                  )
            {
                  // In this case, we will think it is doing Wi-Fi test
                  // And we will not set to short slot when bEnableTxBurst is TRUE.
            }
            else if (pAd->CommonCfg.bEnableTxBurst)
#endif
#ifdef RT30xx
            if (pAd->CommonCfg.bEnableTxBurst)
#endif
                  SlotTime = 9;
      }

      //
      // For some reasons, always set it to short slot time.
      //
      // ToDo: Should consider capability with 11B
      //
      if (pAd->StaCfg.BssType == BSS_ADHOC)
            SlotTime = 20;

      RTMP_IO_READ32(pAd, BKOFF_SLOT_CFG, &RegValue);
      RegValue = RegValue & 0xFFFFFF00;

      RegValue |= SlotTime;

      RTMP_IO_WRITE32(pAd, BKOFF_SLOT_CFG, RegValue);
}

/*
      ========================================================================
      Description:
            Add Shared key information into ASIC.
            Update shared key, TxMic and RxMic to Asic Shared key table
            Update its cipherAlg to Asic Shared key Mode.

    Return:
      ========================================================================
*/
VOID AsicAddSharedKeyEntry(
      IN PRTMP_ADAPTER pAd,
      IN UCHAR           BssIndex,
      IN UCHAR           KeyIdx,
      IN UCHAR           CipherAlg,
      IN PUCHAR          pKey,
      IN PUCHAR          pTxMic,
      IN PUCHAR          pRxMic)
{
      ULONG offset; //, csr0;
      SHAREDKEY_MODE_STRUC csr1;
#ifdef RT2860
      INT   i;
#endif

      DBGPRINT(RT_DEBUG_TRACE, ("AsicAddSharedKeyEntry BssIndex=%d, KeyIdx=%d\n", BssIndex,KeyIdx));
//============================================================================================

      DBGPRINT(RT_DEBUG_TRACE,("AsicAddSharedKeyEntry: %s key #%d\n", CipherName[CipherAlg], BssIndex*4 + KeyIdx));
      DBGPRINT_RAW(RT_DEBUG_TRACE, ("     Key = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
            pKey[0],pKey[1],pKey[2],pKey[3],pKey[4],pKey[5],pKey[6],pKey[7],pKey[8],pKey[9],pKey[10],pKey[11],pKey[12],pKey[13],pKey[14],pKey[15]));
      if (pRxMic)
      {
            DBGPRINT_RAW(RT_DEBUG_TRACE, ("     Rx MIC Key = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
                  pRxMic[0],pRxMic[1],pRxMic[2],pRxMic[3],pRxMic[4],pRxMic[5],pRxMic[6],pRxMic[7]));
      }
      if (pTxMic)
      {
            DBGPRINT_RAW(RT_DEBUG_TRACE, ("     Tx MIC Key = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
                  pTxMic[0],pTxMic[1],pTxMic[2],pTxMic[3],pTxMic[4],pTxMic[5],pTxMic[6],pTxMic[7]));
      }
//============================================================================================
      //
      // fill key material - key + TX MIC + RX MIC
      //

      offset = SHARED_KEY_TABLE_BASE + (4*BssIndex + KeyIdx)*HW_KEY_ENTRY_SIZE;
#ifdef RT2860
      for (i=0; i<MAX_LEN_OF_SHARE_KEY; i++)
      {
            RTMP_IO_WRITE8(pAd, offset + i, pKey[i]);
      }
#endif
#ifdef RT2870
      RTUSBMultiWrite(pAd, offset, pKey, MAX_LEN_OF_SHARE_KEY);
#endif
      offset += MAX_LEN_OF_SHARE_KEY;
      if (pTxMic)
      {
#ifdef RT2860
            for (i=0; i<8; i++)
            {
                  RTMP_IO_WRITE8(pAd, offset + i, pTxMic[i]);
            }
#endif
#ifdef RT2870
            RTUSBMultiWrite(pAd, offset, pTxMic, 8);
#endif
      }

      offset += 8;
      if (pRxMic)
      {
#ifdef RT2860
            for (i=0; i<8; i++)
            {
                  RTMP_IO_WRITE8(pAd, offset + i, pRxMic[i]);
            }
#endif
#ifdef RT2870
            RTUSBMultiWrite(pAd, offset, pRxMic, 8);
#endif
      }


      //
      // Update cipher algorithm. WSTA always use BSS0
      //
      RTMP_IO_READ32(pAd, SHARED_KEY_MODE_BASE+4*(BssIndex/2), &csr1.word);
      DBGPRINT(RT_DEBUG_TRACE,("Read: SHARED_KEY_MODE_BASE at this Bss[%d] KeyIdx[%d]= 0x%x \n", BssIndex,KeyIdx, csr1.word));
      if ((BssIndex%2) == 0)
      {
            if (KeyIdx == 0)
                  csr1.field.Bss0Key0CipherAlg = CipherAlg;
            else if (KeyIdx == 1)
                  csr1.field.Bss0Key1CipherAlg = CipherAlg;
            else if (KeyIdx == 2)
                  csr1.field.Bss0Key2CipherAlg = CipherAlg;
            else
                  csr1.field.Bss0Key3CipherAlg = CipherAlg;
      }
      else
      {
            if (KeyIdx == 0)
                  csr1.field.Bss1Key0CipherAlg = CipherAlg;
            else if (KeyIdx == 1)
                  csr1.field.Bss1Key1CipherAlg = CipherAlg;
            else if (KeyIdx == 2)
                  csr1.field.Bss1Key2CipherAlg = CipherAlg;
            else
                  csr1.field.Bss1Key3CipherAlg = CipherAlg;
      }
      DBGPRINT(RT_DEBUG_TRACE,("Write: SHARED_KEY_MODE_BASE at this Bss[%d] = 0x%x \n", BssIndex, csr1.word));
      RTMP_IO_WRITE32(pAd, SHARED_KEY_MODE_BASE+4*(BssIndex/2), csr1.word);

}

//    IRQL = DISPATCH_LEVEL
VOID AsicRemoveSharedKeyEntry(
      IN PRTMP_ADAPTER pAd,
      IN UCHAR           BssIndex,
      IN UCHAR           KeyIdx)
{
      //ULONG SecCsr0;
      SHAREDKEY_MODE_STRUC csr1;

      DBGPRINT(RT_DEBUG_TRACE,("AsicRemoveSharedKeyEntry: #%d \n", BssIndex*4 + KeyIdx));

      RTMP_IO_READ32(pAd, SHARED_KEY_MODE_BASE+4*(BssIndex/2), &csr1.word);
      if ((BssIndex%2) == 0)
      {
            if (KeyIdx == 0)
                  csr1.field.Bss0Key0CipherAlg = 0;
            else if (KeyIdx == 1)
                  csr1.field.Bss0Key1CipherAlg = 0;
            else if (KeyIdx == 2)
                  csr1.field.Bss0Key2CipherAlg = 0;
            else
                  csr1.field.Bss0Key3CipherAlg = 0;
      }
      else
      {
            if (KeyIdx == 0)
                  csr1.field.Bss1Key0CipherAlg = 0;
            else if (KeyIdx == 1)
                  csr1.field.Bss1Key1CipherAlg = 0;
            else if (KeyIdx == 2)
                  csr1.field.Bss1Key2CipherAlg = 0;
            else
                  csr1.field.Bss1Key3CipherAlg = 0;
      }
      DBGPRINT(RT_DEBUG_TRACE,("Write: SHARED_KEY_MODE_BASE at this Bss[%d] = 0x%x \n", BssIndex, csr1.word));
      RTMP_IO_WRITE32(pAd, SHARED_KEY_MODE_BASE+4*(BssIndex/2), csr1.word);
      ASSERT(BssIndex < 4);
      ASSERT(KeyIdx < 4);

}


VOID AsicUpdateWCIDAttribute(
      IN PRTMP_ADAPTER pAd,
      IN USHORT         WCID,
      IN UCHAR          BssIndex,
      IN UCHAR        CipherAlg,
      IN BOOLEAN        bUsePairewiseKeyTable)
{
      ULONG   WCIDAttri = 0, offset;

      //
      // Update WCID attribute.
      // Only TxKey could update WCID attribute.
      //
      offset = MAC_WCID_ATTRIBUTE_BASE + (WCID * HW_WCID_ATTRI_SIZE);
      WCIDAttri = (BssIndex << 4) | (CipherAlg << 1) | (bUsePairewiseKeyTable);
      RTMP_IO_WRITE32(pAd, offset, WCIDAttri);
}

VOID AsicUpdateWCIDIVEIV(
      IN PRTMP_ADAPTER pAd,
      IN USHORT         WCID,
      IN ULONG        uIV,
      IN ULONG        uEIV)
{
      ULONG offset;

      offset = MAC_IVEIV_TABLE_BASE + (WCID * HW_IVEIV_ENTRY_SIZE);

      RTMP_IO_WRITE32(pAd, offset, uIV);
      RTMP_IO_WRITE32(pAd, offset + 4, uEIV);
}

VOID AsicUpdateRxWCIDTable(
      IN PRTMP_ADAPTER pAd,
      IN USHORT         WCID,
      IN PUCHAR        pAddr)
{
      ULONG offset;
      ULONG Addr;

      offset = MAC_WCID_BASE + (WCID * HW_WCID_ENTRY_SIZE);
      Addr = pAddr[0] + (pAddr[1] << 8) +(pAddr[2] << 16) +(pAddr[3] << 24);
      RTMP_IO_WRITE32(pAd, offset, Addr);
      Addr = pAddr[4] + (pAddr[5] << 8);
      RTMP_IO_WRITE32(pAd, offset + 4, Addr);
}


/*
    ========================================================================

    Routine Description:
        Set Cipher Key, Cipher algorithm, IV/EIV to Asic

    Arguments:
        pAd                     Pointer to our adapter
        WCID                    WCID Entry number.
        BssIndex                BSSID index, station or none multiple BSSID support
                                this value should be 0.
        KeyIdx                  This KeyIdx will set to IV's KeyID if bTxKey enabled
        pCipherKey              Pointer to Cipher Key.
        bUsePairewiseKeyTable   TRUE means saved the key in SharedKey table,
                                otherwise PairewiseKey table
        bTxKey                  This is the transmit key if enabled.

    Return Value:
        None

    Note:
        This routine will set the relative key stuff to Asic including WCID attribute,
        Cipher Key, Cipher algorithm and IV/EIV.

        IV/EIV will be update if this CipherKey is the transmission key because
        ASIC will base on IV's KeyID value to select Cipher Key.

        If bTxKey sets to FALSE, this is not the TX key, but it could be
        RX key

      For AP mode bTxKey must be always set to TRUE.
    ========================================================================
*/
VOID AsicAddKeyEntry(
      IN PRTMP_ADAPTER pAd,
      IN USHORT         WCID,
      IN UCHAR          BssIndex,
      IN UCHAR          KeyIdx,
      IN PCIPHER_KEY    pCipherKey,
      IN BOOLEAN        bUsePairewiseKeyTable,
      IN BOOLEAN        bTxKey)
{
      ULONG offset;
      UCHAR IV4 = 0;
      PUCHAR            pKey = pCipherKey->Key;
      PUCHAR            pTxMic = pCipherKey->TxMic;
      PUCHAR            pRxMic = pCipherKey->RxMic;
      PUCHAR            pTxtsc = pCipherKey->TxTsc;
      UCHAR       CipherAlg = pCipherKey->CipherAlg;
      SHAREDKEY_MODE_STRUC csr1;
#ifdef RT2860
      UCHAR       i;
#endif

      DBGPRINT(RT_DEBUG_TRACE, ("==> AsicAddKeyEntry\n"));
      //
      // 1.) decide key table offset
      //
      if (bUsePairewiseKeyTable)
            offset = PAIRWISE_KEY_TABLE_BASE + (WCID * HW_KEY_ENTRY_SIZE);
      else
            offset = SHARED_KEY_TABLE_BASE + (4 * BssIndex + KeyIdx) * HW_KEY_ENTRY_SIZE;

      //
      // 2.) Set Key to Asic
      //
      //for (i = 0; i < KeyLen; i++)
#ifdef RT2860
      for (i = 0; i < MAX_LEN_OF_PEER_KEY; i++)
      {
            RTMP_IO_WRITE8(pAd, offset + i, pKey[i]);
      }
#endif
#ifdef RT2870
      RTUSBMultiWrite(pAd, offset, pKey, MAX_LEN_OF_PEER_KEY);
#endif
      offset += MAX_LEN_OF_PEER_KEY;

      //
      // 3.) Set MIC key if available
      //
      if (pTxMic)
      {
#ifdef RT2860
            for (i = 0; i < 8; i++)
            {
                  RTMP_IO_WRITE8(pAd, offset + i, pTxMic[i]);
            }
#endif
#ifdef RT2870
            RTUSBMultiWrite(pAd, offset, pTxMic, 8);
#endif
      }
      offset += LEN_TKIP_TXMICK;

      if (pRxMic)
      {
#ifdef RT2860
            for (i = 0; i < 8; i++)
            {
                  RTMP_IO_WRITE8(pAd, offset + i, pRxMic[i]);
            }
#endif
#ifdef RT2870
            RTUSBMultiWrite(pAd, offset, pRxMic, 8);
#endif
      }


      //
      // 4.) Modify IV/EIV if needs
      //     This will force Asic to use this key ID by setting IV.
      //
      if (bTxKey)
      {
#ifdef RT2860
            offset = MAC_IVEIV_TABLE_BASE + (WCID * HW_IVEIV_ENTRY_SIZE);
            //
            // Write IV
            //
            RTMP_IO_WRITE8(pAd, offset, pTxtsc[1]);
            RTMP_IO_WRITE8(pAd, offset + 1, ((pTxtsc[1] | 0x20) & 0x7f));
            RTMP_IO_WRITE8(pAd, offset + 2, pTxtsc[0]);

            IV4 = (KeyIdx << 6);
            if ((CipherAlg == CIPHER_TKIP) || (CipherAlg == CIPHER_TKIP_NO_MIC) ||(CipherAlg == CIPHER_AES))
                  IV4 |= 0x20;  // turn on extension bit means EIV existence

            RTMP_IO_WRITE8(pAd, offset + 3, IV4);

            //
            // Write EIV
            //
            offset += 4;
            for (i = 0; i < 4; i++)
            {
                  RTMP_IO_WRITE8(pAd, offset + i, pTxtsc[i + 2]);
            }

#endif
#ifdef RT2870
            UINT32 tmpVal;

            //
            // Write IV
            //
            IV4 = (KeyIdx << 6);
            if ((CipherAlg == CIPHER_TKIP) || (CipherAlg == CIPHER_TKIP_NO_MIC) ||(CipherAlg == CIPHER_AES))
                  IV4 |= 0x20;  // turn on extension bit means EIV existence

            tmpVal = pTxtsc[1] + (((pTxtsc[1] | 0x20) & 0x7f) << 8) + (pTxtsc[0] << 16) + (IV4 << 24);
            RTMP_IO_WRITE32(pAd, offset, tmpVal);

            //
            // Write EIV
            //
            offset += 4;
            RTMP_IO_WRITE32(pAd, offset, *(PUINT32)&pCipherKey->TxTsc[2]);
#endif // RT2870 //
            AsicUpdateWCIDAttribute(pAd, WCID, BssIndex, CipherAlg, bUsePairewiseKeyTable);
      }

      if (!bUsePairewiseKeyTable)
      {
            //
            // Only update the shared key security mode
            //
            RTMP_IO_READ32(pAd, SHARED_KEY_MODE_BASE + 4 * (BssIndex / 2), &csr1.word);
            if ((BssIndex % 2) == 0)
            {
                  if (KeyIdx == 0)
                        csr1.field.Bss0Key0CipherAlg = CipherAlg;
                  else if (KeyIdx == 1)
                        csr1.field.Bss0Key1CipherAlg = CipherAlg;
                  else if (KeyIdx == 2)
                        csr1.field.Bss0Key2CipherAlg = CipherAlg;
                  else
                        csr1.field.Bss0Key3CipherAlg = CipherAlg;
            }
            else
            {
                  if (KeyIdx == 0)
                        csr1.field.Bss1Key0CipherAlg = CipherAlg;
                  else if (KeyIdx == 1)
                        csr1.field.Bss1Key1CipherAlg = CipherAlg;
                  else if (KeyIdx == 2)
                        csr1.field.Bss1Key2CipherAlg = CipherAlg;
                  else
                        csr1.field.Bss1Key3CipherAlg = CipherAlg;
            }
            RTMP_IO_WRITE32(pAd, SHARED_KEY_MODE_BASE + 4 * (BssIndex / 2), csr1.word);
      }

      DBGPRINT(RT_DEBUG_TRACE, ("<== AsicAddKeyEntry\n"));
}


/*
      ========================================================================
      Description:
            Add Pair-wise key material into ASIC.
            Update pairwise key, TxMic and RxMic to Asic Pair-wise key table

    Return:
      ========================================================================
*/
VOID AsicAddPairwiseKeyEntry(
      IN PRTMP_ADAPTER pAd,
      IN PUCHAR        pAddr,
      IN UCHAR          WCID,
      IN CIPHER_KEY            *pCipherKey)
{
      INT i;
      ULONG             offset;
      PUCHAR             pKey = pCipherKey->Key;
      PUCHAR             pTxMic = pCipherKey->TxMic;
      PUCHAR             pRxMic = pCipherKey->RxMic;
#ifdef DBG
      UCHAR       CipherAlg = pCipherKey->CipherAlg;
#endif // DBG //

      // EKEY
      offset = PAIRWISE_KEY_TABLE_BASE + (WCID * HW_KEY_ENTRY_SIZE);
#ifdef RT2860
      for (i=0; i<MAX_LEN_OF_PEER_KEY; i++)
      {
            RTMP_IO_WRITE8(pAd, offset + i, pKey[i]);
      }
#endif
#ifdef RT2870
      RTUSBMultiWrite(pAd, offset, &pCipherKey->Key[0], MAX_LEN_OF_PEER_KEY);
#endif // RT2870 //
      for (i=0; i<MAX_LEN_OF_PEER_KEY; i+=4)
      {
            UINT32 Value;
            RTMP_IO_READ32(pAd, offset + i, &Value);
      }

      offset += MAX_LEN_OF_PEER_KEY;

      //  MIC KEY
      if (pTxMic)
      {
#ifdef RT2860
            for (i=0; i<8; i++)
            {
                  RTMP_IO_WRITE8(pAd, offset+i, pTxMic[i]);
            }
#endif
#ifdef RT2870
            RTUSBMultiWrite(pAd, offset, &pCipherKey->TxMic[0], 8);
#endif // RT2870 //
      }
      offset += 8;
      if (pRxMic)
      {
#ifdef RT2860
            for (i=0; i<8; i++)
            {
                  RTMP_IO_WRITE8(pAd, offset+i, pRxMic[i]);
            }
#endif
#ifdef RT2870
            RTUSBMultiWrite(pAd, offset, &pCipherKey->RxMic[0], 8);
#endif // RT2870 //
      }

      DBGPRINT(RT_DEBUG_TRACE,("AsicAddPairwiseKeyEntry: WCID #%d Alg=%s\n",WCID, CipherName[CipherAlg]));
      DBGPRINT(RT_DEBUG_TRACE,("    Key = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
            pKey[0],pKey[1],pKey[2],pKey[3],pKey[4],pKey[5],pKey[6],pKey[7],pKey[8],pKey[9],pKey[10],pKey[11],pKey[12],pKey[13],pKey[14],pKey[15]));
      if (pRxMic)
      {
            DBGPRINT(RT_DEBUG_TRACE, ("   Rx MIC Key = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
                  pRxMic[0],pRxMic[1],pRxMic[2],pRxMic[3],pRxMic[4],pRxMic[5],pRxMic[6],pRxMic[7]));
      }
      if (pTxMic)
      {
            DBGPRINT(RT_DEBUG_TRACE, ("   Tx MIC Key = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
                  pTxMic[0],pTxMic[1],pTxMic[2],pTxMic[3],pTxMic[4],pTxMic[5],pTxMic[6],pTxMic[7]));
      }
}
/*
      ========================================================================
      Description:
            Remove Pair-wise key material from ASIC.

    Return:
      ========================================================================
*/
VOID AsicRemovePairwiseKeyEntry(
      IN PRTMP_ADAPTER pAd,
      IN UCHAR           BssIdx,
      IN UCHAR           Wcid)
{
      ULONG       WCIDAttri;
      USHORT            offset;

      // re-set the entry's WCID attribute as OPEN-NONE.
      offset = MAC_WCID_ATTRIBUTE_BASE + (Wcid * HW_WCID_ATTRI_SIZE);
      WCIDAttri = (BssIdx<<4) | PAIRWISEKEYTABLE;
      RTMP_IO_WRITE32(pAd, offset, WCIDAttri);
}

BOOLEAN AsicSendCommandToMcu(
      IN PRTMP_ADAPTER pAd,
      IN UCHAR           Command,
      IN UCHAR           Token,
      IN UCHAR           Arg0,
      IN UCHAR           Arg1)
{
      HOST_CMD_CSR_STRUC      H2MCmd;
      H2M_MAILBOX_STRUC H2MMailbox;
      ULONG                   i = 0;

      do
      {
            RTMP_IO_READ32(pAd, H2M_MAILBOX_CSR, &H2MMailbox.word);
            if (H2MMailbox.field.Owner == 0)
                  break;

            RTMPusecDelay(2);
      } while(i++ < 100);

      if (i > 100)
      {
            {
#ifdef RT2860
                  UINT32 Data;

                  // Reset DMA
                  RTMP_IO_READ32(pAd, PBF_SYS_CTRL, &Data);
                  Data |= 0x2;
                  RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, Data);

                  // After Reset DMA, DMA index will become Zero. So Driver need to reset all ring indexs too.
                  // Reset DMA/CPU ring index
                  RTMPRingCleanUp(pAd, QID_AC_BK);
                  RTMPRingCleanUp(pAd, QID_AC_BE);
                  RTMPRingCleanUp(pAd, QID_AC_VI);
                  RTMPRingCleanUp(pAd, QID_AC_VO);
                  RTMPRingCleanUp(pAd, QID_HCCA);
                  RTMPRingCleanUp(pAd, QID_MGMT);
                  RTMPRingCleanUp(pAd, QID_RX);

                  // Clear Reset
                  RTMP_IO_READ32(pAd, PBF_SYS_CTRL, &Data);
                  Data &= 0xfffffffd;
                  RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, Data);
#endif /* RT2860 */
            DBGPRINT_ERR(("H2M_MAILBOX still hold by MCU. command fail\n"));
            }
            //return FALSE;
#ifdef RT2870
            return FALSE;
#endif
      }

      H2MMailbox.field.Owner    = 1;         // pass ownership to MCU
      H2MMailbox.field.CmdToken = Token;
      H2MMailbox.field.HighByte = Arg1;
      H2MMailbox.field.LowByte  = Arg0;
      RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CSR, H2MMailbox.word);

      H2MCmd.word                     = 0;
      H2MCmd.field.HostCommand  = Command;
      RTMP_IO_WRITE32(pAd, HOST_CMD_CSR, H2MCmd.word);

      if (Command != 0x80)
      {
      }

      return TRUE;
}

#ifdef RT2860
BOOLEAN AsicCheckCommanOk(
      IN PRTMP_ADAPTER pAd,
      IN UCHAR           Command)
{
      UINT32      CmdStatus = 0, CID = 0, i;
      UINT32      ThisCIDMask = 0;

      i = 0;
      do
      {
            RTMP_IO_READ32(pAd, H2M_MAILBOX_CID, &CID);
            // Find where the command is. Because this is randomly specified by firmware.
            if ((CID & CID0MASK) == Command)
            {
                  ThisCIDMask = CID0MASK;
                  break;
            }
            else if ((((CID & CID1MASK)>>8) & 0xff) == Command)
            {
                  ThisCIDMask = CID1MASK;
                  break;
            }
            else if ((((CID & CID2MASK)>>16) & 0xff) == Command)
            {
                  ThisCIDMask = CID2MASK;
                  break;
            }
            else if ((((CID & CID3MASK)>>24) & 0xff) == Command)
            {
                  ThisCIDMask = CID3MASK;
                  break;
            }

            RTMPusecDelay(100);
            i++;
      }while (i < 200);

      // Get CommandStatus Value
      RTMP_IO_READ32(pAd, H2M_MAILBOX_STATUS, &CmdStatus);

      // This command's status is at the same position as command. So AND command position's bitmask to read status.
      if (i < 200)
      {
            // If Status is 1, the comamnd is success.
            if (((CmdStatus & ThisCIDMask) == 0x1) || ((CmdStatus & ThisCIDMask) == 0x100)
                  || ((CmdStatus & ThisCIDMask) == 0x10000) || ((CmdStatus & ThisCIDMask) == 0x1000000))
            {
                  DBGPRINT(RT_DEBUG_TRACE, ("--> AsicCheckCommanOk CID = 0x%x, CmdStatus= 0x%x \n", CID, CmdStatus));
                  RTMP_IO_WRITE32(pAd, H2M_MAILBOX_STATUS, 0xffffffff);
                  RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CID, 0xffffffff);
                  return TRUE;
            }
            DBGPRINT(RT_DEBUG_TRACE, ("--> AsicCheckCommanFail1 CID = 0x%x, CmdStatus= 0x%x \n", CID, CmdStatus));
      }
      else
      {
            DBGPRINT(RT_DEBUG_TRACE, ("--> AsicCheckCommanFail2 Timeout Command = %d, CmdStatus= 0x%x \n", Command, CmdStatus));
      }
      // Clear Command and Status.
      RTMP_IO_WRITE32(pAd, H2M_MAILBOX_STATUS, 0xffffffff);
      RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CID, 0xffffffff);

      return FALSE;
}
#endif /* RT8260 */

/*
      ========================================================================

      Routine Description:
            Verify the support rate for different PHY type

      Arguments:
            pAd                     Pointer to our adapter

      Return Value:
            None

      IRQL = PASSIVE_LEVEL

      ========================================================================
*/
VOID  RTMPCheckRates(
      IN          PRTMP_ADAPTER     pAd,
      IN OUT      UCHAR             SupRate[],
      IN OUT      UCHAR             *SupRateLen)
{
      UCHAR RateIdx, i, j;
      UCHAR NewRate[12], NewRateLen;

      NewRateLen = 0;

      if (pAd->CommonCfg.PhyMode == PHY_11B)
            RateIdx = 4;
      else
            RateIdx = 12;

      // Check for support rates exclude basic rate bit
      for (i = 0; i < *SupRateLen; i++)
            for (j = 0; j < RateIdx; j++)
                  if ((SupRate[i] & 0x7f) == RateIdTo500Kbps[j])
                        NewRate[NewRateLen++] = SupRate[i];

      *SupRateLen = NewRateLen;
      NdisMoveMemory(SupRate, NewRate, NewRateLen);
}

BOOLEAN RTMPCheckChannel(
      IN PRTMP_ADAPTER pAd,
      IN UCHAR          CentralChannel,
      IN UCHAR          Channel)
{
      UCHAR       k;
      UCHAR       UpperChannel = 0, LowerChannel = 0;
      UCHAR       NoEffectChannelinList = 0;

      // Find upper and lower channel according to 40MHz current operation.
      if (CentralChannel < Channel)
      {
            UpperChannel = Channel;
            if (CentralChannel > 2)
                  LowerChannel = CentralChannel - 2;
            else
                  return FALSE;
      }
      else if (CentralChannel > Channel)
      {
            UpperChannel = CentralChannel + 2;
            LowerChannel = Channel;
      }

      for (k = 0;k < pAd->ChannelListNum;k++)
      {
            if (pAd->ChannelList[k].Channel == UpperChannel)
            {
                  NoEffectChannelinList ++;
            }
            if (pAd->ChannelList[k].Channel == LowerChannel)
            {
                  NoEffectChannelinList ++;
            }
      }

      DBGPRINT(RT_DEBUG_TRACE,("Total Channel in Channel List = [%d]\n", NoEffectChannelinList));
      if (NoEffectChannelinList == 2)
            return TRUE;
      else
            return FALSE;
}

/*
      ========================================================================

      Routine Description:
            Verify the support rate for HT phy type

      Arguments:
            pAd                     Pointer to our adapter

      Return Value:
            FALSE if pAd->CommonCfg.SupportedHtPhy doesn't accept the pHtCapability.  (AP Mode)

      IRQL = PASSIVE_LEVEL

      ========================================================================
*/
BOOLEAN     RTMPCheckHt(
      IN    PRTMP_ADAPTER                 pAd,
      IN    UCHAR                         Wcid,
      IN    HT_CAPABILITY_IE        *pHtCapability,
      IN    ADD_HT_INFO_IE                *pAddHtInfo)
{
      if (Wcid >= MAX_LEN_OF_MAC_TABLE)
            return FALSE;

      // If use AMSDU, set flag.
      if (pAd->CommonCfg.DesiredHtPhy.AmsduEnable)
            CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_AMSDU_INUSED);
      // Save Peer Capability
      if (pHtCapability->HtCapInfo.ShortGIfor20)
            CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_SGI20_CAPABLE);
      if (pHtCapability->HtCapInfo.ShortGIfor40)
            CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_SGI40_CAPABLE);
      if (pHtCapability->HtCapInfo.TxSTBC)
            CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_TxSTBC_CAPABLE);
      if (pHtCapability->HtCapInfo.RxSTBC)
            CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_RxSTBC_CAPABLE);
      if (pAd->CommonCfg.bRdg && pHtCapability->ExtHtCapInfo.RDGSupport)
      {
            CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_RDG_CAPABLE);
      }

      if (Wcid < MAX_LEN_OF_MAC_TABLE)
      {
            pAd->MacTab.Content[Wcid].MpduDensity = pHtCapability->HtCapParm.MpduDensity;
      }

      // Will check ChannelWidth for MCSSet[4] below
      pAd->MlmeAux.HtCapability.MCSSet[4] = 0x1;
    switch (pAd->CommonCfg.RxStream)
      {
            case 1:
                  pAd->MlmeAux.HtCapability.MCSSet[0] = 0xff;
                  pAd->MlmeAux.HtCapability.MCSSet[1] = 0x00;
            pAd->MlmeAux.HtCapability.MCSSet[2] = 0x00;
            pAd->MlmeAux.HtCapability.MCSSet[3] = 0x00;
                  break;
            case 2:
                  pAd->MlmeAux.HtCapability.MCSSet[0] = 0xff;
                  pAd->MlmeAux.HtCapability.MCSSet[1] = 0xff;
            pAd->MlmeAux.HtCapability.MCSSet[2] = 0x00;
            pAd->MlmeAux.HtCapability.MCSSet[3] = 0x00;
                  break;
            case 3:
                  pAd->MlmeAux.HtCapability.MCSSet[0] = 0xff;
                  pAd->MlmeAux.HtCapability.MCSSet[1] = 0xff;
            pAd->MlmeAux.HtCapability.MCSSet[2] = 0xff;
            pAd->MlmeAux.HtCapability.MCSSet[3] = 0x00;
                  break;
      }

      pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth = pAddHtInfo->AddHtInfo.RecomWidth & pAd->CommonCfg.DesiredHtPhy.ChannelWidth;

    DBGPRINT(RT_DEBUG_TRACE, ("RTMPCheckHt:: HtCapInfo.ChannelWidth=%d, RecomWidth=%d, DesiredHtPhy.ChannelWidth=%d, BW40MAvailForA/G=%d/%d, PhyMode=%d \n",
            pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth, pAddHtInfo->AddHtInfo.RecomWidth, pAd->CommonCfg.DesiredHtPhy.ChannelWidth,
            pAd->NicConfig2.field.BW40MAvailForA, pAd->NicConfig2.field.BW40MAvailForG, pAd->CommonCfg.PhyMode));

      pAd->MlmeAux.HtCapability.HtCapInfo.GF =  pHtCapability->HtCapInfo.GF &pAd->CommonCfg.DesiredHtPhy.GF;

      // Send Assoc Req with my HT capability.
      pAd->MlmeAux.HtCapability.HtCapInfo.AMsduSize =  pAd->CommonCfg.DesiredHtPhy.AmsduSize;
      pAd->MlmeAux.HtCapability.HtCapInfo.MimoPs =  pAd->CommonCfg.DesiredHtPhy.MimoPs;
      pAd->MlmeAux.HtCapability.HtCapInfo.ShortGIfor20 =  (pAd->CommonCfg.DesiredHtPhy.ShortGIfor20) & (pHtCapability->HtCapInfo.ShortGIfor20);
      pAd->MlmeAux.HtCapability.HtCapInfo.ShortGIfor40 =  (pAd->CommonCfg.DesiredHtPhy.ShortGIfor40) & (pHtCapability->HtCapInfo.ShortGIfor40);
      pAd->MlmeAux.HtCapability.HtCapInfo.TxSTBC =  (pAd->CommonCfg.DesiredHtPhy.TxSTBC)&(pHtCapability->HtCapInfo.RxSTBC);
      pAd->MlmeAux.HtCapability.HtCapInfo.RxSTBC =  (pAd->CommonCfg.DesiredHtPhy.RxSTBC)&(pHtCapability->HtCapInfo.TxSTBC);
      pAd->MlmeAux.HtCapability.HtCapParm.MaxRAmpduFactor = pAd->CommonCfg.DesiredHtPhy.MaxRAmpduFactor;
    pAd->MlmeAux.HtCapability.HtCapParm.MpduDensity = pAd->CommonCfg.HtCapability.HtCapParm.MpduDensity;
      pAd->MlmeAux.HtCapability.ExtHtCapInfo.PlusHTC = pHtCapability->ExtHtCapInfo.PlusHTC;
      pAd->MacTab.Content[Wcid].HTCapability.ExtHtCapInfo.PlusHTC = pHtCapability->ExtHtCapInfo.PlusHTC;
      if (pAd->CommonCfg.bRdg)
      {
            pAd->MlmeAux.HtCapability.ExtHtCapInfo.RDGSupport = pHtCapability->ExtHtCapInfo.RDGSupport;
        pAd->MlmeAux.HtCapability.ExtHtCapInfo.PlusHTC = 1;
      }

    if (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_20)
        pAd->MlmeAux.HtCapability.MCSSet[4] = 0x0;  // BW20 can't transmit MCS32

      COPY_AP_HTSETTINGS_FROM_BEACON(pAd, pHtCapability);
      return TRUE;
}

/*
      ========================================================================

      Routine Description:
            Verify the support rate for different PHY type

      Arguments:
            pAd                     Pointer to our adapter

      Return Value:
            None

      IRQL = PASSIVE_LEVEL

      ========================================================================
*/
VOID RTMPUpdateMlmeRate(
      IN PRTMP_ADAPTER  pAd)
{
      UCHAR MinimumRate;
      UCHAR ProperMlmeRate; //= RATE_54;
      UCHAR i, j, RateIdx = 12; //1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54
      BOOLEAN     bMatch = FALSE;

      switch (pAd->CommonCfg.PhyMode)
      {
            case PHY_11B:
                  ProperMlmeRate = RATE_11;
                  MinimumRate = RATE_1;
                  break;
            case PHY_11BG_MIXED:
            case PHY_11ABGN_MIXED:
            case PHY_11BGN_MIXED:
                  if ((pAd->MlmeAux.SupRateLen == 4) &&
                        (pAd->MlmeAux.ExtRateLen == 0))
                        // B only AP
                        ProperMlmeRate = RATE_11;
                  else
                        ProperMlmeRate = RATE_24;

                  if (pAd->MlmeAux.Channel <= 14)
                        MinimumRate = RATE_1;
                  else
                        MinimumRate = RATE_6;
                  break;
            case PHY_11A:
            case PHY_11N_2_4G:      // rt2860 need to check mlmerate for 802.11n
            case PHY_11GN_MIXED:
            case PHY_11AGN_MIXED:
            case PHY_11AN_MIXED:
            case PHY_11N_5G:
                  ProperMlmeRate = RATE_24;
                  MinimumRate = RATE_6;
                  break;
            case PHY_11ABG_MIXED:
                  ProperMlmeRate = RATE_24;
                  if (pAd->MlmeAux.Channel <= 14)
                     MinimumRate = RATE_1;
                  else
                        MinimumRate = RATE_6;
                  break;
            default: // error
                  ProperMlmeRate = RATE_1;
                  MinimumRate = RATE_1;
                  break;
      }

      for (i = 0; i < pAd->MlmeAux.SupRateLen; i++)
      {
            for (j = 0; j < RateIdx; j++)
            {
                  if ((pAd->MlmeAux.SupRate[i] & 0x7f) == RateIdTo500Kbps[j])
                  {
                        if (j == ProperMlmeRate)
                        {
                              bMatch = TRUE;
                              break;
                        }
                  }
            }

            if (bMatch)
                  break;
      }

      if (bMatch == FALSE)
      {
            for (i = 0; i < pAd->MlmeAux.ExtRateLen; i++)
            {
                  for (j = 0; j < RateIdx; j++)
                  {
                        if ((pAd->MlmeAux.ExtRate[i] & 0x7f) == RateIdTo500Kbps[j])
                        {
                              if (j == ProperMlmeRate)
                              {
                                    bMatch = TRUE;
                                    break;
                              }
                        }
                  }

                  if (bMatch)
                        break;
            }
      }

      if (bMatch == FALSE)
      {
            ProperMlmeRate = MinimumRate;
      }

      pAd->CommonCfg.MlmeRate = MinimumRate;
      pAd->CommonCfg.RtsRate = ProperMlmeRate;
      if (pAd->CommonCfg.MlmeRate >= RATE_6)
      {
            pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM;
            pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate];
            pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MODE = MODE_OFDM;
            pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate];
      }
      else
      {
            pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK;
            pAd->CommonCfg.MlmeTransmit.field.MCS = pAd->CommonCfg.MlmeRate;
            pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MODE = MODE_CCK;
            pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MCS = pAd->CommonCfg.MlmeRate;
      }

      DBGPRINT(RT_DEBUG_TRACE, ("RTMPUpdateMlmeRate ==>   MlmeTransmit = 0x%x  \n" , pAd->CommonCfg.MlmeTransmit.word));
}

CHAR RTMPMaxRssi(
      IN PRTMP_ADAPTER  pAd,
      IN CHAR                       Rssi0,
      IN CHAR                       Rssi1,
      IN CHAR                       Rssi2)
{
      CHAR  larger = -127;

      if ((pAd->Antenna.field.RxPath == 1) && (Rssi0 != 0))
      {
            larger = Rssi0;
      }

      if ((pAd->Antenna.field.RxPath >= 2) && (Rssi1 != 0))
      {
            larger = max(Rssi0, Rssi1);
      }

      if ((pAd->Antenna.field.RxPath == 3) && (Rssi2 != 0))
      {
            larger = max(larger, Rssi2);
      }

      if (larger == -127)
            larger = 0;

      return larger;
}

#ifdef RT30xx
// Antenna divesity use GPIO3 and EESK pin for control
// Antenna and EEPROM access are both using EESK pin,
// Therefor we should avoid accessing EESK at the same time
// Then restore antenna after EEPROM access
VOID AsicSetRxAnt(
      IN PRTMP_ADAPTER  pAd,
      IN UCHAR                Ant)
{
#ifdef RT30xx
      UINT32      Value;
      UINT32      x;

      if ((pAd->EepromAccess)                                                       ||
            (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS))      ||
            (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) ||
            (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))              ||
            (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)))
      {
            return;
      }

      // the antenna selection is through firmware and MAC register(GPIO3)
      if (Ant == 0)
      {
            // Main antenna
            RTMP_IO_READ32(pAd, E2PROM_CSR, &x);
            x |= (EESK);
            RTMP_IO_WRITE32(pAd, E2PROM_CSR, x);

            RTMP_IO_READ32(pAd, GPIO_CTRL_CFG, &Value);
            Value &= ~(0x0808);
            RTMP_IO_WRITE32(pAd, GPIO_CTRL_CFG, Value);
            DBGPRINT_RAW(RT_DEBUG_TRACE, ("AsicSetRxAnt, switch to main antenna\n"));
      }
      else
      {
            // Aux antenna
            RTMP_IO_READ32(pAd, E2PROM_CSR, &x);
            x &= ~(EESK);
            RTMP_IO_WRITE32(pAd, E2PROM_CSR, x);

            RTMP_IO_READ32(pAd, GPIO_CTRL_CFG, &Value);
            Value &= ~(0x0808);
            Value |= 0x08;
            RTMP_IO_WRITE32(pAd, GPIO_CTRL_CFG, Value);
            DBGPRINT_RAW(RT_DEBUG_TRACE, ("AsicSetRxAnt, switch to aux antenna\n"));
      }
#endif // RT30xx //
}
#endif /* RT30xx */

/*
    ========================================================================
    Routine Description:
        Periodic evaluate antenna link status

    Arguments:
        pAd         - Adapter pointer

    Return Value:
        None

    ========================================================================
*/
VOID AsicEvaluateRxAnt(
      IN PRTMP_ADAPTER  pAd)
{
      UCHAR BBPR3 = 0;

#ifndef RT30xx
      {
            if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS     |
                                                fRTMP_ADAPTER_HALT_IN_PROGRESS      |
                                                fRTMP_ADAPTER_RADIO_OFF             |
                                                fRTMP_ADAPTER_NIC_NOT_EXIST         |
                                                fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
                  return;

            if (pAd->StaCfg.Psm == PWR_SAVE)
                  return;
      }

      RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPR3);
      BBPR3 &= (~0x18);
      if(pAd->Antenna.field.RxPath == 3)
      {
            BBPR3 |= (0x10);
      }
      else if(pAd->Antenna.field.RxPath == 2)
      {
            BBPR3 |= (0x8);
      }
      else if(pAd->Antenna.field.RxPath == 1)
      {
            BBPR3 |= (0x0);
      }
      RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3);

#ifdef RT2860
      pAd->StaCfg.BBPR3 = BBPR3;
#endif
#ifdef RT2870
      if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)
            )
      {
            ULONG TxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount +
                                                pAd->RalinkCounters.OneSecTxRetryOkCount +
                                                pAd->RalinkCounters.OneSecTxFailCount;

            if (TxTotalCnt > 50)
            {
                  RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 20);
                  pAd->Mlme.bLowThroughput = FALSE;
            }
            else
            {
                  RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 300);
                  pAd->Mlme.bLowThroughput = TRUE;
            }
      }
#endif
#endif /* RT30xx */
#ifdef RT30xx
      if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS     |
                                          fRTMP_ADAPTER_HALT_IN_PROGRESS      |
                                          fRTMP_ADAPTER_RADIO_OFF             |
                                          fRTMP_ADAPTER_NIC_NOT_EXIST         |
                                          fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS) ||
                                          OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)
#ifdef RT30xx
                                          || (pAd->EepromAccess)
#endif // RT30xx //
                                          )
            return;


      {
            //if (pAd->StaCfg.Psm == PWR_SAVE)
            //    return;
      }

      // two antenna selection mechanism- one is antenna diversity, the other is failed antenna remove
      // one is antenna diversity:there is only one antenna can rx and tx
      // the other is failed antenna remove:two physical antenna can rx and tx
      if (pAd->NicConfig2.field.AntDiversity)
      {
            DBGPRINT(RT_DEBUG_TRACE,("AntDiv - before evaluate Pair1-Ant (%d,%d)\n",
                  pAd->RxAnt.Pair1PrimaryRxAnt, pAd->RxAnt.Pair1SecondaryRxAnt));

            AsicSetRxAnt(pAd, pAd->RxAnt.Pair1SecondaryRxAnt);

            pAd->RxAnt.EvaluatePeriod = 1; // 1:Means switch to SecondaryRxAnt, 0:Means switch to Pair1PrimaryRxAnt
            pAd->RxAnt.FirstPktArrivedWhenEvaluate = FALSE;
            pAd->RxAnt.RcvPktNumWhenEvaluate = 0;

            // a one-shot timer to end the evalution
            // dynamic adjust antenna evaluation period according to the traffic
            if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED))
                  RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 100);
            else
                  RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 300);
      }
      else
      {
            if (pAd->StaCfg.Psm == PWR_SAVE)
                  return;

            RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPR3);
            BBPR3 &= (~0x18);
            if(pAd->Antenna.field.RxPath == 3)
            {
                  BBPR3 |= (0x10);
            }
            else if(pAd->Antenna.field.RxPath == 2)
            {
                  BBPR3 |= (0x8);
            }
            else if(pAd->Antenna.field.RxPath == 1)
            {
                  BBPR3 |= (0x0);
            }
            RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3);
      }
#endif /* RT30xx */

      if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)
            )
      {
            ULONG TxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount +
                                                pAd->RalinkCounters.OneSecTxRetryOkCount +
                                                pAd->RalinkCounters.OneSecTxFailCount;

                  // dynamic adjust antenna evaluation period according to the traffic
            if (TxTotalCnt > 50)
            {
                  RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 20);
                  pAd->Mlme.bLowThroughput = FALSE;
            }
            else
            {
                  RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 300);
                  pAd->Mlme.bLowThroughput = TRUE;
            }
      }
}

/*
    ========================================================================
    Routine Description:
        After evaluation, check antenna link status

    Arguments:
        pAd         - Adapter pointer

    Return Value:
        None

    ========================================================================
*/
VOID AsicRxAntEvalTimeout(
      IN PVOID SystemSpecific1,
      IN PVOID FunctionContext,
      IN PVOID SystemSpecific2,
      IN PVOID SystemSpecific3)
{
      RTMP_ADAPTER      *pAd = (RTMP_ADAPTER *)FunctionContext;
      UCHAR             BBPR3 = 0;
      CHAR              larger = -127, rssi0, rssi1, rssi2;

#ifndef RT30xx
      {
            if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)    ||
                  RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)         ||
                  RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)                ||
                  RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))
                  return;

            if (pAd->StaCfg.Psm == PWR_SAVE)
                  return;


            // if the traffic is low, use average rssi as the criteria
            if (pAd->Mlme.bLowThroughput == TRUE)
            {
                  rssi0 = pAd->StaCfg.RssiSample.LastRssi0;
                  rssi1 = pAd->StaCfg.RssiSample.LastRssi1;
                  rssi2 = pAd->StaCfg.RssiSample.LastRssi2;
            }
            else
            {
                  rssi0 = pAd->StaCfg.RssiSample.AvgRssi0;
                  rssi1 = pAd->StaCfg.RssiSample.AvgRssi1;
                  rssi2 = pAd->StaCfg.RssiSample.AvgRssi2;
            }

            if(pAd->Antenna.field.RxPath == 3)
            {
                  larger = max(rssi0, rssi1);

                  if (larger > (rssi2 + 20))
                        pAd->Mlme.RealRxPath = 2;
                  else
                        pAd->Mlme.RealRxPath = 3;
            }
            else if(pAd->Antenna.field.RxPath == 2)
            {
                  if (rssi0 > (rssi1 + 20))
                        pAd->Mlme.RealRxPath = 1;
                  else
                        pAd->Mlme.RealRxPath = 2;
            }

            RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPR3);
            BBPR3 &= (~0x18);
            if(pAd->Mlme.RealRxPath == 3)
            {
                  BBPR3 |= (0x10);
            }
            else if(pAd->Mlme.RealRxPath == 2)
            {
                  BBPR3 |= (0x8);
            }
            else if(pAd->Mlme.RealRxPath == 1)
            {
                  BBPR3 |= (0x0);
            }
            RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3);
#ifdef RT2860
            pAd->StaCfg.BBPR3 = BBPR3;
#endif
      }
#endif /* RT30xx */
#ifdef RT30xx
      if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS     |
                                          fRTMP_ADAPTER_HALT_IN_PROGRESS      |
                                          fRTMP_ADAPTER_RADIO_OFF             |
                                          fRTMP_ADAPTER_NIC_NOT_EXIST) ||
                                          OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)
#ifdef RT30xx
                                          || (pAd->EepromAccess)
#endif // RT30xx //
                                          )
            return;

      {
            //if (pAd->StaCfg.Psm == PWR_SAVE)
            //    return;

            if (pAd->NicConfig2.field.AntDiversity)
            {
                  if ((pAd->RxAnt.RcvPktNumWhenEvaluate != 0) && (pAd->RxAnt.Pair1AvgRssi[pAd->RxAnt.Pair1SecondaryRxAnt] >= pAd->RxAnt.Pair1AvgRssi[pAd->RxAnt.Pair1PrimaryRxAnt]))
                  {
                        UCHAR             temp;

                        //
                        // select PrimaryRxAntPair
                        //    Role change, Used Pair1SecondaryRxAnt as PrimaryRxAntPair.
                        //    Since Pair1SecondaryRxAnt Quality good than Pair1PrimaryRxAnt
                        //
                        temp = pAd->RxAnt.Pair1PrimaryRxAnt;
                        pAd->RxAnt.Pair1PrimaryRxAnt = pAd->RxAnt.Pair1SecondaryRxAnt;
                        pAd->RxAnt.Pair1SecondaryRxAnt = temp;

                        pAd->RxAnt.Pair1LastAvgRssi = (pAd->RxAnt.Pair1AvgRssi[pAd->RxAnt.Pair1SecondaryRxAnt] >> 3);
                        pAd->RxAnt.EvaluateStableCnt = 0;
                  }
                  else
                  {
                        // if the evaluated antenna is not better than original, switch back to original antenna
                        AsicSetRxAnt(pAd, pAd->RxAnt.Pair1PrimaryRxAnt);
                        pAd->RxAnt.EvaluateStableCnt ++;
                  }

                  pAd->RxAnt.EvaluatePeriod = 0; // 1:Means switch to SecondaryRxAnt, 0:Means switch to Pair1PrimaryRxAnt

                  DBGPRINT(RT_DEBUG_TRACE,("AsicRxAntEvalAction::After Eval(fix in #%d), <%d, %d>, RcvPktNumWhenEvaluate=%ld\n",
                              pAd->RxAnt.Pair1PrimaryRxAnt, (pAd->RxAnt.Pair1AvgRssi[0] >> 3), (pAd->RxAnt.Pair1AvgRssi[1] >> 3), pAd->RxAnt.RcvPktNumWhenEvaluate));
            }
            else
            {
                  if (pAd->StaCfg.Psm == PWR_SAVE)
                        return;

                  // if the traffic is low, use average rssi as the criteria
                  if (pAd->Mlme.bLowThroughput == TRUE)
                  {
                        rssi0 = pAd->StaCfg.RssiSample.LastRssi0;
                        rssi1 = pAd->StaCfg.RssiSample.LastRssi1;
                        rssi2 = pAd->StaCfg.RssiSample.LastRssi2;
                  }
                  else
                  {
                        rssi0 = pAd->StaCfg.RssiSample.AvgRssi0;
                        rssi1 = pAd->StaCfg.RssiSample.AvgRssi1;
                        rssi2 = pAd->StaCfg.RssiSample.AvgRssi2;
                  }

                  if(pAd->Antenna.field.RxPath == 3)
                  {
                        larger = max(rssi0, rssi1);

                        if (larger > (rssi2 + 20))
                              pAd->Mlme.RealRxPath = 2;
                        else
                              pAd->Mlme.RealRxPath = 3;
                  }
                  else if(pAd->Antenna.field.RxPath == 2)
                  {
                        if (rssi0 > (rssi1 + 20))
                              pAd->Mlme.RealRxPath = 1;
                        else
                              pAd->Mlme.RealRxPath = 2;
                  }

                  RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPR3);
                  BBPR3 &= (~0x18);
                  if(pAd->Mlme.RealRxPath == 3)
                  {
                        BBPR3 |= (0x10);
                  }
                  else if(pAd->Mlme.RealRxPath == 2)
                  {
                        BBPR3 |= (0x8);
                  }
                  else if(pAd->Mlme.RealRxPath == 1)
                  {
                        BBPR3 |= (0x0);
                  }
                  RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3);
            }
      }
#endif /* RT30xx */
}



VOID APSDPeriodicExec(
      IN PVOID SystemSpecific1,
      IN PVOID FunctionContext,
      IN PVOID SystemSpecific2,
      IN PVOID SystemSpecific3)
{
      RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;

      if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED))
            return;

      pAd->CommonCfg.TriggerTimerCount++;

}

/*
    ========================================================================
    Routine Description:
        Set/reset MAC registers according to bPiggyBack parameter

    Arguments:
        pAd         - Adapter pointer
        bPiggyBack  - Enable / Disable Piggy-Back

    Return Value:
        None

    ========================================================================
*/
VOID RTMPSetPiggyBack(
    IN PRTMP_ADAPTER    pAd,
    IN BOOLEAN          bPiggyBack)
{
      TX_LINK_CFG_STRUC  TxLinkCfg;

      RTMP_IO_READ32(pAd, TX_LINK_CFG, &TxLinkCfg.word);

      TxLinkCfg.field.TxCFAckEn = bPiggyBack;
      RTMP_IO_WRITE32(pAd, TX_LINK_CFG, TxLinkCfg.word);
}

/*
    ========================================================================
    Routine Description:
        check if this entry need to switch rate automatically

    Arguments:
        pAd
        pEntry

    Return Value:
        TURE
        FALSE

    ========================================================================
*/
BOOLEAN RTMPCheckEntryEnableAutoRateSwitch(
      IN PRTMP_ADAPTER    pAd,
      IN PMAC_TABLE_ENTRY     pEntry)
{
      BOOLEAN           result = TRUE;

      {
            // only associated STA counts
            if (pEntry && (pEntry->ValidAsCLI) && (pEntry->Sst == SST_ASSOC))
            {
                  result = pAd->StaCfg.bAutoTxRateSwitch;
            }
            else
                  result = FALSE;
      }

      return result;
}


BOOLEAN RTMPAutoRateSwitchCheck(
      IN PRTMP_ADAPTER    pAd)
{
      if (pAd->StaCfg.bAutoTxRateSwitch)
            return TRUE;

      return FALSE;
}


/*
    ========================================================================
    Routine Description:
        check if this entry need to fix tx legacy rate

    Arguments:
        pAd
        pEntry

    Return Value:
        TURE
        FALSE

    ========================================================================
*/
UCHAR RTMPStaFixedTxMode(
      IN PRTMP_ADAPTER    pAd,
      IN PMAC_TABLE_ENTRY     pEntry)
{
      UCHAR tx_mode = FIXED_TXMODE_HT;

      tx_mode = (UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode;

      return tx_mode;
}

/*
    ========================================================================
    Routine Description:
        Overwrite HT Tx Mode by Fixed Legency Tx Mode, if specified.

    Arguments:
        pAd
        pEntry

    Return Value:
        TURE
        FALSE

    ========================================================================
*/
VOID RTMPUpdateLegacyTxSetting(
            UCHAR                   fixed_tx_mode,
            PMAC_TABLE_ENTRY  pEntry)
{
      HTTRANSMIT_SETTING TransmitSetting;

      if (fixed_tx_mode == FIXED_TXMODE_HT)
            return;

      TransmitSetting.word = 0;

      TransmitSetting.field.MODE = pEntry->HTPhyMode.field.MODE;
      TransmitSetting.field.MCS = pEntry->HTPhyMode.field.MCS;

      if (fixed_tx_mode == FIXED_TXMODE_CCK)
      {
            TransmitSetting.field.MODE = MODE_CCK;
            // CCK mode allow MCS 0~3
            if (TransmitSetting.field.MCS > MCS_3)
                  TransmitSetting.field.MCS = MCS_3;
      }
      else
      {
            TransmitSetting.field.MODE = MODE_OFDM;
            // OFDM mode allow MCS 0~7
            if (TransmitSetting.field.MCS > MCS_7)
                  TransmitSetting.field.MCS = MCS_7;
      }

      if (pEntry->HTPhyMode.field.MODE >= TransmitSetting.field.MODE)
      {
            pEntry->HTPhyMode.word = TransmitSetting.word;
            DBGPRINT(RT_DEBUG_TRACE, ("RTMPUpdateLegacyTxSetting : wcid-%d, MODE=%s, MCS=%d \n",
                        pEntry->Aid, GetPhyMode(pEntry->HTPhyMode.field.MODE), pEntry->HTPhyMode.field.MCS));
      }
}

/*
      ==========================================================================
      Description:
            dynamic tune BBP R66 to find a balance between sensibility and
            noise isolation

      IRQL = DISPATCH_LEVEL

      ==========================================================================
 */
VOID AsicStaBbpTuning(
      IN PRTMP_ADAPTER pAd)
{
      UCHAR OrigR66Value = 0, R66;//, R66UpperBound = 0x30, R66LowerBound = 0x30;
      CHAR  Rssi;

      // 2860C did not support Fase CCA, therefore can't tune
      if (pAd->MACVersion == 0x28600100)
            return;

      //
      // work as a STA
      //
      if (pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE)  // no R66 tuning when SCANNING
            return;

      if ((pAd->OpMode == OPMODE_STA)
            && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)
                  )
            && !(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))
#ifdef RT2860
            && (pAd->bPCIclkOff == FALSE))
#endif
#ifdef RT2870
            )
#endif
      {
            RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R66, &OrigR66Value);
            R66 = OrigR66Value;

            if (pAd->Antenna.field.RxPath > 1)
                  Rssi = (pAd->StaCfg.RssiSample.AvgRssi0 + pAd->StaCfg.RssiSample.AvgRssi1) >> 1;
            else
                  Rssi = pAd->StaCfg.RssiSample.AvgRssi0;

            if (pAd->LatchRfRegs.Channel <= 14)
            {     //BG band
#ifdef RT2870
                  // RT3070 is a no LNA solution, it should have different control regarding to AGC gain control
                  // Otherwise, it will have some throughput side effect when low RSSI
#ifndef RT30xx
                  if (IS_RT3070(pAd))
#endif
#ifdef RT30xx
                  if (IS_RT30xx(pAd))
#endif
                  {
                        if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY)
                        {
                              R66 = 0x1C + 2*GET_LNA_GAIN(pAd) + 0x20;
                              if (OrigR66Value != R66)
                              {
#ifndef RT30xx
                                    RTUSBWriteBBPRegister(pAd, BBP_R66, R66);
#endif
#ifdef RT30xx
                                    RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
#endif
                              }
                        }
                        else
                        {
                              R66 = 0x1C + 2*GET_LNA_GAIN(pAd);
                              if (OrigR66Value != R66)
                              {
#ifndef RT30xx
                                    RTUSBWriteBBPRegister(pAd, BBP_R66, R66);
#endif
#ifdef RT30xx
                                    RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
#endif
                              }
                        }
                  }
                  else
#endif // RT2870 //
                  {
                        if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY)
                        {
                              R66 = (0x2E + GET_LNA_GAIN(pAd)) + 0x10;
                              if (OrigR66Value != R66)
                              {
                                    RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
                              }
                        }
                        else
                        {
                              R66 = 0x2E + GET_LNA_GAIN(pAd);
                              if (OrigR66Value != R66)
                              {
                                    RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
                              }
                        }
                  }
            }
            else
            {     //A band
                  if (pAd->CommonCfg.BBPCurrentBW == BW_20)
                  {
                        if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY)
                        {
                              R66 = 0x32 + (GET_LNA_GAIN(pAd)*5)/3 + 0x10;
                              if (OrigR66Value != R66)
                              {
                                    RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
                              }
                        }
                        else
                        {
                              R66 = 0x32 + (GET_LNA_GAIN(pAd)*5)/3;
                              if (OrigR66Value != R66)
                              {
                                    RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
                              }
                        }
                  }
                  else
                  {
                        if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY)
                        {
                              R66 = 0x3A + (GET_LNA_GAIN(pAd)*5)/3 + 0x10;
                              if (OrigR66Value != R66)
                              {
                                    RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
                              }
                        }
                        else
                        {
                              R66 = 0x3A + (GET_LNA_GAIN(pAd)*5)/3;
                              if (OrigR66Value != R66)
                              {
                                    RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
                              }
                        }
                  }
            }


      }
}

#ifdef RT2860
VOID AsicResetFromDMABusy(
      IN PRTMP_ADAPTER pAd)
{
      UINT32            Data;
      BOOLEAN           bCtrl = FALSE;

      DBGPRINT(RT_DEBUG_TRACE, ("--->  AsicResetFromDMABusy  !!!!!!!!!!!!!!!!!!!!!!! \n"));

      // Be sure restore link control value so we can write register.
      RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_CAN_GO_SLEEP);
      if (RTMP_TEST_PSFLAG(pAd, fRTMP_PS_SET_PCI_CLK_OFF_COMMAND))
      {
            DBGPRINT(RT_DEBUG_TRACE,("AsicResetFromDMABusy==>\n"));
            RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_HALT);
            RTMPusecDelay(6000);
            pAd->bPCIclkOff = FALSE;
            bCtrl = TRUE;
      }
      // Reset DMA
      RTMP_IO_READ32(pAd, PBF_SYS_CTRL, &Data);
      Data |= 0x2;
      RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, Data);

      // After Reset DMA, DMA index will become Zero. So Driver need to reset all ring indexs too.
      // Reset DMA/CPU ring index
      RTMPRingCleanUp(pAd, QID_AC_BK);
      RTMPRingCleanUp(pAd, QID_AC_BE);
      RTMPRingCleanUp(pAd, QID_AC_VI);
      RTMPRingCleanUp(pAd, QID_AC_VO);
      RTMPRingCleanUp(pAd, QID_HCCA);
      RTMPRingCleanUp(pAd, QID_MGMT);
      RTMPRingCleanUp(pAd, QID_RX);

      // Clear Reset
      RTMP_IO_READ32(pAd, PBF_SYS_CTRL, &Data);
      Data &= 0xfffffffd;
      RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, Data);

      // If in Radio off, should call RTMPPCIePowerLinkCtrl again.
      if ((bCtrl == TRUE) && (pAd->StaCfg.bRadio == FALSE))
            RTMPPCIeLinkCtrlSetting(pAd, 3);

      RTMP_SET_PSFLAG(pAd, fRTMP_PS_CAN_GO_SLEEP);
      RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST | fRTMP_ADAPTER_HALT_IN_PROGRESS);
      DBGPRINT(RT_DEBUG_TRACE, ("<---  AsicResetFromDMABusy !!!!!!!!!!!!!!!!!!!!!!!  \n"));
}

VOID AsicResetBBP(
      IN PRTMP_ADAPTER pAd)
{
      DBGPRINT(RT_DEBUG_TRACE, ("--->  Asic HardReset BBP  !!!!!!!!!!!!!!!!!!!!!!! \n"));

      RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x0);
      RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x2);
      RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0xc);

      // After hard-reset BBP, initialize all BBP values.
      NICRestoreBBPValue(pAd);
      DBGPRINT(RT_DEBUG_TRACE, ("<---  Asic HardReset BBP !!!!!!!!!!!!!!!!!!!!!!!  \n"));
}

VOID AsicResetMAC(
      IN PRTMP_ADAPTER pAd)
{
      ULONG       Data;

      DBGPRINT(RT_DEBUG_TRACE, ("--->  AsicResetMAC   !!!! \n"));
      RTMP_IO_READ32(pAd, PBF_SYS_CTRL, &Data);
      Data |= 0x4;
      RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, Data);
      Data &= 0xfffffffb;
      RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, Data);

      DBGPRINT(RT_DEBUG_TRACE, ("<---  AsicResetMAC   !!!! \n"));
}

VOID AsicResetPBF(
      IN PRTMP_ADAPTER pAd)
{
      ULONG       Value1, Value2;
      ULONG       Data;

      RTMP_IO_READ32(pAd, TXRXQ_PCNT, &Value1);
      RTMP_IO_READ32(pAd, PBF_DBG, &Value2);

      Value2 &= 0xff;
      // sum should be equals to 0xff, which is the total buffer size.
      if ((Value1 + Value2) < 0xff)
      {
            DBGPRINT(RT_DEBUG_TRACE, ("--->  Asic HardReset PBF !!!! \n"));
            RTMP_IO_READ32(pAd, PBF_SYS_CTRL, &Data);
            Data |= 0x8;
            RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, Data);
            Data &= 0xfffffff7;
            RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, Data);

            DBGPRINT(RT_DEBUG_TRACE, ("<---  Asic HardReset PBF !!!! \n"));
      }
}
#endif /* RT2860 */

VOID RTMPSetAGCInitValue(
      IN PRTMP_ADAPTER  pAd,
      IN UCHAR                BandWidth)
{
      UCHAR R66 = 0x30;

      if (pAd->LatchRfRegs.Channel <= 14)
      {     // BG band
            R66 = 0x2E + GET_LNA_GAIN(pAd);
            RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
      }
      else
      {     //A band
            if (BandWidth == BW_20)
            {
                  R66 = (UCHAR)(0x32 + (GET_LNA_GAIN(pAd)*5)/3);
                  RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
            }
            else
            {
                  R66 = (UCHAR)(0x3A + (GET_LNA_GAIN(pAd)*5)/3);
                  RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
            }
      }

}

VOID AsicTurnOffRFClk(
      IN PRTMP_ADAPTER pAd,
      IN    UCHAR       Channel)
{

      // RF R2 bit 18 = 0
      UINT32                  R1 = 0, R2 = 0, R3 = 0;
      UCHAR             index;
      RTMP_RF_REGS      *RFRegTable;

#ifdef RT30xx
      // The RF programming sequence is difference between 3xxx and 2xxx
      if (IS_RT3090(pAd))
      {
            RT30xxLoadRFSleepModeSetup(pAd);  // add by johnli,  RF power sequence setup, load RF sleep-mode setup
      }
      else
      {
#endif // RT30xx //
      RFRegTable = RF2850RegTable;

      switch (pAd->RfIcType)
      {
            case RFIC_2820:
            case RFIC_2850:
            case RFIC_2720:
            case RFIC_2750:

                  for (index = 0; index < NUM_OF_2850_CHNL; index++)
                  {
                        if (Channel == RFRegTable[index].Channel)
                        {
                              R1 = RFRegTable[index].R1 & 0xffffdfff;
                              R2 = RFRegTable[index].R2 & 0xfffbffff;
                              R3 = RFRegTable[index].R3 & 0xfff3ffff;

                              RTMP_RF_IO_WRITE32(pAd, R1);
                              RTMP_RF_IO_WRITE32(pAd, R2);

                              // Program R1b13 to 1, R3/b18,19 to 0, R2b18 to 0.
                              // Set RF R2 bit18=0, R3 bit[18:19]=0
                              //if (pAd->StaCfg.bRadio == FALSE)
                              if (1)
                              {
                                    RTMP_RF_IO_WRITE32(pAd, R3);

                                    DBGPRINT(RT_DEBUG_TRACE, ("AsicTurnOffRFClk#%d(RF=%d, ) , R2=0x%08x,  R3 = 0x%08x \n",
                                          Channel, pAd->RfIcType, R2, R3));
                              }
                              else
                                    DBGPRINT(RT_DEBUG_TRACE, ("AsicTurnOffRFClk#%d(RF=%d, ) , R2=0x%08x \n",
                                          Channel, pAd->RfIcType, R2));
                              break;
                        }
                  }
                  break;

            default:
                  break;
      }
#ifdef RT30xx
      }
#endif // RT30xx //

}


VOID AsicTurnOnRFClk(
      IN PRTMP_ADAPTER pAd,
      IN    UCHAR             Channel)
{

      // RF R2 bit 18 = 0
      UINT32                  R1 = 0, R2 = 0, R3 = 0;
      UCHAR             index;
      RTMP_RF_REGS      *RFRegTable;

#ifdef RT30xx
      // The RF programming sequence is difference between 3xxx and 2xxx
      if (IS_RT3090(pAd))
      {
      }
      else
      {
#endif // RT30xx //
      RFRegTable = RF2850RegTable;

      switch (pAd->RfIcType)
      {
            case RFIC_2820:
            case RFIC_2850:
            case RFIC_2720:
            case RFIC_2750:

                  for (index = 0; index < NUM_OF_2850_CHNL; index++)
                  {
                        if (Channel == RFRegTable[index].Channel)
                        {
                              R3 = pAd->LatchRfRegs.R3;
                              R3 &= 0xfff3ffff;
                              R3 |= 0x00080000;
                              RTMP_RF_IO_WRITE32(pAd, R3);

                              R1 = RFRegTable[index].R1;
                              RTMP_RF_IO_WRITE32(pAd, R1);

                              R2 = RFRegTable[index].R2;
                              if (pAd->Antenna.field.TxPath == 1)
                              {
                                    R2 |= 0x4000;     // If TXpath is 1, bit 14 = 1;
                              }

                              if (pAd->Antenna.field.RxPath == 2)
                              {
                                    R2 |= 0x40; // write 1 to off Rxpath.
                              }
                              else if (pAd->Antenna.field.RxPath == 1)
                              {
                                    R2 |= 0x20040;    // write 1 to off RxPath
                              }
                              RTMP_RF_IO_WRITE32(pAd, R2);

                              break;
                        }
                  }
                  break;

            default:
                  break;
      }

#ifndef RT30xx
      DBGPRINT(RT_DEBUG_TRACE, ("AsicTurnOnRFClk#%d(RF=%d, ) , R2=0x%08x\n",
            Channel,
            pAd->RfIcType,
            R2));
#endif
#ifdef RT30xx
      }
#endif // RT30xx //
}


Generated by  Doxygen 1.6.0   Back to index