| /* |
| ************************************************************************* |
| * 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 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; |
| |
| 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}, |
| }; |
| UCHAR NUM_OF_3020_CHNL=(sizeof(FreqItems3020) / sizeof(FREQUENCY_ITEM)); |
| |
| /* |
| ========================================================================== |
| 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) |
| {// 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)) |
| #else |
| (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)) |
| #endif |
| { |
| // 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) && |
| (pAd->RalinkCounters.OneSecRxOkDataCnt < (ULONG)100)) || |
| ((pAd->StaCfg.HTPhyMode.field.MCS > 3) && |
| (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); |
| } |
| } |
| } |
| } |
| |
| // 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); |
| |
| DBGPRINT(RT_DEBUG_TRACE, ("MlmeSetPsmBit = %d\n", psm)); |
| } |
| |
| // 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 |
| { |
| /* 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))) |
| { |
| 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); |
| } |
| } |
| |
| 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 |
| if (pInBss->WPA.GroupCipher != Ndis802_11GroupWEP40Enabled && |
| pInBss->WPA.GroupCipher != Ndis802_11GroupWEP104Enabled && |
| 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 (pInBss->WPA2.GroupCipher != Ndis802_11GroupWEP40Enabled && |
| pInBss->WPA2.GroupCipher != Ndis802_11GroupWEP104Enabled && |
| 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) |
| { |
| 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: |
| pBss->WPA.GroupCipher = Ndis802_11GroupWEP40Enabled; |
| break; |
| case 5: |
| pBss->WPA.GroupCipher = Ndis802_11GroupWEP104Enabled; |
| 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: |
| pBss->WPA2.GroupCipher = Ndis802_11GroupWEP40Enabled; |
| break; |
| case 5: |
| pBss->WPA2.GroupCipher = Ndis802_11GroupWEP104Enabled; |
| 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 RT2870 |
| /* |
| ========================================================================== |
| 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); |
| } |
| } |
| #endif |
| |
| /* |
| ========================================================================== |
| 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 |
| // 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; |
| } |
| } |
| |
| if (index == MAX_NUM_OF_CHANNELS) |
| DBGPRINT(RT_DEBUG_ERROR, ("AsicSwitchChannel: Can't find the Channel#%d \n", Channel)); |
| |
| #ifdef RT2870 |
| // The RF programming sequence is difference between 3xxx and 2xxx |
| if ((IS_RT3070(pAd) || IS_RT3090(pAd)) && ( |
| (pAd->RfIcType == RFIC_3022) || (pAd->RfIcType == RFIC_3021) || |
| (pAd->RfIcType == RFIC_3020) || (pAd->RfIcType == RFIC_2020))) |
| { |
| /* 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); |
| |
| 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); |
| |
| // Set BW |
| if (!bScan && (pAd->CommonCfg.BBPCurrentBW == BW_40)) |
| { |
| RFValue = pAd->Mlme.CaliBW40RfR24; |
| //DISABLE_11N_CHECK(pAd); |
| } |
| else |
| { |
| RFValue = pAd->Mlme.CaliBW20RfR24; |
| } |
| 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)); |
| break; |
| } |
| } |
| |
| 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)); |
| } |
| 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) |
| { |
| } |
| |
| 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 RT2870 |
| 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 |
| } |
| |
| 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 RT2870 |
| if (pAd->RfIcType == RFIC_3020 || pAd->RfIcType == RFIC_2020) |
| AifsnCsr.field.Aifsn2 = 0x2; //pEdcaParm->Aifsn[QID_AC_VI]; //for WiFi WMM S4-T04. |
| #endif |
| 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; |
| |
| { |
| // 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) |
| 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 RT2870 |
| // 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) |
| { |
| 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 |
| |
| /* |
| ======================================================================== |
| Routine Description: |
| Periodic evaluate antenna link status |
| |
| Arguments: |
| pAd - Adapter pointer |
| |
| Return Value: |
| None |
| |
| ======================================================================== |
| */ |
| VOID AsicEvaluateRxAnt( |
| IN PRTMP_ADAPTER pAd) |
| { |
| UCHAR BBPR3 = 0; |
| |
| 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 RT2870 |
| || (pAd->EepromAccess) |
| #endif |
| ) |
| return; |
| |
| #ifdef RT30xx |
| // 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 |
| #endif |
| { |
| 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 |
| } |
| |
| 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; |
| |
| 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 RT2870 |
| || (pAd->EepromAccess) |
| #endif |
| ) |
| return; |
| |
| { |
| #ifdef RT30xx |
| 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 |
| #endif |
| { |
| 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 |
| } |
| } |
| } |
| |
| 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 |
| if (IS_RT30xx(pAd)) |
| { |
| if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) |
| { |
| R66 = 0x1C + 2*GET_LNA_GAIN(pAd) + 0x20; |
| if (OrigR66Value != R66) |
| RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); |
| } |
| else |
| { |
| R66 = 0x1C + 2*GET_LNA_GAIN(pAd); |
| if (OrigR66Value != R66) |
| RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); |
| } |
| } |
| 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; |
| |
| // 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 |
| return; |
| } |
| |
| 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; |
| } |
| } |
| |
| |
| 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; |
| |
| // The RF programming sequence is difference between 3xxx and 2xxx |
| if (IS_RT3090(pAd)) |
| return; |
| |
| 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; |
| } |
| |
| DBGPRINT(RT_DEBUG_TRACE, ("AsicTurnOnRFClk#%d(RF=%d, ) , R2=0x%08x\n", |
| Channel, |
| pAd->RfIcType, |
| R2)); |
| } |
| |