MOXA linux-2.6.x / linux-2.6.9-uc0 from sdlinux-moxaart.tgz
[linux-2.6.9-moxart.git] / drivers / net / wireless / rtlink / Module / mlme.c
blob1600f0823f7d65adb82165f5c5b6e138d937309d
1 /*************************************************************************
2 * Ralink Tech Inc. *
3 * 4F, No. 2 Technology 5th Rd. *
4 * Science-based Industrial Park *
5 * Hsin-chu, Taiwan, R.O.C. *
6 * *
7 * (c) Copyright 2002, Ralink Technology, Inc. *
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 * This program is distributed in the hope that it will be useful, *
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17 * GNU General Public License for more details. *
18 * *
19 * You should have received a copy of the GNU General Public License *
20 * along with this program; if not, write to the *
21 * Free Software Foundation, Inc., *
22 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
23 * *
24 ************************************************************************/
26 #include "rt_config.h"
27 #include <stdarg.h>
29 // e.g. RssiSafeLevelForTxRate[RATE_36]" means if the current RSSI is greater than
30 // this value, then it's quaranteed capable of operating in 36 mbps TX rate in
31 // clean environment.
32 // TxRate: 1 2 5.5 11 6 9 12 18 24 36 48 54 72 100
33 CHAR RssiSafeLevelForTxRate[] ={ -92, -91, -90, -87, -88, -86, -85, -83, -81, -78, -72, -71, -40, -40 };
35 // 1 2 5.5 11
36 UCHAR Phy11BNextRateDownward[] = {RATE_1, RATE_1, RATE_2, RATE_5_5};
37 UCHAR Phy11BNextRateUpward[] = {RATE_2, RATE_5_5, RATE_11, RATE_11};
39 // 1 2 5.5 11 6 9 12 18 24 36 48 54
40 UCHAR Phy11BGNextRateDownward[]= {RATE_1, RATE_1, RATE_2, RATE_5_5,RATE_11, RATE_6, RATE_11, RATE_12, RATE_18, RATE_24, RATE_36, RATE_48};
41 UCHAR Phy11BGNextRateUpward[] = {RATE_2, RATE_5_5, RATE_11, RATE_12, RATE_9, RATE_12, RATE_18, RATE_24, RATE_36, RATE_48, RATE_54, RATE_54};
43 // 1 2 5.5 11 6 9 12 18 24 36 48 54
44 UCHAR Phy11ANextRateDownward[] = {RATE_6, RATE_6, RATE_6, RATE_6, RATE_6, RATE_6, RATE_9, RATE_12, RATE_18, RATE_24, RATE_36, RATE_48};
45 UCHAR Phy11ANextRateUpward[] = {RATE_9, RATE_9, RATE_9, RATE_9, RATE_9, RATE_12, RATE_18, RATE_24, RATE_36, RATE_48, RATE_54, RATE_54};
47 // 2560D and after has implemented ASIC-based OFDM rate switching, but not
48 // 2560C and before. thus software use different PER for rate switching
49 // RATE_1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54
50 USHORT NewRateUpPER[] = { 40, 40, 35, 20, 20, 20, 20, 16, 10, 16, 10, 6 }; // in percentage
51 USHORT NewRateDownPER[] = { 50, 50, 45, 45, 35, 35, 35, 35, 25, 25, 25, 13 }; // in percentage
53 USHORT OldRateUpPER[] = { 40, 40, 40, 40, 30, 30, 30, 30, 20, 20, 10, 10 }; // in percentage
54 USHORT OldRateDownPER[] = { 45, 45, 45, 45, 35, 35, 35, 35, 25, 25, 25, 12 }; // in percentage
56 UCHAR RateIdToMbps[] = { 1, 2, 5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 72, 100};
57 USHORT RateIdTo500Kbps[] = { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108, 144, 200};
59 RTMP_RF_REGS RF2522RegTable[] = {
60 // ch R1 R2 R3(TX0~4=0) R4
61 {1, 0x94002050, 0x940c1fda, 0x94000101, 0},
62 {2, 0x94002050, 0x940c1fee, 0x94000101, 0},
63 {3, 0x94002050, 0x940c2002, 0x94000101, 0},
64 {4, 0x94002050, 0x940c2016, 0x94000101, 0},
65 {5, 0x94002050, 0x940c202a, 0x94000101, 0},
66 {6, 0x94002050, 0x940c203e, 0x94000101, 0},
67 {7, 0x94002050, 0x940c2052, 0x94000101, 0},
68 {8, 0x94002050, 0x940c2066, 0x94000101, 0},
69 {9, 0x94002050, 0x940c207a, 0x94000101, 0},
70 {10, 0x94002050, 0x940c208e, 0x94000101, 0},
71 {11, 0x94002050, 0x940c20a2, 0x94000101, 0},
72 {12, 0x94002050, 0x940c20b6, 0x94000101, 0},
73 {13, 0x94002050, 0x940c20ca, 0x94000101, 0},
74 {14, 0x94002050, 0x940c20fa, 0x94000101, 0}
76 #define NUM_OF_2522_CHNL (sizeof(RF2522RegTable) / sizeof(RTMP_RF_REGS))
78 RTMP_RF_REGS RF2523RegTable[] = {
79 // ch R1 R2 R3(TX0~4=0) R4
80 {1, 0x94022010, 0x94000c9e, 0x940e0111, 0x94000a1b},
81 {2, 0x94022010, 0x94000ca2, 0x940e0111, 0x94000a1b},
82 {3, 0x94022010, 0x94000ca6, 0x940e0111, 0x94000a1b},
83 {4, 0x94022010, 0x94000caa, 0x940e0111, 0x94000a1b},
84 {5, 0x94022010, 0x94000cae, 0x940e0111, 0x94000a1b},
85 {6, 0x94022010, 0x94000cb2, 0x940e0111, 0x94000a1b},
86 {7, 0x94022010, 0x94000cb6, 0x940e0111, 0x94000a1b},
87 {8, 0x94022010, 0x94000cba, 0x940e0111, 0x94000a1b},
88 {9, 0x94022010, 0x94000cbe, 0x940e0111, 0x94000a1b},
89 {10, 0x94022010, 0x94000d02, 0x940e0111, 0x94000a1b},
90 {11, 0x94022010, 0x94000d06, 0x940e0111, 0x94000a1b},
91 {12, 0x94022010, 0x94000d0a, 0x940e0111, 0x94000a1b},
92 {13, 0x94022010, 0x94000d0e, 0x940e0111, 0x94000a1b},
93 {14, 0x94022010, 0x94000d1a, 0x940e0111, 0x94000a03}
94 #if 0
95 {1, 0x94022050, 0x940c1fda, 0x940e8101, 0},
96 {2, 0x94022050, 0x940c1fee, 0x940e8101, 0},
97 {3, 0x94022050, 0x940c2002, 0x940e8101, 0},
98 {4, 0x94022050, 0x940c2016, 0x940e8101, 0},
99 {5, 0x94022050, 0x940c202a, 0x940e8101, 0},
100 {6, 0x94022050, 0x940c203e, 0x940e8101, 0},
101 {7, 0x94022050, 0x940c2052, 0x940e8101, 0},
102 {8, 0x94022050, 0x940c2066, 0x940e8101, 0},
103 {9, 0x94022050, 0x940c207a, 0x940e8101, 0},
104 {10, 0x94022050, 0x940c208e, 0x940e8101, 0},
105 {11, 0x94022050, 0x940c20a2, 0x940e8101, 0},
106 {12, 0x94022050, 0x940c20b6, 0x940e8101, 0},
107 {13, 0x94022050, 0x940c20ca, 0x940e8101, 0},
108 {14, 0x94022050, 0x940c20fa, 0x940e8101, 0}
109 #endif
111 #define NUM_OF_2523_CHNL (sizeof(RF2523RegTable) / sizeof(RTMP_RF_REGS))
113 RTMP_RF_REGS RF2524RegTable[] = {
114 // ch R1 R2 R3(TX0~4=0) R4
115 {1, 0x94032020, 0x94000c9e, 0x94000101, 0x94000a1b},
116 {2, 0x94032020, 0x94000ca2, 0x94000101, 0x94000a1b},
117 {3, 0x94032020, 0x94000ca6, 0x94000101, 0x94000a1b},
118 {4, 0x94032020, 0x94000caa, 0x94000101, 0x94000a1b},
119 {5, 0x94032020, 0x94000cae, 0x94000101, 0x94000a1b},
120 {6, 0x94032020, 0x94000cb2, 0x94000101, 0x94000a1b},
121 {7, 0x94032020, 0x94000cb6, 0x94000101, 0x94000a1b},
122 {8, 0x94032020, 0x94000cba, 0x94000101, 0x94000a1b},
123 {9, 0x94032020, 0x94000cbe, 0x94000101, 0x94000a1b},
124 {10, 0x94032020, 0x94000d02, 0x94000101, 0x94000a1b},
125 {11, 0x94032020, 0x94000d06, 0x94000101, 0x94000a1b},
126 {12, 0x94032020, 0x94000d0a, 0x94000101, 0x94000a1b},
127 {13, 0x94032020, 0x94000d0e, 0x94000101, 0x94000a1b},
128 {14, 0x94032020, 0x94000d1a, 0x94000101, 0x94000a03}
130 #define NUM_OF_2524_CHNL (sizeof(RF2524RegTable) / sizeof(RTMP_RF_REGS))
132 RTMP_RF_REGS RF2525RegTable[] = {
133 // ch R1 R2 R3(TX0~4=0) R4
134 {1, 0x94022020, 0x94080c9e, 0x94060111, 0x94000a1b}, // {1, 0x94022010, 0x9408062e, 0x94060111, 0x94000a23},
135 {2, 0x94022020, 0x94080ca2, 0x94060111, 0x94000a1b},
136 {3, 0x94022020, 0x94080ca6, 0x94060111, 0x94000a1b},
137 {4, 0x94022020, 0x94080caa, 0x94060111, 0x94000a1b},
138 {5, 0x94022020, 0x94080cae, 0x94060111, 0x94000a1b},
139 {6, 0x94022020, 0x94080cb2, 0x94060111, 0x94000a1b},
140 {7, 0x94022020, 0x94080cb6, 0x94060111, 0x94000a1b},
141 {8, 0x94022020, 0x94080cba, 0x94060111, 0x94000a1b},
142 {9, 0x94022020, 0x94080cbe, 0x94060111, 0x94000a1b},
143 {10, 0x94022020, 0x94080d02, 0x94060111, 0x94000a1b},
144 {11, 0x94022020, 0x94080d06, 0x94060111, 0x94000a1b}, // {11, 0x94022010, 0x94080682, 0x94060111, 0x94000a23},
145 {12, 0x94022020, 0x94080d0a, 0x94060111, 0x94000a1b},
146 {13, 0x94022020, 0x94080d0e, 0x94060111, 0x94000a1b}, // {13, 0x94022010, 0x94080686, 0x94060111, 0x94000a23},
147 {14, 0x94022020, 0x94080d1a, 0x94060111, 0x94000a03}
149 #define NUM_OF_2525_CHNL (sizeof(RF2525RegTable) / sizeof(RTMP_RF_REGS))
151 RTMP_RF_REGS RF2525HBOffsetRegTable[] = {
152 {1, 0x94022020, 0x94080cbe, 0x94060111, 0x94000a1b},
153 {2, 0x94022020, 0x94080d02, 0x94060111, 0x94000a1b},
154 {3, 0x94022020, 0x94080d06, 0x94060111, 0x94000a1b},
155 {4, 0x94022020, 0x94080d0a, 0x94060111, 0x94000a1b},
156 {5, 0x94022020, 0x94080d0e, 0x94060111, 0x94000a1b},
157 {6, 0x94022020, 0x94080d12, 0x94060111, 0x94000a1b},
158 {7, 0x94022020, 0x94080d16, 0x94060111, 0x94000a1b},
159 {8, 0x94022020, 0x94080d1a, 0x94060111, 0x94000a1b},
160 {9, 0x94022020, 0x94080d1e, 0x94060111, 0x94000a1b},
161 {10, 0x94022020, 0x94080d22, 0x94060111, 0x94000a1b},
162 {11, 0x94022020, 0x94080d26, 0x94060111, 0x94000a1b},
163 {12, 0x94022020, 0x94080d2a, 0x94060111, 0x94000a1b},
164 {13, 0x94022020, 0x94080d2e, 0x94060111, 0x94000a1b},
165 {14, 0x94022020, 0x94080d3a, 0x94060111, 0x94000a03}
168 RTMP_RF_REGS RF2525eRegTable[] = {
169 #if 1
170 // using 5 Mhz reference clock
171 // ch R1 R2 R3(TX0~4=0) R4
172 {1, 0x94022020, 0x94081136, 0x94060111, 0x94000a0b},
173 {2, 0x94022020, 0x9408113a, 0x94060111, 0x94000a0b},
174 {3, 0x94022020, 0x9408113e, 0x94060111, 0x94000a0b},
175 {4, 0x94022020, 0x94081182, 0x94060111, 0x94000a0b},
176 {5, 0x94022020, 0x94081186, 0x94060111, 0x94000a0b},
177 {6, 0x94022020, 0x9408118a, 0x94060111, 0x94000a0b},
178 {7, 0x94022020, 0x9408118e, 0x94060111, 0x94000a0b},
179 {8, 0x94022020, 0x94081192, 0x94060111, 0x94000a0b},
180 {9, 0x94022020, 0x94081196, 0x94060111, 0x94000a0b},
181 {10, 0x94022020, 0x9408119a, 0x94060111, 0x94000a0b},
182 {11, 0x94022020, 0x9408119e, 0x94060111, 0x94000a0b},
183 {12, 0x94022020, 0x940811a2, 0x94060111, 0x94000a0b},
184 {13, 0x94022020, 0x940811a6, 0x94060111, 0x94000a0b},
185 {14, 0x94022020, 0x940811ae, 0x94060111, 0x94000a1b}
186 #else
187 // using 10 Mhz reference clock
188 // ch R1 R2 R3(TX0~4=0) R4
189 {1, 0x94022010, 0x9408089a, 0x94060111, 0x94000a1b},
190 {2, 0x94022010, 0x9408089e, 0x94060111, 0x94000a07},
191 {3, 0x94022010, 0x9408089e, 0x94060111, 0x94000a1b},
192 {4, 0x94022010, 0x940808a2, 0x94060111, 0x94000a07},
193 {5, 0x94022010, 0x940808a2, 0x94060111, 0x94000a1b},
194 {6, 0x94022010, 0x940808a6, 0x94060111, 0x94000a07},
195 {7, 0x94022010, 0x940808a6, 0x94060111, 0x94000a1b},
196 {8, 0x94022010, 0x940808aa, 0x94060111, 0x94000a07},
197 {9, 0x94022010, 0x940808aa, 0x94060111, 0x94000a1b},
198 {10, 0x94022010, 0x940808ae, 0x94060111, 0x94000a07},
199 {11, 0x94022010, 0x940808ae, 0x94060111, 0x94000a1b},
200 {12, 0x94022010, 0x940808b2, 0x94060111, 0x94000a07},
201 {13, 0x94022010, 0x940808b2, 0x94060111, 0x94000a1b},
202 {14, 0x94022010, 0x940808b6, 0x94060111, 0x94000a23}
203 #endif
205 #define NUM_OF_2525E_CHNL (sizeof(RF2525eRegTable) / sizeof(RTMP_RF_REGS))
207 RTMP_RF_REGS RF5222RegTable[] = {
208 // ch R1 R2 R3(TX0~4=0) R4
209 {1, 0x94022020, 0x94001136, 0x94000101, 0x94000a0b},
210 {2, 0x94022020, 0x9400113a, 0x94000101, 0x94000a0b},
211 {3, 0x94022020, 0x9400113e, 0x94000101, 0x94000a0b},
212 {4, 0x94022020, 0x94001182, 0x94000101, 0x94000a0b},
213 {5, 0x94022020, 0x94001186, 0x94000101, 0x94000a0b},
214 {6, 0x94022020, 0x9400118a, 0x94000101, 0x94000a0b},
215 {7, 0x94022020, 0x9400118e, 0x94000101, 0x94000a0b},
216 {8, 0x94022020, 0x94001192, 0x94000101, 0x94000a0b},
217 {9, 0x94022020, 0x94001196, 0x94000101, 0x94000a0b},
218 {10, 0x94022020, 0x9400119a, 0x94000101, 0x94000a0b},
219 {11, 0x94022020, 0x9400119e, 0x94000101, 0x94000a0b},
220 {12, 0x94022020, 0x940011a2, 0x94000101, 0x94000a0b},
221 {13, 0x94022020, 0x940011a6, 0x94000101, 0x94000a0b},
222 {14, 0x94022020, 0x940011ae, 0x94000101, 0x94000a1b},
224 // still lack of MMAC(Japan) ch 34,38,42,46
226 {36, 0x94022010, 0x94018896, 0x94000101, 0x94000a1f},
227 {40, 0x94022010, 0x9401889a, 0x94000101, 0x94000a1f},
228 {44, 0x94022010, 0x9401889e, 0x94000101, 0x94000a1f},
229 {48, 0x94022010, 0x940188a2, 0x94000101, 0x94000a1f},
230 {52, 0x94022010, 0x940188a6, 0x94000101, 0x94000a1f},
231 {66, 0x94022010, 0x940188aa, 0x94000101, 0x94000a1f},
232 {60, 0x94022010, 0x940188ae, 0x94000101, 0x94000a1f},
233 {64, 0x94022010, 0x940188b2, 0x94000101, 0x94000a1f},
235 {100, 0x94022010, 0x94008802, 0x94000101, 0x94000a0f},
236 {104, 0x94022010, 0x94008806, 0x94000101, 0x94000a0f},
237 {108, 0x94022010, 0x9400880a, 0x94000101, 0x94000a0f},
238 {112, 0x94022010, 0x9400880e, 0x94000101, 0x94000a0f},
239 {116, 0x94022010, 0x94008812, 0x94000101, 0x94000a0f},
240 {120, 0x94022010, 0x94008816, 0x94000101, 0x94000a0f},
241 {124, 0x94022010, 0x9400881a, 0x94000101, 0x94000a0f},
242 {128, 0x94022010, 0x9400881e, 0x94000101, 0x94000a0f},
243 {132, 0x94022010, 0x94008822, 0x94000101, 0x94000a0f},
244 {136, 0x94022010, 0x94008826, 0x94000101, 0x94000a0f},
245 {140, 0x94022010, 0x9400882a, 0x94000101, 0x94000a0f},
247 {149, 0x94022020, 0x940090a6, 0x94000101, 0x94000a07},
248 {153, 0x94022020, 0x940090ae, 0x94000101, 0x94000a07},
249 {157, 0x94022020, 0x940090b6, 0x94000101, 0x94000a07},
250 {161, 0x94022020, 0x940090be, 0x94000101, 0x94000a07}
252 #define NUM_OF_5222_CHNL (sizeof(RF5222RegTable) / sizeof(RTMP_RF_REGS))
255 ==========================================================================
256 Description:
257 initialize the MLME task and its data structure (queue, spinlock,
258 timer, state machines).
259 Return:
260 always return NDIS_STATUS_SUCCESS
261 ==========================================================================
263 NDIS_STATUS MlmeInit(
264 IN PRTMP_ADAPTER pAd)
266 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
268 DBGPRINT(RT_DEBUG_TRACE, "--> MLME Initialize\n");
272 Status = MlmeQueueInit(&pAd->Mlme.Queue);
273 if(Status != NDIS_STATUS_SUCCESS)
275 break;
278 pAd->Mlme.Running = FALSE;
279 NdisAllocateSpinLock(&pAd->Mlme.TaskLock);
281 // initialize the two tables
282 // MacTableInit(pAd);
283 BssTableInit(&pAd->PortCfg.BssTab);
285 // init state machines
286 ASSERT(ASSOC_FUNC_SIZE == MAX_ASSOC_MSG * MAX_ASSOC_STATE);
287 AssocStateMachineInit(pAd, &pAd->Mlme.AssocMachine, pAd->Mlme.AssocFunc);
289 ASSERT(AUTH_FUNC_SIZE == MAX_AUTH_MSG * MAX_AUTH_STATE);
290 AuthStateMachineInit(pAd, &pAd->Mlme.AuthMachine, pAd->Mlme.AuthFunc);
292 ASSERT(AUTH_RSP_FUNC_SIZE == MAX_AUTH_RSP_MSG * MAX_AUTH_RSP_STATE);
293 AuthRspStateMachineInit(pAd, &pAd->Mlme.AuthRspMachine, pAd->Mlme.AuthRspFunc);
295 ASSERT(SYNC_FUNC_SIZE == MAX_SYNC_MSG * MAX_SYNC_STATE);
296 SyncStateMachineInit(pAd, &pAd->Mlme.SyncMachine, pAd->Mlme.SyncFunc);
298 ASSERT(WPA_PSK_FUNC_SIZE == MAX_WPA_PSK_MSG * MAX_WPA_PSK_STATE);
299 WpaPskStateMachineInit(pAd,&pAd->Mlme.WpaPskMachine,pAd->Mlme.WpaPskFunc);
301 // Since we are using switch/case to implement it, the init is different from the above
302 // state machine init
303 MlmeCntlInit(pAd, &pAd->Mlme.CntlMachine, NULL);
305 // Init mlme periodic timer
306 RTMPInitTimer(pAd, &pAd->Mlme.PeriodicTimer, MlmePeriodicExec);
307 // Set mlme periodic timer
308 RTMPSetTimer(pAd, &pAd->Mlme.PeriodicTimer, MLME_TASK_EXEC_INTV);
310 if (pAd->PortCfg.LedMode == LED_MODE_TXRX_ACTIVITY)
312 // Init blnk timer
313 RTMPInitTimer(pAd, &pAd->PortCfg.LedCntl.BlinkTimer, AsicLedPeriodicExec);
314 // Set blink timer
315 RTMPSetTimer(pAd, &pAd->PortCfg.LedCntl.BlinkTimer, 70);
318 // software-based RX Antenna diversity
319 RTMPInitTimer(pAd, &pAd->PortCfg.RxAnt.RxAntDiversityTimer, AsicRxAntEvalTimeout);
320 } while (FALSE);
322 DBGPRINT(RT_DEBUG_TRACE, "<-- MLME Initialize\n");
324 return Status;
329 ==========================================================================
330 Description:
331 main loop of the MLME
332 Pre:
333 Mlme has to be initialized, and there are something inside the queue
334 Note:
335 This function is invoked from MPSetInformation and MPReceive;
336 This task guarantee only one MlmeHandler will run.
337 ==========================================================================
339 VOID MlmeHandler(
340 IN PRTMP_ADAPTER pAd)
342 MLME_QUEUE_ELEM *Elem = NULL;
343 ULONG IrqFlags;
345 // Only accept MLME and Frame from peer side, no other (control/data) frame should
346 // get into this state machine
348 NdisAcquireSpinLock(&pAd->Mlme.TaskLock, IrqFlags);
349 if(pAd->Mlme.Running)
351 NdisReleaseSpinLock(&pAd->Mlme.TaskLock, IrqFlags);
352 return;
354 else
356 pAd->Mlme.Running = TRUE;
358 NdisReleaseSpinLock(&pAd->Mlme.TaskLock, IrqFlags);
360 while (!MlmeQueueEmpty(&pAd->Mlme.Queue))
362 //From message type, determine which state machine I should drive
363 if (MlmeDequeue(&pAd->Mlme.Queue, &Elem))
365 // if dequeue success
366 switch (Elem->Machine)
368 case ASSOC_STATE_MACHINE:
369 StateMachinePerformAction(pAd, &pAd->Mlme.AssocMachine, Elem);
370 break;
371 case AUTH_STATE_MACHINE:
372 StateMachinePerformAction(pAd, &pAd->Mlme.AuthMachine, Elem);
373 break;
374 case AUTH_RSP_STATE_MACHINE:
375 StateMachinePerformAction(pAd, &pAd->Mlme.AuthRspMachine, Elem);
376 break;
377 case SYNC_STATE_MACHINE:
378 StateMachinePerformAction(pAd, &pAd->Mlme.SyncMachine, Elem);
379 break;
380 case MLME_CNTL_STATE_MACHINE:
381 MlmeCntlMachinePerformAction(pAd, &pAd->Mlme.CntlMachine, Elem);
382 break;
383 case WPA_PSK_STATE_MACHINE:
384 StateMachinePerformAction(pAd, &pAd->Mlme.WpaPskMachine, Elem);
385 break;
386 default:
387 DBGPRINT(RT_DEBUG_TRACE, "ERROR: Illegal machine in MlmeHandler()\n");
388 break;
389 } // end of switch
391 // free MLME element
392 Elem->Occupied = FALSE;
393 Elem->MsgLen = 0;
396 else
398 DBGPRINT(RT_DEBUG_ERROR, "ERROR: empty Elem in MlmeQueue\n");
402 NdisAcquireSpinLock(&pAd->Mlme.TaskLock, IrqFlags);
403 pAd->Mlme.Running = FALSE;
404 NdisReleaseSpinLock(&pAd->Mlme.TaskLock, IrqFlags);
408 ==========================================================================
409 Description:
410 Destructor of MLME (Destroy queue, state machine, spin lock and timer)
411 Parameters:
412 Adapter - NIC Adapter pointer
413 Post:
414 The MLME task will no longer work properly
415 ==========================================================================
417 VOID MlmeHalt(
418 IN PRTMP_ADAPTER pAd)
420 MLME_DISASSOC_REQ_STRUCT DisReq;
421 MLME_QUEUE_ELEM MsgElem;
423 DBGPRINT(RT_DEBUG_TRACE, "==> MlmeHalt\n");
425 if (INFRA_ON(pAd) && !RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))
427 COPY_MAC_ADDR(&DisReq.Addr, &pAd->PortCfg.Bssid);
428 DisReq.Reason = REASON_DISASSOC_STA_LEAVING;
430 MsgElem.Machine = ASSOC_STATE_MACHINE;
431 MsgElem.MsgType = MT2_MLME_DISASSOC_REQ;
432 MsgElem.MsgLen = sizeof(MLME_DISASSOC_REQ_STRUCT);
433 NdisMoveMemory(MsgElem.Msg, &DisReq, sizeof(MLME_DISASSOC_REQ_STRUCT));
435 MlmeDisassocReqAction(pAd, &MsgElem);
437 udelay(1000);
440 if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))
442 // disable BEACON generation and other BEACON related hardware timers
443 AsicDisableSync(pAd);
446 // Cancel pending timers
447 RTMPCancelTimer(&pAd->Mlme.AssocAux.AssocTimer);
448 RTMPCancelTimer(&pAd->Mlme.AssocAux.ReassocTimer);
449 RTMPCancelTimer(&pAd->Mlme.AssocAux.DisassocTimer);
450 RTMPCancelTimer(&pAd->Mlme.AuthAux.AuthTimer);
451 RTMPCancelTimer(&pAd->Mlme.AuthRspAux.AuthRspTimer);
452 RTMPCancelTimer(&pAd->Mlme.SyncAux.BeaconTimer);
453 RTMPCancelTimer(&pAd->Mlme.SyncAux.ScanTimer);
454 RTMPCancelTimer(&pAd->Mlme.PeriodicTimer);
455 // RTMPCancelTimer(&pAd->PortCfg.MacTab.AgedOutTimer);
457 if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))
459 if (pAd->PortCfg.LedMode == LED_MODE_TXRX_ACTIVITY)
460 RTMPCancelTimer(&pAd->PortCfg.LedCntl.BlinkTimer);
461 ASIC_LED_ACT_OFF(pAd);
464 RTMPCancelTimer(&pAd->PortCfg.RxAnt.RxAntDiversityTimer);
465 udelay(1000);
467 MlmeQueueDestroy(&pAd->Mlme.Queue);
468 StateMachineDestroy(&pAd->Mlme.AssocMachine);
469 StateMachineDestroy(&pAd->Mlme.AuthMachine);
470 StateMachineDestroy(&pAd->Mlme.AuthRspMachine);
471 StateMachineDestroy(&pAd->Mlme.SyncMachine);
472 // StateMachineDestroy(&pAd->Mlme.CntlMachine);
473 NdisFreeSpinLock(&pAd->Mlme.Queue.Lock);
474 NdisFreeSpinLock(&pAd->Mlme.TaskLock);
475 // NdisFreeSpinLock(&pAd->PortCfg.MacTab.Lock);
477 MlmeFreeMemoryHandler(pAd); //Free MLME memory handler
479 DBGPRINT(RT_DEBUG_TRACE, "<== MlmeHalt\n");
483 ==========================================================================
484 Description:
485 This routine is executed periodically to -
486 1. Decide if it's a right time to turn on PwrMgmt bit of all
487 outgoiing frames
488 2. Calculate ChannelQuality based on statistics of the last
489 period, so that TX rate won't toggling very frequently between a
490 successful TX and a failed TX.
491 3. If the calculated ChannelQuality indicated current connection not
492 healthy, then a ROAMing attempt is tried here.
493 ==========================================================================
495 #define ADHOC_BEACON_LOST_TIME (10*HZ) // 4 sec
496 VOID MlmePeriodicExec(
497 IN unsigned long data)
499 RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)data;
500 ULONG Now32;
501 CSR15_STRUC Csr15;
503 if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
505 RTMPSetTimer(pAd, &pAd->Mlme.PeriodicTimer, MLME_TASK_EXEC_INTV);
506 return;
509 if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS))
511 RTMPSetTimer(pAd, &pAd->Mlme.PeriodicTimer, MLME_TASK_EXEC_INTV);
512 return;
515 // check every 2 second. If rcv-beacon less than 5 in the past 2 second, then AvgRSSI is no longer a
516 // valid indication of the distance between this AP and its clients.
517 if (pAd->MediaState == NdisMediaStateConnected)
519 if (pAd->PortCfg.NumOfAvgRssiSample < 3)
521 pAd->PortCfg.RxAnt.AvgRssi[0] = (-95 + 120) << 3; // reset Ant-A's RSSI history
522 pAd->PortCfg.RxAnt.AvgRssi[1] = (-95 + 120) << 3; // reset Ant-B's RSSI history
523 pAd->PortCfg.AvgRssi = pAd->PortCfg.LastR17Value;
524 DBGPRINT(RT_DEBUG_TRACE, "MlmePeriodicExec: no traffic, reset Avg RSSI= %d dbm\n", pAd->PortCfg.AvgRssi);
526 else
527 pAd->PortCfg.NumOfAvgRssiSample = 0;
530 Now32 = jiffies;
532 if (pAd->RalinkCounters.MgmtRingFullCount >= 2)
534 RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HARDWARE_ERROR);
536 else
538 pAd->RalinkCounters.MgmtRingFullCount = 0;
541 if ((pAd->PortCfg.bBlockAssoc == TRUE) && (pAd->PortCfg.LastMicErrorTime + (60 * HZ) < Now32))
543 pAd->PortCfg.bBlockAssoc = FALSE;
546 // if Rx Antenna is DIVERSITY ON, then perform Software-based diversity evaluation
547 if ((pAd->PortCfg.CurrentRxAntenna == 0xff) && (pAd->Mlme.PeriodicRound % 2 == 1))
549 SHORT realavgrssi = (pAd->PortCfg.RxAnt.AvgRssi[pAd->PortCfg.RxAnt.PrimaryRxAnt] >> 3) - pAd->PortCfg.RssiToDbm;
550 DBGPRINT(RT_DEBUG_TRACE, "MlmePeriodicExec:(%d), Primary AvgRssi(%d), LastAvgRssi(%d)\n", pAd->PortCfg.RxAnt.PrimaryRxAnt, realavgrssi, pAd->PortCfg.LastAvgRssi);
551 DBGPRINT(RT_DEBUG_TRACE, "Primary AvgRssi(%d), Second AvgRssi(%d)\n", pAd->PortCfg.RxAnt.AvgRssi[pAd->PortCfg.RxAnt.PrimaryRxAnt], pAd->PortCfg.RxAnt.AvgRssi[pAd->PortCfg.RxAnt.SecondaryRxAnt]);
552 if ((realavgrssi > pAd->PortCfg.LastAvgRssi + 5) || (realavgrssi < pAd->PortCfg.LastAvgRssi - 5))
554 //DBGPRINT(RT_DEBUG_TRACE, ("AsicEvaluateSecondaryRxAnt ===> start evaluate second antenna!!!\n"));
555 pAd->PortCfg.LastAvgRssi = realavgrssi;
556 AsicEvaluateSecondaryRxAnt(pAd);
560 #ifndef WIFI_TEST
561 // danamic tune BBP R17 to find a balance between sensibility and noise isolation
562 // 2003-12-05 For 2560C and before, to avoid collision with MAC ASIC, limit
563 // BBP R17 tuning to be within 20 seconds after LINK UP. 2560D (R0=4) and
564 // after can always enable R17 tuning
565 if (pAd->PortCfg.Rt2560Version >= RT2560_VER_D)
566 AsicBbpTuning(pAd);
567 else if ((pAd->MediaState == NdisMediaStateConnected) && (pAd->Mlme.PeriodicRound <= 20))
568 AsicBbpTuning(pAd);
569 #endif
571 if (pAd->MediaState == NdisMediaStateConnected)
573 // update channel quality for Roaming and UI LinkQuality display
574 MlmeCheckChannelQuality(pAd, Now32);
575 #if 0
576 // periodic VCO tuning when there's no traffic.
577 // RF guys suspected VCO will shift away upon temperature change along the time
578 if (((pAd->Mlme.PeriodicRound % 16) == 2) &&
579 ((pAd->DrsCounters.OneSecTxOkCount + pAd->DrsCounters.OneSecTxRetryOkCount)==0))
581 DBGPRINT(RT_DEBUG_TRACE,("Periodic VCO tuning...\n"));
582 AsicSwitchChannel(pAd, pAd->PortCfg.Channel);
583 AsicLockChannel(pAd, pAd->PortCfg.Channel);
585 #endif
586 // perform dynamic tx rate switching based on past TX history
587 MlmeCheckDynamicTxRateSwitching(pAd);
590 AsicAdjustTxPower(pAd);
592 if (INFRA_ON(pAd))
594 // Is PSM bit consistent with user power management policy?
595 // This is the only place that will set PSM bit ON.
596 MlmeCheckForPsmChange(pAd, Now32);
598 // Check for EAPOL frame sent after MIC countermeasures
599 if (pAd->PortCfg.MicErrCnt >= 3)
601 MLME_DISASSOC_REQ_STRUCT DisassocReq;
603 // disassoc from current AP first
604 DBGPRINT(RT_DEBUG_TRACE, "MLME - disassociate with current AP after sending second continuous EAPOL frame\n");
605 DisassocParmFill(pAd, &DisassocReq, &pAd->PortCfg.Bssid, REASON_MIC_FAILURE);
606 MlmeEnqueue(&pAd->Mlme.Queue, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ,
607 sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq);
609 pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC;
610 pAd->PortCfg.bBlockAssoc = TRUE;
613 else
615 // send out a NULL frame every 10 sec. for what??? inform "PwrMgmt" bit?
616 if ((pAd->Mlme.PeriodicRound % 10) == 8)
617 EnqueueNullFrame(pAd, pAd->PortCfg.TxRate);
619 if (CQI_IS_BAD(pAd->Mlme.ChannelQuality))
621 pAd->RalinkCounters.BadCQIAutoRecoveryCount ++;
622 DBGPRINT(RT_DEBUG_TRACE, "MMCHK - Bad CQI. Auto Recovery attempt #%d\n", pAd->RalinkCounters.BadCQIAutoRecoveryCount);
623 MlmeAutoReconnectLastSSID(pAd);
626 else if (CQI_IS_FAIR(pAd->Mlme.ChannelQuality) || CQI_IS_POOR(pAd->Mlme.ChannelQuality))
628 // perform aggresive roaming only when SECURITY OFF or WEP64/128;
629 // WPA and WPA-PSK has no aggresive roaming because re-negotiation
630 // between 802.1x supplicant and authenticator/AAA server is required
631 // but can't be guaranteed.
632 if (pAd->PortCfg.AuthMode < Ndis802_11AuthModeWPA)
633 MlmeCheckForRoaming(pAd, Now32);
637 else if (ADHOC_ON(pAd))
639 if ((pAd->Mlme.PeriodicRound % 2) == 1)
641 // So that even when ASIC's BEACONgen engine been blocked
642 // by peer's BEACON due to slower system clock, this STA still can send out
643 // minimum BEACON to tell the peer I'm alive.
644 // drawback is that this BEACON won't well align at TBTT boundary.
645 RTMP_IO_READ32(pAd, CSR15, &Csr15.word); // read-n-clear "BcnSent" bit
646 if (Csr15.field.BeaconSent == 0)
647 EnqueueBeaconFrame(pAd); // software send BEACON
649 else
651 // if all 11b peers leave this BSS more than 5 seconds, update Tx rate
652 if ((pAd->PortCfg.Channel <= 14) &&
653 (pAd->PortCfg.MaxTxRate <= RATE_11) &&
654 (pAd->PortCfg.MaxDesiredRate > RATE_11) &&
655 ((pAd->PortCfg.Last11bBeaconRxTime + (5 * HZ)) < Now32))
657 DBGPRINT(RT_DEBUG_TRACE, "last 11B peer left, update Tx rates\n");
658 NdisMoveMemory(pAd->PortCfg.SupportedRates, pAd->PortCfg.IbssConfig.SupportedRates, MAX_LEN_OF_SUPPORTED_RATES);
659 pAd->PortCfg.SupportedRatesLen = pAd->PortCfg.IbssConfig.SupportedRatesLen;
660 MlmeUpdateTxRates(pAd, FALSE);
661 MakeIbssBeacon(pAd); // supported rates changed
665 #ifndef SINGLE_ADHOC_LINKUP
666 // If all peers leave, and this STA becomes the last one in this IBSS, then change MediaState
667 // to DISCONNECTED. But still holding this IBSS (i.e. sending BEACON) so that other STAs can
668 // join later.
669 if ((pAd->PortCfg.LastBeaconRxTime + ADHOC_BEACON_LOST_TIME < Now32) &&
670 (pAd->MediaState == NdisMediaStateConnected))
672 DBGPRINT(RT_DEBUG_TRACE, "MMCHK - excessive BEACON lost, last STA in this IBSS, MediaState=Disconnected\n");
674 pAd->MediaState = NdisMediaStateDisconnected;
675 // clean up previous SCAN result, add current BSS back to table if any
676 BssTableDeleteEntry(&pAd->PortCfg.BssTab, &(pAd->PortCfg.Bssid));
678 pAd->PortCfg.LastScanTime = Now32;
680 #endif
683 else
685 DBGPRINT(RT_DEBUG_INFO, "MLME periodic exec, no association so far\n");
686 if (pAd->PortCfg.AutoReconnect == TRUE)
688 if ((pAd->PortCfg.BssTab.BssNr==0) && (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE))
690 MLME_SCAN_REQ_STRUCT ScanReq;
692 if ((pAd->PortCfg.LastScanTime + 10 * HZ) < Now32)
694 DBGPRINT(RT_DEBUG_TRACE, "CNTL - No matching BSS, start a new scan\n");
695 // BroadSsid[0] = '\0';
696 ScanParmFill(pAd, &ScanReq, pAd->Mlme.CntlAux.Ssid, pAd->Mlme.CntlAux.SsidLen, BSS_ANY, SCAN_ACTIVE);
697 MlmeEnqueue(&pAd->Mlme.Queue, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq);
698 pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN;
699 // Reset Missed scan number
700 pAd->PortCfg.IgnoredScanNumber = 0;
701 pAd->PortCfg.LastScanTime = Now32;
703 else if (pAd->PortCfg.BssType == BSS_INDEP) // Quit the forever scan when in a very clean room
704 MlmeAutoReconnectLastSSID(pAd);
706 else if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)
708 if ((pAd->Mlme.PeriodicRound % 10) == 7)
710 if ((pAd->PortCfg.LastScanTime + 10 * HZ) < Now32)
712 MlmeAutoScan(pAd);
713 pAd->PortCfg.LastScanTime = Now32;
716 else
717 MlmeAutoReconnectLastSSID(pAd);
719 DBGPRINT(RT_DEBUG_INFO, "pAd->PortCfg.AutoReconnect is TRUE\n");
723 pAd->Mlme.PeriodicRound ++;
724 MlmeHandler(pAd);
726 if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_ACTIVE))
727 NICCheckForHang(pAd);
729 RTMPSetTimer(pAd, &pAd->Mlme.PeriodicTimer, MLME_TASK_EXEC_INTV);
732 VOID MlmeAutoScan(
733 IN PRTMP_ADAPTER pAd)
735 // check CntlMachine.CurrState to avoid collision with NDIS SetOID request
736 if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)
738 DBGPRINT(RT_DEBUG_TRACE, "MMCHK - Driver auto scan\n");
740 // tell CNTL state machine NOT to call NdisMSetInformationComplete() after completing
741 // this request, because this request is initiated by driver itself.
742 pAd->Mlme.CntlAux.CurrReqIsFromNdis = FALSE;
744 MlmeEnqueue(&pAd->Mlme.Queue,
745 MLME_CNTL_STATE_MACHINE,
746 OID_802_11_BSSID_LIST_SCAN,
748 NULL);
749 MlmeHandler(pAd);
753 VOID MlmeAutoRecoverNetwork(
754 IN PRTMP_ADAPTER pAd)
756 // check CntlMachine.CurrState to avoid collision with NDIS SetOID request
757 if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)
759 NDIS_802_11_SSID OidSsid;
760 OidSsid.SsidLength = pAd->PortCfg.SsidLen;
761 NdisMoveMemory(OidSsid.Ssid, pAd->PortCfg.Ssid, pAd->PortCfg.SsidLen);
763 DBGPRINT(RT_DEBUG_TRACE, "MMCHK - Driver auto recovering network - %s\n", pAd->PortCfg.Ssid);
765 // tell CNTL state machine NOT to call NdisMSetInformationComplete() after completing
766 // this request, because this request is initiated by driver itself.
767 pAd->Mlme.CntlAux.CurrReqIsFromNdis = FALSE;
769 MlmeEnqueue(&pAd->Mlme.Queue,
770 MLME_CNTL_STATE_MACHINE,
771 OID_802_11_SSID,
772 sizeof(NDIS_802_11_SSID),
773 &OidSsid);
774 MlmeHandler(pAd);
779 VOID MlmeAutoReconnectLastSSID(
780 IN PRTMP_ADAPTER pAd)
782 // check CntlMachine.CurrState to avoid collision with NDIS SetOID request
783 if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)
785 NDIS_802_11_SSID OidSsid;
786 OidSsid.SsidLength = pAd->Mlme.CntlAux.SsidLen;
787 NdisMoveMemory(OidSsid.Ssid, pAd->Mlme.CntlAux.Ssid, pAd->Mlme.CntlAux.SsidLen);
789 DBGPRINT(RT_DEBUG_TRACE, "Driver auto reconnect to last OID_802_11_SSID setting - %s\n", pAd->Mlme.CntlAux.Ssid);
791 // We will only try this attemp once, therefore change the AutoReconnect flag afterwards.
792 pAd->Mlme.CntlAux.CurrReqIsFromNdis = FALSE;
794 MlmeEnqueue(&pAd->Mlme.Queue,
795 MLME_CNTL_STATE_MACHINE,
796 OID_802_11_SSID,
797 sizeof(NDIS_802_11_SSID),
798 &OidSsid);
799 MlmeHandler(pAd);
804 ==========================================================================
805 Description:
806 This routine checks if there're other APs out there capable for
807 roaming. Caller should call this routine only when Massoc=TRUE and
808 channel quality is below CQI_GOOD_THRESHOLD.
809 Output:
810 ==========================================================================
812 VOID MlmeCheckForRoaming(
813 IN PRTMP_ADAPTER pAd,
814 IN ULONG Now32)
816 USHORT i;
817 BSS_TABLE *pBssTab = &pAd->Mlme.CntlAux.SsidBssTab;
818 BSS_TABLE *pRoamTab = &pAd->Mlme.CntlAux.RoamTab;
819 BSS_ENTRY *pBss;
821 // put all roaming candidates into RoamTab, and sort in RSSI order
822 BssTableInit(pRoamTab);
823 for (i = 0; i < pBssTab->BssNr; i++)
825 pBss = &pBssTab->BssEntry[i];
827 if ((pBssTab->BssEntry[i].LastBeaconRxTime + BEACON_LOST_TIME) < Now32)
828 continue; // AP disappear
829 if (pBss->Rssi <= RSSI_THRESHOLD_FOR_ROAMING)
830 continue; // RSSI too weak. forget it.
831 if (MAC_ADDR_EQUAL(&pBssTab->BssEntry[i].Bssid, &pAd->PortCfg.Bssid))
832 continue; // skip current AP
833 if (CQI_IS_FAIR(pAd->Mlme.ChannelQuality) && (pAd->PortCfg.LastRssi + RSSI_DELTA > pBss->Rssi))
834 continue; // we're still okay, only AP with stronger RSSI is eligible for roaming
836 // AP passing all above rules is put into roaming candidate table
837 NdisMoveMemory(&pRoamTab->BssEntry[pRoamTab->BssNr], pBss, sizeof(BSS_ENTRY));
838 pRoamTab->BssNr += 1;
841 if (pRoamTab->BssNr > 0)
843 // check CntlMachine.CurrState to avoid collision with NDIS SetOID request
844 if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)
846 // tell CNTL state machine NOT to call NdisMSetInformationComplete() after completing
847 // this request, because this request is initiated by driver itself, not from NDIS.
848 pAd->Mlme.CntlAux.CurrReqIsFromNdis = FALSE;
850 pAd->RalinkCounters.PoorCQIRoamingCount ++;
851 DBGPRINT(RT_DEBUG_TRACE, "MMCHK - Roaming attempt #%d\n", pAd->RalinkCounters.PoorCQIRoamingCount);
852 MlmeEnqueue(&pAd->Mlme.Queue, MLME_CNTL_STATE_MACHINE, MT2_MLME_ROAMING_REQ, 0, NULL);
853 MlmeHandler(pAd);
860 ==========================================================================
861 Description:
862 This routine calculates TxPER, RxPER of the past N-sec period. And
863 according to the calculation result, ChannelQuality is calculated here
864 to decide if current AP is still doing the job.
866 If ChannelQuality is not good, a ROAMing attempt may be tried later.
867 Output:
868 PortCfg.ChannelQuality - 0..100
869 ==========================================================================
871 VOID MlmeCheckChannelQuality(
872 IN PRTMP_ADAPTER pAd,
873 IN ULONG Now32)
875 ULONG TxFailCnt, TxOkCnt, TxRetryCnt, TxCnt, TxPER, TxPRR;
876 ULONG RxFailCnt, RxOkCnt, RxCnt, RxPER, Cnt0, OldFcsCount;
879 // monitor TX counters change for the past period
881 TxFailCnt = pAd->WlanCounters.FailedCount.vv.LowPart -
882 pAd->Mlme.PrevWlanCounters.FailedCount.vv.LowPart;
883 TxRetryCnt = pAd->WlanCounters.RetryCount.vv.LowPart -
884 pAd->Mlme.PrevWlanCounters.RetryCount.vv.LowPart;
885 TxOkCnt = pAd->WlanCounters.TransmittedFragmentCount.vv.LowPart -
886 pAd->Mlme.PrevWlanCounters.TransmittedFragmentCount.vv.LowPart;
887 TxCnt = TxOkCnt + TxFailCnt;
889 if (TxCnt < 5) // if too few TX samples, skip TX related statistics
891 TxPER = 0; // don't take TxPER into CQI consideration if too few sample
892 TxPRR = 0;
894 else
896 TxPER = (TxFailCnt * 100) / TxCnt;
897 TxPRR = ((TxRetryCnt + TxFailCnt) * 100) / TxCnt;
901 // calculate RX PER
904 // Update FCS counters
905 RTMP_IO_READ32(pAd, CNT0, &Cnt0);
906 OldFcsCount= pAd->WlanCounters.FCSErrorCount.vv.LowPart;
907 pAd->WlanCounters.FCSErrorCount.vv.LowPart += ((Cnt0 & 0x0000ffff) >> 7);
908 if (pAd->WlanCounters.FCSErrorCount.vv.LowPart < OldFcsCount)
909 pAd->WlanCounters.FCSErrorCount.vv.HighPart++;
911 // Add FCS error count to private counters
912 OldFcsCount = pAd->RalinkCounters.RealFcsErrCount.vv.LowPart;
913 pAd->RalinkCounters.RealFcsErrCount.vv.LowPart += Cnt0;
914 if (pAd->RalinkCounters.RealFcsErrCount.vv.LowPart < OldFcsCount)
915 pAd->RalinkCounters.RealFcsErrCount.vv.HighPart++;
917 RxOkCnt = pAd->WlanCounters.ReceivedFragmentCount.vv.LowPart -
918 pAd->Mlme.PrevWlanCounters.ReceivedFragmentCount.vv.LowPart;
919 RxFailCnt = pAd->RalinkCounters.RealFcsErrCount.vv.LowPart -
920 pAd->Mlme.PrevWlanCounters.FCSErrorCount.vv.LowPart;
921 RxCnt = RxOkCnt + RxFailCnt;
923 if (RxCnt < 5)
924 RxPER = 0; // don't take RxPER into ChannelQuality consideration if too few sample
925 else
926 RxPER = (RxFailCnt * 100) / RxCnt;
928 // decide ChannelQuality based on: 1)last BEACON received time, 2)last RSSI, 3)TxPER, and 4)RxPER
930 // This value also decides when all roaming fails (or no roaming candidates at
931 // all), should this STA stay with original AP, or a LinkDown signal
932 // is indicated to NDIS
934 if (INFRA_ON(pAd) &&
935 (pAd->PortCfg.LastBeaconRxTime + BEACON_LOST_TIME < Now32)) // BEACON starving?
937 // Ignore lost beacon when NIC in reset state
938 // Ignore lost beacon if traffic still goes well
939 if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) && (TxOkCnt < 2))
941 DBGPRINT(RT_DEBUG_TRACE, "BEACON lost for more than %d sec with TxOkCnt=%d, let CQI = 0\n", BEACON_LOST_TIME/HZ, TxOkCnt);
942 pAd->Mlme.ChannelQuality = 0;
943 // Lost AP, send disconnect & link down event
944 LinkDown(pAd);
947 else
949 // ChannelQuality = W1*RSSI + W2*TxPRR + W3*RxPER (RSSI 0..100), (TxPER 100..0), (RxPER 100..0)
950 pAd->Mlme.ChannelQuality = (RSSI_WEIGHTING * pAd->PortCfg.LastRssi +
951 TX_WEIGHTING * (100 - TxPRR) +
952 RX_WEIGHTING* (100 - RxPER)) / 100;
953 if (pAd->Mlme.ChannelQuality >= 100)
954 pAd->Mlme.ChannelQuality = 100;
957 // latch current WLAN counters for next check-for-roaming usage
958 NdisMoveMemory(&pAd->Mlme.PrevWlanCounters, &pAd->WlanCounters, sizeof(COUNTER_802_11));
959 // make sure copy the real FCS counts into previous mlme counter structure.
960 pAd->Mlme.PrevWlanCounters.FCSErrorCount = pAd->RalinkCounters.RealFcsErrCount;
962 DBGPRINT(RT_DEBUG_INFO, "MMCHK - CQI= %d, (Tx Fail=%d/Retry=%d/Total=%d, Rx Fail=%d/Total=%d, RSSI=%d dbm)\n",
963 pAd->Mlme.ChannelQuality, TxFailCnt, TxRetryCnt, TxCnt, RxFailCnt, RxCnt, pAd->PortCfg.LastRssi - pAd->PortCfg.RssiToDbm);
968 ==========================================================================
969 Description:
970 This routine calculates the acumulated TxPER of eaxh TxRate. And
971 according to the calculation result, change PortCfg.TxRate which
972 is the stable TX Rate we expect the Radio situation could sustained.
974 PortCfg.TxRate will change dynamically within {RATE_1/RATE_6, MaxTxRate}
975 Output:
976 PortCfg.TxRate -
977 NOTE:
978 call this routine every second
979 ==========================================================================
981 VOID MlmeCheckDynamicTxRateSwitching(
982 IN PRTMP_ADAPTER pAd)
984 UCHAR UpRate, DownRate, CurrRate;
985 USHORT TxTotalCnt = pAd->DrsCounters.OneSecTxOkCount + pAd->DrsCounters.OneSecTxRetryOkCount + pAd->DrsCounters.OneSecTxFailCount;
986 USHORT TxErrorRatio;
987 BOOLEAN fUpgradeQuality = FALSE;
988 USHORT *pRateUpPER, *pRateDownPER;
990 pAd->DrsCounters.CurrTxRateStableTime ++;
991 CurrRate = pAd->PortCfg.TxRate;
994 if (pAd->PortCfg.EnableAutoRateSwitching == FALSE)
995 break;
997 // if no traffic in the past 1-sec period, don't change TX rate,
998 // but clear all bad history. because the bad history may affect the next
999 // Chariot throughput test
1000 if (TxTotalCnt == 0)
1002 pAd->DrsCounters.TxRateUpPenalty = 0;
1003 NdisZeroMemory(pAd->DrsCounters.TxQuality, MAX_LEN_OF_SUPPORTED_RATES);
1004 NdisZeroMemory(pAd->DrsCounters.PER, MAX_LEN_OF_SUPPORTED_RATES);
1005 break;
1008 // decide the next upgrade rate and downgrade rate, if any
1009 if (pAd->PortCfg.PhyMode == PHY_11BG_MIXED)
1011 UpRate = Phy11BGNextRateUpward[CurrRate];
1012 DownRate = Phy11BGNextRateDownward[CurrRate];
1014 else if (pAd->PortCfg.PhyMode == PHY_11B)
1016 UpRate = Phy11BNextRateUpward[CurrRate];
1017 DownRate = Phy11BNextRateDownward[CurrRate];
1019 else if (pAd->PortCfg.PhyMode == PHY_11A)
1021 UpRate = Phy11ANextRateUpward[CurrRate];
1022 DownRate = Phy11ANextRateDownward[CurrRate];
1024 else // PHY_11ABG_MIXED
1026 if (pAd->PortCfg.Channel > 14)
1028 UpRate = Phy11ANextRateUpward[CurrRate];
1029 DownRate = Phy11ANextRateDownward[CurrRate];
1031 else
1033 UpRate = Phy11BGNextRateUpward[CurrRate];
1034 DownRate = Phy11BGNextRateDownward[CurrRate];
1038 if (UpRate > pAd->PortCfg.MaxTxRate)
1039 UpRate = pAd->PortCfg.MaxTxRate;
1041 // decide TX quality based on Tx PER when enough samples are available
1042 if (TxTotalCnt > 15)
1044 TxErrorRatio = ((pAd->DrsCounters.OneSecTxRetryOkCount + pAd->DrsCounters.OneSecTxFailCount) *100) / TxTotalCnt;
1046 // 2560D and after has implemented ASIC-based OFDM rate switching,
1047 // but not 2560C & before. thus software use different PER for rate switching
1048 if (pAd->PortCfg.Rt2560Version >= RT2560_VER_D)
1050 pRateUpPER = &NewRateUpPER[0];
1051 pRateDownPER = &NewRateDownPER[0];
1053 else
1055 pRateUpPER = &OldRateUpPER[0];
1056 pRateDownPER = &OldRateDownPER[0];
1059 // downgrade TX quality if PER >= Rate-Down threshold
1060 if (TxErrorRatio >= pRateDownPER[CurrRate])
1062 pAd->DrsCounters.TxQuality[CurrRate] = DRS_TX_QUALITY_WORST_BOUND;
1064 // upgrade TX quality if PER <= Rate-Up threshold
1065 else if (TxErrorRatio <= pRateUpPER[CurrRate])
1067 fUpgradeQuality = TRUE;
1068 if (pAd->DrsCounters.TxQuality[CurrRate])
1069 pAd->DrsCounters.TxQuality[CurrRate] --; // quality very good in CurrRate
1071 if (pAd->DrsCounters.TxRateUpPenalty)
1072 pAd->DrsCounters.TxRateUpPenalty --;
1073 else if (pAd->DrsCounters.TxQuality[UpRate])
1074 pAd->DrsCounters.TxQuality[UpRate] --; // may improve next UP rate's quality
1079 // if not enough TX samples, decide by heuristic rules
1080 else
1082 TxErrorRatio = 0;
1084 // Downgrade TX quality upon any TX failure in the past second
1085 if (pAd->DrsCounters.OneSecTxFailCount)
1087 if ((pAd->DrsCounters.OneSecTxFailCount <= 1) &&
1088 (pAd->DrsCounters.OneSecTxOkCount + pAd->DrsCounters.OneSecTxRetryOkCount))
1090 pAd->DrsCounters.TxQuality[CurrRate] += 2; // degrade quality
1091 if (pAd->DrsCounters.TxQuality[CurrRate] > DRS_TX_QUALITY_WORST_BOUND)
1092 pAd->DrsCounters.TxQuality[CurrRate] = DRS_TX_QUALITY_WORST_BOUND;
1094 else // more than 2 failure, or no TX ok cases
1096 pAd->DrsCounters.TxQuality[CurrRate] = DRS_TX_QUALITY_WORST_BOUND;
1099 // upgrade TX quality if -
1100 // 1. no TX failure but do have TX ok case, and
1101 // 2. there's more one-time-ok cases than retry-ok cases in the past second
1102 else if ((pAd->DrsCounters.OneSecTxOkCount > pAd->DrsCounters.OneSecTxRetryOkCount))
1104 fUpgradeQuality = TRUE;
1105 if (pAd->DrsCounters.TxQuality[CurrRate])
1106 pAd->DrsCounters.TxQuality[CurrRate] --; // quality very good in CurrRate
1108 if (pAd->DrsCounters.TxRateUpPenalty)
1109 pAd->DrsCounters.TxRateUpPenalty --;
1110 else if (pAd->DrsCounters.TxQuality[UpRate])
1111 pAd->DrsCounters.TxQuality[UpRate] --; // may improve next UP rate's quality
1115 pAd->DrsCounters.PER[CurrRate] = (UCHAR)TxErrorRatio;
1117 if (pAd->DrsCounters.fNoisyEnvironment)
1119 DBGPRINT(RT_DEBUG_TRACE,"DRS(noisy):");
1121 else
1123 DBGPRINT(RT_DEBUG_TRACE,"DRS:");
1125 DBGPRINT(RT_DEBUG_TRACE, "Qty[%d]=%d PER=%d%% %d-sec, Qty[%d]=%d, Pty=%d\n",
1126 RateIdToMbps[CurrRate], pAd->DrsCounters.TxQuality[CurrRate],
1127 TxErrorRatio,
1128 pAd->DrsCounters.CurrTxRateStableTime,
1129 RateIdToMbps[UpRate], pAd->DrsCounters.TxQuality[UpRate],
1130 pAd->DrsCounters.TxRateUpPenalty);
1132 // 2004-3-13 special case: Claim noisy environment
1133 // decide if there was a false "rate down" in the past 2 sec due to noisy
1134 // environment. if so, we would rather switch back to the higher TX rate.
1135 // criteria -
1136 // 1. there's a higher rate available, AND
1137 // 2. there was a rate-down happened, AND
1138 // 3. current rate has 75% > PER > 20%, AND
1139 // 4. comparing to UpRate, current rate didn't improve PER more than 5 %
1140 if ((UpRate != CurrRate) &&
1141 (pAd->DrsCounters.LastSecTxRateChangeAction == 2) &&
1142 (TxTotalCnt > 15) && // this line is to prevent the case that not enough TX sample causing PER=0%
1143 (pAd->DrsCounters.PER[CurrRate] < 75) &&
1144 ((pAd->DrsCounters.PER[CurrRate] > 20) || (pAd->DrsCounters.fNoisyEnvironment)) &&
1145 ((pAd->DrsCounters.PER[CurrRate]+5) > pAd->DrsCounters.PER[UpRate]))
1147 // we believe this is a noisy environment. better stay at UpRate
1148 DBGPRINT(RT_DEBUG_TRACE,"DRS: #### enter Noisy environment ####\n");
1149 pAd->DrsCounters.fNoisyEnvironment = TRUE;
1151 // 2004-3-14 when claiming noisy environment, we're not only switch back
1152 // to UpRate, but can be more aggressive to use one more rate up
1153 UpRate++;
1154 // if (UpRate>RATE_54) UpRate=RATE_54;
1155 if ((UpRate==RATE_6) || (UpRate==RATE_9)) UpRate=RATE_12;
1156 if (UpRate > pAd->PortCfg.MaxTxRate)
1157 UpRate = pAd->PortCfg.MaxTxRate;
1158 pAd->PortCfg.TxRate = UpRate;
1159 break;
1162 // 2004-3-12 special case: Leave noisy environment
1163 // The interference has gone suddenly. reset TX rate to
1164 // the theoritical value according to RSSI. Criteria -
1165 // 1. it's currently in noisy environment
1166 // 2. PER drops to be below 12%
1167 if ((pAd->DrsCounters.fNoisyEnvironment == TRUE) &&
1168 (TxTotalCnt > 15) && (pAd->DrsCounters.PER[CurrRate] <= 12))
1170 UCHAR JumpUpRate;
1172 pAd->DrsCounters.fNoisyEnvironment = FALSE;
1173 for (JumpUpRate = RATE_54; JumpUpRate > RATE_1; JumpUpRate--)
1175 if (pAd->PortCfg.AvgRssi > (RssiSafeLevelForTxRate[JumpUpRate] + pAd->PortCfg.RssiToDbm))
1176 break;
1179 if (JumpUpRate > pAd->PortCfg.MaxTxRate)
1180 JumpUpRate = pAd->PortCfg.MaxTxRate;
1182 DBGPRINT(RT_DEBUG_TRACE,"DRS: #### leave Noisy environment ####, RSSI=%d, JumpUpRate=%d\n",
1183 pAd->PortCfg.AvgRssi - pAd->PortCfg.RssiToDbm, RateIdToMbps[JumpUpRate]);
1185 if (JumpUpRate > CurrRate)
1187 pAd->PortCfg.TxRate = JumpUpRate;
1188 break;
1192 // we're going to upgrade CurrRate to UpRate at next few seconds,
1193 // but before that, we'd better try a NULL frame @ UpRate and
1194 // see if UpRate is stable or not. If this NULL frame fails, it will
1195 // downgrade TxQuality[CurrRate], so that STA won't switch to
1196 // to UpRate in the next second
1197 // 2004-04-07 requested by David Tung - sent test frames only in OFDM rates
1198 if (fUpgradeQuality &&
1199 INFRA_ON(pAd) &&
1200 (UpRate != CurrRate) &&
1201 (UpRate > RATE_11) &&
1202 (pAd->DrsCounters.TxQuality[CurrRate] <= 1) &&
1203 (pAd->DrsCounters.TxQuality[UpRate] <= 1))
1205 DBGPRINT(RT_DEBUG_TRACE,"DRS: 2 NULL frames at UpRate = %d Mbps\n",RateIdToMbps[UpRate]);
1206 EnqueueNullFrame(pAd, UpRate);
1207 EnqueueNullFrame(pAd, UpRate);
1210 // perform DRS - consider TxRate Down first, then rate up.
1211 // 1. rate down, if current TX rate's quality is not good
1212 // 2. rate up, if UPRate's quality is very good
1213 if ((pAd->DrsCounters.TxQuality[CurrRate] >= DRS_TX_QUALITY_WORST_BOUND) &&
1214 (CurrRate != DownRate))
1216 #ifdef WIFI_TEST
1217 if (DownRate <= RATE_2) break; // never goes lower than 5.5 Mbps TX rate
1218 #endif
1219 pAd->PortCfg.TxRate = DownRate;
1221 else if ((pAd->DrsCounters.TxQuality[CurrRate] <= 0) &&
1222 (pAd->DrsCounters.TxQuality[UpRate] <=0) &&
1223 (CurrRate != UpRate))
1225 pAd->PortCfg.TxRate = UpRate;
1228 }while (FALSE);
1231 // if rate-up happen, clear all bad history of all TX rates
1232 if (pAd->PortCfg.TxRate > CurrRate)
1234 DBGPRINT(RT_DEBUG_TRACE,"DRS: ++TX rate from %d to %d Mbps\n", RateIdToMbps[CurrRate],RateIdToMbps[pAd->PortCfg.TxRate]);
1235 pAd->DrsCounters.CurrTxRateStableTime = 0;
1236 pAd->DrsCounters.TxRateUpPenalty = 0;
1237 pAd->DrsCounters.LastSecTxRateChangeAction = 1; // rate UP
1238 NdisZeroMemory(pAd->DrsCounters.TxQuality, MAX_LEN_OF_SUPPORTED_RATES);
1239 NdisZeroMemory(pAd->DrsCounters.PER, MAX_LEN_OF_SUPPORTED_RATES);
1241 // if rate-down happen, only clear DownRate's bad history
1242 else if (pAd->PortCfg.TxRate < CurrRate)
1244 DBGPRINT(RT_DEBUG_TRACE,"DRS: --TX rate from %d to %d Mbps\n", RateIdToMbps[CurrRate],RateIdToMbps[pAd->PortCfg.TxRate]);
1245 // shorter stable time require more penalty in next rate UP criteria
1246 if (pAd->DrsCounters.CurrTxRateStableTime < 4) // less then 4 sec
1247 pAd->DrsCounters.TxRateUpPenalty = DRS_PENALTY; // add 8 sec penalty
1248 else if (pAd->DrsCounters.CurrTxRateStableTime < 8) // less then 8 sec
1249 pAd->DrsCounters.TxRateUpPenalty = 2; // add 2 sec penalty
1250 else // >= 8 sec
1251 pAd->DrsCounters.TxRateUpPenalty = 0; // no penalty
1253 pAd->DrsCounters.CurrTxRateStableTime = 0;
1254 pAd->DrsCounters.LastSecTxRateChangeAction = 2; // rate DOWN
1255 pAd->DrsCounters.TxQuality[pAd->PortCfg.TxRate] = 0;
1256 pAd->DrsCounters.PER[pAd->PortCfg.TxRate] = 0;
1258 else
1259 pAd->DrsCounters.LastSecTxRateChangeAction = 0; // rate no change
1261 // reset all OneSecxxx counters
1262 pAd->DrsCounters.OneSecTxFailCount = 0;
1263 pAd->DrsCounters.OneSecTxOkCount = 0;
1264 pAd->DrsCounters.OneSecTxRetryOkCount = 0;
1268 ==========================================================================
1269 Description:
1270 This routine is executed periodically inside MlmePeriodicExec() after
1271 association with an AP.
1272 It checks if PortCfg.Psm is consistent with user policy (recorded in
1273 PortCfg.WindowsPowerMode). If not, enforce user policy. However,
1274 there're some conditions to consider:
1275 1. we don't support power-saving in ADHOC mode, so Psm=PWR_ACTIVE all
1276 the time when Mibss==TRUE
1277 2. When Massoc==TRUE (INFRA mode), Psm should not be switch to PWR_SAVE
1278 if outgoing traffic available in TxRing or PrioRing.
1279 Output:
1280 1. change pAd->PortCfg.Psm to PWR_SAVE or leave it untouched
1281 ==========================================================================
1283 VOID MlmeCheckForPsmChange(
1284 IN PRTMP_ADAPTER pAd,
1285 IN ULONG Now32)
1287 ULONG PowerMode;
1288 // condition -
1289 // 1. Psm maybe ON only happen in INFRASTRUCTURE mode
1290 // 2. user wants either MAX_PSP or FAST_PSP
1291 // 3. but current psm is not in PWR_SAVE
1292 // 4. CNTL state machine is not doing SCANning
1293 // 5. no TX SUCCESS event for the past period
1294 PowerMode = pAd->PortCfg.WindowsPowerMode;
1296 if (INFRA_ON(pAd) &&
1297 (PowerMode != Ndis802_11PowerModeCAM) &&
1298 (pAd->PortCfg.Psm == PWR_ACTIVE) &&
1299 (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) &&
1300 (pAd->WlanCounters.TransmittedFragmentCount.vv.LowPart == pAd->Mlme.PrevTxCnt))
1302 MlmeSetPsmBit(pAd, PWR_SAVE);
1303 EnqueueNullFrame(pAd, pAd->PortCfg.TxRate);
1306 // latch current count for next-time comparison
1307 pAd->Mlme.PrevTxCnt = pAd->WlanCounters.TransmittedFragmentCount.vv.LowPart;
1311 VOID MlmeSetPsmBit(
1312 IN PRTMP_ADAPTER pAd,
1313 IN USHORT psm)
1315 TXCSR7_STRUC txcsr7;
1317 txcsr7.word = 0;
1318 pAd->PortCfg.Psm = psm;
1320 DBGPRINT(RT_DEBUG_TRACE, "MMCHK - change PSM bit to %d <<<\n", psm);
1321 if (psm == PWR_SAVE)
1323 txcsr7.field.ARPowerManage = 1;
1324 RTMP_IO_WRITE32(pAd, TXCSR7, txcsr7.word);
1326 else
1328 txcsr7.field.ARPowerManage = 0;
1329 RTMP_IO_WRITE32(pAd, TXCSR7, txcsr7.word);
1333 VOID MlmeSetTxPreamble(
1334 IN PRTMP_ADAPTER pAd,
1335 IN USHORT TxPreamble)
1337 ULONG Plcp1MCsr = 0x00700400; // 0x13c, ACK/CTS PLCP at 1 Mbps
1338 ULONG Plcp2MCsr = 0x00380401; // 0x140, ACK/CTS PLCP at 2 Mbps
1339 ULONG Plcp5MCsr = 0x00150402; // 0x144, ACK/CTS PLCP at 5.5 Mbps
1340 ULONG Plcp11MCsr = 0x000b8403; // 0x148, ACK/CTS PLCP at 11 Mbps
1342 if (TxPreamble == Rt802_11PreambleShort)
1344 DBGPRINT(RT_DEBUG_TRACE, "MlmeSetTxPreamble (= SHORT PREAMBLE)\n");
1345 // Plcp1MCsr |= 0x00000008; // 1Mbps should always use long preamble
1346 Plcp2MCsr |= 0x00000008;
1347 Plcp5MCsr |= 0x00000008;
1348 Plcp11MCsr |= 0x00000008;
1349 pAd->PortCfg.TxPreambleInUsed = Rt802_11PreambleShort;
1351 else
1353 DBGPRINT(RT_DEBUG_TRACE, "MlmeSetTxPreamble (= LONG PREAMBLE)\n");
1354 pAd->PortCfg.TxPreambleInUsed = Rt802_11PreambleLong;
1357 RTMP_IO_WRITE32(pAd, PLCP1MCSR, Plcp1MCsr);
1358 RTMP_IO_WRITE32(pAd, PLCP2MCSR, Plcp2MCsr);
1359 RTMP_IO_WRITE32(pAd, PLCP5MCSR, Plcp5MCsr);
1360 RTMP_IO_WRITE32(pAd, PLCP11MCSR, Plcp11MCsr);
1363 VOID MlmeUpdateTxRates(
1364 IN PRTMP_ADAPTER pAd,
1365 IN BOOLEAN bLinkUp)
1367 int i, num;
1368 UCHAR Rate, MaxDesire = RATE_1, MaxSupport = RATE_1;
1369 ULONG BasicRateBitmap = 0;
1370 UCHAR CurrBasicRate = RATE_1;
1372 // find max desired rate
1373 num = 0;
1374 for (i=0; i<MAX_LEN_OF_SUPPORTED_RATES; i++)
1376 switch (pAd->PortCfg.DesiredRates[i] & 0x7f)
1378 case 2: Rate = RATE_1; num++; break;
1379 case 4: Rate = RATE_2; num++; break;
1380 case 11: Rate = RATE_5_5; num++; break;
1381 case 22: Rate = RATE_11; num++; break;
1382 case 12: Rate = RATE_6; num++; break;
1383 case 18: Rate = RATE_9; num++; break;
1384 case 24: Rate = RATE_12; num++; break;
1385 case 36: Rate = RATE_18; num++; break;
1386 case 48: Rate = RATE_24; num++; break;
1387 case 72: Rate = RATE_36; num++; break;
1388 case 96: Rate = RATE_48; num++; break;
1389 case 108: Rate = RATE_54; num++; break;
1390 default: Rate = RATE_1; break;
1392 if (MaxDesire < Rate) MaxDesire = Rate;
1395 // 2003-12-10 802.11g WIFI spec disallow OFDM rates in 802.11g ADHOC mode
1396 if ((pAd->PortCfg.BssType == BSS_INDEP) &&
1397 (pAd->PortCfg.PhyMode == PHY_11BG_MIXED) &&
1398 (pAd->PortCfg.AdhocMode == 0) &&
1399 (MaxDesire > RATE_11))
1400 MaxDesire = RATE_11;
1402 pAd->PortCfg.MaxDesiredRate = MaxDesire;
1404 // Auto rate switching is enabled only if more than one DESIRED RATES are
1405 // specified; otherwise disabled
1406 if (num <= 1)
1407 pAd->PortCfg.EnableAutoRateSwitching = FALSE;
1408 else
1409 pAd->PortCfg.EnableAutoRateSwitching = TRUE;
1411 // find max supported rate
1412 for (i=0; i<pAd->PortCfg.SupportedRatesLen; i++)
1414 switch (pAd->PortCfg.SupportedRates[i] & 0x7f)
1416 case 2: Rate = RATE_1;
1417 if (pAd->PortCfg.SupportedRates[i] & 0x80)
1418 BasicRateBitmap |= 0x0001;
1419 break;
1420 case 4: Rate = RATE_2;
1421 if (pAd->PortCfg.SupportedRates[i] & 0x80)
1422 BasicRateBitmap |= 0x0002;
1423 break;
1424 case 11:
1425 Rate = RATE_5_5;
1426 if (pAd->PortCfg.SupportedRates[i] & 0x80)
1427 BasicRateBitmap |= 0x0004;
1428 break;
1429 case 22:
1430 Rate = RATE_11;
1431 if (pAd->PortCfg.SupportedRates[i] & 0x80)
1432 BasicRateBitmap |= 0x0008;
1433 break;
1434 case 12:
1435 Rate = RATE_6;
1436 // if (pAd->PortCfg.SupportedRates[i] & 0x80)
1437 BasicRateBitmap |= 0x0010;
1438 break;
1439 case 18:
1440 Rate = RATE_9;
1441 if (pAd->PortCfg.SupportedRates[i] & 0x80)
1442 BasicRateBitmap |= 0x0020;
1443 break;
1444 case 24:
1445 Rate = RATE_12;
1446 // if (pAd->PortCfg.SupportedRates[i] & 0x80)
1447 BasicRateBitmap |= 0x0040;
1448 break;
1449 case 36:
1450 Rate = RATE_18;
1451 if (pAd->PortCfg.SupportedRates[i] & 0x80)
1452 BasicRateBitmap |= 0x0080;
1453 break;
1454 case 48:
1455 Rate = RATE_24;
1456 // if (pAd->PortCfg.SupportedRates[i] & 0x80)
1457 BasicRateBitmap |= 0x0100;
1458 break;
1459 case 72:
1460 Rate = RATE_36;
1461 if (pAd->PortCfg.SupportedRates[i] & 0x80)
1462 BasicRateBitmap |= 0x0200;
1463 break;
1464 case 96:
1465 Rate = RATE_48;
1466 if (pAd->PortCfg.SupportedRates[i] & 0x80)
1467 BasicRateBitmap |= 0x0400;
1468 break;
1469 case 108:
1470 Rate = RATE_54;
1471 if (pAd->PortCfg.SupportedRates[i] & 0x80)
1472 BasicRateBitmap |= 0x0800;
1473 break;
1474 default:
1475 Rate = RATE_1;
1476 break;
1478 if (MaxSupport < Rate) MaxSupport = Rate;
1480 RTMP_IO_WRITE32(pAd, ARCSR1, BasicRateBitmap);
1482 // calculate the exptected ACK rate for each TX rate. This info is used to caculate
1483 // the DURATION field of outgoing uniicast DATA/MGMT frame
1484 for (i=0; i<MAX_LEN_OF_SUPPORTED_RATES; i++)
1486 if (BasicRateBitmap & (0x01 << i))
1487 CurrBasicRate = (UCHAR)i;
1488 pAd->PortCfg.ExpectedACKRate[i] = CurrBasicRate;
1489 DBGPRINT(RT_DEBUG_INFO,"Exptected ACK rate[%d] = %d Mbps\n", RateIdToMbps[i], RateIdToMbps[CurrBasicRate]);
1492 // max tx rate = min {max desire rate, max supported rate}
1493 if (MaxSupport < MaxDesire)
1494 pAd->PortCfg.MaxTxRate = MaxSupport;
1495 else
1496 pAd->PortCfg.MaxTxRate = MaxDesire;
1498 // 2003-07-31 john - 2500 doesn't have good sensitivity at high OFDM rates. to increase the success
1499 // ratio of initial DHCP packet exchange, TX rate starts from a lower rate depending
1500 // on average RSSI
1501 // 1. RSSI >= -70db, start at 54 Mbps (short distance)
1502 // 2. -70 > RSSI >= -75, start at 24 Mbps (mid distance)
1503 // 3. -75 > RSSI, start at 11 Mbps (long distance)
1504 if (pAd->PortCfg.EnableAutoRateSwitching)
1506 if (pAd->PortCfg.Channel > 14)
1507 pAd->PortCfg.TxRate = RATE_6; // 802.11a
1508 else
1510 short dbm = pAd->PortCfg.AvgRssi - pAd->PortCfg.RssiToDbm;
1511 if (bLinkUp == TRUE)
1512 pAd->PortCfg.TxRate = RATE_24;
1513 else
1514 pAd->PortCfg.TxRate = pAd->PortCfg.MaxTxRate;
1515 if (dbm < -75)
1516 pAd->PortCfg.TxRate = RATE_11;
1517 else if ((dbm < -70) && (pAd->PortCfg.TxRate > RATE_24))
1518 pAd->PortCfg.TxRate = RATE_24;
1519 DBGPRINT(RT_DEBUG_TRACE, " MlmeUpdateTxRates (Rssi=%d, init TX rate = %d Mbps)\n", dbm, RateIdToMbps[pAd->PortCfg.TxRate]);
1522 else
1523 pAd->PortCfg.TxRate = pAd->PortCfg.MaxTxRate;
1525 switch (pAd->PortCfg.PhyMode) {
1526 case PHY_11BG_MIXED:
1527 case PHY_11B:
1528 pAd->PortCfg.MlmeRate = RATE_2;
1529 #ifdef WIFI_TEST
1530 pAd->PortCfg.RtsRate = RATE_11;
1531 #else
1532 pAd->PortCfg.RtsRate = RATE_2;
1533 #endif
1534 break;
1535 case PHY_11A:
1536 pAd->PortCfg.MlmeRate = RATE_6;
1537 pAd->PortCfg.RtsRate = RATE_6;
1538 break;
1539 case PHY_11ABG_MIXED:
1540 if (pAd->PortCfg.Channel <= 14)
1542 pAd->PortCfg.MlmeRate = RATE_2;
1543 pAd->PortCfg.RtsRate = RATE_2;
1545 else
1547 pAd->PortCfg.MlmeRate = RATE_6;
1548 pAd->PortCfg.RtsRate = RATE_6;
1550 break;
1551 default: // error
1552 pAd->PortCfg.MlmeRate = RATE_2;
1553 pAd->PortCfg.RtsRate = RATE_2;
1554 break;
1557 DBGPRINT(RT_DEBUG_TRACE, " MlmeUpdateTxRates (MaxDesire=%d, MaxSupport=%d, MaxTxRate=%d, Rate Switching =%d)\n",
1558 RateIdToMbps[MaxDesire], RateIdToMbps[MaxSupport], RateIdToMbps[pAd->PortCfg.MaxTxRate], pAd->PortCfg.EnableAutoRateSwitching);
1559 DBGPRINT(RT_DEBUG_TRACE, " MlmeUpdateTxRates (TxRate=%d, RtsRate=%d, BasicRateBitmap=0x%04x)\n",
1560 RateIdToMbps[pAd->PortCfg.TxRate], RateIdToMbps[pAd->PortCfg.RtsRate], BasicRateBitmap);
1563 VOID MlmeRadioOff(
1564 IN PRTMP_ADAPTER pAd)
1566 // Set Radio off flag
1567 RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1569 // Link down first if any association exists
1570 if (INFRA_ON(pAd) || ADHOC_ON(pAd))
1571 LinkDown(pAd);
1573 // Abort Tx
1574 RTMP_IO_WRITE32(pAd, TXCSR0, 0x08);
1575 // Disable Rx
1576 RTMP_IO_WRITE32(pAd, RXCSR0, 0x01);
1577 // Turn off radio
1578 RTMP_IO_WRITE32(pAd, PWRCSR0, 0x00000000);
1580 if (pAd->PortCfg.LedMode == LED_MODE_ASUS)
1582 ASIC_LED_ACT_OFF(pAd);
1585 // Clean up old bss table
1586 BssTableInit(&pAd->PortCfg.BssTab);
1589 VOID MlmeRadioOn(
1590 IN PRTMP_ADAPTER pAd)
1592 // Turn on radio
1593 RTMP_IO_WRITE32(pAd, PWRCSR0, 0x3f3b3100);
1595 // Abort Tx
1596 RTMP_IO_WRITE32(pAd, TXCSR0, 0x08);
1597 // Disable Rx
1598 RTMP_IO_WRITE32(pAd, RXCSR0, 0x01);
1600 RTMPRingCleanUp(pAd, TX_RING);
1601 RTMPRingCleanUp(pAd, PRIO_RING);
1602 RTMPRingCleanUp(pAd, RX_RING);
1604 NICResetFromError(pAd);
1605 // Clear Radio off flag
1606 RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1608 if (pAd->PortCfg.LedMode == LED_MODE_ASUS)
1610 RTMP_IO_WRITE32(pAd, LEDCSR, 0x0002461E);
1614 // ===========================================================================================
1615 // bss_table.c
1616 // ===========================================================================================
1619 /*! \brief initialize BSS table
1620 * \param p_tab pointer to the table
1621 * \return none
1622 * \pre
1623 * \post
1625 VOID BssTableInit(
1626 IN BSS_TABLE *Tab)
1628 int i;
1630 Tab->BssNr = 0;
1631 for (i = 0; i < MAX_LEN_OF_BSS_TABLE; i++)
1633 NdisZeroMemory(&Tab->BssEntry[i], sizeof(BSS_ENTRY));
1637 /*! \brief search the BSS table by SSID
1638 * \param p_tab pointer to the bss table
1639 * \param ssid SSID string
1640 * \return index of the table, BSS_NOT_FOUND if not in the table
1641 * \pre
1642 * \post
1643 * \note search by sequential search
1645 ULONG BssTableSearch(
1646 IN BSS_TABLE *Tab,
1647 IN PMACADDR Bssid)
1649 UCHAR i;
1651 for (i = 0; i < Tab->BssNr; i++)
1653 //printf("comparing %s and %s\n", p_tab->bss[i].ssid, ssid);
1654 if (MAC_ADDR_EQUAL(&(Tab->BssEntry[i].Bssid), Bssid))
1656 return i;
1659 return (ULONG)BSS_NOT_FOUND;
1662 VOID BssTableDeleteEntry(
1663 IN OUT BSS_TABLE *Tab,
1664 IN PMACADDR Bssid)
1666 UCHAR i, j;
1668 for (i = 0; i < Tab->BssNr; i++)
1670 //printf("comparing %s and %s\n", p_tab->bss[i].ssid, ssid);
1671 if (MAC_ADDR_EQUAL(&(Tab->BssEntry[i].Bssid), Bssid))
1673 for (j = i; j < Tab->BssNr - 1; j++)
1675 NdisMoveMemory(&(Tab->BssEntry[j]), &(Tab->BssEntry[j + 1]), sizeof(BSS_ENTRY));
1677 Tab->BssNr -= 1;
1678 return;
1683 UCHAR ZeroSsid[32] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1684 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1685 /*! \brief
1686 * \param
1687 * \return
1688 * \pre
1689 * \post
1691 VOID BssEntrySet(
1692 IN PRTMP_ADAPTER pAd,
1693 OUT BSS_ENTRY *pBss,
1694 IN MACADDR *pBssid,
1695 IN CHAR Ssid[],
1696 IN UCHAR SsidLen,
1697 IN UCHAR BssType,
1698 IN USHORT BeaconPeriod,
1699 IN BOOLEAN CfExist,
1700 IN CF_PARM *pCfParm,
1701 IN USHORT AtimWin,
1702 IN USHORT CapabilityInfo,
1703 IN UCHAR Rates[],
1704 IN UCHAR RatesLen,
1705 IN BOOLEAN ExtendedRateIeExist,
1706 IN UCHAR Channel,
1707 IN UCHAR Rssi,
1708 IN LARGE_INTEGER TimeStamp,
1709 IN PNDIS_802_11_VARIABLE_IEs pVIE)
1711 COPY_MAC_ADDR(&pBss->Bssid, pBssid);
1712 // Default Hidden SSID to be TRUE, it will be turned to FALSE after coping SSID
1713 pBss->Hidden = 1;
1714 if (SsidLen > 0)
1716 // For hidden SSID AP, it might send beacon with SSID len equal to 0
1717 // Or send beacon /probe response with SSID len matching real SSID length,
1718 // but SSID is all zero. such as "00-00-00-00" with length 4.
1719 // We have to prevent this case overwrite correct table
1720 if (NdisEqualMemory(Ssid, ZeroSsid, SsidLen) == 0)
1722 NdisMoveMemory(pBss->Ssid, Ssid, SsidLen);
1723 pBss->SsidLen = SsidLen;
1724 pBss->Hidden = 0;
1727 pBss->BssType = BssType;
1728 pBss->BeaconPeriod = BeaconPeriod;
1729 if (BssType == BSS_INFRA)
1731 if (CfExist)
1733 pBss->CfpCount = pCfParm->CfpCount;
1734 pBss->CfpPeriod = pCfParm->CfpPeriod;
1735 pBss->CfpMaxDuration = pCfParm->CfpMaxDuration;
1736 pBss->CfpDurRemaining = pCfParm->CfpDurRemaining;
1739 else
1741 pBss->AtimWin = AtimWin;
1744 pBss->CapabilityInfo = CapabilityInfo;
1745 // The privacy bit indicate security is ON, it maight be WEP, TKIP or AES
1746 // Combine with AuthMode, they will decide the connection methods.
1747 pBss->Privacy = CAP_IS_PRIVACY_ON(pBss->CapabilityInfo);
1748 NdisMoveMemory(pBss->Rates, Rates, RatesLen);
1749 pBss->RatesLen = RatesLen;
1750 pBss->ExtendedRateIeExist = ExtendedRateIeExist;
1751 pBss->Channel = Channel;
1752 pBss->Rssi = Rssi;
1754 // New for microsoft Fixed IEs
1755 NdisMoveMemory(pBss->FixIEs.Timestamp, &TimeStamp, 8);
1756 pBss->FixIEs.BeaconInterval = BeaconPeriod;
1757 pBss->FixIEs.Capabilities = CapabilityInfo;
1759 // New for microsoft Variable IEs
1760 if (pVIE->Length != 0)
1762 pBss->VarIELen = pVIE->Length + 2;
1763 NdisMoveMemory(pBss->VarIEs, pVIE, pBss->VarIELen);
1764 pBss->WepStatus = BssCipherParse(pBss->VarIEs);
1766 else
1768 pBss->VarIELen = 0;
1769 // No SSN ID, if security is on, this is WEP algorithm
1770 if (pBss->Privacy)
1771 pBss->WepStatus = Ndis802_11WEPEnabled;
1772 // No SSN ID, security is also off.
1773 else
1774 pBss->WepStatus = Ndis802_11WEPDisabled;
1779 * \brief insert an entry into the bss table
1780 * \param p_tab The BSS table
1781 * \param Bssid BSSID
1782 * \param ssid SSID
1783 * \param ssid_len Length of SSID
1784 * \param bss_type
1785 * \param beacon_period
1786 * \param timestamp
1787 * \param p_cf
1788 * \param atim_win
1789 * \param cap
1790 * \param rates
1791 * \param rates_len
1792 * \param channel_idx
1793 * \return none
1794 * \pre
1795 * \post
1796 * \note If SSID is identical, the old entry will be replaced by the new one
1798 ULONG BssTableSetEntry(
1799 IN PRTMP_ADAPTER pAd,
1800 OUT BSS_TABLE *Tab,
1801 IN MACADDR *Bssid,
1802 IN CHAR Ssid[],
1803 IN UCHAR SsidLen,
1804 IN UCHAR BssType,
1805 IN USHORT BeaconPeriod,
1806 IN BOOLEAN CfExist,
1807 IN CF_PARM *CfParm,
1808 IN USHORT AtimWin,
1809 IN USHORT CapabilityInfo,
1810 IN UCHAR Rates[],
1811 IN UCHAR RatesLen,
1812 IN BOOLEAN ExtendedRateIeExist,
1813 IN UCHAR ChannelNo,
1814 IN UCHAR Rssi,
1815 IN LARGE_INTEGER TimeStamp,
1816 IN PNDIS_802_11_VARIABLE_IEs pVIE)
1818 ULONG Idx;
1820 Idx = BssTableSearch(Tab, Bssid);
1821 if (Idx == BSS_NOT_FOUND)
1823 if (Tab->BssNr >= MAX_LEN_OF_BSS_TABLE)
1824 return BSS_NOT_FOUND;
1825 Idx = Tab->BssNr;
1826 BssEntrySet(pAd, &Tab->BssEntry[Idx], Bssid, Ssid, SsidLen, BssType, BeaconPeriod,
1827 CfExist, CfParm, AtimWin, CapabilityInfo, Rates, RatesLen, ExtendedRateIeExist,
1828 ChannelNo, Rssi, TimeStamp, pVIE);
1829 Tab->BssNr++;
1831 else
1833 BssEntrySet(pAd, &Tab->BssEntry[Idx], Bssid, Ssid, SsidLen, BssType, BeaconPeriod,
1834 CfExist, CfParm, AtimWin, CapabilityInfo, Rates, RatesLen, ExtendedRateIeExist,
1835 ChannelNo, Rssi, TimeStamp, pVIE);
1838 return Idx;
1841 VOID BssTableSsidSort(
1842 IN PRTMP_ADAPTER pAd,
1843 OUT BSS_TABLE *OutTab,
1844 IN CHAR Ssid[],
1845 IN UCHAR SsidLen)
1847 INT i;
1848 BssTableInit(OutTab);
1850 for (i = 0; i < pAd->PortCfg.BssTab.BssNr; i++)
1852 BSS_ENTRY *pInBss = &pAd->PortCfg.BssTab.BssEntry[i];
1854 if ((pInBss->BssType == pAd->PortCfg.BssType) &&
1855 ((pInBss->SsidLen==SsidLen) && RTMPEqualMemory(pInBss->Ssid, Ssid, (ULONG) SsidLen)))
1857 BSS_ENTRY *pOutBss = &OutTab->BssEntry[OutTab->BssNr];
1859 // Bss Type matched, SSID matched.
1860 // We will check wepstatus for qualification Bss
1861 if (pAd->PortCfg.WepStatus != pInBss->WepStatus)
1862 continue;
1864 // Since the AP is using hidden SSID, and we are trying to connect to ANY
1865 // It definitely will fail. So, skip it.
1866 // CCX also require not even try to connect it!!
1867 if (SsidLen == 0)
1868 continue;
1870 // copy matching BSS from InTab to OutTab
1871 NdisMoveMemory(pOutBss, pInBss, sizeof(BSS_ENTRY));
1873 OutTab->BssNr++;
1875 else if ((pInBss->BssType == pAd->PortCfg.BssType) && (SsidLen == 0))
1877 BSS_ENTRY *pOutBss = &OutTab->BssEntry[OutTab->BssNr];
1879 // Bss Type matched, SSID matched.
1880 // We will check wepstatus for qualification Bss
1881 if (pAd->PortCfg.WepStatus != pInBss->WepStatus)
1882 continue;
1884 // copy matching BSS from InTab to OutTab
1885 NdisMoveMemory(pOutBss, pInBss, sizeof(BSS_ENTRY));
1887 OutTab->BssNr++;
1889 #if 0
1890 else if ((pInBss->BssType == pAd->PortCfg.BssType) && (pInBss->SsidLen == 0))
1892 // Add for hidden SSID. But we have to verify the security suite too.
1893 BSS_ENTRY *pOutBss = &OutTab->BssEntry[OutTab->BssNr];
1895 // Bss Type matched, SSID matched.
1896 // We will check wepstatus for qualification Bss
1897 if (pAd->PortCfg.WepStatus != pInBss->WepStatus)
1898 continue;
1900 // copy matching BSS from InTab to OutTab
1901 NdisMoveMemory(pOutBss, pInBss, sizeof(BSS_ENTRY));
1903 OutTab->BssNr++;
1905 #endif
1906 if (OutTab->BssNr >= MAX_LEN_OF_BSS_TABLE)
1907 break;
1911 BssTableSortByRssi(OutTab);
1914 VOID BssTableSortByRssi(
1915 IN OUT BSS_TABLE *OutTab)
1917 INT i, j;
1918 BSS_ENTRY TmpBss;
1920 for (i = 0; i < OutTab->BssNr - 1; i++)
1922 for (j = i+1; j < OutTab->BssNr; j++)
1924 if (OutTab->BssEntry[j].Rssi > OutTab->BssEntry[i].Rssi)
1926 NdisMoveMemory(&TmpBss, &OutTab->BssEntry[j], sizeof(BSS_ENTRY));
1927 NdisMoveMemory(&OutTab->BssEntry[j], &OutTab->BssEntry[i], sizeof(BSS_ENTRY));
1928 NdisMoveMemory(&OutTab->BssEntry[i], &TmpBss, sizeof(BSS_ENTRY));
1934 NDIS_802_11_WEP_STATUS BssCipherParse(
1935 IN PUCHAR pCipher)
1937 PBEACON_EID_STRUCT pEid;
1938 PUCHAR pTmp;
1940 pEid = (PBEACON_EID_STRUCT) pCipher;
1942 // Double check sanity information, although it should be done at peer beacon sanity check already.
1943 if (pEid->Eid != IE_WPA)
1944 return (Ndis802_11WEPDisabled);
1946 // Double check Var IE length, it must be no less than 0x16
1947 if (pEid->Len < 0x16)
1948 return (Ndis802_11WEPDisabled);
1950 // Skip OUI, version, and multicast suite
1951 // This part should be improved in the future when AP supported multiple cipher suite.
1952 // For now, it's OK since almost all APs have fixed cipher suite supported.
1953 pTmp = (PUCHAR) pEid->Octet;
1954 pTmp += 9;
1956 if (*pTmp == 4) // AES
1957 return (Ndis802_11Encryption3Enabled);
1958 else if (*pTmp == 2) // TKIP
1959 return (Ndis802_11Encryption2Enabled);
1961 return (Ndis802_11WEPDisabled);
1964 // ===========================================================================================
1965 // mac_table.c
1966 // ===========================================================================================
1968 /*! \brief generates a random mac address value for IBSS BSSID
1969 * \param Addr the bssid location
1970 * \return none
1971 * \pre
1972 * \post
1974 VOID MacAddrRandomBssid(
1975 IN PRTMP_ADAPTER pAd,
1976 OUT MACADDR *Addr)
1978 INT i;
1980 for (i = 0; i < MAC_ADDR_LEN; i++)
1982 Addr->Octet[i] = RandomByte(pAd);
1985 Addr->Octet[0] = (Addr->Octet[0] & 0xfe) | 0x02; // the first 2 bits must be 01xxxxxxxx
1988 /*! \brief init the management mac frame header
1989 * \param p_hdr mac header
1990 * \param subtype subtype of the frame
1991 * \param p_ds destination address, don't care if it is a broadcast address
1992 * \return none
1993 * \pre the station has the following information in the pAd->PortCfg
1994 * - bssid
1995 * - station address
1996 * \post
1997 * \note this function initializes the following field
1999 VOID MgtMacHeaderInit(
2000 IN PRTMP_ADAPTER pAd,
2001 IN OUT PMACHDR Hdr,
2002 IN UCHAR Subtype,
2003 IN UCHAR ToDs,
2004 IN PMACADDR Ds,
2005 IN PMACADDR Bssid)
2007 NdisZeroMemory(Hdr, sizeof(MACHDR));
2008 Hdr->Type = BTYPE_MGMT;
2009 Hdr->SubType = Subtype;
2010 Hdr->Tods = ToDs;
2011 COPY_MAC_ADDR(&Hdr->Addr1, Ds);
2012 COPY_MAC_ADDR(&Hdr->Addr2, &pAd->CurrentAddress);
2013 COPY_MAC_ADDR(&Hdr->Addr3, Bssid);
2016 // ===========================================================================================
2017 // mem_mgmt.c
2018 // ===========================================================================================
2020 /*!***************************************************************************
2021 * This routine build an outgoing frame, and fill all information specified
2022 * in argument list to the frame body. The actual frame size is the summation
2023 * of all arguments.
2024 * input params:
2025 * Buffer - pointer to a pre-allocated memory segment
2026 * args - a list of <int arg_size, arg> pairs.
2027 * NOTE NOTE NOTE!!!! the last argument must be NULL, otherwise this
2028 * function will FAIL!!!
2029 * return:
2030 * Size of the buffer
2031 * usage:
2032 * MakeOutgoingFrame(Buffer, output_length, 2, &fc, 2, &dur, 6, p_addr1, 6,p_addr2, END_OF_ARGS);
2033 ****************************************************************************/
2034 ULONG MakeOutgoingFrame(
2035 OUT CHAR *Buffer,
2036 OUT ULONG *FrameLen, ...)
2038 CHAR *p;
2039 int leng;
2040 ULONG TotLeng;
2041 va_list Args;
2043 // calculates the total length
2044 TotLeng = 0;
2045 va_start(Args, FrameLen);
2048 leng = va_arg(Args, int);
2049 if (leng == END_OF_ARGS)
2051 break;
2053 p = va_arg(Args, PVOID);
2054 NdisMoveMemory(&Buffer[TotLeng], p, leng);
2055 TotLeng = TotLeng + leng;
2056 } while(TRUE);
2058 va_end(Args); /* clean up */
2059 *FrameLen = TotLeng;
2060 return TotLeng;
2063 // ===========================================================================================
2064 // mlme_queue.c
2065 // ===========================================================================================
2067 /*! \brief Initialize The MLME Queue, used by MLME Functions
2068 * \param *Queue The MLME Queue
2069 * \return Always Return NDIS_STATE_SUCCESS in this implementation
2070 * \pre
2071 * \post
2072 * \note Because this is done only once (at the init stage), no need to be locked
2074 NDIS_STATUS MlmeQueueInit(
2075 IN MLME_QUEUE *Queue)
2077 INT i;
2079 NdisAllocateSpinLock(&Queue->Lock);
2081 Queue->Num = 0;
2082 Queue->Head = 0;
2083 Queue->Tail = 0;
2085 for (i = 0; i < MAX_LEN_OF_MLME_QUEUE; i++)
2087 Queue->Entry[i].Occupied = FALSE;
2088 Queue->Entry[i].MsgLen = 0;
2089 NdisZeroMemory(Queue->Entry[i].Msg, MAX_LEN_OF_MLME_BUFFER);
2092 return NDIS_STATUS_SUCCESS;
2096 /*! \brief Enqueue a message for other threads, if they want to send messages to MLME thread
2097 * \param *Queue The MLME Queue
2098 * \param Machine The State Machine Id
2099 * \param MsgType The Message Type
2100 * \param MsgLen The Message length
2101 * \param *Msg The message pointer
2102 * \return TRUE if enqueue is successful, FALSE if the queue is full
2103 * \pre
2104 * \post
2105 * \note The message has to be initialized
2107 BOOLEAN MlmeEnqueue(
2108 OUT MLME_QUEUE *Queue,
2109 IN ULONG Machine,
2110 IN ULONG MsgType,
2111 IN ULONG MsgLen,
2112 IN VOID *Msg)
2114 INT Tail;
2115 ULONG IrqFlags;
2117 // First check the size, it MUST not exceed the mlme queue size
2118 if (MsgLen > MAX_LEN_OF_MLME_BUFFER)
2120 DBGPRINT(RT_DEBUG_ERROR, "MlmeEnqueueForRecv mlme frame too large, size = %d \n", MsgLen);
2121 return FALSE;
2124 if (MlmeQueueFull(Queue))
2126 DBGPRINT(RT_DEBUG_ERROR, "MlmeEnqueue full, msg dropped and may corrupt MLME\n");
2127 return FALSE;
2130 NdisAcquireSpinLock(&(Queue->Lock), IrqFlags);
2131 Tail = Queue->Tail;
2132 Queue->Tail++;
2133 Queue->Num++;
2134 if (Queue->Tail == MAX_LEN_OF_MLME_QUEUE)
2136 Queue->Tail = 0;
2139 DBGPRINT(RT_DEBUG_INFO, "MlmeEnqueue, num=%d\n",Queue->Num);
2141 Queue->Entry[Tail].Occupied = TRUE;
2142 Queue->Entry[Tail].Machine = Machine;
2143 Queue->Entry[Tail].MsgType = MsgType;
2144 Queue->Entry[Tail].MsgLen = MsgLen;
2145 if (Msg != NULL)
2146 NdisMoveMemory(Queue->Entry[Tail].Msg, Msg, MsgLen);
2147 NdisReleaseSpinLock(&(Queue->Lock), IrqFlags);
2148 return TRUE;
2151 /*! \brief This function is used when Recv gets a MLME message
2152 * \param *Queue The MLME Queue
2153 * \param TimeStampHigh The upper 32 bit of timestamp
2154 * \param TimeStampLow The lower 32 bit of timestamp
2155 * \param Rssi The receiving RSSI strength
2156 * \param MsgLen The length of the message
2157 * \param *Msg The message pointer
2158 * \return TRUE if everything ok, FALSE otherwise (like Queue Full)
2159 * \pre
2160 * \post
2162 BOOLEAN MlmeEnqueueForRecv(
2163 IN PRTMP_ADAPTER pAd,
2164 OUT MLME_QUEUE *Queue,
2165 IN ULONG TimeStampHigh,
2166 IN ULONG TimeStampLow,
2167 IN UCHAR Rssi,
2168 IN ULONG MsgLen,
2169 IN VOID *Msg)
2171 INT Tail, Machine;
2172 MACFRAME *Fr = (MACFRAME *)Msg;
2173 ULONG MsgType;
2174 ULONG IrqFlags;
2176 // First check the size, it MUST not exceed the mlme queue size
2177 if (MsgLen > MAX_LEN_OF_MLME_BUFFER)
2179 DBGPRINT(RT_DEBUG_ERROR, "MlmeEnqueueForRecv mlme frame too large, size = %d \n", MsgLen);
2180 return FALSE;
2183 if (MlmeQueueFull(Queue))
2185 DBGPRINT(RT_DEBUG_ERROR, "MlmeEnqueueForRecv (queue full error) \n");
2186 return FALSE;
2189 if (!MsgTypeSubst(Fr, &Machine, &MsgType))
2191 DBGPRINT(RT_DEBUG_ERROR, "MlmeEnqueueForRecv (drop mgmt->subtype=%d)\n",Fr->Hdr.SubType);
2192 return FALSE;
2195 // OK, we got all the informations, it is time to put things into queue
2196 NdisAcquireSpinLock(&(Queue->Lock), IrqFlags);
2197 Tail = Queue->Tail;
2198 Queue->Tail++;
2199 Queue->Num++;
2200 if (Queue->Tail == MAX_LEN_OF_MLME_QUEUE)
2202 Queue->Tail = 0;
2205 DBGPRINT(RT_DEBUG_INFO, "MlmeEnqueueForRecv, num=%d\n",Queue->Num);
2207 Queue->Entry[Tail].Occupied = TRUE;
2208 Queue->Entry[Tail].Machine = Machine;
2209 Queue->Entry[Tail].MsgType = MsgType;
2210 Queue->Entry[Tail].MsgLen = MsgLen;
2211 Queue->Entry[Tail].TimeStamp.vv.LowPart = TimeStampLow;
2212 Queue->Entry[Tail].TimeStamp.vv.HighPart = TimeStampHigh;
2213 Queue->Entry[Tail].Rssi = Rssi;
2214 if (Msg != NULL)
2215 NdisMoveMemory(Queue->Entry[Tail].Msg, Msg, MsgLen);
2216 NdisReleaseSpinLock(&(Queue->Lock), IrqFlags);
2218 MlmeHandler(pAd);
2220 return TRUE;
2223 /*! \brief Dequeue a message from the MLME Queue
2224 * \param *Queue The MLME Queue
2225 * \param *Elem The message dequeued from MLME Queue
2226 * \return TRUE if the Elem contains something, FALSE otherwise
2227 * \pre
2228 * \post
2230 BOOLEAN MlmeDequeue(
2231 IN MLME_QUEUE *Queue,
2232 OUT MLME_QUEUE_ELEM **Elem)
2234 ULONG IrqFlags;
2236 NdisAcquireSpinLock(&(Queue->Lock), IrqFlags);
2237 *Elem = &(Queue->Entry[Queue->Head]);
2238 Queue->Num--;
2239 Queue->Head++;
2240 if (Queue->Head == MAX_LEN_OF_MLME_QUEUE)
2242 Queue->Head = 0;
2244 NdisReleaseSpinLock(&(Queue->Lock), IrqFlags);
2245 DBGPRINT(RT_DEBUG_INFO, "MlmeDequeue, num=%d\n",Queue->Num);
2247 return TRUE;
2250 VOID MlmeRestartStateMachine(
2251 IN PRTMP_ADAPTER pAd)
2253 MLME_QUEUE_ELEM *Elem = NULL;
2254 ULONG IrqFlags;
2256 NdisAcquireSpinLock(&pAd->Mlme.TaskLock, IrqFlags);
2257 if(pAd->Mlme.Running)
2259 NdisReleaseSpinLock(&pAd->Mlme.TaskLock, IrqFlags);
2260 return;
2262 else
2264 pAd->Mlme.Running = TRUE;
2266 NdisReleaseSpinLock(&pAd->Mlme.TaskLock, IrqFlags);
2268 // Remove all Mlme queues elements
2269 while (!MlmeQueueEmpty(&pAd->Mlme.Queue))
2271 //From message type, determine which state machine I should drive
2272 if (MlmeDequeue(&pAd->Mlme.Queue, &Elem))
2274 // free MLME element
2275 Elem->Occupied = FALSE;
2276 Elem->MsgLen = 0;
2279 else {
2280 DBGPRINT(RT_DEBUG_ERROR, "ERROR: empty Elem in MlmeQueue\n");
2284 // Cancel all timer events
2285 // Be careful to cancel new added timer
2286 RTMPCancelTimer(&pAd->Mlme.AssocAux.AssocTimer);
2287 RTMPCancelTimer(&pAd->Mlme.AssocAux.ReassocTimer);
2288 RTMPCancelTimer(&pAd->Mlme.AssocAux.DisassocTimer);
2289 RTMPCancelTimer(&pAd->Mlme.AuthAux.AuthTimer);
2290 RTMPCancelTimer(&pAd->Mlme.AuthRspAux.AuthRspTimer);
2291 RTMPCancelTimer(&pAd->Mlme.SyncAux.BeaconTimer);
2292 RTMPCancelTimer(&pAd->Mlme.SyncAux.ScanTimer);
2293 RTMPCancelTimer(&pAd->PortCfg.RfTuningTimer);
2295 // Change back to original channel in case of doing scan
2296 AsicSwitchChannel(pAd, pAd->PortCfg.Channel);
2297 AsicLockChannel(pAd, pAd->PortCfg.Channel);
2299 // Resume MSDU which is turned off durning scan
2300 RTMPResumeMsduTransmission(pAd);
2302 // Set all state machines back IDLE
2303 pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
2304 pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
2305 pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE;
2306 pAd->Mlme.AuthRspMachine.CurrState = AUTH_RSP_IDLE;
2307 pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE;
2309 // Remove running state
2310 NdisAcquireSpinLock(&pAd->Mlme.TaskLock, IrqFlags);
2311 pAd->Mlme.Running = FALSE;
2312 NdisReleaseSpinLock(&pAd->Mlme.TaskLock, IrqFlags);
2315 /*! \brief test if the MLME Queue is empty
2316 * \param *Queue The MLME Queue
2317 * \return TRUE if the Queue is empty, FALSE otherwise
2318 * \pre
2319 * \post
2321 BOOLEAN MlmeQueueEmpty(
2322 IN MLME_QUEUE *Queue)
2324 BOOLEAN Ans;
2325 ULONG IrqFlags;
2327 NdisAcquireSpinLock(&(Queue->Lock), IrqFlags);
2328 Ans = (Queue->Num == 0);
2329 NdisReleaseSpinLock(&(Queue->Lock), IrqFlags);
2331 return Ans;
2334 /*! \brief test if the MLME Queue is full
2335 * \param *Queue The MLME Queue
2336 * \return TRUE if the Queue is empty, FALSE otherwise
2337 * \pre
2338 * \post
2340 BOOLEAN MlmeQueueFull(
2341 IN MLME_QUEUE *Queue)
2343 BOOLEAN Ans;
2344 ULONG IrqFlags;
2346 NdisAcquireSpinLock(&(Queue->Lock), IrqFlags);
2347 Ans = (Queue->Num == MAX_LEN_OF_MLME_QUEUE);
2348 NdisReleaseSpinLock(&(Queue->Lock), IrqFlags);
2350 return Ans;
2353 /*! \brief The destructor of MLME Queue
2354 * \param
2355 * \return
2356 * \pre
2357 * \post
2358 * \note Clear Mlme Queue, Set Queue->Num to Zero.
2360 VOID MlmeQueueDestroy(
2361 IN MLME_QUEUE *Queue)
2363 ULONG IrqFlags;
2365 NdisAcquireSpinLock(&(Queue->Lock), IrqFlags);
2366 Queue->Num = 0;
2367 Queue->Head = 0;
2368 Queue->Tail = 0;
2369 NdisReleaseSpinLock(&(Queue->Lock), IrqFlags);
2372 /*! \brief To substitute the message type if the message is coming from external
2373 * \param *Fr The frame received
2374 * \param *Machine The state machine
2375 * \param *MsgType the message type for the state machine
2376 * \return TRUE if the substitution is successful, FALSE otherwise
2377 * \pre
2378 * \post
2380 BOOLEAN MsgTypeSubst(
2381 IN MACFRAME *Fr,
2382 OUT INT *Machine,
2383 OUT INT *MsgType)
2385 USHORT Seq;
2386 UCHAR EAPType;
2388 // The only data type will pass to this function is EAPOL frame
2389 if (Fr->Hdr.Type == BTYPE_DATA)
2391 *Machine = WPA_PSK_STATE_MACHINE;
2392 EAPType = *((UCHAR*)Fr + LENGTH_802_11 + LENGTH_802_1_H + 1);
2393 return(WpaMsgTypeSubst(EAPType, MsgType));
2396 switch (Fr->Hdr.SubType)
2398 case SUBTYPE_ASSOC_REQ:
2399 *Machine = ASSOC_STATE_MACHINE;
2400 *MsgType = MT2_PEER_ASSOC_REQ;
2401 break;
2402 case SUBTYPE_ASSOC_RSP:
2403 *Machine = ASSOC_STATE_MACHINE;
2404 *MsgType = MT2_PEER_ASSOC_RSP;
2405 break;
2406 case SUBTYPE_REASSOC_REQ:
2407 *Machine = ASSOC_STATE_MACHINE;
2408 *MsgType = MT2_PEER_REASSOC_REQ;
2409 break;
2410 case SUBTYPE_REASSOC_RSP:
2411 *Machine = ASSOC_STATE_MACHINE;
2412 *MsgType = MT2_PEER_REASSOC_RSP;
2413 break;
2414 case SUBTYPE_PROBE_REQ:
2415 *Machine = SYNC_STATE_MACHINE;
2416 *MsgType = MT2_PEER_PROBE_REQ;
2417 break;
2418 case SUBTYPE_PROBE_RSP:
2419 *Machine = SYNC_STATE_MACHINE;
2420 *MsgType = MT2_PEER_PROBE_RSP;
2421 break;
2422 case SUBTYPE_BEACON:
2423 *Machine = SYNC_STATE_MACHINE;
2424 *MsgType = MT2_PEER_BEACON;
2425 break;
2426 case SUBTYPE_ATIM:
2427 *Machine = SYNC_STATE_MACHINE;
2428 *MsgType = MT2_PEER_ATIM;
2429 break;
2430 case SUBTYPE_DISASSOC:
2431 *Machine = ASSOC_STATE_MACHINE;
2432 *MsgType = MT2_PEER_DISASSOC_REQ;
2433 break;
2434 case SUBTYPE_AUTH:
2435 // get the sequence number from payload 24 Mac Header + 2 bytes algorithm
2436 NdisMoveMemory(&Seq, &Fr->Octet[2], sizeof(USHORT));
2437 if (Seq == 1 || Seq == 3)
2439 *Machine = AUTH_RSP_STATE_MACHINE;
2440 *MsgType = MT2_PEER_AUTH_ODD;
2442 else if (Seq == 2 || Seq == 4)
2444 *Machine = AUTH_STATE_MACHINE;
2445 *MsgType = MT2_PEER_AUTH_EVEN;
2447 else
2449 return FALSE;
2451 break;
2452 case SUBTYPE_DEAUTH:
2453 *Machine = AUTH_RSP_STATE_MACHINE;
2454 *MsgType = MT2_PEER_DEAUTH;
2455 break;
2456 default:
2457 return FALSE;
2458 break;
2461 return TRUE;
2464 // ===========================================================================================
2465 // state_machine.c
2466 // ===========================================================================================
2468 /*! \brief Initialize the state machine.
2469 * \param *S pointer to the state machine
2470 * \param Trans State machine transition function
2471 * \param StNr number of states
2472 * \param MsgNr number of messages
2473 * \param DefFunc default function, when there is invalid state/message combination
2474 * \param InitState initial state of the state machine
2475 * \param Base StateMachine base, internal use only
2476 * \pre p_sm should be a legal pointer
2477 * \post
2480 VOID StateMachineInit(
2481 IN STATE_MACHINE *S,
2482 IN STATE_MACHINE_FUNC Trans[],
2483 IN ULONG StNr,
2484 IN ULONG MsgNr,
2485 IN STATE_MACHINE_FUNC DefFunc,
2486 IN ULONG InitState,
2487 IN ULONG Base)
2489 ULONG i, j;
2491 // set number of states and messages
2492 S->NrState = StNr;
2493 S->NrMsg = MsgNr;
2494 S->Base = Base;
2496 S->TransFunc = Trans;
2498 // init all state transition to default function
2499 for (i = 0; i < StNr; i++)
2501 for (j = 0; j < MsgNr; j++)
2503 S->TransFunc[i * MsgNr + j] = DefFunc;
2507 // set the starting state
2508 S->CurrState = InitState;
2512 /*! \brief This function fills in the function pointer into the cell in the state machine
2513 * \param *S pointer to the state machine
2514 * \param St state
2515 * \param Msg incoming message
2516 * \param f the function to be executed when (state, message) combination occurs at the state machine
2517 * \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
2518 * \post
2520 VOID StateMachineSetAction(
2521 IN STATE_MACHINE *S,
2522 IN ULONG St,
2523 IN ULONG Msg,
2524 IN STATE_MACHINE_FUNC Func)
2526 ULONG MsgIdx;
2528 MsgIdx = Msg - S->Base;
2530 if (St < S->NrState && MsgIdx < S->NrMsg)
2532 // boundary checking before setting the action
2533 S->TransFunc[St * S->NrMsg + MsgIdx] = Func;
2537 /*! \brief The destructor of the state machine
2538 * \param *S the statemachine
2539 * \note doing nothing at this moment, may need to do something if the implementation changed
2541 VOID
2542 StateMachineDestroy(IN STATE_MACHINE *S)
2546 /*! \brief This function does the state transition
2547 * \param *Adapter the NIC adapter pointer
2548 * \param *S the state machine
2549 * \param *Elem the message to be executed
2550 * \return None
2552 VOID StateMachinePerformAction(
2553 IN PRTMP_ADAPTER pAd,
2554 IN STATE_MACHINE *S,
2555 IN MLME_QUEUE_ELEM *Elem)
2557 (*(S->TransFunc[S->CurrState * S->NrMsg + Elem->MsgType - S->Base]))(pAd, Elem);
2561 ==========================================================================
2562 Description:
2563 The drop function, when machine executes this, the message is simply
2564 ignored. This function does nothing, the message is freed in
2565 StateMachinePerformAction()
2566 ==========================================================================
2568 VOID Drop(
2569 IN PRTMP_ADAPTER pAd,
2570 IN MLME_QUEUE_ELEM *Elem)
2572 #if 0
2573 if ((Elem->MsgType == MT2_PEER_BEACON) ||
2574 (Elem->MsgType == MT2_PEER_PROBE_REQ) ||
2575 (Elem->MsgType == MT2_PEER_PROBE_RSP))
2577 else
2579 DBGPRINT(RT_DEBUG_TRACE, ("Warn:>>Drop Msg=%d<<\n",Elem->MsgType));
2581 #endif
2584 // ===========================================================================================
2585 // lfsr.c
2586 // ===========================================================================================
2589 ==========================================================================
2590 Description:
2591 ==========================================================================
2593 VOID LfsrInit(
2594 IN PRTMP_ADAPTER pAd,
2595 IN ULONG Seed)
2597 if (Seed == 0)
2598 pAd->Mlme.ShiftReg = 1;
2599 else
2600 pAd->Mlme.ShiftReg = Seed;
2604 ==========================================================================
2605 Description:
2606 ==========================================================================
2608 UCHAR RandomByte(
2609 IN PRTMP_ADAPTER pAd)
2611 ULONG i;
2612 UCHAR R, Result;
2614 R = 0;
2616 for (i = 0; i < 8; i++)
2618 if (pAd->Mlme.ShiftReg & 0x00000001)
2620 pAd->Mlme.ShiftReg = ((pAd->Mlme.ShiftReg ^ LFSR_MASK) >> 1) | 0x80000000;
2621 Result = 1;
2623 else
2625 pAd->Mlme.ShiftReg = pAd->Mlme.ShiftReg >> 1;
2626 Result = 0;
2628 R = (R << 1) | Result;
2631 return R;
2635 ==========================================================================
2636 Description:
2637 ==========================================================================
2639 VOID AsicSwitchChannel(
2640 IN PRTMP_ADAPTER pAd,
2641 IN UCHAR Channel)
2643 ULONG R3;
2644 UCHAR index;
2646 // TODO: need to update E2PROM format to add 802.11a channel's TX power calibration values
2647 if (Channel <= 14)
2648 R3 = pAd->PortCfg.ChannelTxPower[Channel - 1];
2649 else
2650 R3 = pAd->PortCfg.ChannelTxPower[0];
2652 if (R3 > 31) R3 = 31;
2654 // E2PROM setting is calibrated for maximum TX power (i.e. 100%)
2655 // We lower TX power here according to the percentage specified from UI
2656 if (pAd->PortCfg.TxPowerPercentage > 90) // 91 ~ 100%, treat as 100% in terms of mW
2658 else if (pAd->PortCfg.TxPowerPercentage > 60) // 61 ~ 90%, treat as 75% in terms of mW
2659 R3 -= 1;
2660 else if (pAd->PortCfg.TxPowerPercentage > 30) // 31 ~ 60%, treat as 50% in terms of mW
2661 R3 -= 3;
2662 else if (pAd->PortCfg.TxPowerPercentage > 15) // 16 ~ 30%, treat as 25% in terms of mW
2663 R3 -= 6;
2664 else if (pAd->PortCfg.TxPowerPercentage > 9) // 10 ~ 15%, treat as 12.5% in terms of mW
2665 R3 -= 9;
2666 else // 0 ~ 9 %, treat as 6.25% in terms of mW
2667 R3 -= 12;
2669 R3 = R3 << 9; // shift TX power control to correct RF R3 bit position
2671 switch (pAd->PortCfg.RfType)
2673 case RFIC_2522:
2674 for (index = 0; index < NUM_OF_2522_CHNL; index++)
2676 if (Channel == RF2522RegTable[index].Channel)
2678 R3 = R3 | RF2522RegTable[index].R3; // set TX power
2679 RTMP_RF_IO_WRITE32(pAd, RF2522RegTable[index].R1);
2680 RTMP_RF_IO_WRITE32(pAd, RF2522RegTable[index].R2);
2681 RTMP_RF_IO_WRITE32(pAd, R3);
2682 pAd->PortCfg.LatchRfRegs.Channel = Channel;
2683 pAd->PortCfg.LatchRfRegs.R1 = RF2522RegTable[index].R1;
2684 pAd->PortCfg.LatchRfRegs.R2 = RF2522RegTable[index].R2;
2685 pAd->PortCfg.LatchRfRegs.R3 = R3;
2686 pAd->PortCfg.LatchRfRegs.R4 = RF2522RegTable[index].R4;
2687 break;
2690 break;
2692 case RFIC_2523:
2693 for (index = 0; index < NUM_OF_2523_CHNL; index++)
2695 if (Channel == RF2523RegTable[index].Channel)
2697 R3 = R3 | RF2523RegTable[index].R3; // set TX power
2698 RTMP_RF_IO_WRITE32(pAd, RF2523RegTable[index].R1);
2699 RTMP_RF_IO_WRITE32(pAd, RF2523RegTable[index].R2);
2700 RTMP_RF_IO_WRITE32(pAd, R3);
2701 RTMP_RF_IO_WRITE32(pAd, RF2523RegTable[index].R4);
2702 pAd->PortCfg.LatchRfRegs.Channel = Channel;
2703 pAd->PortCfg.LatchRfRegs.R1 = RF2523RegTable[index].R1;
2704 pAd->PortCfg.LatchRfRegs.R2 = RF2523RegTable[index].R2;
2705 pAd->PortCfg.LatchRfRegs.R3 = R3;
2706 pAd->PortCfg.LatchRfRegs.R4 = RF2523RegTable[index].R4;
2707 break;
2710 break;
2712 case RFIC_2524:
2713 for (index = 0; index < NUM_OF_2524_CHNL; index++)
2715 if (Channel == RF2524RegTable[index].Channel)
2717 R3 = R3 | RF2524RegTable[index].R3; // set TX power
2718 RTMP_RF_IO_WRITE32(pAd, RF2524RegTable[index].R1);
2719 RTMP_RF_IO_WRITE32(pAd, RF2524RegTable[index].R2);
2720 RTMP_RF_IO_WRITE32(pAd, R3);
2721 RTMP_RF_IO_WRITE32(pAd, RF2524RegTable[index].R4);
2722 pAd->PortCfg.LatchRfRegs.Channel = Channel;
2723 pAd->PortCfg.LatchRfRegs.R1 = RF2524RegTable[index].R1;
2724 pAd->PortCfg.LatchRfRegs.R2 = RF2524RegTable[index].R2;
2725 pAd->PortCfg.LatchRfRegs.R3 = R3;
2726 pAd->PortCfg.LatchRfRegs.R4 = RF2524RegTable[index].R4;
2727 break;
2730 break;
2732 case RFIC_2525:
2733 for (index = 0; index < NUM_OF_2525_CHNL; index++)
2735 if (Channel == RF2525RegTable[index].Channel)
2737 // Tx power should based on the real channel value
2738 R3 = R3 | RF2525RegTable[index].R3; // set TX power
2739 // Set the channel to half band higher - 8 channels
2740 // The addition is based on Gary and Sheng's request
2741 RTMP_RF_IO_WRITE32(pAd, RF2525HBOffsetRegTable[index].R1);
2742 RTMP_RF_IO_WRITE32(pAd, RF2525HBOffsetRegTable[index].R2);
2743 RTMP_RF_IO_WRITE32(pAd, R3);
2744 RTMP_RF_IO_WRITE32(pAd, RF2525HBOffsetRegTable[index].R4);
2745 // Chnage to teh connect channel
2746 RTMP_RF_IO_WRITE32(pAd, RF2525RegTable[index].R1);
2747 RTMP_RF_IO_WRITE32(pAd, RF2525RegTable[index].R2);
2748 RTMP_RF_IO_WRITE32(pAd, R3);
2749 RTMP_RF_IO_WRITE32(pAd, RF2525RegTable[index].R4);
2750 pAd->PortCfg.LatchRfRegs.Channel = Channel;
2751 pAd->PortCfg.LatchRfRegs.R1 = RF2525RegTable[index].R1;
2752 pAd->PortCfg.LatchRfRegs.R2 = RF2525RegTable[index].R2;
2753 pAd->PortCfg.LatchRfRegs.R3 = R3;
2754 pAd->PortCfg.LatchRfRegs.R4 = RF2525RegTable[index].R4;
2755 break;
2758 break;
2760 case RFIC_2525E:
2761 for (index = 0; index < NUM_OF_2525E_CHNL; index++)
2763 if (Channel == RF2525eRegTable[index].Channel)
2765 R3 = R3 | RF2525eRegTable[index].R3; // set TX power
2766 RTMP_RF_IO_WRITE32(pAd, RF2525eRegTable[index].R1);
2767 RTMP_RF_IO_WRITE32(pAd, RF2525eRegTable[index].R2);
2768 RTMP_RF_IO_WRITE32(pAd, R3);
2769 RTMP_RF_IO_WRITE32(pAd, RF2525eRegTable[index].R4);
2770 pAd->PortCfg.LatchRfRegs.Channel = Channel;
2771 pAd->PortCfg.LatchRfRegs.R1 = RF2525eRegTable[index].R1;
2772 pAd->PortCfg.LatchRfRegs.R2 = RF2525eRegTable[index].R2;
2773 pAd->PortCfg.LatchRfRegs.R3 = R3;
2774 pAd->PortCfg.LatchRfRegs.R4 = RF2525eRegTable[index].R4;
2775 break;
2778 break;
2780 case RFIC_5222:
2781 for (index = 0; index < NUM_OF_5222_CHNL; index++)
2783 if (Channel == RF5222RegTable[index].Channel)
2785 R3 = R3 | RF5222RegTable[index].R3; // set TX power
2786 RTMP_RF_IO_WRITE32(pAd, RF5222RegTable[index].R1);
2787 RTMP_RF_IO_WRITE32(pAd, RF5222RegTable[index].R2);
2788 RTMP_RF_IO_WRITE32(pAd, R3);
2789 RTMP_RF_IO_WRITE32(pAd, RF5222RegTable[index].R4);
2790 pAd->PortCfg.LatchRfRegs.Channel = Channel;
2791 pAd->PortCfg.LatchRfRegs.R1 = RF5222RegTable[index].R1;
2792 pAd->PortCfg.LatchRfRegs.R2 = RF5222RegTable[index].R2;
2793 pAd->PortCfg.LatchRfRegs.R3 = R3;
2794 pAd->PortCfg.LatchRfRegs.R4 = RF5222RegTable[index].R4;
2795 break;
2798 break;
2800 default:
2801 break;
2804 DBGPRINT(RT_DEBUG_INFO, "AsicSwitchChannel(RF=%d) to #%d, TXPwr=%d%%, R1=0x%08x, R2=0x%08x, R3=0x%08x, R4=0x%08x\n",
2805 pAd->PortCfg.RfType,
2806 pAd->PortCfg.LatchRfRegs.Channel,
2807 pAd->PortCfg.TxPowerPercentage,
2808 pAd->PortCfg.LatchRfRegs.R1,
2809 pAd->PortCfg.LatchRfRegs.R2,
2810 pAd->PortCfg.LatchRfRegs.R3,
2811 pAd->PortCfg.LatchRfRegs.R4);
2815 ==========================================================================
2816 Description:
2817 This function is required for 2421 only, and should not be used during
2818 site survey. It's only required after NIC decided to stay at a channel
2819 for a longer period.
2820 When this function is called, it's always after AsicSwitchChannel().
2821 ==========================================================================
2823 VOID AsicLockChannel(
2824 IN PRTMP_ADAPTER pAd,
2825 IN UCHAR Channel)
2827 UCHAR r70;
2828 ULONG FcsCnt;
2830 RTMPCancelTimer(&pAd->PortCfg.RfTuningTimer);
2831 RTMPSetTimer(pAd, &pAd->PortCfg.RfTuningTimer, 1000/HZ); // 1 msec timer to turn OFF RF auto tuning
2833 RTMP_BBP_IO_READ32_BY_REG_ID(pAd, 70, &r70);
2834 if (Channel == 14)
2835 r70 = 0x4E; //set r70 to 0x4E instead of r70 |= 0x08; for turn on Japan filter bit
2836 else
2837 r70 = 0x46; //set r70 to 0x46 instead of r70 &= 0xf7; for turn off Japan filter bit
2838 RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, 70, r70);
2840 // Clear false CRC durning switch channel
2841 RTMP_IO_READ32(pAd, CNT0, &FcsCnt);
2844 VOID AsicRfTuningExec(
2845 IN unsigned long data)
2847 RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)data;
2849 switch (pAd->PortCfg.RfType)
2851 case RFIC_2522:
2852 case RFIC_2524:
2853 case RFIC_2525:
2854 case RFIC_5222:
2855 case RFIC_2525E:
2856 pAd->PortCfg.LatchRfRegs.R1 &= 0xfffdffff; // RF R1.bit17 "tune_en1" OFF
2857 pAd->PortCfg.LatchRfRegs.R3 &= 0xfffffeff; // RF R3.bit8 "tune_en2" OFF
2858 RTMP_RF_IO_WRITE32(pAd, pAd->PortCfg.LatchRfRegs.R1);
2859 RTMP_RF_IO_WRITE32(pAd, pAd->PortCfg.LatchRfRegs.R3);
2860 DBGPRINT(RT_DEBUG_INFO, "AsicRfTuningExec(R1=0x%x,R3=0x%x)\n",pAd->PortCfg.LatchRfRegs.R1,pAd->PortCfg.LatchRfRegs.R3);
2861 break;
2863 case RFIC_2523:
2864 pAd->PortCfg.LatchRfRegs.R3 &= 0xfffffeff; // RF R3.bit8 "tune_en2" OFF
2865 RTMP_RF_IO_WRITE32(pAd, pAd->PortCfg.LatchRfRegs.R3);
2866 DBGPRINT(RT_DEBUG_INFO, "AsicRfTuningExec(R3=0x%x)\n",pAd->PortCfg.LatchRfRegs.R3);
2867 break;
2869 default:
2870 break;
2875 ==========================================================================
2876 Description:
2877 Gives CCK TX rate 2 more dB TX power.
2878 This routine works only in LINK UP in INFRASTRUCTURE mode.
2880 calculate desired Tx power in RF R3.Tx0~5, should consider -
2881 1. TxPowerPercentage
2882 2. auto calibration based on TSSI feedback
2883 3. extra 2 db for CCK
2884 4. -10 db upon very-short distance (AvgRSSI >= -40db) to AP
2885 ==========================================================================
2887 VOID AsicAdjustTxPower(
2888 IN PRTMP_ADAPTER pAd)
2890 ULONG R3, Channel, CurrTxPwr;
2892 if ((pAd->PortCfg.Channel >= 1) && (pAd->PortCfg.Channel <= 14))
2893 Channel = pAd->PortCfg.Channel;
2894 else
2895 Channel = 1; // don't have calibration info for 11A, temporarily use Channel 1
2897 // get TX Power base from E2PROM
2898 R3 = pAd->PortCfg.ChannelTxPower[Channel - 1];
2899 if (R3 > 31) R3 = 31;
2901 // E2PROM setting is calibrated for maximum TX power (i.e. 100%)
2902 // We lower TX power here according to the percentage specified from UI
2903 if (pAd->PortCfg.TxPowerPercentage == 0xffffffff) // AUTO TX POWER control
2905 // only INFRASTRUCTURE mode and 100% TX power need furthur calibration
2906 if (pAd->MediaState == NdisMediaStateConnected)
2908 // low TX power upon very-short distance to AP to solve some vendor's AP RX problem
2909 // in this case, no TSSI compensation is required.
2910 if ((pAd->DrsCounters.fNoisyEnvironment == FALSE) &&
2911 (pAd->PortCfg.AvgRssi > (pAd->PortCfg.RssiToDbm - RSSI_FOR_LOWEST_TX_POWER)))
2912 R3 -= LOWEST_TX_POWER_DELTA;
2913 else if ((pAd->DrsCounters.fNoisyEnvironment == FALSE) &&
2914 (pAd->PortCfg.AvgRssi > (pAd->PortCfg.RssiToDbm - RSSI_FOR_LOW_TX_POWER)))
2915 R3 -= LOW_TX_POWER_DELTA;
2917 // 2004-03-16 give OFDM rates lower than 48 mbps 2 more DB
2918 else if ((pAd->PortCfg.TxRate <= RATE_36) && (pAd->PortCfg.TxRate > RATE_11))
2920 R3 +=2;
2921 if (R3 > 31) R3 = 31;
2924 // 2 exclusive rules applied on CCK rates only -
2925 // 1. always plus 2 db for CCK
2926 // 2. adjust TX Power based on TSSI
2927 else if (pAd->PortCfg.TxRate <= RATE_11)
2929 // if "auto calibration based on TSSI" is not required, then
2930 // always give CCK 2 more db
2931 if (pAd->PortCfg.bAutoTxAgc == FALSE)
2933 R3 += 2; // plus 2 db
2934 if (R3 > 31) R3 = 31;
2937 // Auto calibrate Tx AGC if bAutoTxAgc is TRUE and TX rate is CCK,
2938 // because E2PROM's TSSI reference is valid only in CCK range.
2939 else
2941 UCHAR R1,TxPowerRef, TssiRef;
2943 R3 = (pAd->PortCfg.LatchRfRegs.R3 >> 9) & 0x0000001f;
2944 if (pAd->Mlme.PeriodicRound % 4 == 0) // every 4 second
2946 TxPowerRef = pAd->PortCfg.ChannelTxPower[Channel - 1];
2947 TssiRef = pAd->PortCfg.ChannelTssiRef[Channel - 1];
2948 RTMP_BBP_IO_READ32_BY_REG_ID(pAd, BBP_Tx_Tssi, &R1);
2949 if ((TssiRef >= (R1 + pAd->PortCfg.ChannelTssiDelta)) ||
2950 (TssiRef <= (R1 - pAd->PortCfg.ChannelTssiDelta)))
2952 // Need R3 adjustment. However, we have to make sure there is only
2953 // plus / minus 5 variation allowed
2954 if (TssiRef > R1)
2956 R3 = (R3 < (ULONG) (TxPowerRef + 5)) ? (R3 + 1) : R3;
2957 if (R3 > 31)
2958 R3 = 31;
2959 DBGPRINT(RT_DEBUG_INFO,"TSSI(R1)=%d, ++TxPwr=%d\n", R1, R3);
2961 else
2963 R3 = (R3 > (ULONG) (TxPowerRef - 5)) ? (R3 - 1) : R3;
2964 DBGPRINT(RT_DEBUG_INFO,"TSSI(R1)=%d, --TxPwr=%d\n", R1, R3);
2973 else // fixed AUTO TX power
2975 if (pAd->PortCfg.TxPowerPercentage > 90) // 91 ~ 100%, treat as 100% in terms of mW
2977 else if (pAd->PortCfg.TxPowerPercentage > 60) // 61 ~ 90%, treat as 75% in terms of mW
2978 R3 -= 1;
2979 else if (pAd->PortCfg.TxPowerPercentage > 30) // 31 ~ 60%, treat as 50% in terms of mW
2980 R3 -= 3;
2981 else if (pAd->PortCfg.TxPowerPercentage > 15) // 16 ~ 30%, treat as 25% in terms of mW
2982 R3 -= 6;
2983 else if (pAd->PortCfg.TxPowerPercentage > 9) // 10 ~ 15%, treat as 12.5% in terms of mW
2984 R3 -= 9;
2985 else // 0 ~ 9 %, treat as MIN(~3%) in terms of mW
2986 R3 -= 12;
2987 if (R3 > 31) R3 = 0; // negative value, set as minimum 0
2989 // 2004-03-16 give TX rates <= 36 mbps 2 more DB
2990 if (pAd->PortCfg.TxRate <= RATE_36)
2992 R3 +=2;
2993 if (R3 > 31) R3 = 31;
2997 // compare the desired R3.TxPwr value with current R3, if not equal
2998 // set new R3.TxPwr
2999 CurrTxPwr = (pAd->PortCfg.LatchRfRegs.R3 >> 9) & 0x0000001f;
3000 if (CurrTxPwr != R3)
3002 CurrTxPwr = R3;
3003 R3 = (pAd->PortCfg.LatchRfRegs.R3 & 0xffffc1ff) | (R3 << 9);
3004 RTMP_RF_IO_WRITE32(pAd, R3);
3005 pAd->PortCfg.LatchRfRegs.R3 = R3;
3007 DBGPRINT(RT_DEBUG_INFO, "AsicAdjustTxPower = %d, AvgRssi = %d\n",
3008 CurrTxPwr, pAd->PortCfg.AvgRssi - pAd->PortCfg.RssiToDbm);
3012 ==========================================================================
3013 Description:
3014 put PHY to sleep here, and set next wakeup timer
3015 ==========================================================================
3017 VOID AsicSleepThenAutoWakeup(
3018 IN PRTMP_ADAPTER pAd,
3019 IN USHORT TbttNumToNextWakeUp)
3021 CSR20_STRUC Csr20;
3022 PWRCSR1_STRUC Pwrcsr1;
3024 // we have decided to SLEEP, so at least do it for a BEACON period.
3025 if (TbttNumToNextWakeUp==0)
3026 TbttNumToNextWakeUp=1;
3028 // PWRCSR0 remains untouched
3030 // set CSR20 for next wakeup
3031 Csr20.word = 0;
3032 Csr20.field.NumBcnBeforeWakeup = TbttNumToNextWakeUp - 1;
3033 Csr20.field.DelayAfterBcn = (pAd->PortCfg.BeaconPeriod - 20) << 4; // 20 TU ahead of desired TBTT
3034 Csr20.field.AutoWake = 1;
3035 RTMP_IO_WRITE32(pAd, CSR20, Csr20.word);
3037 // set PWRCSR1 to put PHY into SLEEP state
3038 Pwrcsr1.word = 0;
3039 Pwrcsr1.field.PutToSleep = 1;
3040 Pwrcsr1.field.BbpDesireState = 1; // 01:SLEEP
3041 Pwrcsr1.field.RfDesireState = 1; // 01:SLEEP
3042 RTMP_IO_WRITE32(pAd, PWRCSR1, Pwrcsr1.word);
3043 pAd->PortCfg.Pss = PWR_SAVE;
3047 ==========================================================================
3048 Description:
3049 AsicForceWakeup() is used whenever manual wakeup is required
3050 AsicForceSleep() should only be used when Massoc==FALSE. When
3051 Massoc==TRUE, we should use AsicSleepThenAutoWakeup() instead.
3052 ==========================================================================
3054 VOID AsicForceSleep(
3055 IN PRTMP_ADAPTER pAd)
3057 PWRCSR1_STRUC Pwrcsr1;
3059 if (pAd->PortCfg.Pss == PWR_ACTIVE)
3061 DBGPRINT(RT_DEBUG_TRACE, ">>>AsicForceSleep<<<\n");
3062 Pwrcsr1.word = 0;
3063 Pwrcsr1.field.RfDesireState = 1; // 01:SLEEP state
3064 Pwrcsr1.field.BbpDesireState = 1; // 01:SLEEP state
3065 Pwrcsr1.field.SetState = 1;
3066 RTMP_IO_WRITE32(pAd, PWRCSR1, Pwrcsr1.word);
3067 pAd->PortCfg.Pss = PWR_SAVE;
3071 VOID AsicForceWakeup(
3072 IN PRTMP_ADAPTER pAd)
3074 CSR20_STRUC Csr20;
3075 PWRCSR1_STRUC Pwrcsr1;
3077 if (pAd->PortCfg.Pss == PWR_SAVE)
3079 DBGPRINT(RT_DEBUG_TRACE, ">>>AsicForceWakeup<<<\n");
3081 // 2003-12-19 turn OFF auto wakeup first
3082 Csr20.word = 0;
3083 Csr20.field.AutoWake = 0;
3084 RTMP_IO_WRITE32(pAd, CSR20, Csr20.word);
3086 Pwrcsr1.word = 0;
3087 Pwrcsr1.field.RfDesireState = 3; // 11:AWAKE state
3088 Pwrcsr1.field.BbpDesireState = 3; // 11:AWAKE state
3089 Pwrcsr1.field.SetState = 1;
3090 RTMP_IO_WRITE32(pAd, PWRCSR1, Pwrcsr1.word);
3091 pAd->PortCfg.Pss = PWR_ACTIVE;
3096 ==========================================================================
3097 Description:
3098 ==========================================================================
3100 VOID AsicSetBssid(
3101 IN PRTMP_ADAPTER pAd,
3102 IN MACADDR *Bssid)
3104 ULONG Addr4;
3106 Addr4 = (ULONG)(Bssid->Octet[0]) |
3107 (ULONG)(Bssid->Octet[1] << 8) |
3108 (ULONG)(Bssid->Octet[2] << 16) |
3109 (ULONG)(Bssid->Octet[3] << 24);
3110 RTMP_IO_WRITE32(pAd, CSR5, Addr4);
3112 Addr4 = (ULONG)(Bssid->Octet[4]) | (ULONG)(Bssid->Octet[5] << 8);
3113 RTMP_IO_WRITE32(pAd, CSR6, Addr4);
3117 ==========================================================================
3118 Description:
3119 ==========================================================================
3121 VOID AsicDisableSync(
3122 IN PRTMP_ADAPTER pAd)
3124 // TIMECSR_STRUC TimeCsr;
3125 DBGPRINT(RT_DEBUG_TRACE, "--->Disable TSF synchronization\n");
3126 #if 1
3127 // 2003-12-20 disable TSF and Tbcn while NIC in power-saving have side effect
3128 // that NIC will never wakes up because TSF stops and no more TBTT interrupts
3129 RTMP_IO_WRITE32(pAd, CSR14, 0x00000009);
3130 #else
3131 RTMP_IO_WRITE32(pAd, CSR14, 0x00000000);
3132 #endif
3134 #if 0
3135 RTMP_IO_READ32(pAd, TIMECSR, &TimeCsr.word);
3137 // restore to 33 PCI-tick-per-Usec. for 2560a only where PCI-clock is used as TSF timing source
3138 if (TimeCsr.field.UsCnt != 0x21)
3140 TimeCsr.field.UsCnt = 0x21;
3141 RTMP_IO_WRITE32(pAd, TIMECSR, TimeCsr.word);
3143 #endif
3147 ==========================================================================
3148 Description:
3149 ==========================================================================
3151 VOID AsicEnableBssSync(
3152 IN PRTMP_ADAPTER pAd)
3154 CSR12_STRUC Csr12;
3155 CSR13_STRUC Csr13;
3156 CSR14_STRUC Csr14;
3157 BCNCSR1_STRUC Bcncsr1;
3158 BOOLEAN IsApPc;
3160 DBGPRINT(RT_DEBUG_TRACE, "--->AsicEnableBssSync(INFRA mode)\n");
3162 RTMP_IO_WRITE32(pAd, CSR14, 0x00000000);
3164 Csr12.word = 0;
3165 Csr12.field.BeaconInterval = pAd->PortCfg.BeaconPeriod << 4; // ASIC register in units of 1/16 TU
3166 Csr12.field.CfpMaxDuration = pAd->PortCfg.CfpMaxDuration << 4; // ASIC register in units of 1/16 TU
3167 RTMP_IO_WRITE32(pAd, CSR12, Csr12.word);
3169 Csr13.word = 0;
3170 Csr13.field.CfpPeriod = pAd->PortCfg.CfpDurRemain << 4; // ASIC register in units of 1/16 TU
3171 RTMP_IO_WRITE32(pAd, CSR13, Csr13.word);
3173 Bcncsr1.word = 0;
3174 Bcncsr1.field.Preload = TBTT_PRELOAD_TIME; // we guess TBTT is 2 TU ahead of BEACON-RxEnd time
3175 Bcncsr1.field.BeaconCwMin = 5;
3176 RTMP_IO_WRITE32(pAd, BCNCSR1, Bcncsr1.word);
3178 IsApPc = (CAP_IS_CF_POLLABLE_ON(pAd->PortCfg.CapabilityInfo) &&
3179 CAP_IS_CF_POLL_REQ_ON(pAd->PortCfg.CapabilityInfo));
3180 IsApPc = FALSE; // TODO: not support so far
3182 Csr14.word = 0;
3183 Csr14.field.TsfCount = 1;
3184 Csr14.field.TsfSync = 1; // sync TSF in INFRASTRUCTURE mode
3185 if (IsApPc)
3187 Csr14.field.CfpCntPreload = pAd->PortCfg.CfpCount;
3188 Csr14.field.Tcfp = 1;
3190 Csr14.field.BeaconGen = 0;
3191 // Csr14.field.TbcnPreload = (pAd->PortCfg.BeaconPeriod - 30) << 4; // TODO: ???? 1 TU ???
3192 Csr14.field.Tbcn = 1;
3193 RTMP_IO_WRITE32(pAd, CSR14, Csr14.word);
3198 ==========================================================================
3199 Description:
3200 Note:
3201 BEACON frame in shared memory should be built ok before this routine
3202 can be called. Otherwise, a garbage frame maybe transmitted out every
3203 Beacon period.
3204 ==========================================================================
3206 VOID AsicEnableIbssSync(
3207 IN PRTMP_ADAPTER pAd)
3209 CSR12_STRUC Csr12;
3210 CSR13_STRUC Csr13;
3211 CSR14_STRUC Csr14;
3212 // BCNCSR_STRUC Bcncsr;
3213 BCNCSR1_STRUC Bcncsr1;
3215 DBGPRINT(RT_DEBUG_TRACE, "--->AsicEnableIbssSync(ADHOC mode)\n");
3217 RTMP_IO_WRITE32(pAd, CSR14, 0x00000000);
3219 Csr12.word = 0;
3220 Csr12.field.BeaconInterval = pAd->PortCfg.BeaconPeriod << 4; // ASIC register in units of 1/16 TU
3221 RTMP_IO_WRITE32(pAd, CSR12, Csr12.word);
3223 Csr13.word = 0;
3224 Csr13.field.AtimwDuration = pAd->PortCfg.AtimWin << 4; // ASIC register in units of 1/16 TU
3225 RTMP_IO_WRITE32(pAd, CSR13, Csr13.word);
3227 Bcncsr1.word = 0;
3228 if ((pAd->PortCfg.PhyMode == PHY_11B) || (pAd->PortCfg.PhyMode == PHY_11BG_MIXED))
3230 Bcncsr1.field.BeaconCwMin = 5;
3231 Bcncsr1.field.Preload = 1024; // 192 + ((MAC_HDR_LEN << 4) / RateIdTo500Kbps[pAd->PortCfg.MlmeRate]);
3233 else
3235 Bcncsr1.field.BeaconCwMin = 6;
3236 Bcncsr1.field.Preload = 700; // 24 + ((MAC_HDR_LEN << 4) / RateIdTo500Kbps[pAd->PortCfg.MlmeRate]);
3238 RTMP_IO_WRITE32(pAd, BCNCSR1, Bcncsr1.word);
3240 Csr14.word = 0;
3241 Csr14.field.TsfCount = 1;
3242 Csr14.field.TsfSync = 2; // sync TSF in IBSS mode
3243 Csr14.field.Tbcn = 1;
3244 Csr14.field.BeaconGen = 1;
3245 RTMP_IO_WRITE32(pAd, CSR14, Csr14.word);
3248 VOID AsicLedPeriodicExec(
3249 IN unsigned long data)
3251 RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)data;
3252 ULONG LedCsr = 0x0000461E; // 0x0000461E;
3254 pAd->PortCfg.LedCntl.fOdd = ! pAd->PortCfg.LedCntl.fOdd;
3256 if (INFRA_ON(pAd) || ADHOC_ON(pAd))
3257 LedCsr |= 0x00010000; // enable hardwired TX activity LED
3258 if (pAd->PortCfg.LedCntl.fOdd && pAd->PortCfg.LedCntl.fRxActivity)
3259 LedCsr |= 0x00020000; // turn on software-based RX activity LED
3260 pAd->PortCfg.LedCntl.fRxActivity = FALSE;
3262 if (LedCsr != pAd->PortCfg.LedCntl.LastLedCsr)
3264 // DBGPRINT(RT_DEBUG_TRACE, ("AsicLedPeriodicExec(%8x)\n",LedCsr));
3265 pAd->PortCfg.LedCntl.LastLedCsr = LedCsr;
3266 RTMP_IO_WRITE32(pAd, LEDCSR, LedCsr);
3269 RTMPSetTimer(pAd, &pAd->PortCfg.LedCntl.BlinkTimer, 70);
3272 // pAd->PortCfg.CurrentRxAntenna
3273 // 0xff: diversity, 0:antenna A, 1:antenna B
3274 VOID AsicSetRxAnt(
3275 IN PRTMP_ADAPTER pAd)
3277 UCHAR RxValue, TxValue;
3278 ULONG Bbpcsr1;
3280 RTMPCancelTimer(&pAd->PortCfg.RxAnt.RxAntDiversityTimer);
3281 pAd->PortCfg.RxAnt.AvgRssi[0] = (-95 + 120) << 3; // reset Ant-A's RSSI history
3282 pAd->PortCfg.RxAnt.AvgRssi[1] = (-95 + 120) << 3; // reset Ant-B's RSSI history
3283 pAd->PortCfg.RxAnt.PrimaryInUsed = TRUE;
3285 if (pAd->PortCfg.CurrentRxAntenna == 0xff) // Diversity
3287 pAd->PortCfg.RxAnt.PrimaryRxAnt = 1; // assume ant-B
3288 pAd->PortCfg.RxAnt.SecondaryRxAnt = 0; // assume ant-A
3290 else if (pAd->PortCfg.CurrentRxAntenna == 0) // ant-A
3292 pAd->PortCfg.RxAnt.PrimaryRxAnt = 0; // assume ant-A
3293 pAd->PortCfg.RxAnt.SecondaryRxAnt = 1; // assume ant-B
3295 else // ant-B
3297 pAd->PortCfg.RxAnt.PrimaryRxAnt = 1; // assume ant-B
3298 pAd->PortCfg.RxAnt.SecondaryRxAnt = 0; // assume ant-A
3301 DBGPRINT(RT_DEBUG_TRACE,"AntDiv - set RxAnt=%d, primary=%d, second=%d\n",
3302 pAd->PortCfg.CurrentRxAntenna, pAd->PortCfg.RxAnt.PrimaryRxAnt, pAd->PortCfg.RxAnt.SecondaryRxAnt);
3304 // use primary antenna
3305 RTMP_IO_READ32(pAd, BBPCSR1, &Bbpcsr1);
3306 TxValue = pAd->PortCfg.BbpWriteLatch[BBP_Tx_Configure];
3307 RxValue = pAd->PortCfg.BbpWriteLatch[BBP_Rx_Configure];
3308 if (pAd->PortCfg.RxAnt.PrimaryRxAnt == 0) // ant-A
3310 TxValue = (TxValue & 0xFC) | 0x00;
3311 //RxValue = (RxValue & 0xFC) | 0x00;
3312 RxValue = 0x1c;
3313 Bbpcsr1 = (Bbpcsr1 & 0xFFFCFFFC) | 0x00000000;
3315 else // ant-B
3317 TxValue = (TxValue & 0xFC) | 0x02;
3318 //RxValue = (RxValue & 0xFC) | 0x02;
3319 RxValue = 0x1e;
3320 Bbpcsr1 = (Bbpcsr1 & 0xFFFCFFFC) | 0x00020002;
3322 RTMP_IO_WRITE32(pAd, BBPCSR1, Bbpcsr1);
3323 //RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, BBP_Tx_Configure, TxValue);
3324 RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, BBP_Rx_Configure, RxValue);
3328 // switch to secondary RxAnt for a while to collect it's average RSSI
3329 // also set a timeout routine to DO the actual evaluation. If evaluation
3330 // result shows a much better RSSI using secondary RxAnt, then a official
3331 // RX antenna switch is performed.
3332 VOID AsicEvaluateSecondaryRxAnt(
3333 IN PRTMP_ADAPTER pAd)
3335 UCHAR RxValue, TxValue;
3336 ULONG Bbpcsr1;
3338 if (pAd->PortCfg.CurrentRxAntenna != 0xff)
3339 return;
3341 pAd->PortCfg.RxAnt.PrimaryInUsed = FALSE;
3342 pAd->PortCfg.RxAnt.FirstPktArrivedWhenEvaluate = FALSE;
3343 pAd->PortCfg.RxAnt.RcvPktNumWhenEvaluate = 0;
3344 // pAd->PortCfg.RxAnt.AvgRssi[pAd->PortCfg.RxAnt.SecondaryRxAnt] = 0;
3346 DBGPRINT(RT_DEBUG_TRACE,"AntDiv - evaluate Ant #%d\n", pAd->PortCfg.RxAnt.SecondaryRxAnt);
3348 // temporarily switch to secondary antenna
3349 RxValue = pAd->PortCfg.BbpWriteLatch[BBP_Rx_Configure];
3350 TxValue = pAd->PortCfg.BbpWriteLatch[BBP_Tx_Configure];
3351 RTMP_IO_READ32(pAd, BBPCSR1, &Bbpcsr1);
3353 if (pAd->PortCfg.RxAnt.SecondaryRxAnt == 0) // ant-A
3355 TxValue = (TxValue & 0xFC) | 0x00;
3356 //RxValue = (RxValue & 0xFC) | 0x00;
3357 RxValue = 0x1c;
3358 Bbpcsr1 = (Bbpcsr1 & 0xFFFCFFFC) | 0x00000000;
3360 else // ant-B
3362 TxValue = (TxValue & 0xFC) | 0x02;
3363 //RxValue = (RxValue & 0xFC) | 0x02;
3364 RxValue = 0x1e;
3365 Bbpcsr1 = (Bbpcsr1 & 0xFFFCFFFC) | 0x00020002;
3367 RTMP_IO_WRITE32(pAd, BBPCSR1, Bbpcsr1);
3368 //RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, BBP_Tx_Configure, TxValue);
3369 RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, BBP_Rx_Configure, RxValue);
3371 // a one-shot timer to end the evalution
3372 if (pAd->MediaState == NdisMediaStateConnected)
3373 RTMPSetTimer(pAd, &pAd->PortCfg.RxAnt.RxAntDiversityTimer, 150);
3374 else
3375 RTMPSetTimer(pAd, &pAd->PortCfg.RxAnt.RxAntDiversityTimer, 300);
3378 // this timeout routine collect AvgRssi[SecondaryRxAnt] and decide if
3379 // SecondaryRxAnt is much better than PrimaryRxAnt
3380 VOID AsicRxAntEvalTimeout(
3381 IN unsigned long data)
3383 RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)data;
3386 DBGPRINT(RT_DEBUG_TRACE,"AntDiv - AsicRxAntEvalTimeout, \n");
3387 // Do nothing if the driver is starting halt state.
3388 // This might happen when timer already been fired before cancel timer with mlmehalt
3389 if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS))
3390 return;
3392 if (pAd->PortCfg.RxAnt.PrimaryInUsed == TRUE)
3393 return;
3395 // 1-db or more will we consider to switch antenna
3396 if ((pAd->PortCfg.RxAnt.RcvPktNumWhenEvaluate != 0) && (pAd->PortCfg.RxAnt.AvgRssi[pAd->PortCfg.RxAnt.SecondaryRxAnt] >=
3397 (pAd->PortCfg.RxAnt.AvgRssi[pAd->PortCfg.RxAnt.PrimaryRxAnt])))
3399 UCHAR temp;
3400 // secondary antenna is much better than primary, switch RX antenna
3401 temp = pAd->PortCfg.RxAnt.PrimaryRxAnt;
3402 pAd->PortCfg.RxAnt.PrimaryRxAnt = pAd->PortCfg.RxAnt.SecondaryRxAnt;
3403 pAd->PortCfg.RxAnt.SecondaryRxAnt = temp;
3404 pAd->PortCfg.LastAvgRssi = (pAd->PortCfg.RxAnt.AvgRssi[pAd->PortCfg.RxAnt.SecondaryRxAnt] >> 3) - pAd->PortCfg.RssiToDbm;
3405 DBGPRINT(RT_DEBUG_TRACE,"AntDiv - Switch to Ant #%d, RSSI[0,1]=<%d, %d>\n",
3406 pAd->PortCfg.RxAnt.PrimaryRxAnt, pAd->PortCfg.RxAnt.AvgRssi[0], pAd->PortCfg.RxAnt.AvgRssi[1]);
3408 else
3410 UCHAR RxValue, TxValue;
3411 ULONG Bbpcsr1;
3413 // end of evaluation, swicth back to primary antenna
3414 RxValue = pAd->PortCfg.BbpWriteLatch[BBP_Rx_Configure];
3415 TxValue = pAd->PortCfg.BbpWriteLatch[BBP_Tx_Configure];
3416 RTMP_IO_READ32(pAd, BBPCSR1, &Bbpcsr1);
3417 if (pAd->PortCfg.RxAnt.PrimaryRxAnt == 0) // ant-A
3419 TxValue = (TxValue & 0xFC) | 0x00;
3420 //RxValue = (RxValue & 0xFC) | 0x00;
3421 RxValue = 0x1c;
3422 Bbpcsr1 = (Bbpcsr1 & 0xFFFCFFFC) | 0x00000000;
3424 else // ant-B
3426 TxValue = (TxValue & 0xFC) | 0x02;
3427 //RxValue = (RxValue & 0xFC) | 0x02;
3428 RxValue = 0x1e;
3429 Bbpcsr1 = (Bbpcsr1 & 0xFFFCFFFC) | 0x00020002;
3431 RTMP_IO_WRITE32(pAd, BBPCSR1, Bbpcsr1);
3432 //RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, BBP_Tx_Configure, TxValue);
3433 RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, BBP_Rx_Configure, RxValue);
3434 DBGPRINT(RT_DEBUG_TRACE,"AntDiv - remain Ant #%d, RSSI[0,1]=<%d, %d>, RcvPktNumWhenEvaluate=%d\n",
3435 pAd->PortCfg.RxAnt.PrimaryRxAnt, (pAd->PortCfg.RxAnt.AvgRssi[0] >> 3) - pAd->PortCfg.RssiToDbm, (pAd->PortCfg.RxAnt.AvgRssi[1] >> 3) - pAd->PortCfg.RssiToDbm, pAd->PortCfg.RxAnt.RcvPktNumWhenEvaluate);
3438 // pAd->PortCfg.RxAnt.AvgRssi[0] = 0; // reset Ant-A's RSSI history
3439 // pAd->PortCfg.RxAnt.AvgRssi[1] = 0; // reset Ant-B's RSSI history
3440 pAd->PortCfg.RxAnt.PrimaryInUsed = TRUE;
3441 pAd->PortCfg.RxAnt.FirstPktArrivedWhenEvaluate = TRUE;
3445 ==========================================================================
3446 Description:
3447 ==========================================================================
3449 VOID AsicSetSlotTime(
3450 IN PRTMP_ADAPTER pAd,
3451 IN BOOLEAN UseShortSlotTime)
3453 CSR11_STRUC Csr11;
3454 CSR18_STRUC Csr18;
3455 CSR19_STRUC Csr19;
3456 UCHAR PhyMode;
3458 pAd->PortCfg.ShortSlotInUsed = UseShortSlotTime;
3460 PhyMode = pAd->PortCfg.PhyMode;
3461 if (PhyMode == PHY_11ABG_MIXED)
3463 if (pAd->PortCfg.Channel <=14)
3464 PhyMode = PHY_11BG_MIXED;
3465 else
3466 PhyMode = PHY_11A;
3469 RTMP_IO_READ32(pAd, CSR11, &Csr11.word);
3470 if (PhyMode == PHY_11A)
3471 Csr11.field.SlotTime = 9;
3472 else
3473 Csr11.field.SlotTime = (UseShortSlotTime)? 9 : 20;
3474 RTMP_IO_WRITE32(pAd, CSR11, Csr11.word);
3476 RTMP_IO_READ32(pAd, CSR18, &Csr18.word);
3477 Csr18.field.PIFS = Csr18.field.SIFS + Csr11.field.SlotTime;
3478 RTMP_IO_WRITE32(pAd, CSR18, Csr18.word);
3480 Csr19.word = 0;
3481 Csr19.field.DIFS = Csr18.field.PIFS + Csr11.field.SlotTime;
3482 if (PhyMode == PHY_11B)
3483 Csr19.field.EIFS = 364; // SIFS + ACK @1Mbps
3484 else
3485 Csr19.field.EIFS = 60; // roughly = SIFS + ACK @6Mbps
3486 RTMP_IO_WRITE32(pAd, CSR19, Csr19.word);
3488 #if 1
3489 // force using short SLOT time for FAE to demo performance only
3490 if (pAd->PortCfg.EnableTxBurst == 1)
3491 Csr11.field.SlotTime = 9;
3492 RTMP_IO_WRITE32(pAd, CSR11, Csr11.word);
3493 #endif
3495 DBGPRINT(RT_DEBUG_TRACE, "AsicSetSlotTime(=%d us, CSR18=0x%08x, CSR19=0x%08x)\n",
3496 Csr11.field.SlotTime, Csr18.word, Csr19.word);
3500 ==========================================================================
3501 Description:
3502 This routine is used for 2560a only where 2560a still use non-accurate
3503 PCI-clock as TSF 1-usec source. we have to dynamically change tick-per-usec
3504 to avoid ADHOC synchronization issue with SYMBOL 11b card
3505 ==========================================================================
3507 VOID AsicAdjustUsec(
3508 IN PRTMP_ADAPTER pAd)
3510 TIMECSR_STRUC TimeCsr;
3511 UCHAR TickPerUsec = 20;
3512 pAd->PortCfg.PciAdjustmentRound = (pAd->PortCfg.PciAdjustmentRound+1) & 0x03;
3514 RTMP_IO_READ32(pAd, TIMECSR, &TimeCsr.word);
3515 if (pAd->PortCfg.PciAdjustmentRound == 0)
3516 TickPerUsec = 0x21;
3517 else if (pAd->PortCfg.PciAdjustmentRound == 1)
3518 TickPerUsec = 0x21;
3519 else if (pAd->PortCfg.PciAdjustmentRound == 2)
3520 TickPerUsec = 0x20;
3521 else
3522 TickPerUsec = 0x21;
3524 if (TimeCsr.field.UsCnt!= TickPerUsec)
3526 TimeCsr.field.UsCnt= TickPerUsec;
3527 RTMP_IO_WRITE32(pAd, TIMECSR, TimeCsr.word);
3528 DBGPRINT(RT_DEBUG_INFO, "AsicAdjustUsec - change TIMECSR=0x%08x)\n",TimeCsr.word);
3533 ==========================================================================
3534 Description:
3535 danamic tune BBP R17 to find a balance between sensibility and
3536 noise isolation
3537 ==========================================================================
3539 VOID AsicBbpTuning(
3540 IN PRTMP_ADAPTER pAd)
3542 ULONG Value;
3543 UCHAR R17;
3544 ULONG FalseCcaUpperThreshold = pAd->PortCfg.BbpTuning.FalseCcaUpperThreshold << 7;
3545 int dbm = pAd->PortCfg.AvgRssi - pAd->PortCfg.RssiToDbm;
3547 if ((! pAd->PortCfg.BbpTuningEnable) || (pAd->PortCfg.BbpTuning.VgcDelta==0))
3548 return;
3550 R17 = pAd->PortCfg.BbpWriteLatch[17];
3552 if ((pAd->PortCfg.Rt2560Version >= RT2560_VER_D) &&
3553 (pAd->MediaState == NdisMediaStateConnected))
3555 // Rule 0.
3556 // when RSSI is too weak, many signals will become false CCA thus affect R17 tuning.
3557 // so in this case, just stop R17 tuning (be sure R17 remains in <E2PROM-6, BBP_R17_DYNAMIC_UP_BOUND> range)
3558 if ((dbm < -80) && (pAd->Mlme.PeriodicRound > 20))
3560 if (R17 >= BBP_R17_MID_SENSIBILITY)
3562 R17 = pAd->PortCfg.LastR17Value;
3563 RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, 17, R17);
3565 DBGPRINT(RT_DEBUG_INFO, "RSSI = %d dbm, stop R17 at 0x%x\n", dbm, R17);
3566 return;
3568 // Rule 1. "special big-R17 for short-distance" when not SCANNING
3569 else if ((dbm >= RSSI_FOR_LOW_SENSIBILITY) &&
3570 (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE))
3572 if (R17 != BBP_R17_LOW_SENSIBILITY)
3574 R17 = BBP_R17_LOW_SENSIBILITY;
3575 RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, 17, R17);
3577 DBGPRINT(RT_DEBUG_INFO, "RSSI = %d dbm, fixed R17 at 0x%x\n", dbm, R17);
3578 return;
3580 // Rule 2. "special mid-R17 for mid-distance" when not SCANNING
3581 else if ((dbm >= RSSI_FOR_MID_SENSIBILITY) &&
3582 (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE))
3584 if (R17 != BBP_R17_MID_SENSIBILITY)
3586 R17 = BBP_R17_MID_SENSIBILITY;
3587 RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, 17, R17);
3589 DBGPRINT(RT_DEBUG_INFO, "RSSI = %d dbm, fixed R17 at 0x%x\n", dbm, R17);
3590 return;
3592 // Rule 3. leave "short or mid-distance" condition, restore R17 to the
3593 // dynamic tuning range <E2PROM-6, BBP_R17_DYNAMIC_UP_BOUND>
3594 else if (R17 >= BBP_R17_MID_SENSIBILITY)
3596 R17 = pAd->PortCfg.LastR17Value;
3597 RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, 17, R17);
3598 DBGPRINT(RT_DEBUG_INFO, "RSSI = %d dbm, restore R17 to 0x%x\n", dbm, R17);
3599 return;
3603 // Rule 3. otherwise, R17 is currenly in dyanmic tuning range: <E2PROM-6, BBP_R17_DYNAMIC_UP_BOUND>.
3604 // Keep dynamic tuning based on False CCA conter
3606 RTMP_IO_READ32(pAd, CNT3, &Value);
3607 pAd->PrivateInfo.CCAErrCnt = (Value & 0x0000ffff);
3608 DBGPRINT(RT_DEBUG_INFO, "CCA flase alarm = %d, Avg RSSI= %d dbm\n",
3609 pAd->PrivateInfo.CCAErrCnt, dbm);
3611 if ((pAd->PrivateInfo.CCAErrCnt > FalseCcaUpperThreshold) &&
3612 (R17 < pAd->PortCfg.BbpTuning.VgcUpperBound))
3614 R17 += pAd->PortCfg.BbpTuning.VgcDelta;
3615 pAd->PortCfg.LastR17Value = R17;
3616 RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, 17, R17);
3617 DBGPRINT(RT_DEBUG_INFO, "++R17= 0x%x\n", R17);
3619 else if ((pAd->PrivateInfo.CCAErrCnt < pAd->PortCfg.BbpTuning.FalseCcaLowerThreshold) &&
3620 (R17 > pAd->PortCfg.VgcLowerBound))
3622 R17 -= pAd->PortCfg.BbpTuning.VgcDelta;
3623 pAd->PortCfg.LastR17Value = R17;
3624 RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, 17, R17);
3625 DBGPRINT(RT_DEBUG_INFO, "--R17= 0x%x\n", R17);
3629 // stop and restore R17 value upon SITE-SURVEY and LINK-DOWN
3630 VOID AsicRestoreBbpSensibility(
3631 IN PRTMP_ADAPTER pAd)
3633 UCHAR R17;
3635 R17 = pAd->PortCfg.BbpWriteLatch[17];
3636 if (R17 >= BBP_R17_MID_SENSIBILITY)
3638 R17 = pAd->PortCfg.LastR17Value;
3639 RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, 17, R17);
3640 DBGPRINT(RT_DEBUG_TRACE, "AsicRestoreBbpSensibility(set R17= 0x%x)\n", R17);
3645 ========================================================================
3647 Routine Description:
3648 Mlme free the in-used nonpaged memory,
3649 move it to the unused memory link list
3651 Arguments:
3652 pAd Pointer to our adapter
3653 AllocVa Pointer to the base virtual address for free
3655 Return Value:
3656 None
3658 Note:
3660 ========================================================================
3662 VOID MlmeFreeMemory(
3663 IN PRTMP_ADAPTER pAd,
3664 IN PVOID AllocVa)
3666 PMLME_MEMORY_STRUCT pPrevious = NULL;
3667 PMLME_MEMORY_STRUCT pMlmeMemoryStruct = NULL;
3668 UINT Index = 0;
3669 BOOLEAN bIsFound = FALSE;
3670 ULONG IrqFlags;
3672 DBGPRINT(RT_DEBUG_INFO, "==> MlmeFreeMemory\n");
3673 NdisAcquireSpinLock(&pAd->MemLock, IrqFlags);
3674 if (pAd->Mlme.MemHandler.MemRunning)
3676 //Mlme memory handler is busy.
3677 //Move it to the Pending array for later free
3678 pAd->Mlme.MemHandler.MemFreePending[pAd->Mlme.MemHandler.PendingCount++] = (PULONG) AllocVa;
3680 DBGPRINT(RT_DEBUG_INFO, "Mlme memory Handler Busy!! move free memory to pending list [IN:%d][UN:%d][Pending:%d]\n",
3681 pAd->Mlme.MemHandler.InUseCount, pAd->Mlme.MemHandler.UnUseCount, pAd->Mlme.MemHandler.PendingCount);
3682 DBGPRINT(RT_DEBUG_INFO, "<== MlmeFreeMemory\n");
3683 NdisReleaseSpinLock(&pAd->MemLock, IrqFlags);
3684 return;
3686 else
3688 pAd->Mlme.MemHandler.MemRunning = TRUE;
3689 NdisReleaseSpinLock(&pAd->MemLock, IrqFlags);
3692 //First check is there have to free memory in the pAd->Mlme.MemHandler.MemFreePending.
3693 while (pAd->Mlme.MemHandler.PendingCount > 0)
3695 pPrevious = NULL;
3696 pMlmeMemoryStruct = pAd->Mlme.MemHandler.pInUseHead;
3697 while (pMlmeMemoryStruct)
3699 if (pMlmeMemoryStruct->AllocVa == (PVOID) pAd->Mlme.MemHandler.MemFreePending[Index])
3701 //Found virtual address in the in-used link list
3702 //Remove it from the memory in-used link list, and move it to the unused link list
3703 if (pPrevious == NULL)
3705 pAd->Mlme.MemHandler.pInUseHead = pAd->Mlme.MemHandler.pInUseHead->Next;
3707 // Update pInUseTail pointer, if this is an Empty list
3709 if (pAd->Mlme.MemHandler.pInUseHead == NULL)
3710 pAd->Mlme.MemHandler.pInUseTail = NULL;
3712 else
3714 pPrevious->Next = pMlmeMemoryStruct->Next;
3716 // Update pInUseTail pointer, if move the pInUserTail to Unused link list.
3717 // move the pInuseTail to his previous.
3719 if (pMlmeMemoryStruct->Next == NULL)
3722 // This pMlmeMemoryStruct is the one pInUseTail, since it's next pointer is NULL.
3723 // Then we need to update pInUseTail.
3725 pAd->Mlme.MemHandler.pInUseTail = pPrevious;
3729 if ((pAd->Mlme.MemHandler.pUnUseHead == NULL))
3730 { //No head, add it as head
3731 pMlmeMemoryStruct->Next = NULL;
3732 pAd->Mlme.MemHandler.pUnUseHead = pMlmeMemoryStruct;
3733 pAd->Mlme.MemHandler.pUnUseTail = pAd->Mlme.MemHandler.pUnUseHead;
3735 else
3737 //Append it to the tail in pAd->Mlme.MemHandler.pUnUseTail
3738 pMlmeMemoryStruct->Next = NULL;
3739 pAd->Mlme.MemHandler.pUnUseTail->Next = pMlmeMemoryStruct;
3740 pAd->Mlme.MemHandler.pUnUseTail = pAd->Mlme.MemHandler.pUnUseTail->Next;
3742 pAd->Mlme.MemHandler.MemFreePending[Index++] = NULL;
3743 pAd->Mlme.MemHandler.PendingCount--;
3744 pAd->Mlme.MemHandler.UnUseCount++;
3745 pAd->Mlme.MemHandler.InUseCount--;
3746 bIsFound = TRUE;
3747 break;
3749 else
3751 pPrevious = pMlmeMemoryStruct;
3752 pMlmeMemoryStruct = pMlmeMemoryStruct->Next;
3756 if (!bIsFound)
3758 //This shoult not be happened! Just in case!
3759 DBGPRINT(RT_DEBUG_INFO, "<Warning>Free memory faild!! memory corruption on [Va:0x%lu] not found in In-Used link list [IN:%d][UN:%d][Pending:%d]\n",
3760 (unsigned long)pAd->Mlme.MemHandler.MemFreePending[pAd->Mlme.MemHandler.PendingCount],
3761 pAd->Mlme.MemHandler.InUseCount, pAd->Mlme.MemHandler.UnUseCount, pAd->Mlme.MemHandler.PendingCount);
3762 //lost a memory
3763 pAd->Mlme.MemHandler.MemFreePending[Index++] = NULL;
3764 pAd->Mlme.MemHandler.PendingCount--;
3768 pPrevious = NULL;
3769 pMlmeMemoryStruct = pAd->Mlme.MemHandler.pInUseHead;
3770 while (pMlmeMemoryStruct)
3772 if (pMlmeMemoryStruct->AllocVa == AllocVa)
3774 //Found virtual address in the in-used link list
3775 //Remove it from the memory in-used link list, and move it to the unused link list
3776 if (pPrevious == NULL)
3778 pAd->Mlme.MemHandler.pInUseHead = pAd->Mlme.MemHandler.pInUseHead->Next;
3780 // Update pInUseTail pointer, if this is an Empty list
3782 if (pAd->Mlme.MemHandler.pInUseHead == NULL)
3783 pAd->Mlme.MemHandler.pInUseTail = NULL;
3785 else
3787 pPrevious->Next = pMlmeMemoryStruct->Next;
3789 // Update pInUseTail pointer, if move the pInUserTail to Unused link list.
3790 // move the pInuseTail to his previous.
3792 if (pMlmeMemoryStruct->Next == NULL)
3795 // This pMlmeMemoryStruct is the one pInUseTail, since it's next pointer is NULL.
3796 // Then we need to update pInUseTail.
3798 pAd->Mlme.MemHandler.pInUseTail = pPrevious;
3802 if (pAd->Mlme.MemHandler.pUnUseHead == NULL)
3804 pMlmeMemoryStruct->Next = NULL;
3805 pAd->Mlme.MemHandler.pUnUseHead = pMlmeMemoryStruct;
3806 pAd->Mlme.MemHandler.pUnUseTail = pMlmeMemoryStruct;
3808 else
3810 pMlmeMemoryStruct->Next = NULL;
3811 pAd->Mlme.MemHandler.pUnUseTail->Next = pMlmeMemoryStruct;
3812 pAd->Mlme.MemHandler.pUnUseTail = pMlmeMemoryStruct;
3815 pAd->Mlme.MemHandler.InUseCount--;
3816 pAd->Mlme.MemHandler.UnUseCount++;
3817 DBGPRINT(RT_DEBUG_INFO, "MlmeFreeMemory Add it to the Unused memory link List[pMlmeMemoryStruct=0x%lu][VA=0x%lu]\n", (unsigned long)pMlmeMemoryStruct, (unsigned long)pMlmeMemoryStruct->AllocVa);
3818 break;
3820 pPrevious = pMlmeMemoryStruct;
3821 pMlmeMemoryStruct = pMlmeMemoryStruct->Next;
3824 NdisAcquireSpinLock(&pAd->MemLock, IrqFlags);
3825 pAd->Mlme.MemHandler.MemRunning = FALSE;
3826 NdisReleaseSpinLock(&pAd->MemLock, IrqFlags);
3828 DBGPRINT(RT_DEBUG_INFO, "<== MlmeFreeMemory [IN:%d][UN:%d][Pending:%d]\n",
3829 pAd->Mlme.MemHandler.InUseCount, pAd->Mlme.MemHandler.UnUseCount, pAd->Mlme.MemHandler.PendingCount);
3833 ========================================================================
3835 Routine Description:
3836 Get an unused nonpaged system-space memory for use
3838 Arguments:
3839 pAd Pointer to our adapter
3840 AllocVa Pointer to the base virtual address for later use
3842 Return Value:
3843 NDIS_STATUS_SUCCESS
3844 NDIS_STATUS_FAILURE
3845 NDIS_STATUS_RESOURCES
3847 Note:
3849 ========================================================================
3851 NDIS_STATUS MlmeAllocateMemory(
3852 IN PRTMP_ADAPTER pAd,
3853 OUT PVOID *AllocVa)
3855 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
3856 PMLME_MEMORY_STRUCT pMlmeMemoryStruct = NULL;
3857 ULONG IrqFlags;
3859 DBGPRINT(RT_DEBUG_INFO, "==> MlmeAllocateMemory\n");
3860 NdisAcquireSpinLock(&pAd->MemLock, IrqFlags);
3861 if (pAd->Mlme.MemHandler.MemRunning)
3863 DBGPRINT(RT_DEBUG_INFO, "Mlme memory Handler Busy!!, MlmeAllocateMemory failed!!\n");
3864 Status = NDIS_STATUS_FAILURE;
3865 DBGPRINT(RT_DEBUG_INFO, "<== MlmeAllocateMemory\n");
3866 NdisReleaseSpinLock(&pAd->MemLock, IrqFlags);
3867 return (Status);
3869 else
3871 pAd->Mlme.MemHandler.MemRunning = TRUE;
3872 NdisReleaseSpinLock(&pAd->MemLock, IrqFlags);
3875 if (pAd->Mlme.MemHandler.pUnUseHead == NULL)
3876 { //There are no available memory for caller use
3877 Status = NDIS_STATUS_RESOURCES;
3878 NdisAcquireSpinLock(&pAd->MemLock, IrqFlags);
3879 pAd->Mlme.MemHandler.MemRunning = FALSE;
3880 NdisReleaseSpinLock(&pAd->MemLock, IrqFlags);
3881 DBGPRINT(RT_DEBUG_INFO, "MlmeAllocateMemory, failed!! (There are no available memory in list)\n");
3882 DBGPRINT(RT_DEBUG_INFO, "<== MlmeAllocateMemory\n");
3883 return (Status);
3886 pMlmeMemoryStruct = pAd->Mlme.MemHandler.pUnUseHead;
3887 *AllocVa = pMlmeMemoryStruct->AllocVa; //Saved porint to Pointer the base virtual address of the nonpaged memory for caller use.
3888 //Unused memory point to next available
3889 pAd->Mlme.MemHandler.pUnUseHead = pAd->Mlme.MemHandler.pUnUseHead->Next;
3890 pAd->Mlme.MemHandler.UnUseCount--;
3892 //Append the unused memory link list to the in-used link list tail
3893 if (pAd->Mlme.MemHandler.pInUseHead == NULL)
3894 {//no head, so current Item assign to In-use Head.
3895 pAd->Mlme.MemHandler.pInUseHead = pMlmeMemoryStruct;
3896 pAd->Mlme.MemHandler.pInUseHead->Next = NULL;
3897 pAd->Mlme.MemHandler.pInUseTail = pAd->Mlme.MemHandler.pInUseHead;
3899 else
3901 pMlmeMemoryStruct->Next = NULL;
3902 pAd->Mlme.MemHandler.pInUseTail->Next = pMlmeMemoryStruct;
3903 pAd->Mlme.MemHandler.pInUseTail = pAd->Mlme.MemHandler.pInUseTail->Next;
3905 pAd->Mlme.MemHandler.InUseCount++;
3906 NdisAcquireSpinLock(&pAd->MemLock, IrqFlags);
3907 pAd->Mlme.MemHandler.MemRunning = FALSE;
3908 NdisReleaseSpinLock(&pAd->MemLock, IrqFlags);
3909 DBGPRINT(RT_DEBUG_INFO, "MlmeAllocateMemory [pMlmeMemoryStruct=0x%lu][VA=0x%lu]\n", (unsigned long)pMlmeMemoryStruct, (unsigned long)pMlmeMemoryStruct->AllocVa);
3910 DBGPRINT(RT_DEBUG_INFO, "<== MlmeAllocateMemory[IN:%d][UN:%d][Pending:%d]\n",
3911 pAd->Mlme.MemHandler.InUseCount, pAd->Mlme.MemHandler.UnUseCount, pAd->Mlme.MemHandler.PendingCount);
3913 return (Status);
3917 ========================================================================
3919 Routine Description:
3920 Allocates resident (nonpaged) system-space memory for MLME send frames
3922 Arguments:
3923 pAd Pointer to our adapter
3924 Number Total nonpaged memory for use
3925 Size Each nonpaged memory size
3927 Return Value:
3928 NDIS_STATUS_SUCCESS
3929 NDIS_STATUS_RESOURCES
3931 Note:
3933 ========================================================================
3935 NDIS_STATUS MlmeInitMemoryHandler(
3936 IN PRTMP_ADAPTER pAd,
3937 IN UINT Number,
3938 IN UINT Size)
3940 PMLME_MEMORY_STRUCT Current = NULL;
3941 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
3942 UINT i;
3944 DBGPRINT(RT_DEBUG_INFO, "==> MlmeInitMemory\n");
3945 pAd->Mlme.MemHandler.MemoryCount = 0;
3946 pAd->Mlme.MemHandler.pInUseHead = NULL;
3947 pAd->Mlme.MemHandler.pInUseTail = NULL;
3948 pAd->Mlme.MemHandler.pUnUseHead = NULL;
3949 pAd->Mlme.MemHandler.pUnUseTail = NULL;
3950 pAd->Mlme.MemHandler.MemRunning = FALSE;
3952 //initial the memory free-pending array all to NULL;
3953 for (i = 0; i < MAX_MLME_HANDLER_MEMORY; i++)
3954 pAd->Mlme.MemHandler.MemFreePending[i] = NULL;
3957 // Available nonpaged memory counts MAX_MLME_HANDLER_MEMORY
3959 if (Number > MAX_MLME_HANDLER_MEMORY)
3960 Number = MAX_MLME_HANDLER_MEMORY;
3962 for (i = 0; i < Number; i++)
3964 //Allocate a nonpaged memory for link list use.
3965 Current = kmalloc(sizeof(MLME_MEMORY_STRUCT), GFP_KERNEL);
3966 if (Current == NULL)
3968 Status = NDIS_STATUS_RESOURCES;
3969 break;
3972 //Allocate a nonpaged memory for mlme use, Current->AllocVa is VirtualAddress pointer
3973 Current->AllocVa = kmalloc(Size, GFP_KERNEL);
3974 if (Current->AllocVa == NULL)
3976 Status = NDIS_STATUS_RESOURCES;
3977 //Free the nonpaged memory of the current link list
3978 kfree((VOID *)Current);
3979 break;
3981 NdisZeroMemory(Current->AllocVa, Size);
3983 pAd->Mlme.MemHandler.MemoryCount++;
3985 //build up the link list
3986 if (pAd->Mlme.MemHandler.pUnUseHead != NULL)
3988 Current->Next = pAd->Mlme.MemHandler.pUnUseHead;
3989 pAd->Mlme.MemHandler.pUnUseHead = Current;
3991 else
3993 Current->Next = NULL;
3994 pAd->Mlme.MemHandler.pUnUseHead = Current;
3997 if (pAd->Mlme.MemHandler.pUnUseTail == NULL)
3998 pAd->Mlme.MemHandler.pUnUseTail = Current;
4002 if (pAd->Mlme.MemHandler.MemoryCount < Number)
4004 Status = NDIS_STATUS_RESOURCES;
4005 DBGPRINT(RT_DEBUG_TRACE, "MlmeInitMemory Initial failed [Require=%d, available=%d]\n", Number, pAd->Mlme.MemHandler.MemoryCount);
4008 pAd->Mlme.MemHandler.InUseCount = 0;
4009 pAd->Mlme.MemHandler.UnUseCount = Number;
4010 pAd->Mlme.MemHandler.PendingCount = 0;
4011 DBGPRINT(RT_DEBUG_INFO, "<== MlmeInitMemory\n");
4012 return (Status);
4016 ========================================================================
4018 Routine Description:
4019 Free Mlme memory handler (link list, nonpaged memory, spin lock)
4021 Arguments:
4022 pAd Pointer to our adapter
4024 Return Value:
4025 None
4026 ========================================================================
4028 VOID MlmeFreeMemoryHandler(
4029 IN PRTMP_ADAPTER pAd)
4031 PMLME_MEMORY_STRUCT pMlmeMemoryStruct = NULL;
4033 //Free nonpaged memory, free it in the *In-used* link list.
4034 while (pAd->Mlme.MemHandler.pInUseHead != NULL)
4036 pMlmeMemoryStruct = pAd->Mlme.MemHandler.pInUseHead;
4037 pAd->Mlme.MemHandler.pInUseHead = pAd->Mlme.MemHandler.pInUseHead->Next;
4038 //Free the virtual address in AllocVa which size is MAX_LEN_OF_MLME_BUFFER
4039 kfree(pMlmeMemoryStruct->AllocVa);
4040 //Free the link list item self
4041 kfree(pMlmeMemoryStruct);
4044 //Free nonpaged memory, free it in the *Unused* link list.
4045 while (pAd->Mlme.MemHandler.pUnUseHead != NULL)
4047 pMlmeMemoryStruct = pAd->Mlme.MemHandler.pUnUseHead;
4048 pAd->Mlme.MemHandler.pUnUseHead = pAd->Mlme.MemHandler.pUnUseHead->Next;
4049 //Free the virtual address in AllocVa which size is MAX_LEN_OF_MLME_BUFFER
4050 kfree(pMlmeMemoryStruct->AllocVa);
4051 //Free the link list item self
4052 kfree(pMlmeMemoryStruct);