MOXA linux-2.6.x / linux-2.6.9-uc0 from sdlinux-moxaart.tgz
[linux-2.6.9-moxart.git] / drivers / net / wireless / rtlink.org / mlme.c
blob56064ef2c51759e95c2641828af944095a416cd7
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 * (c) Copyright 2002, Ralink Technology, Inc.
8 * All rights reserved. Ralink's source code is an unpublished work and the
9 * use of a copyright notice does not imply otherwise. This source code
10 * contains confidential trade secret material of Ralink Tech. Any attemp
11 * or participation in deciphering, decoding, reverse engineering or in any
12 * way altering the source code is stricitly prohibited, unless the prior
13 * written consent of Ralink Technology, Inc. is obtained.
14 ****************************************************************************/
16 #include "rt_config.h"
17 #include <stdarg.h>
19 // e.g. RssiSafeLevelForTxRate[RATE_36]" means if the current RSSI is greater than
20 // this value, then it's quaranteed capable of operating in 36 mbps TX rate in
21 // clean environment.
22 // TxRate: 1 2 5.5 11 6 9 12 18 24 36 48 54 72 100
23 CHAR RssiSafeLevelForTxRate[] ={ -92, -91, -90, -87, -88, -86, -85, -83, -81, -78, -72, -71, -40, -40 };
25 // 1 2 5.5 11
26 UCHAR Phy11BNextRateDownward[] = {RATE_1, RATE_1, RATE_2, RATE_5_5};
27 UCHAR Phy11BNextRateUpward[] = {RATE_2, RATE_5_5, RATE_11, RATE_11};
29 // 1 2 5.5 11 6 9 12 18 24 36 48 54
30 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};
31 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};
33 // 1 2 5.5 11 6 9 12 18 24 36 48 54
34 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};
35 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};
37 // 2560D and after has implemented ASIC-based OFDM rate switching, but not
38 // 2560C and before. thus software use different PER for rate switching
39 // RATE_1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54
40 USHORT NewRateUpPER[] = { 40, 40, 35, 20, 20, 20, 20, 16, 10, 16, 10, 6 }; // in percentage
41 USHORT NewRateDownPER[] = { 50, 50, 45, 45, 35, 35, 35, 35, 25, 25, 25, 13 }; // in percentage
43 USHORT OldRateUpPER[] = { 40, 40, 40, 40, 30, 30, 30, 30, 20, 20, 10, 10 }; // in percentage
44 USHORT OldRateDownPER[] = { 45, 45, 45, 45, 35, 35, 35, 35, 25, 25, 25, 12 }; // in percentage
46 UCHAR RateIdToMbps[] = { 1, 2, 5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 72, 100};
47 USHORT RateIdTo500Kbps[] = { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108, 144, 200};
49 RTMP_RF_REGS RF2522RegTable[] = {
50 // ch R1 R2 R3(TX0~4=0) R4
51 {1, 0x94002050, 0x940c1fda, 0x94000101, 0},
52 {2, 0x94002050, 0x940c1fee, 0x94000101, 0},
53 {3, 0x94002050, 0x940c2002, 0x94000101, 0},
54 {4, 0x94002050, 0x940c2016, 0x94000101, 0},
55 {5, 0x94002050, 0x940c202a, 0x94000101, 0},
56 {6, 0x94002050, 0x940c203e, 0x94000101, 0},
57 {7, 0x94002050, 0x940c2052, 0x94000101, 0},
58 {8, 0x94002050, 0x940c2066, 0x94000101, 0},
59 {9, 0x94002050, 0x940c207a, 0x94000101, 0},
60 {10, 0x94002050, 0x940c208e, 0x94000101, 0},
61 {11, 0x94002050, 0x940c20a2, 0x94000101, 0},
62 {12, 0x94002050, 0x940c20b6, 0x94000101, 0},
63 {13, 0x94002050, 0x940c20ca, 0x94000101, 0},
64 {14, 0x94002050, 0x940c20fa, 0x94000101, 0}
66 #define NUM_OF_2522_CHNL (sizeof(RF2522RegTable) / sizeof(RTMP_RF_REGS))
68 RTMP_RF_REGS RF2523RegTable[] = {
69 // ch R1 R2 R3(TX0~4=0) R4
70 {1, 0x94022010, 0x94000c9e, 0x940e0111, 0x94000a1b},
71 {2, 0x94022010, 0x94000ca2, 0x940e0111, 0x94000a1b},
72 {3, 0x94022010, 0x94000ca6, 0x940e0111, 0x94000a1b},
73 {4, 0x94022010, 0x94000caa, 0x940e0111, 0x94000a1b},
74 {5, 0x94022010, 0x94000cae, 0x940e0111, 0x94000a1b},
75 {6, 0x94022010, 0x94000cb2, 0x940e0111, 0x94000a1b},
76 {7, 0x94022010, 0x94000cb6, 0x940e0111, 0x94000a1b},
77 {8, 0x94022010, 0x94000cba, 0x940e0111, 0x94000a1b},
78 {9, 0x94022010, 0x94000cbe, 0x940e0111, 0x94000a1b},
79 {10, 0x94022010, 0x94000d02, 0x940e0111, 0x94000a1b},
80 {11, 0x94022010, 0x94000d06, 0x940e0111, 0x94000a1b},
81 {12, 0x94022010, 0x94000d0a, 0x940e0111, 0x94000a1b},
82 {13, 0x94022010, 0x94000d0e, 0x940e0111, 0x94000a1b},
83 {14, 0x94022010, 0x94000d1a, 0x940e0111, 0x94000a03}
84 #if 0
85 {1, 0x94022050, 0x940c1fda, 0x940e8101, 0},
86 {2, 0x94022050, 0x940c1fee, 0x940e8101, 0},
87 {3, 0x94022050, 0x940c2002, 0x940e8101, 0},
88 {4, 0x94022050, 0x940c2016, 0x940e8101, 0},
89 {5, 0x94022050, 0x940c202a, 0x940e8101, 0},
90 {6, 0x94022050, 0x940c203e, 0x940e8101, 0},
91 {7, 0x94022050, 0x940c2052, 0x940e8101, 0},
92 {8, 0x94022050, 0x940c2066, 0x940e8101, 0},
93 {9, 0x94022050, 0x940c207a, 0x940e8101, 0},
94 {10, 0x94022050, 0x940c208e, 0x940e8101, 0},
95 {11, 0x94022050, 0x940c20a2, 0x940e8101, 0},
96 {12, 0x94022050, 0x940c20b6, 0x940e8101, 0},
97 {13, 0x94022050, 0x940c20ca, 0x940e8101, 0},
98 {14, 0x94022050, 0x940c20fa, 0x940e8101, 0}
99 #endif
101 #define NUM_OF_2523_CHNL (sizeof(RF2523RegTable) / sizeof(RTMP_RF_REGS))
103 RTMP_RF_REGS RF2524RegTable[] = {
104 // ch R1 R2 R3(TX0~4=0) R4
105 {1, 0x94032020, 0x94000c9e, 0x94000101, 0x94000a1b},
106 {2, 0x94032020, 0x94000ca2, 0x94000101, 0x94000a1b},
107 {3, 0x94032020, 0x94000ca6, 0x94000101, 0x94000a1b},
108 {4, 0x94032020, 0x94000caa, 0x94000101, 0x94000a1b},
109 {5, 0x94032020, 0x94000cae, 0x94000101, 0x94000a1b},
110 {6, 0x94032020, 0x94000cb2, 0x94000101, 0x94000a1b},
111 {7, 0x94032020, 0x94000cb6, 0x94000101, 0x94000a1b},
112 {8, 0x94032020, 0x94000cba, 0x94000101, 0x94000a1b},
113 {9, 0x94032020, 0x94000cbe, 0x94000101, 0x94000a1b},
114 {10, 0x94032020, 0x94000d02, 0x94000101, 0x94000a1b},
115 {11, 0x94032020, 0x94000d06, 0x94000101, 0x94000a1b},
116 {12, 0x94032020, 0x94000d0a, 0x94000101, 0x94000a1b},
117 {13, 0x94032020, 0x94000d0e, 0x94000101, 0x94000a1b},
118 {14, 0x94032020, 0x94000d1a, 0x94000101, 0x94000a03}
120 #define NUM_OF_2524_CHNL (sizeof(RF2524RegTable) / sizeof(RTMP_RF_REGS))
122 RTMP_RF_REGS RF2525RegTable[] = {
123 // ch R1 R2 R3(TX0~4=0) R4
124 {1, 0x94022020, 0x94080c9e, 0x94060111, 0x94000a1b}, // {1, 0x94022010, 0x9408062e, 0x94060111, 0x94000a23},
125 {2, 0x94022020, 0x94080ca2, 0x94060111, 0x94000a1b},
126 {3, 0x94022020, 0x94080ca6, 0x94060111, 0x94000a1b},
127 {4, 0x94022020, 0x94080caa, 0x94060111, 0x94000a1b},
128 {5, 0x94022020, 0x94080cae, 0x94060111, 0x94000a1b},
129 {6, 0x94022020, 0x94080cb2, 0x94060111, 0x94000a1b},
130 {7, 0x94022020, 0x94080cb6, 0x94060111, 0x94000a1b},
131 {8, 0x94022020, 0x94080cba, 0x94060111, 0x94000a1b},
132 {9, 0x94022020, 0x94080cbe, 0x94060111, 0x94000a1b},
133 {10, 0x94022020, 0x94080d02, 0x94060111, 0x94000a1b},
134 {11, 0x94022020, 0x94080d06, 0x94060111, 0x94000a1b}, // {11, 0x94022010, 0x94080682, 0x94060111, 0x94000a23},
135 {12, 0x94022020, 0x94080d0a, 0x94060111, 0x94000a1b},
136 {13, 0x94022020, 0x94080d0e, 0x94060111, 0x94000a1b}, // {13, 0x94022010, 0x94080686, 0x94060111, 0x94000a23},
137 {14, 0x94022020, 0x94080d1a, 0x94060111, 0x94000a03}
139 #define NUM_OF_2525_CHNL (sizeof(RF2525RegTable) / sizeof(RTMP_RF_REGS))
141 RTMP_RF_REGS RF2525HBOffsetRegTable[] = {
142 {1, 0x94022020, 0x94080cbe, 0x94060111, 0x94000a1b},
143 {2, 0x94022020, 0x94080d02, 0x94060111, 0x94000a1b},
144 {3, 0x94022020, 0x94080d06, 0x94060111, 0x94000a1b},
145 {4, 0x94022020, 0x94080d0a, 0x94060111, 0x94000a1b},
146 {5, 0x94022020, 0x94080d0e, 0x94060111, 0x94000a1b},
147 {6, 0x94022020, 0x94080d12, 0x94060111, 0x94000a1b},
148 {7, 0x94022020, 0x94080d16, 0x94060111, 0x94000a1b},
149 {8, 0x94022020, 0x94080d1a, 0x94060111, 0x94000a1b},
150 {9, 0x94022020, 0x94080d1e, 0x94060111, 0x94000a1b},
151 {10, 0x94022020, 0x94080d22, 0x94060111, 0x94000a1b},
152 {11, 0x94022020, 0x94080d26, 0x94060111, 0x94000a1b},
153 {12, 0x94022020, 0x94080d2a, 0x94060111, 0x94000a1b},
154 {13, 0x94022020, 0x94080d2e, 0x94060111, 0x94000a1b},
155 {14, 0x94022020, 0x94080d3a, 0x94060111, 0x94000a03}
158 RTMP_RF_REGS RF2525eRegTable[] = {
159 #if 1
160 // using 5 Mhz reference clock
161 // ch R1 R2 R3(TX0~4=0) R4
162 {1, 0x94022020, 0x94081136, 0x94060111, 0x94000a0b},
163 {2, 0x94022020, 0x9408113a, 0x94060111, 0x94000a0b},
164 {3, 0x94022020, 0x9408113e, 0x94060111, 0x94000a0b},
165 {4, 0x94022020, 0x94081182, 0x94060111, 0x94000a0b},
166 {5, 0x94022020, 0x94081186, 0x94060111, 0x94000a0b},
167 {6, 0x94022020, 0x9408118a, 0x94060111, 0x94000a0b},
168 {7, 0x94022020, 0x9408118e, 0x94060111, 0x94000a0b},
169 {8, 0x94022020, 0x94081192, 0x94060111, 0x94000a0b},
170 {9, 0x94022020, 0x94081196, 0x94060111, 0x94000a0b},
171 {10, 0x94022020, 0x9408119a, 0x94060111, 0x94000a0b},
172 {11, 0x94022020, 0x9408119e, 0x94060111, 0x94000a0b},
173 {12, 0x94022020, 0x940811a2, 0x94060111, 0x94000a0b},
174 {13, 0x94022020, 0x940811a6, 0x94060111, 0x94000a0b},
175 {14, 0x94022020, 0x940811ae, 0x94060111, 0x94000a1b}
176 #else
177 // using 10 Mhz reference clock
178 // ch R1 R2 R3(TX0~4=0) R4
179 {1, 0x94022010, 0x9408089a, 0x94060111, 0x94000a1b},
180 {2, 0x94022010, 0x9408089e, 0x94060111, 0x94000a07},
181 {3, 0x94022010, 0x9408089e, 0x94060111, 0x94000a1b},
182 {4, 0x94022010, 0x940808a2, 0x94060111, 0x94000a07},
183 {5, 0x94022010, 0x940808a2, 0x94060111, 0x94000a1b},
184 {6, 0x94022010, 0x940808a6, 0x94060111, 0x94000a07},
185 {7, 0x94022010, 0x940808a6, 0x94060111, 0x94000a1b},
186 {8, 0x94022010, 0x940808aa, 0x94060111, 0x94000a07},
187 {9, 0x94022010, 0x940808aa, 0x94060111, 0x94000a1b},
188 {10, 0x94022010, 0x940808ae, 0x94060111, 0x94000a07},
189 {11, 0x94022010, 0x940808ae, 0x94060111, 0x94000a1b},
190 {12, 0x94022010, 0x940808b2, 0x94060111, 0x94000a07},
191 {13, 0x94022010, 0x940808b2, 0x94060111, 0x94000a1b},
192 {14, 0x94022010, 0x940808b6, 0x94060111, 0x94000a23}
193 #endif
195 #define NUM_OF_2525E_CHNL (sizeof(RF2525eRegTable) / sizeof(RTMP_RF_REGS))
197 RTMP_RF_REGS RF5222RegTable[] = {
198 // ch R1 R2 R3(TX0~4=0) R4
199 {1, 0x94022020, 0x94001136, 0x94000101, 0x94000a0b},
200 {2, 0x94022020, 0x9400113a, 0x94000101, 0x94000a0b},
201 {3, 0x94022020, 0x9400113e, 0x94000101, 0x94000a0b},
202 {4, 0x94022020, 0x94001182, 0x94000101, 0x94000a0b},
203 {5, 0x94022020, 0x94001186, 0x94000101, 0x94000a0b},
204 {6, 0x94022020, 0x9400118a, 0x94000101, 0x94000a0b},
205 {7, 0x94022020, 0x9400118e, 0x94000101, 0x94000a0b},
206 {8, 0x94022020, 0x94001192, 0x94000101, 0x94000a0b},
207 {9, 0x94022020, 0x94001196, 0x94000101, 0x94000a0b},
208 {10, 0x94022020, 0x9400119a, 0x94000101, 0x94000a0b},
209 {11, 0x94022020, 0x9400119e, 0x94000101, 0x94000a0b},
210 {12, 0x94022020, 0x940011a2, 0x94000101, 0x94000a0b},
211 {13, 0x94022020, 0x940011a6, 0x94000101, 0x94000a0b},
212 {14, 0x94022020, 0x940011ae, 0x94000101, 0x94000a1b},
214 // still lack of MMAC(Japan) ch 34,38,42,46
216 {36, 0x94022010, 0x94018896, 0x94000101, 0x94000a1f},
217 {40, 0x94022010, 0x9401889a, 0x94000101, 0x94000a1f},
218 {44, 0x94022010, 0x9401889e, 0x94000101, 0x94000a1f},
219 {48, 0x94022010, 0x940188a2, 0x94000101, 0x94000a1f},
220 {52, 0x94022010, 0x940188a6, 0x94000101, 0x94000a1f},
221 {66, 0x94022010, 0x940188aa, 0x94000101, 0x94000a1f},
222 {60, 0x94022010, 0x940188ae, 0x94000101, 0x94000a1f},
223 {64, 0x94022010, 0x940188b2, 0x94000101, 0x94000a1f},
225 {100, 0x94022010, 0x94008802, 0x94000101, 0x94000a0f},
226 {104, 0x94022010, 0x94008806, 0x94000101, 0x94000a0f},
227 {108, 0x94022010, 0x9400880a, 0x94000101, 0x94000a0f},
228 {112, 0x94022010, 0x9400880e, 0x94000101, 0x94000a0f},
229 {116, 0x94022010, 0x94008812, 0x94000101, 0x94000a0f},
230 {120, 0x94022010, 0x94008816, 0x94000101, 0x94000a0f},
231 {124, 0x94022010, 0x9400881a, 0x94000101, 0x94000a0f},
232 {128, 0x94022010, 0x9400881e, 0x94000101, 0x94000a0f},
233 {132, 0x94022010, 0x94008822, 0x94000101, 0x94000a0f},
234 {136, 0x94022010, 0x94008826, 0x94000101, 0x94000a0f},
235 {140, 0x94022010, 0x9400882a, 0x94000101, 0x94000a0f},
237 {149, 0x94022020, 0x940090a6, 0x94000101, 0x94000a07},
238 {153, 0x94022020, 0x940090ae, 0x94000101, 0x94000a07},
239 {157, 0x94022020, 0x940090b6, 0x94000101, 0x94000a07},
240 {161, 0x94022020, 0x940090be, 0x94000101, 0x94000a07}
242 #define NUM_OF_5222_CHNL (sizeof(RF5222RegTable) / sizeof(RTMP_RF_REGS))
244 void MlmePrintMemory(IN PRTMP_ADAPTER pAd);
247 ==========================================================================
248 Description:
249 initialize the MLME task and its data structure (queue, spinlock,
250 timer, state machines).
251 Return:
252 always return NDIS_STATUS_SUCCESS
253 ==========================================================================
255 NDIS_STATUS MlmeInit(
256 IN PRTMP_ADAPTER pAd)
258 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
260 DBGPRINT(RT_DEBUG_TRACE, "--> MLME Initialize\n");
264 Status = MlmeQueueInit(&pAd->Mlme.Queue);
265 if(Status != NDIS_STATUS_SUCCESS)
267 break;
270 pAd->Mlme.Running = FALSE;
271 NdisAllocateSpinLock(&pAd->Mlme.TaskLock);
273 // initialize the two tables
274 // MacTableInit(pAd);
275 BssTableInit(&pAd->PortCfg.BssTab);
277 // init state machines
278 ASSERT(ASSOC_FUNC_SIZE == MAX_ASSOC_MSG * MAX_ASSOC_STATE);
279 AssocStateMachineInit(pAd, &pAd->Mlme.AssocMachine, pAd->Mlme.AssocFunc);
281 ASSERT(AUTH_FUNC_SIZE == MAX_AUTH_MSG * MAX_AUTH_STATE);
282 AuthStateMachineInit(pAd, &pAd->Mlme.AuthMachine, pAd->Mlme.AuthFunc);
284 ASSERT(AUTH_RSP_FUNC_SIZE == MAX_AUTH_RSP_MSG * MAX_AUTH_RSP_STATE);
285 AuthRspStateMachineInit(pAd, &pAd->Mlme.AuthRspMachine, pAd->Mlme.AuthRspFunc);
287 ASSERT(SYNC_FUNC_SIZE == MAX_SYNC_MSG * MAX_SYNC_STATE);
288 SyncStateMachineInit(pAd, &pAd->Mlme.SyncMachine, pAd->Mlme.SyncFunc);
290 ASSERT(WPA_PSK_FUNC_SIZE == MAX_WPA_PSK_MSG * MAX_WPA_PSK_STATE);
291 WpaPskStateMachineInit(pAd,&pAd->Mlme.WpaPskMachine,pAd->Mlme.WpaPskFunc);
293 // Since we are using switch/case to implement it, the init is different from the above
294 // state machine init
295 MlmeCntlInit(pAd, &pAd->Mlme.CntlMachine, NULL);
297 // Init mlme periodic timer
298 RTMPInitTimer(pAd, &pAd->Mlme.PeriodicTimer, MlmePeriodicExec);
299 // Set mlme periodic timer
300 RTMPSetTimer(pAd, &pAd->Mlme.PeriodicTimer, MLME_TASK_EXEC_INTV);
302 if (pAd->PortCfg.LedMode == LED_MODE_TXRX_ACTIVITY)
304 // Init blnk timer
305 RTMPInitTimer(pAd, &pAd->PortCfg.LedCntl.BlinkTimer, AsicLedPeriodicExec);
306 // Set blink timer
307 RTMPSetTimer(pAd, &pAd->PortCfg.LedCntl.BlinkTimer, 70);
310 // software-based RX Antenna diversity
311 RTMPInitTimer(pAd, &pAd->PortCfg.RxAnt.RxAntDiversityTimer, AsicRxAntEvalTimeout);
312 } while (FALSE);
314 DBGPRINT(RT_DEBUG_TRACE, "<-- MLME Initialize\n");
316 return Status;
321 ==========================================================================
322 Description:
323 main loop of the MLME
324 Pre:
325 Mlme has to be initialized, and there are something inside the queue
326 Note:
327 This function is invoked from MPSetInformation and MPReceive;
328 This task guarantee only one MlmeHandler will run.
329 ==========================================================================
331 VOID MlmeHandler(
332 IN PRTMP_ADAPTER pAd)
334 MLME_QUEUE_ELEM *Elem = NULL;
335 unsigned long IrqFlags;
337 // Only accept MLME and Frame from peer side, no other (control/data) frame should
338 // get into this state machine
340 NdisAcquireSpinLock(&pAd->Mlme.TaskLock);
341 if(pAd->Mlme.Running)
343 NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
344 return;
346 else
348 pAd->Mlme.Running = TRUE;
350 NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
352 while (!MlmeQueueEmpty(&pAd->Mlme.Queue))
354 //From message type, determine which state machine I should drive
355 if (MlmeDequeue(&pAd->Mlme.Queue, &Elem))
357 // if dequeue success
358 switch (Elem->Machine)
360 case ASSOC_STATE_MACHINE:
361 StateMachinePerformAction(pAd, &pAd->Mlme.AssocMachine, Elem);
362 break;
363 case AUTH_STATE_MACHINE:
364 StateMachinePerformAction(pAd, &pAd->Mlme.AuthMachine, Elem);
365 break;
366 case AUTH_RSP_STATE_MACHINE:
367 StateMachinePerformAction(pAd, &pAd->Mlme.AuthRspMachine, Elem);
368 break;
369 case SYNC_STATE_MACHINE:
370 StateMachinePerformAction(pAd, &pAd->Mlme.SyncMachine, Elem);
371 break;
372 case MLME_CNTL_STATE_MACHINE:
373 MlmeCntlMachinePerformAction(pAd, &pAd->Mlme.CntlMachine, Elem);
374 break;
375 case WPA_PSK_STATE_MACHINE:
376 StateMachinePerformAction(pAd, &pAd->Mlme.WpaPskMachine, Elem);
377 break;
378 default:
379 DBGPRINT(RT_DEBUG_TRACE, "ERROR: Illegal machine in MlmeHandler()\n");
380 break;
381 } // end of switch
383 // free MLME element
384 Elem->Occupied = FALSE;
385 Elem->MsgLen = 0;
386 Elem->TimeStamp.u.HighPart = 0; // Scott added @2005-01-13, for debug only
387 Elem->TimeStamp.u.LowPart = 0; // Scott added @2005-01-13, for debug only
389 else
391 DBGPRINT(RT_DEBUG_ERROR, "ERROR: empty Elem in MlmeQueue\n");
395 NdisAcquireSpinLock(&pAd->Mlme.TaskLock);
396 pAd->Mlme.Running = FALSE;
397 NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
401 ==========================================================================
402 Description:
403 Destructor of MLME (Destroy queue, state machine, spin lock and timer)
404 Parameters:
405 Adapter - NIC Adapter pointer
406 Post:
407 The MLME task will no longer work properly
408 ==========================================================================
410 VOID MlmeHalt(
411 IN PRTMP_ADAPTER pAd)
413 MLME_DISASSOC_REQ_STRUCT DisReq;
414 MLME_QUEUE_ELEM MsgElem;
416 DBGPRINT(RT_DEBUG_TRACE, "==> MlmeHalt\n");
418 if (INFRA_ON(pAd) && !RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))
420 COPY_MAC_ADDR(&DisReq.Addr, &pAd->PortCfg.Bssid);
421 DisReq.Reason = REASON_DISASSOC_STA_LEAVING;
423 MsgElem.Machine = ASSOC_STATE_MACHINE;
424 MsgElem.MsgType = MT2_MLME_DISASSOC_REQ;
425 MsgElem.MsgLen = sizeof(MLME_DISASSOC_REQ_STRUCT);
426 NdisMoveMemory(MsgElem.Msg, &DisReq, sizeof(MLME_DISASSOC_REQ_STRUCT));
428 MlmeDisassocReqAction(pAd, &MsgElem);
430 udelay(1000);
433 if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))
435 // disable BEACON generation and other BEACON related hardware timers
436 AsicDisableSync(pAd);
439 // Cancel pending timers
440 RTMPCancelTimer(&pAd->Mlme.AssocAux.AssocTimer);
441 RTMPCancelTimer(&pAd->Mlme.AssocAux.ReassocTimer);
442 RTMPCancelTimer(&pAd->Mlme.AssocAux.DisassocTimer);
443 RTMPCancelTimer(&pAd->Mlme.AuthAux.AuthTimer);
444 RTMPCancelTimer(&pAd->Mlme.AuthRspAux.AuthRspTimer);
445 RTMPCancelTimer(&pAd->Mlme.SyncAux.BeaconTimer);
446 RTMPCancelTimer(&pAd->Mlme.SyncAux.ScanTimer);
447 RTMPCancelTimer(&pAd->Mlme.PeriodicTimer);
448 // RTMPCancelTimer(&pAd->PortCfg.MacTab.AgedOutTimer);
450 if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))
452 if (pAd->PortCfg.LedMode == LED_MODE_TXRX_ACTIVITY)
453 RTMPCancelTimer(&pAd->PortCfg.LedCntl.BlinkTimer);
454 ASIC_LED_ACT_OFF(pAd);
457 RTMPCancelTimer(&pAd->PortCfg.RxAnt.RxAntDiversityTimer);
458 udelay(1000);
460 MlmeQueueDestroy(&pAd->Mlme.Queue);
461 StateMachineDestroy(&pAd->Mlme.AssocMachine);
462 StateMachineDestroy(&pAd->Mlme.AuthMachine);
463 StateMachineDestroy(&pAd->Mlme.AuthRspMachine);
464 StateMachineDestroy(&pAd->Mlme.SyncMachine);
465 // StateMachineDestroy(&pAd->Mlme.CntlMachine);
466 NdisFreeSpinLock(&pAd->Mlme.Queue.Lock);
467 NdisFreeSpinLock(&pAd->Mlme.TaskLock);
468 // NdisFreeSpinLock(&pAd->PortCfg.MacTab.Lock);
470 MlmeFreeMemoryHandler(pAd); //Free MLME memory handler
472 DBGPRINT(RT_DEBUG_TRACE, "<== MlmeHalt\n");
476 ==========================================================================
477 Description:
478 This routine is executed periodically to -
479 1. Decide if it's a right time to turn on PwrMgmt bit of all
480 outgoiing frames
481 2. Calculate ChannelQuality based on statistics of the last
482 period, so that TX rate won't toggling very frequently between a
483 successful TX and a failed TX.
484 3. If the calculated ChannelQuality indicated current connection not
485 healthy, then a ROAMing attempt is tried here.
486 ==========================================================================
488 #define ADHOC_BEACON_LOST_TIME (10*HZ) // 4 sec
489 VOID MlmePeriodicExec(
490 IN unsigned long data)
492 RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)data;
493 ULONG Now32;
494 CSR15_STRUC Csr15;
496 if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
498 RTMPSetTimer(pAd, &pAd->Mlme.PeriodicTimer, MLME_TASK_EXEC_INTV);
499 return;
502 if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS))
504 RTMPSetTimer(pAd, &pAd->Mlme.PeriodicTimer, MLME_TASK_EXEC_INTV);
505 return;
508 Now32 = jiffies;
510 if (pAd->RalinkCounters.MgmtRingFullCount >= 2)
512 RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HARDWARE_ERROR);
514 else
516 pAd->RalinkCounters.MgmtRingFullCount = 0;
519 if ((pAd->PortCfg.bBlockAssoc == TRUE) && (pAd->PortCfg.LastMicErrorTime + (60 * HZ) < Now32))
521 pAd->PortCfg.bBlockAssoc = FALSE;
524 // if Rx Antenna is DIVERSITY ON, then perform Software-based diversity evaluation
525 if ((pAd->PortCfg.CurrentRxAntenna == 0xff) && (pAd->Mlme.PeriodicRound % 4 ==1))
526 AsicEvaluateSecondaryRxAnt(pAd);
528 #ifndef WIFI_TEST
529 // danamic tune BBP R17 to find a balance between sensibility and noise isolation
530 // 2003-12-05 For 2560C and before, to avoid collision with MAC ASIC, limit
531 // BBP R17 tuning to be within 20 seconds after LINK UP. 2560D (R0=4) and
532 // after can always enable R17 tuning
533 if (pAd->PortCfg.Rt2560Version >= RT2560_VER_D)
534 AsicBbpTuning(pAd);
535 else if ((pAd->MediaState == NdisMediaStateConnected) && (pAd->Mlme.PeriodicRound <= 20))
536 AsicBbpTuning(pAd);
537 #endif
539 if (pAd->MediaState == NdisMediaStateConnected)
541 // update channel quality for Roaming and UI LinkQuality display
542 MlmeCheckChannelQuality(pAd, Now32);
543 #if 0
544 // periodic VCO tuning when there's no traffic.
545 // RF guys suspected VCO will shift away upon temperature change along the time
546 if (((pAd->Mlme.PeriodicRound % 16) == 2) &&
547 ((pAd->DrsCounters.OneSecTxOkCount + pAd->DrsCounters.OneSecTxRetryOkCount)==0))
549 DBGPRINT(RT_DEBUG_TRACE,("Periodic VCO tuning...\n"));
550 AsicSwitchChannel(pAd, pAd->PortCfg.Channel);
551 AsicLockChannel(pAd, pAd->PortCfg.Channel);
553 #endif
554 // perform dynamic tx rate switching based on past TX history
555 MlmeCheckDynamicTxRateSwitching(pAd);
558 AsicAdjustTxPower(pAd);
560 if (INFRA_ON(pAd))
562 // Is PSM bit consistent with user power management policy?
563 // This is the only place that will set PSM bit ON.
564 MlmeCheckForPsmChange(pAd, Now32);
566 // Check for EAPOL frame sent after MIC countermeasures
567 if (pAd->PortCfg.MicErrCnt >= 3)
569 MLME_DISASSOC_REQ_STRUCT DisassocReq;
571 // disassoc from current AP first
572 DBGPRINT(RT_DEBUG_TRACE, "MLME - disassociate with current AP after sending second continuous EAPOL frame\n");
573 DisassocParmFill(pAd, &DisassocReq, &pAd->PortCfg.Bssid, REASON_MIC_FAILURE);
574 MlmeEnqueue(&pAd->Mlme.Queue, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ,
575 sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq);
577 pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC;
578 pAd->PortCfg.bBlockAssoc = TRUE;
581 else
583 // send out a NULL frame every 10 sec. for what??? inform "PwrMgmt" bit?
584 if ((pAd->Mlme.PeriodicRound % 10) == 8)
585 EnqueueNullFrame(pAd, pAd->PortCfg.TxRate);
587 if (CQI_IS_BAD(pAd->Mlme.ChannelQuality))
589 pAd->RalinkCounters.BadCQIAutoRecoveryCount ++;
590 DBGPRINT(RT_DEBUG_TRACE, "MMCHK - Bad CQI. Auto Recovery attempt #%d\n", pAd->RalinkCounters.BadCQIAutoRecoveryCount);
591 MlmeAutoReconnectLastSSID(pAd);
594 else if (CQI_IS_FAIR(pAd->Mlme.ChannelQuality) || CQI_IS_POOR(pAd->Mlme.ChannelQuality))
596 // perform aggresive roaming only when SECURITY OFF or WEP64/128;
597 // WPA and WPA-PSK has no aggresive roaming because re-negotiation
598 // between 802.1x supplicant and authenticator/AAA server is required
599 // but can't be guaranteed.
600 if (pAd->PortCfg.AuthMode < Ndis802_11AuthModeWPA)
601 MlmeCheckForRoaming(pAd, Now32);
605 else if (ADHOC_ON(pAd))
607 if ((pAd->Mlme.PeriodicRound % 2) == 1)
609 // So that even when ASIC's BEACONgen engine been blocked
610 // by peer's BEACON due to slower system clock, this STA still can send out
611 // minimum BEACON to tell the peer I'm alive.
612 // drawback is that this BEACON won't well align at TBTT boundary.
613 RTMP_IO_READ32(pAd, CSR15, &Csr15.word); // read-n-clear "BcnSent" bit
614 if (Csr15.field.BeaconSent == 0)
615 EnqueueBeaconFrame(pAd); // software send BEACON
617 else
619 // if all 11b peers leave this BSS more than 5 seconds, update Tx rate
620 if ((pAd->PortCfg.Channel <= 14) &&
621 (pAd->PortCfg.MaxTxRate <= RATE_11) &&
622 (pAd->PortCfg.MaxDesiredRate > RATE_11) &&
623 ((pAd->PortCfg.Last11bBeaconRxTime + (5 * HZ)) < Now32))
625 DBGPRINT(RT_DEBUG_TRACE, "last 11B peer left, update Tx rates\n");
626 NdisMoveMemory(pAd->PortCfg.SupportedRates, pAd->PortCfg.IbssConfig.SupportedRates, MAX_LEN_OF_SUPPORTED_RATES);
627 pAd->PortCfg.SupportedRatesLen = pAd->PortCfg.IbssConfig.SupportedRatesLen;
628 MlmeUpdateTxRates(pAd, FALSE);
629 MakeIbssBeacon(pAd); // supported rates changed
633 #ifndef SINGLE_ADHOC_LINKUP
634 // If all peers leave, and this STA becomes the last one in this IBSS, then change MediaState
635 // to DISCONNECTED. But still holding this IBSS (i.e. sending BEACON) so that other STAs can
636 // join later.
637 if ((pAd->PortCfg.LastBeaconRxTime + ADHOC_BEACON_LOST_TIME < Now32) &&
638 (pAd->MediaState == NdisMediaStateConnected))
640 DBGPRINT(RT_DEBUG_TRACE, "MMCHK - excessive BEACON lost, last STA in this IBSS, MediaState=Disconnected\n");
642 pAd->MediaState = NdisMediaStateDisconnected;
643 // clean up previous SCAN result, add current BSS back to table if any
644 BssTableDeleteEntry(&pAd->PortCfg.BssTab, &(pAd->PortCfg.Bssid));
646 pAd->PortCfg.LastScanTime = Now32;
648 #endif
651 else
653 DBGPRINT(RT_DEBUG_INFO, "MLME periodic exec, no association so far (CurrState=%d)\n", pAd->Mlme.CntlMachine.CurrState);
654 if (pAd->PortCfg.AutoReconnect == TRUE)
656 if ((pAd->PortCfg.BssTab.BssNr==0) && (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE))
658 MLME_SCAN_REQ_STRUCT ScanReq;
660 if ((pAd->PortCfg.LastScanTime + 10 * HZ) < Now32)
662 DBGPRINT(RT_DEBUG_TRACE, "CNTL1 - No matching BSS, start a new scan\n");
663 // BroadSsid[0] = '\0';
664 ScanParmFill(pAd, &ScanReq, pAd->Mlme.CntlAux.Ssid, pAd->Mlme.CntlAux.SsidLen, BSS_ANY, SCAN_ACTIVE);
665 MlmeEnqueue(&pAd->Mlme.Queue, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq);
666 pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN;
667 // Reset Missed scan number
668 pAd->PortCfg.IgnoredScanNumber = 0;
669 pAd->PortCfg.LastScanTime = Now32;
671 else if (pAd->PortCfg.BssType == BSS_INDEP) // Quit the forever scan when in a very clean room
673 DBGPRINT(RT_DEBUG_TRACE, "**MlmeCntlPeriodicExec 1**\n");
674 MlmeAutoReconnectLastSSID(pAd);
677 else if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)
679 if ((pAd->Mlme.PeriodicRound % 10) == 7)
681 if ((pAd->PortCfg.LastScanTime + 10 * HZ) < Now32)
683 MlmeAutoScan(pAd);
684 pAd->PortCfg.LastScanTime = Now32;
687 else
689 MlmeAutoReconnectLastSSID(pAd);
692 DBGPRINT(RT_DEBUG_INFO, "pAd->PortCfg.AutoReconnect is TRUE\n");
696 pAd->Mlme.PeriodicRound ++;
697 DBGPRINT(RT_DEBUG_INFO, "Call MlmeHandler() in MlmePeriodicExec()\n");
698 MlmeHandler(pAd);
700 if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_ACTIVE))
701 NICCheckForHang(pAd);
703 RTMPSetTimer(pAd, &pAd->Mlme.PeriodicTimer, MLME_TASK_EXEC_INTV);
706 VOID MlmeAutoScan(
707 IN PRTMP_ADAPTER pAd)
709 // check CntlMachine.CurrState to avoid collision with NDIS SetOID request
710 if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)
712 DBGPRINT(RT_DEBUG_TRACE, "MMCHK - Driver auto scan\n");
714 // tell CNTL state machine NOT to call NdisMSetInformationComplete() after completing
715 // this request, because this request is initiated by driver itself.
716 pAd->Mlme.CntlAux.CurrReqIsFromNdis = FALSE;
718 MlmeEnqueue(&pAd->Mlme.Queue,
719 MLME_CNTL_STATE_MACHINE,
720 OID_802_11_BSSID_LIST_SCAN,
722 NULL);
723 MlmeHandler(pAd);
727 VOID MlmeAutoRecoverNetwork(
728 IN PRTMP_ADAPTER pAd)
730 // check CntlMachine.CurrState to avoid collision with NDIS SetOID request
731 if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)
733 NDIS_802_11_SSID OidSsid;
734 OidSsid.SsidLength = pAd->PortCfg.SsidLen;
735 NdisMoveMemory(OidSsid.Ssid, pAd->PortCfg.Ssid, pAd->PortCfg.SsidLen);
737 DBGPRINT(RT_DEBUG_TRACE, "MMCHK - Driver auto recovering network - %s\n", pAd->PortCfg.Ssid);
739 // tell CNTL state machine NOT to call NdisMSetInformationComplete() after completing
740 // this request, because this request is initiated by driver itself.
741 pAd->Mlme.CntlAux.CurrReqIsFromNdis = FALSE;
743 MlmeEnqueue(&pAd->Mlme.Queue,
744 MLME_CNTL_STATE_MACHINE,
745 OID_802_11_SSID,
746 sizeof(NDIS_802_11_SSID),
747 &OidSsid);
748 MlmeHandler(pAd);
753 VOID MlmeAutoReconnectLastSSID(
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->Mlme.CntlAux.SsidLen;
761 NdisMoveMemory(OidSsid.Ssid, pAd->Mlme.CntlAux.Ssid, pAd->Mlme.CntlAux.SsidLen);
763 DBGPRINT(RT_DEBUG_TRACE, "Auto reconnect to last OID_802_11_SSID- %s\n", pAd->Mlme.CntlAux.Ssid);
765 // We will only try this attemp once, therefore change the AutoReconnect flag afterwards.
766 pAd->Mlme.CntlAux.CurrReqIsFromNdis = FALSE;
768 MlmeEnqueue(&pAd->Mlme.Queue,
769 MLME_CNTL_STATE_MACHINE,
770 OID_802_11_SSID,
771 sizeof(NDIS_802_11_SSID),
772 &OidSsid);
773 MlmeHandler(pAd);
775 else
776 DBGPRINT(RT_DEBUG_TRACE, "pAd->Mlme.CntlMachine.CurrState=%d\n", pAd->Mlme.CntlMachine.CurrState); // Scott
780 ==========================================================================
781 Description:
782 This routine checks if there're other APs out there capable for
783 roaming. Caller should call this routine only when Massoc=TRUE and
784 channel quality is below CQI_GOOD_THRESHOLD.
785 Output:
786 ==========================================================================
788 VOID MlmeCheckForRoaming(
789 IN PRTMP_ADAPTER pAd,
790 IN ULONG Now32)
792 USHORT i;
793 BSS_TABLE *pBssTab = &pAd->Mlme.CntlAux.SsidBssTab;
794 BSS_TABLE *pRoamTab = &pAd->Mlme.CntlAux.RoamTab;
795 BSS_ENTRY *pBss;
797 // put all roaming candidates into RoamTab, and sort in RSSI order
798 BssTableInit(pRoamTab);
799 for (i = 0; i < pBssTab->BssNr; i++)
801 pBss = &pBssTab->BssEntry[i];
803 if ((pBssTab->BssEntry[i].LastBeaconRxTime + BEACON_LOST_TIME) < Now32)
804 continue; // AP disappear
805 if (pBss->Rssi <= RSSI_THRESHOLD_FOR_ROAMING)
806 continue; // RSSI too weak. forget it.
807 if (MAC_ADDR_EQUAL(&pBssTab->BssEntry[i].Bssid, &pAd->PortCfg.Bssid))
808 continue; // skip current AP
809 if (CQI_IS_FAIR(pAd->Mlme.ChannelQuality) && (pAd->PortCfg.LastRssi + RSSI_DELTA > pBss->Rssi))
810 continue; // we're still okay, only AP with stronger RSSI is eligible for roaming
812 // AP passing all above rules is put into roaming candidate table
813 NdisMoveMemory(&pRoamTab->BssEntry[pRoamTab->BssNr], pBss, sizeof(BSS_ENTRY));
814 pRoamTab->BssNr += 1;
817 if (pRoamTab->BssNr > 0)
819 // check CntlMachine.CurrState to avoid collision with NDIS SetOID request
820 if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)
822 // tell CNTL state machine NOT to call NdisMSetInformationComplete() after completing
823 // this request, because this request is initiated by driver itself, not from NDIS.
824 pAd->Mlme.CntlAux.CurrReqIsFromNdis = FALSE;
826 pAd->RalinkCounters.PoorCQIRoamingCount ++;
827 DBGPRINT(RT_DEBUG_TRACE, "MMCHK - Roaming attempt #%d\n", pAd->RalinkCounters.PoorCQIRoamingCount);
828 MlmeEnqueue(&pAd->Mlme.Queue, MLME_CNTL_STATE_MACHINE, MT2_MLME_ROAMING_REQ, 0, NULL);
829 MlmeHandler(pAd);
836 ==========================================================================
837 Description:
838 This routine calculates TxPER, RxPER of the past N-sec period. And
839 according to the calculation result, ChannelQuality is calculated here
840 to decide if current AP is still doing the job.
842 If ChannelQuality is not good, a ROAMing attempt may be tried later.
843 Output:
844 PortCfg.ChannelQuality - 0..100
845 ==========================================================================
847 VOID MlmeCheckChannelQuality(
848 IN PRTMP_ADAPTER pAd,
849 IN ULONG Now32)
851 ULONG TxFailCnt, TxOkCnt, TxRetryCnt, TxCnt, TxPER, TxPRR;
852 ULONG RxFailCnt, RxOkCnt, RxCnt, RxPER, Cnt0, OldFcsCount;
855 // monitor TX counters change for the past period
857 TxFailCnt = pAd->WlanCounters.FailedCount.u.LowPart -
858 pAd->Mlme.PrevWlanCounters.FailedCount.u.LowPart;
859 TxRetryCnt = pAd->WlanCounters.RetryCount.u.LowPart -
860 pAd->Mlme.PrevWlanCounters.RetryCount.u.LowPart;
861 TxOkCnt = pAd->WlanCounters.TransmittedFragmentCount.u.LowPart -
862 pAd->Mlme.PrevWlanCounters.TransmittedFragmentCount.u.LowPart;
863 TxCnt = TxOkCnt + TxFailCnt;
865 if ( TxCnt < 5 ) { // if too few TX samples, skip TX related statistics
866 TxPER = 0; // don't take TxPER into CQI consideration if too few sample
867 TxPRR = 0;
868 } else {
869 TxPER = (TxFailCnt * 100) / TxCnt;
870 TxPRR = ((TxRetryCnt + TxFailCnt) * 100) / TxCnt;
874 // calculate RX PER
877 // Update FCS counters
878 RTMP_IO_READ32(pAd, CNT0, &Cnt0);
879 OldFcsCount= pAd->WlanCounters.FCSErrorCount.u.LowPart;
880 pAd->WlanCounters.FCSErrorCount.u.LowPart += ((Cnt0 & 0x0000ffff) >> 7);
881 if ( pAd->WlanCounters.FCSErrorCount.u.LowPart < OldFcsCount )
882 pAd->WlanCounters.FCSErrorCount.u.HighPart++;
884 // Add FCS error count to private counters
885 OldFcsCount = pAd->RalinkCounters.RealFcsErrCount.u.LowPart;
886 pAd->RalinkCounters.RealFcsErrCount.u.LowPart += Cnt0;
887 if ( pAd->RalinkCounters.RealFcsErrCount.u.LowPart < OldFcsCount )
888 pAd->RalinkCounters.RealFcsErrCount.u.HighPart++;
890 RxOkCnt = pAd->WlanCounters.ReceivedFragmentCount.u.LowPart -
891 pAd->Mlme.PrevWlanCounters.ReceivedFragmentCount.u.LowPart;
892 RxFailCnt = pAd->RalinkCounters.RealFcsErrCount.u.LowPart -
893 pAd->Mlme.PrevWlanCounters.FCSErrorCount.u.LowPart;
894 RxCnt = RxOkCnt + RxFailCnt;
896 if ( RxCnt < 5 )
897 RxPER = 0; // don't take RxPER into ChannelQuality consideration if too few sample
898 else
899 RxPER = (RxFailCnt * 100) / RxCnt;
901 // decide ChannelQuality based on: 1)last BEACON received time, 2)last RSSI,
902 // 3)TxPER, and 4)RxPER
903 // This value also decides when all roaming fails (or no roaming candidates at
904 // all), should this STA stay with original AP, or a LinkDown signal
905 // is indicated to NDIS
907 if ( INFRA_ON(pAd) &&
908 (pAd->PortCfg.LastBeaconRxTime + BEACON_LOST_TIME < Now32) ) { // BEACON starving?
909 // Ignore lost beacon when NIC in reset state
910 // Ignore lost beacon if traffic still goes well
911 if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) && (TxOkCnt < 2)) {
912 DBGPRINT(RT_DEBUG_TRACE, "BEACON lost for more than %d sec with TxOkCnt=%d, let CQI = 0\n", BEACON_LOST_TIME/HZ, TxOkCnt);
913 pAd->Mlme.ChannelQuality = 0;
914 // Lost AP, send disconnect & link down event
915 LinkDown(pAd);
917 } else {
918 // ChannelQuality = W1*RSSI + W2*TxPRR + W3*RxPER (RSSI 0..100), (TxPER 100..0), (RxPER 100..0)
919 pAd->Mlme.ChannelQuality = (RSSI_WEIGHTING * pAd->PortCfg.LastRssi +
920 TX_WEIGHTING * (100 - TxPRR) +
921 RX_WEIGHTING* (100 - RxPER)) / 100;
922 if (pAd->Mlme.ChannelQuality >= 100)
923 pAd->Mlme.ChannelQuality = 100;
926 // latch current WLAN counters for next check-for-roaming usage
927 NdisMoveMemory(&pAd->Mlme.PrevWlanCounters, &pAd->WlanCounters, sizeof(COUNTER_802_11));
928 // make sure copy the real FCS counts into previous mlme counter structure.
929 pAd->Mlme.PrevWlanCounters.FCSErrorCount = pAd->RalinkCounters.RealFcsErrCount;
931 DBGPRINT(RT_DEBUG_INFO, "MMCHK - CQI= %d, (Tx Fail=%d/Retry=%d/Total=%d, Rx Fail=%d/Total=%d, RSSI=%d dbm)\n",
932 pAd->Mlme.ChannelQuality, TxFailCnt, TxRetryCnt, TxCnt, RxFailCnt, RxCnt, pAd->PortCfg.LastRssi - RSSI_TO_DBM_OFFSET);
936 ==========================================================================
937 Description:
938 This routine calculates the acumulated TxPER of eaxh TxRate. And
939 according to the calculation result, change PortCfg.TxRate which
940 is the stable TX Rate we expect the Radio situation could sustained.
942 PortCfg.TxRate will change dynamically within {RATE_1/RATE_6, MaxTxRate}
943 Output:
944 PortCfg.TxRate -
945 NOTE:
946 call this routine every second
947 ==========================================================================
949 VOID MlmeCheckDynamicTxRateSwitching(
950 IN PRTMP_ADAPTER pAd)
952 UCHAR UpRate, DownRate, CurrRate;
953 USHORT TxTotalCnt = pAd->DrsCounters.OneSecTxOkCount + pAd->DrsCounters.OneSecTxRetryOkCount + pAd->DrsCounters.OneSecTxFailCount;
954 USHORT TxErrorRatio;
955 BOOLEAN fUpgradeQuality = FALSE;
956 USHORT *pRateUpPER, *pRateDownPER;
958 pAd->DrsCounters.CurrTxRateStableTime ++;
959 CurrRate = pAd->PortCfg.TxRate;
962 if (pAd->PortCfg.EnableAutoRateSwitching == FALSE)
963 break;
965 // if no traffic in the past 1-sec period, don't change TX rate,
966 // but clear all bad history. because the bad history may affect the next
967 // Chariot throughput test
968 if (TxTotalCnt == 0)
970 pAd->DrsCounters.TxRateUpPenalty = 0;
971 NdisZeroMemory(pAd->DrsCounters.TxQuality, MAX_LEN_OF_SUPPORTED_RATES);
972 NdisZeroMemory(pAd->DrsCounters.PER, MAX_LEN_OF_SUPPORTED_RATES);
973 break;
976 // decide the next upgrade rate and downgrade rate, if any
977 if (pAd->PortCfg.PhyMode == PHY_11BG_MIXED)
979 UpRate = Phy11BGNextRateUpward[CurrRate];
980 DownRate = Phy11BGNextRateDownward[CurrRate];
982 else if (pAd->PortCfg.PhyMode == PHY_11B)
984 UpRate = Phy11BNextRateUpward[CurrRate];
985 DownRate = Phy11BNextRateDownward[CurrRate];
987 else if (pAd->PortCfg.PhyMode == PHY_11A)
989 UpRate = Phy11ANextRateUpward[CurrRate];
990 DownRate = Phy11ANextRateDownward[CurrRate];
992 else // PHY_11ABG_MIXED
994 if (pAd->PortCfg.Channel > 14)
996 UpRate = Phy11ANextRateUpward[CurrRate];
997 DownRate = Phy11ANextRateDownward[CurrRate];
999 else
1001 UpRate = Phy11BGNextRateUpward[CurrRate];
1002 DownRate = Phy11BGNextRateDownward[CurrRate];
1006 if (UpRate > pAd->PortCfg.MaxTxRate)
1007 UpRate = pAd->PortCfg.MaxTxRate;
1009 // decide TX quality based on Tx PER when enough samples are available
1010 if (TxTotalCnt > 15)
1012 TxErrorRatio = ((pAd->DrsCounters.OneSecTxRetryOkCount + pAd->DrsCounters.OneSecTxFailCount) *100) / TxTotalCnt;
1014 // 2560D and after has implemented ASIC-based OFDM rate switching,
1015 // but not 2560C & before. thus software use different PER for rate switching
1016 if (pAd->PortCfg.Rt2560Version >= RT2560_VER_D)
1018 pRateUpPER = &NewRateUpPER[0];
1019 pRateDownPER = &NewRateDownPER[0];
1021 else
1023 pRateUpPER = &OldRateUpPER[0];
1024 pRateDownPER = &OldRateDownPER[0];
1027 // downgrade TX quality if PER >= Rate-Down threshold
1028 if (TxErrorRatio >= pRateDownPER[CurrRate])
1030 pAd->DrsCounters.TxQuality[CurrRate] = DRS_TX_QUALITY_WORST_BOUND;
1032 // upgrade TX quality if PER <= Rate-Up threshold
1033 else if (TxErrorRatio <= pRateUpPER[CurrRate])
1035 fUpgradeQuality = TRUE;
1036 if (pAd->DrsCounters.TxQuality[CurrRate])
1037 pAd->DrsCounters.TxQuality[CurrRate] --; // quality very good in CurrRate
1039 if (pAd->DrsCounters.TxRateUpPenalty)
1040 pAd->DrsCounters.TxRateUpPenalty --;
1041 else if (pAd->DrsCounters.TxQuality[UpRate])
1042 pAd->DrsCounters.TxQuality[UpRate] --; // may improve next UP rate's quality
1047 // if not enough TX samples, decide by heuristic rules
1048 else
1050 TxErrorRatio = 0;
1052 // Downgrade TX quality upon any TX failure in the past second
1053 if (pAd->DrsCounters.OneSecTxFailCount)
1055 if ((pAd->DrsCounters.OneSecTxFailCount <= 1) &&
1056 (pAd->DrsCounters.OneSecTxOkCount + pAd->DrsCounters.OneSecTxRetryOkCount))
1058 pAd->DrsCounters.TxQuality[CurrRate] += 2; // degrade quality
1059 if (pAd->DrsCounters.TxQuality[CurrRate] > DRS_TX_QUALITY_WORST_BOUND)
1060 pAd->DrsCounters.TxQuality[CurrRate] = DRS_TX_QUALITY_WORST_BOUND;
1062 else // more than 2 failure, or no TX ok cases
1064 pAd->DrsCounters.TxQuality[CurrRate] = DRS_TX_QUALITY_WORST_BOUND;
1067 // upgrade TX quality if -
1068 // 1. no TX failure but do have TX ok case, and
1069 // 2. there's more one-time-ok cases than retry-ok cases in the past second
1070 else if ((pAd->DrsCounters.OneSecTxOkCount > pAd->DrsCounters.OneSecTxRetryOkCount))
1072 fUpgradeQuality = TRUE;
1073 if (pAd->DrsCounters.TxQuality[CurrRate])
1074 pAd->DrsCounters.TxQuality[CurrRate] --; // quality very good in CurrRate
1076 if (pAd->DrsCounters.TxRateUpPenalty)
1077 pAd->DrsCounters.TxRateUpPenalty --;
1078 else if (pAd->DrsCounters.TxQuality[UpRate])
1079 pAd->DrsCounters.TxQuality[UpRate] --; // may improve next UP rate's quality
1083 pAd->DrsCounters.PER[CurrRate] = (UCHAR)TxErrorRatio;
1085 if (pAd->DrsCounters.fNoisyEnvironment)
1087 DBGPRINT(RT_DEBUG_TRACE,"DRS(noisy):");
1089 else
1091 DBGPRINT(RT_DEBUG_TRACE,"DRS:");
1093 // Scott
1094 /*printk("Qty[%d]=%d PER=%d%% %d-sec, Qty[%d]=%d, Pty=%d\n",
1095 RateIdToMbps[CurrRate], pAd->DrsCounters.TxQuality[CurrRate],
1096 TxErrorRatio,
1097 pAd->DrsCounters.CurrTxRateStableTime,
1098 RateIdToMbps[UpRate], pAd->DrsCounters.TxQuality[UpRate],
1099 pAd->DrsCounters.TxRateUpPenalty);*/
1101 // 2004-3-13 special case: Claim noisy environment
1102 // decide if there was a false "rate down" in the past 2 sec due to noisy
1103 // environment. if so, we would rather switch back to the higher TX rate.
1104 // criteria -
1105 // 1. there's a higher rate available, AND
1106 // 2. there was a rate-down happened, AND
1107 // 3. current rate has 75% > PER > 20%, AND
1108 // 4. comparing to UpRate, current rate didn't improve PER more than 5 %
1109 if ((UpRate != CurrRate) &&
1110 (pAd->DrsCounters.LastSecTxRateChangeAction == 2) &&
1111 (TxTotalCnt > 15) && // this line is to prevent the case that not enough TX sample causing PER=0%
1112 (pAd->DrsCounters.PER[CurrRate] < 75) &&
1113 ((pAd->DrsCounters.PER[CurrRate] > 20) || (pAd->DrsCounters.fNoisyEnvironment)) &&
1114 ((pAd->DrsCounters.PER[CurrRate]+5) > pAd->DrsCounters.PER[UpRate]))
1116 // we believe this is a noisy environment. better stay at UpRate
1117 DBGPRINT(RT_DEBUG_TRACE,"DRS: #### enter Noisy environment ####\n");
1118 pAd->DrsCounters.fNoisyEnvironment = TRUE;
1120 // 2004-3-14 when claiming noisy environment, we're not only switch back
1121 // to UpRate, but can be more aggressive to use one more rate up
1122 UpRate++;
1123 // if (UpRate>RATE_54) UpRate=RATE_54;
1124 if ((UpRate==RATE_6) || (UpRate==RATE_9)) UpRate=RATE_12;
1125 if (UpRate > pAd->PortCfg.MaxTxRate)
1126 UpRate = pAd->PortCfg.MaxTxRate;
1127 pAd->PortCfg.TxRate = UpRate;
1128 break;
1131 // 2004-3-12 special case: Leave noisy environment
1132 // The interference has gone suddenly. reset TX rate to
1133 // the theoritical value according to RSSI. Criteria -
1134 // 1. it's currently in noisy environment
1135 // 2. PER drops to be below 12%
1136 if ((pAd->DrsCounters.fNoisyEnvironment == TRUE) &&
1137 (TxTotalCnt > 15) && (pAd->DrsCounters.PER[CurrRate] <= 12))
1139 UCHAR JumpUpRate;
1141 pAd->DrsCounters.fNoisyEnvironment = FALSE;
1142 for (JumpUpRate = RATE_54; JumpUpRate > RATE_1; JumpUpRate--)
1144 if (pAd->PortCfg.AvgRssi > (RssiSafeLevelForTxRate[JumpUpRate] + RSSI_TO_DBM_OFFSET))
1145 break;
1148 if (JumpUpRate > pAd->PortCfg.MaxTxRate)
1149 JumpUpRate = pAd->PortCfg.MaxTxRate;
1151 DBGPRINT(RT_DEBUG_TRACE,"DRS: #### leave Noisy environment ####, RSSI=%d, JumpUpRate=%d\n",
1152 pAd->PortCfg.AvgRssi - RSSI_TO_DBM_OFFSET, RateIdToMbps[JumpUpRate]);
1154 if (JumpUpRate > CurrRate)
1156 pAd->PortCfg.TxRate = JumpUpRate;
1157 break;
1161 // we're going to upgrade CurrRate to UpRate at next few seconds,
1162 // but before that, we'd better try a NULL frame @ UpRate and
1163 // see if UpRate is stable or not. If this NULL frame fails, it will
1164 // downgrade TxQuality[CurrRate], so that STA won't switch to
1165 // to UpRate in the next second
1166 // 2004-04-07 requested by David Tung - sent test frames only in OFDM rates
1167 if (fUpgradeQuality &&
1168 INFRA_ON(pAd) &&
1169 (UpRate != CurrRate) &&
1170 (UpRate > RATE_11) &&
1171 (pAd->DrsCounters.TxQuality[CurrRate] <= 1) &&
1172 (pAd->DrsCounters.TxQuality[UpRate] <= 1))
1174 DBGPRINT(RT_DEBUG_TRACE,"DRS: 2 NULL frames at UpRate = %d Mbps\n",RateIdToMbps[UpRate]);
1175 EnqueueNullFrame(pAd, UpRate);
1176 EnqueueNullFrame(pAd, UpRate);
1179 // perform DRS - consider TxRate Down first, then rate up.
1180 // 1. rate down, if current TX rate's quality is not good
1181 // 2. rate up, if UPRate's quality is very good
1182 if ((pAd->DrsCounters.TxQuality[CurrRate] >= DRS_TX_QUALITY_WORST_BOUND) &&
1183 (CurrRate != DownRate))
1185 #ifdef WIFI_TEST
1186 if (DownRate <= RATE_2) break; // never goes lower than 5.5 Mbps TX rate
1187 #endif
1188 pAd->PortCfg.TxRate = DownRate;
1190 else if ((pAd->DrsCounters.TxQuality[CurrRate] <= 0) &&
1191 (pAd->DrsCounters.TxQuality[UpRate] <=0) &&
1192 (CurrRate != UpRate))
1194 pAd->PortCfg.TxRate = UpRate;
1197 }while (FALSE);
1200 // if rate-up happen, clear all bad history of all TX rates
1201 if (pAd->PortCfg.TxRate > CurrRate)
1203 DBGPRINT(RT_DEBUG_TRACE,"DRS: ++TX rate from %d to %d Mbps\n", RateIdToMbps[CurrRate],RateIdToMbps[pAd->PortCfg.TxRate]);
1204 pAd->DrsCounters.CurrTxRateStableTime = 0;
1205 pAd->DrsCounters.TxRateUpPenalty = 0;
1206 pAd->DrsCounters.LastSecTxRateChangeAction = 1; // rate UP
1207 NdisZeroMemory(pAd->DrsCounters.TxQuality, MAX_LEN_OF_SUPPORTED_RATES);
1208 NdisZeroMemory(pAd->DrsCounters.PER, MAX_LEN_OF_SUPPORTED_RATES);
1210 // if rate-down happen, only clear DownRate's bad history
1211 else if (pAd->PortCfg.TxRate < CurrRate)
1213 DBGPRINT(RT_DEBUG_TRACE,"DRS: --TX rate from %d to %d Mbps\n", RateIdToMbps[CurrRate],RateIdToMbps[pAd->PortCfg.TxRate]);
1214 // shorter stable time require more penalty in next rate UP criteria
1215 if (pAd->DrsCounters.CurrTxRateStableTime < 4) // less then 4 sec
1216 pAd->DrsCounters.TxRateUpPenalty = DRS_PENALTY; // add 8 sec penalty
1217 else if (pAd->DrsCounters.CurrTxRateStableTime < 8) // less then 8 sec
1218 pAd->DrsCounters.TxRateUpPenalty = 2; // add 2 sec penalty
1219 else // >= 8 sec
1220 pAd->DrsCounters.TxRateUpPenalty = 0; // no penalty
1222 pAd->DrsCounters.CurrTxRateStableTime = 0;
1223 pAd->DrsCounters.LastSecTxRateChangeAction = 2; // rate DOWN
1224 pAd->DrsCounters.TxQuality[pAd->PortCfg.TxRate] = 0;
1225 pAd->DrsCounters.PER[pAd->PortCfg.TxRate] = 0;
1227 else
1228 pAd->DrsCounters.LastSecTxRateChangeAction = 0; // rate no change
1230 // reset all OneSecxxx counters
1231 pAd->DrsCounters.OneSecTxFailCount = 0;
1232 pAd->DrsCounters.OneSecTxOkCount = 0;
1233 pAd->DrsCounters.OneSecTxRetryOkCount = 0;
1237 ==========================================================================
1238 Description:
1239 This routine is executed periodically inside MlmePeriodicExec() after
1240 association with an AP.
1241 It checks if PortCfg.Psm is consistent with user policy (recorded in
1242 PortCfg.WindowsPowerMode). If not, enforce user policy. However,
1243 there're some conditions to consider:
1244 1. we don't support power-saving in ADHOC mode, so Psm=PWR_ACTIVE all
1245 the time when Mibss==TRUE
1246 2. When Massoc==TRUE (INFRA mode), Psm should not be switch to PWR_SAVE
1247 if outgoing traffic available in TxRing or PrioRing.
1248 Output:
1249 1. change pAd->PortCfg.Psm to PWR_SAVE or leave it untouched
1250 ==========================================================================
1252 VOID MlmeCheckForPsmChange(
1253 IN PRTMP_ADAPTER pAd,
1254 IN ULONG Now32)
1256 ULONG PowerMode;
1257 // condition -
1258 // 1. Psm maybe ON only happen in INFRASTRUCTURE mode
1259 // 2. user wants either MAX_PSP or FAST_PSP
1260 // 3. but current psm is not in PWR_SAVE
1261 // 4. CNTL state machine is not doing SCANning
1262 // 5. no TX SUCCESS event for the past period
1263 PowerMode = pAd->PortCfg.WindowsPowerMode;
1265 if (INFRA_ON(pAd) &&
1266 (PowerMode != Ndis802_11PowerModeCAM) &&
1267 (pAd->PortCfg.Psm == PWR_ACTIVE) &&
1268 (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) &&
1269 (pAd->WlanCounters.TransmittedFragmentCount.u.LowPart == pAd->Mlme.PrevTxCnt))
1271 MlmeSetPsmBit(pAd, PWR_SAVE);
1272 EnqueueNullFrame(pAd, pAd->PortCfg.TxRate);
1275 // latch current count for next-time comparison
1276 pAd->Mlme.PrevTxCnt = pAd->WlanCounters.TransmittedFragmentCount.u.LowPart;
1280 VOID MlmeSetPsmBit(
1281 IN PRTMP_ADAPTER pAd,
1282 IN USHORT psm)
1284 TXCSR7_STRUC txcsr7;
1286 txcsr7.word = 0;
1287 pAd->PortCfg.Psm = psm;
1289 DBGPRINT(RT_DEBUG_TRACE, "MMCHK - change PSM bit to %d <<<\n", psm);
1290 if (psm == PWR_SAVE)
1292 txcsr7.field.ARPowerManage = 1;
1293 RTMP_IO_WRITE32(pAd, TXCSR7, txcsr7.word);
1295 else
1297 txcsr7.field.ARPowerManage = 0;
1298 RTMP_IO_WRITE32(pAd, TXCSR7, txcsr7.word);
1302 VOID MlmeSetTxPreamble(
1303 IN PRTMP_ADAPTER pAd,
1304 IN USHORT TxPreamble)
1306 ULONG Plcp1MCsr = 0x00700400; // 0x13c, ACK/CTS PLCP at 1 Mbps
1307 ULONG Plcp2MCsr = 0x00380401; // 0x140, ACK/CTS PLCP at 2 Mbps
1308 ULONG Plcp5MCsr = 0x00150402; // 0x144, ACK/CTS PLCP at 5.5 Mbps
1309 ULONG Plcp11MCsr = 0x000b8403; // 0x148, ACK/CTS PLCP at 11 Mbps
1311 if (TxPreamble == Rt802_11PreambleShort)
1313 DBGPRINT(RT_DEBUG_TRACE, "MlmeSetTxPreamble (= SHORT PREAMBLE)\n");
1314 // Plcp1MCsr |= 0x00000008; // 1Mbps should always use long preamble
1315 Plcp2MCsr |= 0x00000008;
1316 Plcp5MCsr |= 0x00000008;
1317 Plcp11MCsr |= 0x00000008;
1318 pAd->PortCfg.TxPreambleInUsed = Rt802_11PreambleShort;
1320 else
1322 DBGPRINT(RT_DEBUG_TRACE, "MlmeSetTxPreamble (= LONG PREAMBLE)\n");
1323 pAd->PortCfg.TxPreambleInUsed = Rt802_11PreambleLong;
1326 RTMP_IO_WRITE32(pAd, PLCP1MCSR, Plcp1MCsr);
1327 RTMP_IO_WRITE32(pAd, PLCP2MCSR, Plcp2MCsr);
1328 RTMP_IO_WRITE32(pAd, PLCP5MCSR, Plcp5MCsr);
1329 RTMP_IO_WRITE32(pAd, PLCP11MCSR, Plcp11MCsr);
1332 VOID MlmeUpdateTxRates(
1333 IN PRTMP_ADAPTER pAd,
1334 IN BOOLEAN bLinkUp)
1336 int i, num;
1337 UCHAR Rate, MaxDesire = RATE_1, MaxSupport = RATE_1;
1338 ULONG BasicRateBitmap = 0;
1339 UCHAR CurrBasicRate = RATE_1;
1341 // find max desired rate
1342 num = 0;
1343 for (i=0; i<MAX_LEN_OF_SUPPORTED_RATES; i++)
1345 switch (pAd->PortCfg.DesiredRates[i] & 0x7f)
1347 case 2: Rate = RATE_1; num++; break;
1348 case 4: Rate = RATE_2; num++; break;
1349 case 11: Rate = RATE_5_5; num++; break;
1350 case 22: Rate = RATE_11; num++; break;
1351 case 12: Rate = RATE_6; num++; break;
1352 case 18: Rate = RATE_9; num++; break;
1353 case 24: Rate = RATE_12; num++; break;
1354 case 36: Rate = RATE_18; num++; break;
1355 case 48: Rate = RATE_24; num++; break;
1356 case 72: Rate = RATE_36; num++; break;
1357 case 96: Rate = RATE_48; num++; break;
1358 case 108: Rate = RATE_54; num++; break;
1359 default: Rate = RATE_1; break;
1361 if (MaxDesire < Rate) MaxDesire = Rate;
1364 // 2003-12-10 802.11g WIFI spec disallow OFDM rates in 802.11g ADHOC mode
1365 if ((pAd->PortCfg.BssType == BSS_INDEP) &&
1366 (pAd->PortCfg.PhyMode == PHY_11BG_MIXED) &&
1367 (pAd->PortCfg.AdhocMode == 0) &&
1368 (MaxDesire > RATE_11))
1369 MaxDesire = RATE_11;
1371 pAd->PortCfg.MaxDesiredRate = MaxDesire;
1373 // Auto rate switching is enabled only if more than one DESIRED RATES are
1374 // specified; otherwise disabled
1375 if (num <= 1)
1376 pAd->PortCfg.EnableAutoRateSwitching = FALSE;
1377 else
1378 pAd->PortCfg.EnableAutoRateSwitching = TRUE;
1380 // find max supported rate
1381 for (i=0; i<pAd->PortCfg.SupportedRatesLen; i++)
1383 switch (pAd->PortCfg.SupportedRates[i] & 0x7f)
1385 case 2: Rate = RATE_1;
1386 if (pAd->PortCfg.SupportedRates[i] & 0x80)
1387 BasicRateBitmap |= 0x0001;
1388 break;
1389 case 4: Rate = RATE_2;
1390 if (pAd->PortCfg.SupportedRates[i] & 0x80)
1391 BasicRateBitmap |= 0x0002;
1392 break;
1393 case 11:
1394 Rate = RATE_5_5;
1395 if (pAd->PortCfg.SupportedRates[i] & 0x80)
1396 BasicRateBitmap |= 0x0004;
1397 break;
1398 case 22:
1399 Rate = RATE_11;
1400 if (pAd->PortCfg.SupportedRates[i] & 0x80)
1401 BasicRateBitmap |= 0x0008;
1402 break;
1403 case 12:
1404 Rate = RATE_6;
1405 // if (pAd->PortCfg.SupportedRates[i] & 0x80)
1406 BasicRateBitmap |= 0x0010;
1407 break;
1408 case 18:
1409 Rate = RATE_9;
1410 if (pAd->PortCfg.SupportedRates[i] & 0x80)
1411 BasicRateBitmap |= 0x0020;
1412 break;
1413 case 24:
1414 Rate = RATE_12;
1415 // if (pAd->PortCfg.SupportedRates[i] & 0x80)
1416 BasicRateBitmap |= 0x0040;
1417 break;
1418 case 36:
1419 Rate = RATE_18;
1420 if (pAd->PortCfg.SupportedRates[i] & 0x80)
1421 BasicRateBitmap |= 0x0080;
1422 break;
1423 case 48:
1424 Rate = RATE_24;
1425 // if (pAd->PortCfg.SupportedRates[i] & 0x80)
1426 BasicRateBitmap |= 0x0100;
1427 break;
1428 case 72:
1429 Rate = RATE_36;
1430 if (pAd->PortCfg.SupportedRates[i] & 0x80)
1431 BasicRateBitmap |= 0x0200;
1432 break;
1433 case 96:
1434 Rate = RATE_48;
1435 if (pAd->PortCfg.SupportedRates[i] & 0x80)
1436 BasicRateBitmap |= 0x0400;
1437 break;
1438 case 108:
1439 Rate = RATE_54;
1440 if (pAd->PortCfg.SupportedRates[i] & 0x80)
1441 BasicRateBitmap |= 0x0800;
1442 break;
1443 default:
1444 Rate = RATE_1;
1445 break;
1447 if (MaxSupport < Rate) MaxSupport = Rate;
1449 RTMP_IO_WRITE32(pAd, ARCSR1, BasicRateBitmap);
1451 // calculate the exptected ACK rate for each TX rate. This info is used to caculate
1452 // the DURATION field of outgoing uniicast DATA/MGMT frame
1453 for (i=0; i<MAX_LEN_OF_SUPPORTED_RATES; i++)
1455 if (BasicRateBitmap & (0x01 << i))
1456 CurrBasicRate = (UCHAR)i;
1457 pAd->PortCfg.ExpectedACKRate[i] = CurrBasicRate;
1458 DBGPRINT(RT_DEBUG_INFO,"Exptected ACK rate[%d] = %d Mbps\n", RateIdToMbps[i], RateIdToMbps[CurrBasicRate]);
1461 // max tx rate = min {max desire rate, max supported rate}
1462 if (MaxSupport < MaxDesire)
1463 pAd->PortCfg.MaxTxRate = MaxSupport;
1464 else
1465 pAd->PortCfg.MaxTxRate = MaxDesire;
1467 // 2003-07-31 john - 2500 doesn't have good sensitivity at high OFDM rates. to increase the success
1468 // ratio of initial DHCP packet exchange, TX rate starts from a lower rate depending
1469 // on average RSSI
1470 // 1. RSSI >= -70db, start at 54 Mbps (short distance)
1471 // 2. -70 > RSSI >= -75, start at 24 Mbps (mid distance)
1472 // 3. -75 > RSSI, start at 11 Mbps (long distance)
1473 if (pAd->PortCfg.EnableAutoRateSwitching)
1475 if (pAd->PortCfg.Channel > 14)
1476 pAd->PortCfg.TxRate = RATE_6; // 802.11a
1477 else
1479 short dbm = pAd->PortCfg.AvgRssi - RSSI_TO_DBM_OFFSET;
1480 if (bLinkUp == TRUE)
1481 pAd->PortCfg.TxRate = RATE_24;
1482 else
1483 pAd->PortCfg.TxRate = pAd->PortCfg.MaxTxRate;
1484 if (dbm < -75)
1485 pAd->PortCfg.TxRate = RATE_11;
1486 else if ((dbm < -70) && (pAd->PortCfg.TxRate > RATE_24))
1487 pAd->PortCfg.TxRate = RATE_24;
1488 DBGPRINT(RT_DEBUG_TRACE, " MlmeUpdateTxRates (Rssi=%d, init TX rate = %d Mbps)\n", dbm, RateIdToMbps[pAd->PortCfg.TxRate]);
1491 else
1492 pAd->PortCfg.TxRate = pAd->PortCfg.MaxTxRate;
1494 switch (pAd->PortCfg.PhyMode) {
1495 case PHY_11BG_MIXED:
1496 case PHY_11B:
1497 pAd->PortCfg.MlmeRate = RATE_2;
1498 #ifdef WIFI_TEST
1499 pAd->PortCfg.RtsRate = RATE_11;
1500 #else
1501 pAd->PortCfg.RtsRate = RATE_2;
1502 #endif
1503 break;
1504 case PHY_11A:
1505 pAd->PortCfg.MlmeRate = RATE_6;
1506 pAd->PortCfg.RtsRate = RATE_6;
1507 break;
1508 case PHY_11ABG_MIXED:
1509 if (pAd->PortCfg.Channel <= 14)
1511 pAd->PortCfg.MlmeRate = RATE_2;
1512 pAd->PortCfg.RtsRate = RATE_2;
1514 else
1516 pAd->PortCfg.MlmeRate = RATE_6;
1517 pAd->PortCfg.RtsRate = RATE_6;
1519 break;
1520 default: // error
1521 pAd->PortCfg.MlmeRate = RATE_2;
1522 pAd->PortCfg.RtsRate = RATE_2;
1523 break;
1526 DBGPRINT(RT_DEBUG_TRACE, " MlmeUpdateTxRates (MaxDesire=%d, MaxSupport=%d, MaxTxRate=%d, Rate Switching =%d)\n",
1527 RateIdToMbps[MaxDesire], RateIdToMbps[MaxSupport], RateIdToMbps[pAd->PortCfg.MaxTxRate], pAd->PortCfg.EnableAutoRateSwitching);
1528 DBGPRINT(RT_DEBUG_TRACE, " MlmeUpdateTxRates (TxRate=%d, RtsRate=%d, BasicRateBitmap=0x%04x)\n",
1529 RateIdToMbps[pAd->PortCfg.TxRate], RateIdToMbps[pAd->PortCfg.RtsRate], BasicRateBitmap);
1532 VOID MlmeRadioOff(
1533 IN PRTMP_ADAPTER pAd)
1535 // Set Radio off flag
1536 RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1538 // Link down first if any association exists
1539 if (INFRA_ON(pAd) || ADHOC_ON(pAd))
1540 LinkDown(pAd);
1542 // Abort Tx
1543 RTMP_IO_WRITE32(pAd, TXCSR0, 0x08);
1544 // Disable Rx
1545 RTMP_IO_WRITE32(pAd, RXCSR0, 0x01);
1546 // Turn off radio
1547 RTMP_IO_WRITE32(pAd, PWRCSR0, 0x00000000);
1549 if (pAd->PortCfg.LedMode == LED_MODE_ASUS)
1551 ASIC_LED_ACT_OFF(pAd);
1554 // Clean up old bss table
1555 BssTableInit(&pAd->PortCfg.BssTab);
1558 VOID MlmeRadioOn(
1559 IN PRTMP_ADAPTER pAd)
1561 // Turn on radio
1562 RTMP_IO_WRITE32(pAd, PWRCSR0, 0x3f3b3100);
1564 // Abort Tx
1565 RTMP_IO_WRITE32(pAd, TXCSR0, 0x08);
1566 // Disable Rx
1567 RTMP_IO_WRITE32(pAd, RXCSR0, 0x01);
1569 RTMPRingCleanUp(pAd, TX_RING);
1570 RTMPRingCleanUp(pAd, PRIO_RING);
1571 RTMPRingCleanUp(pAd, RX_RING);
1573 NICResetFromError(pAd);
1574 // Clear Radio off flag
1575 RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1577 if (pAd->PortCfg.LedMode == LED_MODE_ASUS)
1579 RTMP_IO_WRITE32(pAd, LEDCSR, 0x0002461E);
1583 // ===========================================================================================
1584 // bss_table.c
1585 // ===========================================================================================
1588 /*! \brief initialize BSS table
1589 * \param p_tab pointer to the table
1590 * \return none
1591 * \pre
1592 * \post
1594 VOID BssTableInit(
1595 IN BSS_TABLE *Tab)
1597 int i;
1599 Tab->BssNr = 0;
1600 for (i = 0; i < MAX_LEN_OF_BSS_TABLE; i++)
1602 NdisZeroMemory(&Tab->BssEntry[i], sizeof(BSS_ENTRY));
1606 /*! \brief search the BSS table by SSID
1607 * \param p_tab pointer to the bss table
1608 * \param ssid SSID string
1609 * \return index of the table, BSS_NOT_FOUND if not in the table
1610 * \pre
1611 * \post
1612 * \note search by sequential search
1614 ULONG BssTableSearch(
1615 IN BSS_TABLE *Tab,
1616 IN PMACADDR Bssid)
1618 UCHAR i;
1620 for (i = 0; i < Tab->BssNr; i++)
1622 //printf("comparing %s and %s\n", p_tab->bss[i].ssid, ssid);
1623 if (MAC_ADDR_EQUAL(&(Tab->BssEntry[i].Bssid), Bssid))
1625 return i;
1628 return (ULONG)BSS_NOT_FOUND;
1631 VOID BssTableDeleteEntry(
1632 IN OUT BSS_TABLE *Tab,
1633 IN PMACADDR Bssid)
1635 UCHAR i, j;
1637 for (i = 0; i < Tab->BssNr; i++)
1639 //printf("comparing %s and %s\n", p_tab->bss[i].ssid, ssid);
1640 if (MAC_ADDR_EQUAL(&(Tab->BssEntry[i].Bssid), Bssid))
1642 for (j = i; j < Tab->BssNr - 1; j++)
1644 NdisMoveMemory(&(Tab->BssEntry[j]), &(Tab->BssEntry[j + 1]), sizeof(BSS_ENTRY));
1646 Tab->BssNr -= 1;
1647 return;
1652 UCHAR ZeroSsid[32] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1653 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1654 /*! \brief
1655 * \param
1656 * \return
1657 * \pre
1658 * \post
1660 VOID BssEntrySet(
1661 IN PRTMP_ADAPTER pAd,
1662 OUT BSS_ENTRY *pBss,
1663 IN MACADDR *pBssid,
1664 IN CHAR Ssid[],
1665 IN UCHAR SsidLen,
1666 IN UCHAR BssType,
1667 IN USHORT BeaconPeriod,
1668 IN BOOLEAN CfExist,
1669 IN CF_PARM *pCfParm,
1670 IN USHORT AtimWin,
1671 IN USHORT CapabilityInfo,
1672 IN UCHAR Rates[],
1673 IN UCHAR RatesLen,
1674 IN BOOLEAN ExtendedRateIeExist,
1675 IN UCHAR Channel,
1676 IN UCHAR Rssi,
1677 IN LARGE_INTEGER TimeStamp,
1678 IN PNDIS_802_11_VARIABLE_IEs pVIE)
1680 COPY_MAC_ADDR(&pBss->Bssid, pBssid);
1681 // Default Hidden SSID to be TRUE, it will be turned to FALSE after coping SSID
1682 pBss->Hidden = 1;
1683 if (SsidLen > 0)
1685 // For hidden SSID AP, it might send beacon with SSID len equal to 0
1686 // Or send beacon /probe response with SSID len matching real SSID length,
1687 // but SSID is all zero. such as "00-00-00-00" with length 4.
1688 // We have to prevent this case overwrite correct table
1689 if (NdisEqualMemory(Ssid, ZeroSsid, SsidLen) == 0)
1691 NdisMoveMemory(pBss->Ssid, Ssid, SsidLen);
1692 pBss->SsidLen = SsidLen;
1693 pBss->Hidden = 0;
1696 pBss->BssType = BssType;
1697 pBss->BeaconPeriod = BeaconPeriod;
1698 if (BssType == BSS_INFRA)
1700 if (CfExist)
1702 pBss->CfpCount = pCfParm->CfpCount;
1703 pBss->CfpPeriod = pCfParm->CfpPeriod;
1704 pBss->CfpMaxDuration = pCfParm->CfpMaxDuration;
1705 pBss->CfpDurRemaining = pCfParm->CfpDurRemaining;
1708 else
1710 pBss->AtimWin = AtimWin;
1713 pBss->CapabilityInfo = CapabilityInfo;
1714 // The privacy bit indicate security is ON, it maight be WEP, TKIP or AES
1715 // Combine with AuthMode, they will decide the connection methods.
1716 pBss->Privacy = CAP_IS_PRIVACY_ON(pBss->CapabilityInfo);
1717 NdisMoveMemory(pBss->Rates, Rates, RatesLen);
1718 pBss->RatesLen = RatesLen;
1719 pBss->ExtendedRateIeExist = ExtendedRateIeExist;
1720 pBss->Channel = Channel;
1721 pBss->Rssi = Rssi;
1723 // New for microsoft Fixed IEs
1724 NdisMoveMemory(pBss->FixIEs.Timestamp, &TimeStamp, 8);
1725 pBss->FixIEs.BeaconInterval = BeaconPeriod;
1726 pBss->FixIEs.Capabilities = CapabilityInfo;
1728 // New for microsoft Variable IEs
1729 if (pVIE->Length != 0)
1731 pBss->VarIELen = pVIE->Length + 2;
1732 NdisMoveMemory(pBss->VarIEs, pVIE, pBss->VarIELen);
1733 pBss->WepStatus = BssCipherParse(pBss->VarIEs);
1735 else
1737 pBss->VarIELen = 0;
1738 // No SSN ID, if security is on, this is WEP algorithm
1739 if (pBss->Privacy)
1740 pBss->WepStatus = Ndis802_11WEPEnabled;
1741 // No SSN ID, security is also off.
1742 else
1743 pBss->WepStatus = Ndis802_11WEPDisabled;
1747 /*!
1748 * \brief insert an entry into the bss table
1749 * \param p_tab The BSS table
1750 * \param Bssid BSSID
1751 * \param ssid SSID
1752 * \param ssid_len Length of SSID
1753 * \param bss_type
1754 * \param beacon_period
1755 * \param timestamp
1756 * \param p_cf
1757 * \param atim_win
1758 * \param cap
1759 * \param rates
1760 * \param rates_len
1761 * \param channel_idx
1762 * \return none
1763 * \pre
1764 * \post
1765 * \note If SSID is identical, the old entry will be replaced by the new one
1767 ULONG BssTableSetEntry(
1768 IN PRTMP_ADAPTER pAd,
1769 OUT BSS_TABLE *Tab,
1770 IN MACADDR *Bssid,
1771 IN CHAR Ssid[],
1772 IN UCHAR SsidLen,
1773 IN UCHAR BssType,
1774 IN USHORT BeaconPeriod,
1775 IN BOOLEAN CfExist,
1776 IN CF_PARM *CfParm,
1777 IN USHORT AtimWin,
1778 IN USHORT CapabilityInfo,
1779 IN UCHAR Rates[],
1780 IN UCHAR RatesLen,
1781 IN BOOLEAN ExtendedRateIeExist,
1782 IN UCHAR ChannelNo,
1783 IN UCHAR Rssi,
1784 IN LARGE_INTEGER TimeStamp,
1785 IN PNDIS_802_11_VARIABLE_IEs pVIE)
1787 ULONG Idx;
1789 Idx = BssTableSearch(Tab, Bssid);
1790 if (Idx == BSS_NOT_FOUND)
1792 if (Tab->BssNr >= MAX_LEN_OF_BSS_TABLE)
1793 return BSS_NOT_FOUND;
1794 Idx = Tab->BssNr;
1795 BssEntrySet(pAd, &Tab->BssEntry[Idx], Bssid, Ssid, SsidLen, BssType, BeaconPeriod,
1796 CfExist, CfParm, AtimWin, CapabilityInfo, Rates, RatesLen, ExtendedRateIeExist,
1797 ChannelNo, Rssi, TimeStamp, pVIE);
1798 Tab->BssNr++;
1800 else
1802 BssEntrySet(pAd, &Tab->BssEntry[Idx], Bssid, Ssid, SsidLen, BssType, BeaconPeriod,
1803 CfExist, CfParm, AtimWin, CapabilityInfo, Rates, RatesLen, ExtendedRateIeExist,
1804 ChannelNo, Rssi, TimeStamp, pVIE);
1807 return Idx;
1810 VOID BssTableSsidSort(
1811 IN PRTMP_ADAPTER pAd,
1812 OUT BSS_TABLE *OutTab,
1813 IN CHAR Ssid[],
1814 IN UCHAR SsidLen)
1816 INT i;
1817 BssTableInit(OutTab);
1819 for (i = 0; i < pAd->PortCfg.BssTab.BssNr; i++)
1821 BSS_ENTRY *pInBss = &pAd->PortCfg.BssTab.BssEntry[i];
1823 if ((pInBss->BssType == pAd->PortCfg.BssType) &&
1824 ((pInBss->SsidLen==SsidLen) && RTMPEqualMemory(pInBss->Ssid, Ssid, (ULONG) SsidLen)))
1826 BSS_ENTRY *pOutBss = &OutTab->BssEntry[OutTab->BssNr];
1828 // Bss Type matched, SSID matched.
1829 // We will check wepstatus for qualification Bss
1830 if (pAd->PortCfg.WepStatus != pInBss->WepStatus)
1831 continue;
1833 // Since the AP is using hidden SSID, and we are trying to connect to ANY
1834 // It definitely will fail. So, skip it.
1835 // CCX also require not even try to connect it!!
1836 if (SsidLen == 0)
1837 continue;
1839 // copy matching BSS from InTab to OutTab
1840 NdisMoveMemory(pOutBss, pInBss, sizeof(BSS_ENTRY));
1842 OutTab->BssNr++;
1844 else if ((pInBss->BssType == pAd->PortCfg.BssType) && (SsidLen == 0))
1846 BSS_ENTRY *pOutBss = &OutTab->BssEntry[OutTab->BssNr];
1848 // Bss Type matched, SSID matched.
1849 // We will check wepstatus for qualification Bss
1850 if (pAd->PortCfg.WepStatus != pInBss->WepStatus)
1851 continue;
1853 // copy matching BSS from InTab to OutTab
1854 NdisMoveMemory(pOutBss, pInBss, sizeof(BSS_ENTRY));
1856 OutTab->BssNr++;
1858 #if 0
1859 else if ((pInBss->BssType == pAd->PortCfg.BssType) && (pInBss->SsidLen == 0))
1861 // Add for hidden SSID. But we have to verify the security suite too.
1862 BSS_ENTRY *pOutBss = &OutTab->BssEntry[OutTab->BssNr];
1864 // Bss Type matched, SSID matched.
1865 // We will check wepstatus for qualification Bss
1866 if (pAd->PortCfg.WepStatus != pInBss->WepStatus)
1867 continue;
1869 // copy matching BSS from InTab to OutTab
1870 NdisMoveMemory(pOutBss, pInBss, sizeof(BSS_ENTRY));
1872 OutTab->BssNr++;
1874 #endif
1875 if (OutTab->BssNr >= MAX_LEN_OF_BSS_TABLE)
1876 break;
1880 BssTableSortByRssi(OutTab);
1883 VOID BssTableSortByRssi(
1884 IN OUT BSS_TABLE *OutTab)
1886 INT i, j;
1887 BSS_ENTRY TmpBss;
1889 for (i = 0; i < OutTab->BssNr - 1; i++)
1891 for (j = i+1; j < OutTab->BssNr; j++)
1893 if (OutTab->BssEntry[j].Rssi > OutTab->BssEntry[i].Rssi)
1895 NdisMoveMemory(&TmpBss, &OutTab->BssEntry[j], sizeof(BSS_ENTRY));
1896 NdisMoveMemory(&OutTab->BssEntry[j], &OutTab->BssEntry[i], sizeof(BSS_ENTRY));
1897 NdisMoveMemory(&OutTab->BssEntry[i], &TmpBss, sizeof(BSS_ENTRY));
1903 NDIS_802_11_WEP_STATUS BssCipherParse(
1904 IN PUCHAR pCipher)
1906 PBEACON_EID_STRUCT pEid;
1907 PUCHAR pTmp;
1909 pEid = (PBEACON_EID_STRUCT) pCipher;
1911 // Double check sanity information, although it should be done at peer beacon sanity check already.
1912 if (pEid->Eid != IE_WPA)
1913 return (Ndis802_11WEPDisabled);
1915 // Double check Var IE length, it must be no less than 0x16
1916 if (pEid->Len < 0x16)
1917 return (Ndis802_11WEPDisabled);
1919 // Skip OUI, version, and multicast suite
1920 // This part should be improved in the future when AP supported multiple cipher suite.
1921 // For now, it's OK since almost all APs have fixed cipher suite supported.
1922 pTmp = (PUCHAR) pEid->Octet;
1923 pTmp += 9;
1925 if (*pTmp == 4) // AES
1926 return (Ndis802_11Encryption3Enabled);
1927 else if (*pTmp == 2) // TKIP
1928 return (Ndis802_11Encryption2Enabled);
1930 return (Ndis802_11WEPDisabled);
1933 // ===========================================================================================
1934 // mac_table.c
1935 // ===========================================================================================
1937 /*! \brief generates a random mac address value for IBSS BSSID
1938 * \param Addr the bssid location
1939 * \return none
1940 * \pre
1941 * \post
1943 VOID MacAddrRandomBssid(
1944 IN PRTMP_ADAPTER pAd,
1945 OUT MACADDR *Addr)
1947 INT i;
1949 for (i = 0; i < MAC_ADDR_LEN; i++)
1951 Addr->Octet[i] = RandomByte(pAd);
1954 Addr->Octet[0] = (Addr->Octet[0] & 0xfe) | 0x02; // the first 2 bits must be 01xxxxxxxx
1957 /*! \brief init the management mac frame header
1958 * \param p_hdr mac header
1959 * \param subtype subtype of the frame
1960 * \param p_ds destination address, don't care if it is a broadcast address
1961 * \return none
1962 * \pre the station has the following information in the pAd->PortCfg
1963 * - bssid
1964 * - station address
1965 * \post
1966 * \note this function initializes the following field
1968 VOID MgtMacHeaderInit(
1969 IN PRTMP_ADAPTER pAd,
1970 IN OUT PMACHDR Hdr,
1971 IN UCHAR Subtype,
1972 IN UCHAR ToDs,
1973 IN PMACADDR Ds,
1974 IN PMACADDR Bssid)
1976 NdisZeroMemory(Hdr, sizeof(MACHDR));
1977 Hdr->Type = BTYPE_MGMT;
1978 Hdr->SubType = Subtype;
1979 Hdr->Tods = ToDs;
1980 COPY_MAC_ADDR(&Hdr->Addr1, Ds);
1981 COPY_MAC_ADDR(&Hdr->Addr2, &pAd->CurrentAddress);
1982 COPY_MAC_ADDR(&Hdr->Addr3, Bssid);
1985 // ===========================================================================================
1986 // mem_mgmt.c
1987 // ===========================================================================================
1989 /*!***************************************************************************
1990 * This routine build an outgoing frame, and fill all information specified
1991 * in argument list to the frame body. The actual frame size is the summation
1992 * of all arguments.
1993 * input params:
1994 * Buffer - pointer to a pre-allocated memory segment
1995 * args - a list of <int arg_size, arg> pairs.
1996 * NOTE NOTE NOTE!!!! the last argument must be NULL, otherwise this
1997 * function will FAIL!!!
1998 * return:
1999 * Size of the buffer
2000 * usage:
2001 * MakeOutgoingFrame(Buffer, output_length, 2, &fc, 2, &dur, 6, p_addr1, 6,p_addr2, END_OF_ARGS);
2002 ****************************************************************************/
2003 ULONG MakeOutgoingFrame(
2004 OUT CHAR *Buffer,
2005 OUT ULONG *FrameLen, ...)
2007 CHAR *p;
2008 int leng;
2009 ULONG TotLeng;
2010 va_list Args;
2012 // calculates the total length
2013 TotLeng = 0;
2014 va_start(Args, FrameLen);
2017 leng = va_arg(Args, int);
2018 if (leng == END_OF_ARGS)
2020 break;
2022 p = va_arg(Args, PVOID);
2023 NdisMoveMemory(&Buffer[TotLeng], p, leng);
2024 TotLeng = TotLeng + leng;
2025 } while(TRUE);
2027 va_end(Args); /* clean up */
2028 *FrameLen = TotLeng;
2029 return TotLeng;
2032 // ===========================================================================================
2033 // mlme_queue.c
2034 // ===========================================================================================
2036 /*! \brief Initialize The MLME Queue, used by MLME Functions
2037 * \param *Queue The MLME Queue
2038 * \return Always Return NDIS_STATE_SUCCESS in this implementation
2039 * \pre
2040 * \post
2041 * \note Because this is done only once (at the init stage), no need to be locked
2043 NDIS_STATUS MlmeQueueInit(
2044 IN MLME_QUEUE *Queue)
2046 INT i;
2048 NdisAllocateSpinLock(&Queue->Lock);
2050 Queue->Num = 0;
2051 Queue->Head = 0;
2052 Queue->Tail = 0;
2054 for (i = 0; i < MAX_LEN_OF_MLME_QUEUE; i++)
2056 Queue->Entry[i].Occupied = FALSE;
2057 Queue->Entry[i].MsgLen = 0;
2058 NdisZeroMemory(Queue->Entry[i].Msg, MAX_LEN_OF_MLME_BUFFER);
2059 Queue->Entry[i].Reserved = i; // Scott added @2005-01-13, for debug only
2062 return NDIS_STATUS_SUCCESS;
2066 /*! \brief Enqueue a message for other threads, if they want to send messages to MLME thread
2067 * \param *Queue The MLME Queue
2068 * \param Machine The State Machine Id
2069 * \param MsgType The Message Type
2070 * \param MsgLen The Message length
2071 * \param *Msg The message pointer
2072 * \return TRUE if enqueue is successful, FALSE if the queue is full
2073 * \pre
2074 * \post
2075 * \note The message has to be initialized
2077 BOOLEAN MlmeEnqueue(
2078 OUT MLME_QUEUE *Queue,
2079 IN ULONG Machine,
2080 IN ULONG MsgType,
2081 IN ULONG MsgLen,
2082 IN VOID *Msg)
2084 INT Tail;
2085 unsigned long IrqFlags;
2087 // First check the size, it MUST not exceed the mlme queue size
2088 if (MsgLen > MAX_LEN_OF_MLME_BUFFER)
2090 DBGPRINT(RT_DEBUG_ERROR, "MlmeEnqueueForRecv mlme frame too large, size = %d \n", MsgLen);
2091 return FALSE;
2094 if (MlmeQueueFull(Queue))
2096 DBGPRINT(RT_DEBUG_ERROR, "MlmeEnqueue full, msg dropped and may corrupt MLME\n");
2097 return FALSE;
2100 NdisAcquireSpinLock(&(Queue->Lock));
2101 Tail = Queue->Tail;
2102 Queue->Tail++;
2103 Queue->Num++;
2104 if (Queue->Tail == MAX_LEN_OF_MLME_QUEUE)
2106 Queue->Tail = 0;
2108 DBGPRINT(RT_DEBUG_INFO, "MlmeEnqueue, num=%d\n",Queue->Num);
2110 Queue->Entry[Tail].Occupied = TRUE;
2111 Queue->Entry[Tail].Machine = Machine;
2112 Queue->Entry[Tail].MsgType = MsgType;
2113 Queue->Entry[Tail].MsgLen = MsgLen;
2114 NdisMoveMemory(Queue->Entry[Tail].Msg, Msg, MsgLen);
2115 NdisReleaseSpinLock(&(Queue->Lock)); // Scott added @2005-01-13, move here to ensure everything is filled before dequeue
2116 return TRUE;
2119 /*! \brief This function is used when Recv gets a MLME message
2120 * \param *Queue The MLME Queue
2121 * \param TimeStampHigh The upper 32 bit of timestamp
2122 * \param TimeStampLow The lower 32 bit of timestamp
2123 * \param Rssi The receiving RSSI strength
2124 * \param MsgLen The length of the message
2125 * \param *Msg The message pointer
2126 * \return TRUE if everything ok, FALSE otherwise (like Queue Full)
2127 * \pre
2128 * \post
2130 BOOLEAN MlmeEnqueueForRecv(
2131 IN PRTMP_ADAPTER pAd,
2132 OUT MLME_QUEUE *Queue,
2133 IN ULONG TimeStampHigh,
2134 IN ULONG TimeStampLow,
2135 IN UCHAR Rssi,
2136 IN ULONG MsgLen,
2137 IN VOID *Msg)
2139 INT Tail, Machine;
2140 MACFRAME *Fr = (MACFRAME *)Msg;
2141 ULONG MsgType;
2142 unsigned long IrqFlags;
2144 // First check the size, it MUST not exceed the mlme queue size
2145 if (MsgLen > MAX_LEN_OF_MLME_BUFFER)
2147 DBGPRINT(RT_DEBUG_ERROR, "MlmeEnqueueForRecv mlme frame too large, size = %d \n", MsgLen);
2148 return FALSE;
2151 if (MlmeQueueFull(Queue))
2153 DBGPRINT(RT_DEBUG_ERROR, "MlmeEnqueueForRecv (queue full error) \n");
2154 return FALSE;
2157 if (!MsgTypeSubst(Fr, &Machine, &MsgType))
2159 DBGPRINT(RT_DEBUG_ERROR, "MlmeEnqueueForRecv (drop mgmt->subtype=%d)\n",Fr->Hdr.SubType);
2160 return FALSE;
2163 // OK, we got all the informations, it is time to put things into queue
2164 NdisAcquireSpinLock(&(Queue->Lock));
2165 Tail = Queue->Tail;
2166 Queue->Tail++;
2167 Queue->Num++;
2168 if (Queue->Tail == MAX_LEN_OF_MLME_QUEUE)
2170 Queue->Tail = 0;
2172 //DBGPRINT(RT_DEBUG_INFO, "MlmeEnqueueForRecv, num=%d\n",Queue->Num);
2174 Queue->Entry[Tail].Occupied = TRUE;
2175 Queue->Entry[Tail].Machine = Machine;
2176 Queue->Entry[Tail].MsgType = MsgType;
2177 Queue->Entry[Tail].MsgLen = MsgLen;
2178 Queue->Entry[Tail].TimeStamp.u.LowPart = TimeStampLow;
2179 Queue->Entry[Tail].TimeStamp.u.HighPart = TimeStampHigh;
2180 Queue->Entry[Tail].Rssi = Rssi;
2182 NdisMoveMemory(Queue->Entry[Tail].Msg, Msg, MsgLen);
2183 NdisReleaseSpinLock(&(Queue->Lock)); // Scott added @2005-01-13, move here to ensure everything is filled before dequeue
2185 MlmeHandler(pAd);
2187 return TRUE;
2190 /*! \brief Dequeue a message from the MLME Queue
2191 * \param *Queue The MLME Queue
2192 * \param *Elem The message dequeued from MLME Queue
2193 * \return TRUE if the Elem contains something, FALSE otherwise
2194 * \pre
2195 * \post
2197 BOOLEAN MlmeDequeue(
2198 IN MLME_QUEUE *Queue,
2199 OUT MLME_QUEUE_ELEM **Elem)
2201 unsigned long IrqFlags;
2203 NdisAcquireSpinLock(&(Queue->Lock));
2204 *Elem = &(Queue->Entry[Queue->Head]);
2205 Queue->Num--;
2206 Queue->Head++;
2207 if (Queue->Head == MAX_LEN_OF_MLME_QUEUE)
2209 Queue->Head = 0;
2211 NdisReleaseSpinLock(&(Queue->Lock));
2212 DBGPRINT(RT_DEBUG_INFO, "MlmeDequeue, num=%d\n",Queue->Num);
2214 return TRUE;
2217 VOID MlmeRestartStateMachine(
2218 IN PRTMP_ADAPTER pAd)
2220 MLME_QUEUE_ELEM *Elem = NULL;
2221 unsigned long IrqFlags;
2223 NdisAcquireSpinLock(&pAd->Mlme.TaskLock);
2224 if(pAd->Mlme.Running)
2226 NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
2227 return;
2229 else
2231 pAd->Mlme.Running = TRUE;
2233 NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
2235 // Remove all Mlme queues elements
2236 while (!MlmeQueueEmpty(&pAd->Mlme.Queue))
2238 //From message type, determine which state machine I should drive
2239 if (MlmeDequeue(&pAd->Mlme.Queue, &Elem))
2241 // free MLME element
2242 Elem->Occupied = FALSE;
2243 Elem->MsgLen = 0;
2245 else {
2246 DBGPRINT(RT_DEBUG_ERROR, "ERROR: empty Elem in MlmeQueue\n");
2250 // Cancel all timer events
2251 // Be careful to cancel new added timer
2252 RTMPCancelTimer(&pAd->Mlme.AssocAux.AssocTimer);
2253 RTMPCancelTimer(&pAd->Mlme.AssocAux.ReassocTimer);
2254 RTMPCancelTimer(&pAd->Mlme.AssocAux.DisassocTimer);
2255 RTMPCancelTimer(&pAd->Mlme.AuthAux.AuthTimer);
2256 RTMPCancelTimer(&pAd->Mlme.AuthRspAux.AuthRspTimer);
2257 RTMPCancelTimer(&pAd->Mlme.SyncAux.BeaconTimer);
2258 RTMPCancelTimer(&pAd->Mlme.SyncAux.ScanTimer);
2259 RTMPCancelTimer(&pAd->PortCfg.RfTuningTimer);
2261 // Change back to original channel in case of doing scan
2262 AsicSwitchChannel(pAd, pAd->PortCfg.Channel);
2263 AsicLockChannel(pAd, pAd->PortCfg.Channel);
2265 // Resume MSDU which is turned off durning scan
2266 RTMPResumeMsduTransmission(pAd);
2268 // Set all state machines back IDLE
2269 pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
2270 pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
2271 pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE;
2272 pAd->Mlme.AuthRspMachine.CurrState = AUTH_RSP_IDLE;
2273 pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE;
2275 // Remove running state
2276 NdisAcquireSpinLock(&pAd->Mlme.TaskLock);
2277 pAd->Mlme.Running = FALSE;
2278 NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
2281 /*! \brief test if the MLME Queue is empty
2282 * \param *Queue The MLME Queue
2283 * \return TRUE if the Queue is empty, FALSE otherwise
2284 * \pre
2285 * \post
2287 BOOLEAN MlmeQueueEmpty(
2288 IN MLME_QUEUE *Queue)
2290 BOOLEAN Ans;
2291 unsigned long IrqFlags;
2293 NdisAcquireSpinLock(&(Queue->Lock));
2294 Ans = (Queue->Num == 0);
2295 NdisReleaseSpinLock(&(Queue->Lock));
2297 return Ans;
2300 /*! \brief test if the MLME Queue is full
2301 * \param *Queue The MLME Queue
2302 * \return TRUE if the Queue is empty, FALSE otherwise
2303 * \pre
2304 * \post
2306 BOOLEAN MlmeQueueFull(
2307 IN MLME_QUEUE *Queue)
2309 BOOLEAN Ans;
2310 unsigned long IrqFlags;
2312 NdisAcquireSpinLock(&(Queue->Lock));
2313 Ans = (Queue->Num == MAX_LEN_OF_MLME_QUEUE);
2314 NdisReleaseSpinLock(&(Queue->Lock));
2316 return Ans;
2319 /*! \brief The destructor of MLME Queue
2320 * \param
2321 * \return
2322 * \pre
2323 * \post
2324 * \note Clear Mlme Queue, Set Queue->Num to Zero.
2326 VOID MlmeQueueDestroy(
2327 IN MLME_QUEUE *Queue)
2329 unsigned long IrqFlags;
2331 NdisAcquireSpinLock(&(Queue->Lock));
2332 Queue->Num = 0;
2333 Queue->Head = 0;
2334 Queue->Tail = 0;
2335 NdisReleaseSpinLock(&(Queue->Lock));
2338 /*! \brief To substitute the message type if the message is coming from external
2339 * \param *Fr The frame received
2340 * \param *Machine The state machine
2341 * \param *MsgType the message type for the state machine
2342 * \return TRUE if the substitution is successful, FALSE otherwise
2343 * \pre
2344 * \post
2346 BOOLEAN MsgTypeSubst(
2347 IN MACFRAME *Fr,
2348 OUT INT *Machine,
2349 OUT INT *MsgType)
2351 USHORT Seq;
2352 UCHAR EAPType;
2354 // The only data type will pass to this function is EAPOL frame
2355 if (Fr->Hdr.Type == BTYPE_DATA)
2357 *Machine = WPA_PSK_STATE_MACHINE;
2358 EAPType = *((UCHAR*)Fr + LENGTH_802_11 + LENGTH_802_1_H + 1);
2359 return(WpaMsgTypeSubst(EAPType, MsgType));
2362 switch (Fr->Hdr.SubType)
2364 case SUBTYPE_ASSOC_REQ:
2365 *Machine = ASSOC_STATE_MACHINE;
2366 *MsgType = MT2_PEER_ASSOC_REQ;
2367 break;
2368 case SUBTYPE_ASSOC_RSP:
2369 *Machine = ASSOC_STATE_MACHINE;
2370 *MsgType = MT2_PEER_ASSOC_RSP;
2371 break;
2372 case SUBTYPE_REASSOC_REQ:
2373 *Machine = ASSOC_STATE_MACHINE;
2374 *MsgType = MT2_PEER_REASSOC_REQ;
2375 break;
2376 case SUBTYPE_REASSOC_RSP:
2377 *Machine = ASSOC_STATE_MACHINE;
2378 *MsgType = MT2_PEER_REASSOC_RSP;
2379 break;
2380 case SUBTYPE_PROBE_REQ:
2381 *Machine = SYNC_STATE_MACHINE;
2382 *MsgType = MT2_PEER_PROBE_REQ;
2383 break;
2384 case SUBTYPE_PROBE_RSP:
2385 *Machine = SYNC_STATE_MACHINE;
2386 *MsgType = MT2_PEER_PROBE_RSP;
2387 break;
2388 case SUBTYPE_BEACON:
2389 *Machine = SYNC_STATE_MACHINE;
2390 *MsgType = MT2_PEER_BEACON;
2391 break;
2392 case SUBTYPE_ATIM:
2393 *Machine = SYNC_STATE_MACHINE;
2394 *MsgType = MT2_PEER_ATIM;
2395 break;
2396 case SUBTYPE_DISASSOC:
2397 *Machine = ASSOC_STATE_MACHINE;
2398 *MsgType = MT2_PEER_DISASSOC_REQ;
2399 break;
2400 case SUBTYPE_AUTH:
2401 // get the sequence number from payload 24 Mac Header + 2 bytes algorithm
2402 NdisMoveMemory(&Seq, &Fr->Octet[2], sizeof(USHORT));
2403 if (Seq == 1 || Seq == 3)
2405 *Machine = AUTH_RSP_STATE_MACHINE;
2406 *MsgType = MT2_PEER_AUTH_ODD;
2408 else if (Seq == 2 || Seq == 4)
2410 *Machine = AUTH_STATE_MACHINE;
2411 *MsgType = MT2_PEER_AUTH_EVEN;
2413 else
2415 return FALSE;
2417 break;
2418 case SUBTYPE_DEAUTH:
2419 *Machine = AUTH_RSP_STATE_MACHINE;
2420 *MsgType = MT2_PEER_DEAUTH;
2421 break;
2422 default:
2423 return FALSE;
2424 break;
2427 return TRUE;
2430 // ===========================================================================================
2431 // state_machine.c
2432 // ===========================================================================================
2434 /*! \brief Initialize the state machine.
2435 * \param *S pointer to the state machine
2436 * \param Trans State machine transition function
2437 * \param StNr number of states
2438 * \param MsgNr number of messages
2439 * \param DefFunc default function, when there is invalid state/message combination
2440 * \param InitState initial state of the state machine
2441 * \param Base StateMachine base, internal use only
2442 * \pre p_sm should be a legal pointer
2443 * \post
2446 VOID StateMachineInit(
2447 IN STATE_MACHINE *S,
2448 IN STATE_MACHINE_FUNC Trans[],
2449 IN ULONG StNr,
2450 IN ULONG MsgNr,
2451 IN STATE_MACHINE_FUNC DefFunc,
2452 IN ULONG InitState,
2453 IN ULONG Base)
2455 ULONG i, j;
2457 // set number of states and messages
2458 S->NrState = StNr;
2459 S->NrMsg = MsgNr;
2460 S->Base = Base;
2462 S->TransFunc = Trans;
2464 // init all state transition to default function
2465 for (i = 0; i < StNr; i++)
2467 for (j = 0; j < MsgNr; j++)
2469 S->TransFunc[i * MsgNr + j] = DefFunc;
2473 // set the starting state
2474 S->CurrState = InitState;
2478 /*! \brief This function fills in the function pointer into the cell in the state machine
2479 * \param *S pointer to the state machine
2480 * \param St state
2481 * \param Msg incoming message
2482 * \param f the function to be executed when (state, message) combination occurs at the state machine
2483 * \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
2484 * \post
2486 VOID StateMachineSetAction(
2487 IN STATE_MACHINE *S,
2488 IN ULONG St,
2489 IN ULONG Msg,
2490 IN STATE_MACHINE_FUNC Func)
2492 ULONG MsgIdx;
2494 MsgIdx = Msg - S->Base;
2496 if (St < S->NrState && MsgIdx < S->NrMsg)
2498 // boundary checking before setting the action
2499 S->TransFunc[St * S->NrMsg + MsgIdx] = Func;
2503 /*! \brief The destructor of the state machine
2504 * \param *S the statemachine
2505 * \note doing nothing at this moment, may need to do something if the implementation changed
2507 VOID
2508 StateMachineDestroy(IN STATE_MACHINE *S)
2512 /*! \brief This function does the state transition
2513 * \param *Adapter the NIC adapter pointer
2514 * \param *S the state machine
2515 * \param *Elem the message to be executed
2516 * \return None
2518 VOID StateMachinePerformAction(
2519 IN PRTMP_ADAPTER pAd,
2520 IN STATE_MACHINE *S,
2521 IN MLME_QUEUE_ELEM *Elem)
2523 //DBGPRINT(RT_DEBUG_TRACE, "(%d,%d,%d,%d)(%d)(F %X)\n", S->CurrState, S->NrMsg, Elem->MsgType, S->Base, S->CurrState * S->NrMsg + Elem->MsgType - S->Base, (S->TransFunc[S->CurrState * S->NrMsg + Elem->MsgType - S->Base]));
2524 (*(S->TransFunc[S->CurrState * S->NrMsg + Elem->MsgType - S->Base]))(pAd, Elem);
2528 ==========================================================================
2529 Description:
2530 The drop function, when machine executes this, the message is simply
2531 ignored. This function does nothing, the message is freed in
2532 StateMachinePerformAction()
2533 ==========================================================================
2535 VOID Drop(
2536 IN PRTMP_ADAPTER pAd,
2537 IN MLME_QUEUE_ELEM *Elem)
2539 #if 0
2540 if ((Elem->MsgType == MT2_PEER_BEACON) ||
2541 (Elem->MsgType == MT2_PEER_PROBE_REQ) ||
2542 (Elem->MsgType == MT2_PEER_PROBE_RSP))
2544 else
2546 DBGPRINT(RT_DEBUG_TRACE, ("Warn:>>Drop Msg=%d<<\n",Elem->MsgType));
2548 #endif
2551 // ===========================================================================================
2552 // lfsr.c
2553 // ===========================================================================================
2556 ==========================================================================
2557 Description:
2558 ==========================================================================
2560 VOID LfsrInit(
2561 IN PRTMP_ADAPTER pAd,
2562 IN ULONG Seed)
2564 if (Seed == 0)
2565 pAd->Mlme.ShiftReg = 1;
2566 else
2567 pAd->Mlme.ShiftReg = Seed;
2571 ==========================================================================
2572 Description:
2573 ==========================================================================
2575 UCHAR RandomByte(
2576 IN PRTMP_ADAPTER pAd)
2578 ULONG i;
2579 UCHAR R, Result;
2581 R = 0;
2583 for (i = 0; i < 8; i++)
2585 if (pAd->Mlme.ShiftReg & 0x00000001)
2587 pAd->Mlme.ShiftReg = ((pAd->Mlme.ShiftReg ^ LFSR_MASK) >> 1) | 0x80000000;
2588 Result = 1;
2590 else
2592 pAd->Mlme.ShiftReg = pAd->Mlme.ShiftReg >> 1;
2593 Result = 0;
2595 R = (R << 1) | Result;
2598 return R;
2602 ==========================================================================
2603 Description:
2604 ==========================================================================
2606 VOID AsicSwitchChannel(
2607 IN PRTMP_ADAPTER pAd,
2608 IN UCHAR Channel)
2610 ULONG R3;
2611 UCHAR index;
2613 // TODO: need to update E2PROM format to add 802.11a channel's TX power calibration values
2614 if (Channel <= 14)
2615 R3 = pAd->PortCfg.ChannelTxPower[Channel - 1];
2616 else
2617 R3 = pAd->PortCfg.ChannelTxPower[0];
2619 if (R3 > 31) R3 = 31;
2621 // E2PROM setting is calibrated for maximum TX power (i.e. 100%)
2622 // We lower TX power here according to the percentage specified from UI
2623 if (pAd->PortCfg.TxPowerPercentage > 90) // 91 ~ 100%, treat as 100% in terms of mW
2625 else if (pAd->PortCfg.TxPowerPercentage > 60) // 61 ~ 90%, treat as 75% in terms of mW
2626 R3 -= 1;
2627 else if (pAd->PortCfg.TxPowerPercentage > 30) // 31 ~ 60%, treat as 50% in terms of mW
2628 R3 -= 3;
2629 else if (pAd->PortCfg.TxPowerPercentage > 15) // 16 ~ 30%, treat as 25% in terms of mW
2630 R3 -= 6;
2631 else if (pAd->PortCfg.TxPowerPercentage > 9) // 10 ~ 15%, treat as 12.5% in terms of mW
2632 R3 -= 9;
2633 else // 0 ~ 9 %, treat as 6.25% in terms of mW
2634 R3 -= 12;
2636 R3 = R3 << 9; // shift TX power control to correct RF R3 bit position
2638 switch (pAd->PortCfg.RfType)
2640 case RFIC_2522:
2641 for (index = 0; index < NUM_OF_2522_CHNL; index++)
2643 if (Channel == RF2522RegTable[index].Channel)
2645 R3 = R3 | RF2522RegTable[index].R3; // set TX power
2646 RTMP_RF_IO_WRITE32(pAd, RF2522RegTable[index].R1);
2647 RTMP_RF_IO_WRITE32(pAd, RF2522RegTable[index].R2);
2648 RTMP_RF_IO_WRITE32(pAd, R3);
2649 pAd->PortCfg.LatchRfRegs.Channel = Channel;
2650 pAd->PortCfg.LatchRfRegs.R1 = RF2522RegTable[index].R1;
2651 pAd->PortCfg.LatchRfRegs.R2 = RF2522RegTable[index].R2;
2652 pAd->PortCfg.LatchRfRegs.R3 = R3;
2653 pAd->PortCfg.LatchRfRegs.R4 = RF2522RegTable[index].R4;
2654 break;
2657 break;
2659 case RFIC_2523:
2660 for (index = 0; index < NUM_OF_2523_CHNL; index++)
2662 if (Channel == RF2523RegTable[index].Channel)
2664 R3 = R3 | RF2523RegTable[index].R3; // set TX power
2665 RTMP_RF_IO_WRITE32(pAd, RF2523RegTable[index].R1);
2666 RTMP_RF_IO_WRITE32(pAd, RF2523RegTable[index].R2);
2667 RTMP_RF_IO_WRITE32(pAd, R3);
2668 RTMP_RF_IO_WRITE32(pAd, RF2523RegTable[index].R4);
2669 pAd->PortCfg.LatchRfRegs.Channel = Channel;
2670 pAd->PortCfg.LatchRfRegs.R1 = RF2523RegTable[index].R1;
2671 pAd->PortCfg.LatchRfRegs.R2 = RF2523RegTable[index].R2;
2672 pAd->PortCfg.LatchRfRegs.R3 = R3;
2673 pAd->PortCfg.LatchRfRegs.R4 = RF2523RegTable[index].R4;
2674 break;
2677 break;
2679 case RFIC_2524:
2680 for (index = 0; index < NUM_OF_2524_CHNL; index++)
2682 if (Channel == RF2524RegTable[index].Channel)
2684 R3 = R3 | RF2524RegTable[index].R3; // set TX power
2685 RTMP_RF_IO_WRITE32(pAd, RF2524RegTable[index].R1);
2686 RTMP_RF_IO_WRITE32(pAd, RF2524RegTable[index].R2);
2687 RTMP_RF_IO_WRITE32(pAd, R3);
2688 RTMP_RF_IO_WRITE32(pAd, RF2524RegTable[index].R4);
2689 pAd->PortCfg.LatchRfRegs.Channel = Channel;
2690 pAd->PortCfg.LatchRfRegs.R1 = RF2524RegTable[index].R1;
2691 pAd->PortCfg.LatchRfRegs.R2 = RF2524RegTable[index].R2;
2692 pAd->PortCfg.LatchRfRegs.R3 = R3;
2693 pAd->PortCfg.LatchRfRegs.R4 = RF2524RegTable[index].R4;
2694 break;
2697 break;
2699 case RFIC_2525:
2700 for (index = 0; index < NUM_OF_2525_CHNL; index++)
2702 if (Channel == RF2525RegTable[index].Channel)
2704 // Tx power should based on the real channel value
2705 R3 = R3 | RF2525RegTable[index].R3; // set TX power
2706 // Set the channel to half band higher - 8 channels
2707 // The addition is based on Gary and Sheng's request
2708 RTMP_RF_IO_WRITE32(pAd, RF2525HBOffsetRegTable[index].R1);
2709 RTMP_RF_IO_WRITE32(pAd, RF2525HBOffsetRegTable[index].R2);
2710 RTMP_RF_IO_WRITE32(pAd, R3);
2711 RTMP_RF_IO_WRITE32(pAd, RF2525HBOffsetRegTable[index].R4);
2712 // Chnage to teh connect channel
2713 RTMP_RF_IO_WRITE32(pAd, RF2525RegTable[index].R1);
2714 RTMP_RF_IO_WRITE32(pAd, RF2525RegTable[index].R2);
2715 RTMP_RF_IO_WRITE32(pAd, R3);
2716 RTMP_RF_IO_WRITE32(pAd, RF2525RegTable[index].R4);
2717 pAd->PortCfg.LatchRfRegs.Channel = Channel;
2718 pAd->PortCfg.LatchRfRegs.R1 = RF2525RegTable[index].R1;
2719 pAd->PortCfg.LatchRfRegs.R2 = RF2525RegTable[index].R2;
2720 pAd->PortCfg.LatchRfRegs.R3 = R3;
2721 pAd->PortCfg.LatchRfRegs.R4 = RF2525RegTable[index].R4;
2722 break;
2725 break;
2727 case RFIC_2525E:
2728 for (index = 0; index < NUM_OF_2525E_CHNL; index++)
2730 if (Channel == RF2525eRegTable[index].Channel)
2732 R3 = R3 | RF2525eRegTable[index].R3; // set TX power
2733 RTMP_RF_IO_WRITE32(pAd, RF2525eRegTable[index].R1);
2734 RTMP_RF_IO_WRITE32(pAd, RF2525eRegTable[index].R2);
2735 RTMP_RF_IO_WRITE32(pAd, R3);
2736 RTMP_RF_IO_WRITE32(pAd, RF2525eRegTable[index].R4);
2737 pAd->PortCfg.LatchRfRegs.Channel = Channel;
2738 pAd->PortCfg.LatchRfRegs.R1 = RF2525eRegTable[index].R1;
2739 pAd->PortCfg.LatchRfRegs.R2 = RF2525eRegTable[index].R2;
2740 pAd->PortCfg.LatchRfRegs.R3 = R3;
2741 pAd->PortCfg.LatchRfRegs.R4 = RF2525eRegTable[index].R4;
2742 break;
2745 break;
2747 case RFIC_5222:
2748 for (index = 0; index < NUM_OF_5222_CHNL; index++)
2750 if (Channel == RF5222RegTable[index].Channel)
2752 R3 = R3 | RF5222RegTable[index].R3; // set TX power
2753 RTMP_RF_IO_WRITE32(pAd, RF5222RegTable[index].R1);
2754 RTMP_RF_IO_WRITE32(pAd, RF5222RegTable[index].R2);
2755 RTMP_RF_IO_WRITE32(pAd, R3);
2756 RTMP_RF_IO_WRITE32(pAd, RF5222RegTable[index].R4);
2757 pAd->PortCfg.LatchRfRegs.Channel = Channel;
2758 pAd->PortCfg.LatchRfRegs.R1 = RF5222RegTable[index].R1;
2759 pAd->PortCfg.LatchRfRegs.R2 = RF5222RegTable[index].R2;
2760 pAd->PortCfg.LatchRfRegs.R3 = R3;
2761 pAd->PortCfg.LatchRfRegs.R4 = RF5222RegTable[index].R4;
2762 break;
2765 break;
2767 default:
2768 break;
2771 DBGPRINT(RT_DEBUG_INFO, "AsicSwitchChannel(RF=%d) to #%d, TXPwr=%d%%, R1=0x%08x, R2=0x%08x, R3=0x%08x, R4=0x%08x\n",
2772 pAd->PortCfg.RfType,
2773 pAd->PortCfg.LatchRfRegs.Channel,
2774 pAd->PortCfg.TxPowerPercentage,
2775 pAd->PortCfg.LatchRfRegs.R1,
2776 pAd->PortCfg.LatchRfRegs.R2,
2777 pAd->PortCfg.LatchRfRegs.R3,
2778 pAd->PortCfg.LatchRfRegs.R4);
2782 ==========================================================================
2783 Description:
2784 This function is required for 2421 only, and should not be used during
2785 site survey. It's only required after NIC decided to stay at a channel
2786 for a longer period.
2787 When this function is called, it's always after AsicSwitchChannel().
2788 ==========================================================================
2790 VOID AsicLockChannel(
2791 IN PRTMP_ADAPTER pAd,
2792 IN UCHAR Channel)
2794 UCHAR r70;
2795 ULONG FcsCnt;
2797 RTMPCancelTimer(&pAd->PortCfg.RfTuningTimer);
2798 RTMPSetTimer(pAd, &pAd->PortCfg.RfTuningTimer, 1000/HZ); // 1 msec timer to turn OFF RF auto tuning
2800 RTMP_BBP_IO_READ32_BY_REG_ID(pAd, 70, &r70);
2801 if (Channel == 14)
2802 // Scott:2004-11-29 r70 |= 0x08; // turn on Japan filter bit
2803 r70 = 0x4E; // turn on Japan filter bit
2804 else
2805 // Scott:2004-11-29 r70 &= 0xf7; // turn off Japan filter bit
2806 r70 = 0x46; // turn off Japan filter bit
2807 RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, 70, r70);
2809 // Clear false CRC durning switch channel
2810 RTMP_IO_READ32(pAd, CNT0, &FcsCnt);
2813 VOID AsicRfTuningExec(
2814 IN unsigned long data)
2816 RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)data;
2818 switch (pAd->PortCfg.RfType)
2820 case RFIC_2522:
2821 case RFIC_2524:
2822 case RFIC_2525:
2823 case RFIC_5222:
2824 case RFIC_2525E:
2825 pAd->PortCfg.LatchRfRegs.R1 &= 0xfffdffff; // RF R1.bit17 "tune_en1" OFF
2826 pAd->PortCfg.LatchRfRegs.R3 &= 0xfffffeff; // RF R3.bit8 "tune_en2" OFF
2827 RTMP_RF_IO_WRITE32(pAd, pAd->PortCfg.LatchRfRegs.R1);
2828 RTMP_RF_IO_WRITE32(pAd, pAd->PortCfg.LatchRfRegs.R3);
2829 DBGPRINT(RT_DEBUG_INFO, "AsicRfTuningExec(R1=0x%x,R3=0x%x)\n",pAd->PortCfg.LatchRfRegs.R1,pAd->PortCfg.LatchRfRegs.R3);
2830 break;
2832 case RFIC_2523:
2833 pAd->PortCfg.LatchRfRegs.R3 &= 0xfffffeff; // RF R3.bit8 "tune_en2" OFF
2834 RTMP_RF_IO_WRITE32(pAd, pAd->PortCfg.LatchRfRegs.R3);
2835 DBGPRINT(RT_DEBUG_INFO, "AsicRfTuningExec(R3=0x%x)\n",pAd->PortCfg.LatchRfRegs.R3);
2836 break;
2838 default:
2839 break;
2844 ==========================================================================
2845 Description:
2846 Gives CCK TX rate 2 more dB TX power.
2847 This routine works only in LINK UP in INFRASTRUCTURE mode.
2849 calculate desired Tx power in RF R3.Tx0~5, should consider -
2850 1. TxPowerPercentage
2851 2. auto calibration based on TSSI feedback
2852 3. extra 2 db for CCK
2853 4. -10 db upon very-short distance (AvgRSSI >= -40db) to AP
2854 ==========================================================================
2856 VOID AsicAdjustTxPower(
2857 IN PRTMP_ADAPTER pAd)
2859 ULONG R3, Channel, CurrTxPwr;
2861 if ((pAd->PortCfg.Channel >= 1) && (pAd->PortCfg.Channel <= 14))
2862 Channel = pAd->PortCfg.Channel;
2863 else
2864 Channel = 1; // don't have calibration info for 11A, temporarily use Channel 1
2866 // get TX Power base from E2PROM
2867 R3 = pAd->PortCfg.ChannelTxPower[Channel - 1];
2868 if (R3 > 31) R3 = 31;
2870 // E2PROM setting is calibrated for maximum TX power (i.e. 100%)
2871 // We lower TX power here according to the percentage specified from UI
2872 if (pAd->PortCfg.TxPowerPercentage == 0xffffffff) // AUTO TX POWER control
2874 // only INFRASTRUCTURE mode and 100% TX power need furthur calibration
2875 if (pAd->MediaState == NdisMediaStateConnected)
2877 // low TX power upon very-short distance to AP to solve some vendor's AP RX problem
2878 // in this case, no TSSI compensation is required.
2879 if ((pAd->DrsCounters.fNoisyEnvironment == FALSE) &&
2880 (pAd->PortCfg.AvgRssi > (RSSI_TO_DBM_OFFSET - RSSI_FOR_LOWEST_TX_POWER)))
2881 R3 -= LOWEST_TX_POWER_DELTA;
2882 else if ((pAd->DrsCounters.fNoisyEnvironment == FALSE) &&
2883 (pAd->PortCfg.AvgRssi > (RSSI_TO_DBM_OFFSET - RSSI_FOR_LOW_TX_POWER)))
2884 R3 -= LOW_TX_POWER_DELTA;
2886 // 2004-03-16 give OFDM rates lower than 48 mbps 2 more DB
2887 else if ((pAd->PortCfg.TxRate <= RATE_36) && (pAd->PortCfg.TxRate > RATE_11))
2889 R3 +=2;
2890 if (R3 > 31) R3 = 31;
2893 // 2 exclusive rules applied on CCK rates only -
2894 // 1. always plus 2 db for CCK
2895 // 2. adjust TX Power based on TSSI
2896 else if (pAd->PortCfg.TxRate <= RATE_11)
2898 // if "auto calibration based on TSSI" is not required, then
2899 // always give CCK 2 more db
2900 if (pAd->PortCfg.bAutoTxAgc == FALSE)
2902 R3 += 2; // plus 2 db
2903 if (R3 > 31) R3 = 31;
2906 // Auto calibrate Tx AGC if bAutoTxAgc is TRUE and TX rate is CCK,
2907 // because E2PROM's TSSI reference is valid only in CCK range.
2908 else
2910 UCHAR R1,TxPowerRef, TssiRef;
2912 R3 = (pAd->PortCfg.LatchRfRegs.R3 >> 9) & 0x0000001f;
2913 if (pAd->Mlme.PeriodicRound % 4 == 0) // every 4 second
2915 TxPowerRef = pAd->PortCfg.ChannelTxPower[Channel - 1];
2916 TssiRef = pAd->PortCfg.ChannelTssiRef[Channel - 1];
2917 RTMP_BBP_IO_READ32_BY_REG_ID(pAd, BBP_Tx_Tssi, &R1);
2918 if ((TssiRef >= (R1 + pAd->PortCfg.ChannelTssiDelta)) ||
2919 (TssiRef <= (R1 - pAd->PortCfg.ChannelTssiDelta)))
2921 // Need R3 adjustment. However, we have to make sure there is only
2922 // plus / minus 5 variation allowed
2923 if (TssiRef > R1)
2925 R3 = (R3 < (ULONG) (TxPowerRef + 5)) ? (R3 + 1) : R3;
2926 if (R3 > 31)
2927 R3 = 31;
2928 DBGPRINT(RT_DEBUG_INFO,"TSSI(R1)=%d, ++TxPwr=%d\n", R1, R3);
2930 else
2932 R3 = (R3 > (ULONG) (TxPowerRef - 5)) ? (R3 - 1) : R3;
2933 DBGPRINT(RT_DEBUG_INFO,"TSSI(R1)=%d, --TxPwr=%d\n", R1, R3);
2942 else // fixed AUTO TX power
2944 if (pAd->PortCfg.TxPowerPercentage > 90) // 91 ~ 100%, treat as 100% in terms of mW
2946 else if (pAd->PortCfg.TxPowerPercentage > 60) // 61 ~ 90%, treat as 75% in terms of mW
2947 R3 -= 1;
2948 else if (pAd->PortCfg.TxPowerPercentage > 30) // 31 ~ 60%, treat as 50% in terms of mW
2949 R3 -= 3;
2950 else if (pAd->PortCfg.TxPowerPercentage > 15) // 16 ~ 30%, treat as 25% in terms of mW
2951 R3 -= 6;
2952 else if (pAd->PortCfg.TxPowerPercentage > 9) // 10 ~ 15%, treat as 12.5% in terms of mW
2953 R3 -= 9;
2954 else // 0 ~ 9 %, treat as MIN(~3%) in terms of mW
2955 R3 -= 12;
2956 if (R3 > 31) R3 = 0; // negative value, set as minimum 0
2958 // 2004-03-16 give TX rates <= 36 mbps 2 more DB
2959 if (pAd->PortCfg.TxRate <= RATE_36)
2961 R3 +=2;
2962 if (R3 > 31) R3 = 31;
2966 // compare the desired R3.TxPwr value with current R3, if not equal
2967 // set new R3.TxPwr
2968 CurrTxPwr = (pAd->PortCfg.LatchRfRegs.R3 >> 9) & 0x0000001f;
2969 if (CurrTxPwr != R3)
2971 CurrTxPwr = R3;
2972 R3 = (pAd->PortCfg.LatchRfRegs.R3 & 0xffffc1ff) | (R3 << 9);
2973 RTMP_RF_IO_WRITE32(pAd, R3);
2974 pAd->PortCfg.LatchRfRegs.R3 = R3;
2976 DBGPRINT(RT_DEBUG_INFO, "AsicAdjustTxPower = %d, AvgRssi = %d\n",
2977 CurrTxPwr, pAd->PortCfg.AvgRssi - RSSI_TO_DBM_OFFSET);
2981 ==========================================================================
2982 Description:
2983 put PHY to sleep here, and set next wakeup timer
2984 ==========================================================================
2986 VOID AsicSleepThenAutoWakeup(
2987 IN PRTMP_ADAPTER pAd,
2988 IN USHORT TbttNumToNextWakeUp)
2990 CSR20_STRUC Csr20;
2991 PWRCSR1_STRUC Pwrcsr1;
2993 // we have decided to SLEEP, so at least do it for a BEACON period.
2994 if (TbttNumToNextWakeUp==0)
2995 TbttNumToNextWakeUp=1;
2997 // PWRCSR0 remains untouched
2999 // set CSR20 for next wakeup
3000 Csr20.word = 0;
3001 Csr20.field.NumBcnBeforeWakeup = TbttNumToNextWakeUp - 1;
3002 Csr20.field.DelayAfterBcn = (pAd->PortCfg.BeaconPeriod - 20) << 4; // 20 TU ahead of desired TBTT
3003 Csr20.field.AutoWake = 1;
3004 RTMP_IO_WRITE32(pAd, CSR20, Csr20.word);
3006 // set PWRCSR1 to put PHY into SLEEP state
3007 Pwrcsr1.word = 0;
3008 Pwrcsr1.field.PutToSleep = 1;
3009 Pwrcsr1.field.BbpDesireState = 1; // 01:SLEEP
3010 Pwrcsr1.field.RfDesireState = 1; // 01:SLEEP
3011 RTMP_IO_WRITE32(pAd, PWRCSR1, Pwrcsr1.word);
3012 pAd->PortCfg.Pss = PWR_SAVE;
3016 ==========================================================================
3017 Description:
3018 AsicForceWakeup() is used whenever manual wakeup is required
3019 AsicForceSleep() should only be used when Massoc==FALSE. When
3020 Massoc==TRUE, we should use AsicSleepThenAutoWakeup() instead.
3021 ==========================================================================
3023 VOID AsicForceSleep(
3024 IN PRTMP_ADAPTER pAd)
3026 PWRCSR1_STRUC Pwrcsr1;
3028 if (pAd->PortCfg.Pss == PWR_ACTIVE)
3030 DBGPRINT(RT_DEBUG_TRACE, ">>>AsicForceSleep<<<\n");
3031 Pwrcsr1.word = 0;
3032 Pwrcsr1.field.RfDesireState = 1; // 01:SLEEP state
3033 Pwrcsr1.field.BbpDesireState = 1; // 01:SLEEP state
3034 Pwrcsr1.field.SetState = 1;
3035 RTMP_IO_WRITE32(pAd, PWRCSR1, Pwrcsr1.word);
3036 pAd->PortCfg.Pss = PWR_SAVE;
3040 VOID AsicForceWakeup(
3041 IN PRTMP_ADAPTER pAd)
3043 CSR20_STRUC Csr20;
3044 PWRCSR1_STRUC Pwrcsr1;
3046 if (pAd->PortCfg.Pss == PWR_SAVE)
3048 DBGPRINT(RT_DEBUG_TRACE, ">>>AsicForceWakeup<<<\n");
3050 // 2003-12-19 turn OFF auto wakeup first
3051 Csr20.word = 0;
3052 Csr20.field.AutoWake = 0;
3053 RTMP_IO_WRITE32(pAd, CSR20, Csr20.word);
3055 Pwrcsr1.word = 0;
3056 Pwrcsr1.field.RfDesireState = 3; // 11:AWAKE state
3057 Pwrcsr1.field.BbpDesireState = 3; // 11:AWAKE state
3058 Pwrcsr1.field.SetState = 1;
3059 RTMP_IO_WRITE32(pAd, PWRCSR1, Pwrcsr1.word);
3060 pAd->PortCfg.Pss = PWR_ACTIVE;
3065 ==========================================================================
3066 Description:
3067 ==========================================================================
3069 VOID AsicSetBssid(
3070 IN PRTMP_ADAPTER pAd,
3071 IN MACADDR *Bssid)
3073 ULONG Addr4;
3075 Addr4 = (ULONG)(Bssid->Octet[0]) |
3076 (ULONG)(Bssid->Octet[1] << 8) |
3077 (ULONG)(Bssid->Octet[2] << 16) |
3078 (ULONG)(Bssid->Octet[3] << 24);
3079 RTMP_IO_WRITE32(pAd, CSR5, Addr4);
3081 Addr4 = (ULONG)(Bssid->Octet[4]) | (ULONG)(Bssid->Octet[5] << 8);
3082 RTMP_IO_WRITE32(pAd, CSR6, Addr4);
3086 ==========================================================================
3087 Description:
3088 ==========================================================================
3090 VOID AsicDisableSync(
3091 IN PRTMP_ADAPTER pAd)
3093 // TIMECSR_STRUC TimeCsr;
3094 DBGPRINT(RT_DEBUG_TRACE, "--->Disable TSF synchronization\n");
3095 #if 1
3096 // 2003-12-20 disable TSF and Tbcn while NIC in power-saving have side effect
3097 // that NIC will never wakes up because TSF stops and no more TBTT interrupts
3098 RTMP_IO_WRITE32(pAd, CSR14, 0x00000009);
3099 #else
3100 RTMP_IO_WRITE32(pAd, CSR14, 0x00000000);
3101 #endif
3103 #if 0
3104 RTMP_IO_READ32(pAd, TIMECSR, &TimeCsr.word);
3106 // restore to 33 PCI-tick-per-Usec. for 2560a only where PCI-clock is used as TSF timing source
3107 if (TimeCsr.field.UsCnt != 0x21)
3109 TimeCsr.field.UsCnt = 0x21;
3110 RTMP_IO_WRITE32(pAd, TIMECSR, TimeCsr.word);
3112 #endif
3116 ==========================================================================
3117 Description:
3118 ==========================================================================
3120 VOID AsicEnableBssSync(
3121 IN PRTMP_ADAPTER pAd)
3123 CSR12_STRUC Csr12;
3124 CSR13_STRUC Csr13;
3125 CSR14_STRUC Csr14;
3126 BCNCSR1_STRUC Bcncsr1;
3127 BOOLEAN IsApPc;
3129 DBGPRINT(RT_DEBUG_TRACE, "--->AsicEnableBssSync(INFRA mode)\n");
3131 RTMP_IO_WRITE32(pAd, CSR14, 0x00000000);
3133 Csr12.word = 0;
3134 Csr12.field.BeaconInterval = pAd->PortCfg.BeaconPeriod << 4; // ASIC register in units of 1/16 TU
3135 Csr12.field.CfpMaxDuration = pAd->PortCfg.CfpMaxDuration << 4; // ASIC register in units of 1/16 TU
3136 RTMP_IO_WRITE32(pAd, CSR12, Csr12.word);
3138 Csr13.word = 0;
3139 Csr13.field.CfpPeriod = pAd->PortCfg.CfpDurRemain << 4; // ASIC register in units of 1/16 TU
3140 RTMP_IO_WRITE32(pAd, CSR13, Csr13.word);
3142 Bcncsr1.word = 0;
3143 Bcncsr1.field.Preload = TBTT_PRELOAD_TIME; // we guess TBTT is 2 TU ahead of BEACON-RxEnd time
3144 Bcncsr1.field.BeaconCwMin = 5;
3145 RTMP_IO_WRITE32(pAd, BCNCSR1, Bcncsr1.word);
3147 IsApPc = (CAP_IS_CF_POLLABLE_ON(pAd->PortCfg.CapabilityInfo) &&
3148 CAP_IS_CF_POLL_REQ_ON(pAd->PortCfg.CapabilityInfo));
3149 IsApPc = FALSE; // TODO: not support so far
3151 Csr14.word = 0;
3152 Csr14.field.TsfCount = 1;
3153 Csr14.field.TsfSync = 1; // sync TSF in INFRASTRUCTURE mode
3154 if (IsApPc)
3156 Csr14.field.CfpCntPreload = pAd->PortCfg.CfpCount;
3157 Csr14.field.Tcfp = 1;
3159 Csr14.field.BeaconGen = 0;
3160 // Csr14.field.TbcnPreload = (pAd->PortCfg.BeaconPeriod - 30) << 4; // TODO: ???? 1 TU ???
3161 Csr14.field.Tbcn = 1;
3162 RTMP_IO_WRITE32(pAd, CSR14, Csr14.word);
3167 ==========================================================================
3168 Description:
3169 Note:
3170 BEACON frame in shared memory should be built ok before this routine
3171 can be called. Otherwise, a garbage frame maybe transmitted out every
3172 Beacon period.
3173 ==========================================================================
3175 VOID AsicEnableIbssSync(
3176 IN PRTMP_ADAPTER pAd)
3178 CSR12_STRUC Csr12;
3179 CSR13_STRUC Csr13;
3180 CSR14_STRUC Csr14;
3181 // BCNCSR_STRUC Bcncsr;
3182 BCNCSR1_STRUC Bcncsr1;
3184 DBGPRINT(RT_DEBUG_TRACE, "--->AsicEnableIbssSync(ADHOC mode)\n");
3186 RTMP_IO_WRITE32(pAd, CSR14, 0x00000000);
3188 Csr12.word = 0;
3189 Csr12.field.BeaconInterval = pAd->PortCfg.BeaconPeriod << 4; // ASIC register in units of 1/16 TU
3190 RTMP_IO_WRITE32(pAd, CSR12, Csr12.word);
3192 Csr13.word = 0;
3193 Csr13.field.AtimwDuration = pAd->PortCfg.AtimWin << 4; // ASIC register in units of 1/16 TU
3194 RTMP_IO_WRITE32(pAd, CSR13, Csr13.word);
3196 Bcncsr1.word = 0;
3197 if ((pAd->PortCfg.PhyMode == PHY_11B) || (pAd->PortCfg.PhyMode == PHY_11BG_MIXED))
3199 Bcncsr1.field.BeaconCwMin = 5;
3200 Bcncsr1.field.Preload = 1024; // 192 + ((MAC_HDR_LEN << 4) / RateIdTo500Kbps[pAd->PortCfg.MlmeRate]);
3202 else
3204 Bcncsr1.field.BeaconCwMin = 6;
3205 Bcncsr1.field.Preload = 700; // 24 + ((MAC_HDR_LEN << 4) / RateIdTo500Kbps[pAd->PortCfg.MlmeRate]);
3207 RTMP_IO_WRITE32(pAd, BCNCSR1, Bcncsr1.word);
3209 Csr14.word = 0;
3210 Csr14.field.TsfCount = 1;
3211 Csr14.field.TsfSync = 2; // sync TSF in IBSS mode
3212 Csr14.field.Tbcn = 1;
3213 Csr14.field.BeaconGen = 1;
3214 RTMP_IO_WRITE32(pAd, CSR14, Csr14.word);
3217 VOID AsicLedPeriodicExec(
3218 IN unsigned long data)
3220 RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)data;
3221 ULONG LedCsr = 0x0000461E; // 0x0000461E;
3223 pAd->PortCfg.LedCntl.fOdd = ! pAd->PortCfg.LedCntl.fOdd;
3225 if (INFRA_ON(pAd) || ADHOC_ON(pAd))
3226 LedCsr |= 0x00010000; // enable hardwired TX activity LED
3227 if (pAd->PortCfg.LedCntl.fOdd && pAd->PortCfg.LedCntl.fRxActivity)
3228 LedCsr |= 0x00020000; // turn on software-based RX activity LED
3229 pAd->PortCfg.LedCntl.fRxActivity = FALSE;
3231 if (LedCsr != pAd->PortCfg.LedCntl.LastLedCsr)
3233 // DBGPRINT(RT_DEBUG_TRACE, ("AsicLedPeriodicExec(%8x)\n",LedCsr));
3234 pAd->PortCfg.LedCntl.LastLedCsr = LedCsr;
3235 RTMP_IO_WRITE32(pAd, LEDCSR, LedCsr);
3238 RTMPSetTimer(pAd, &pAd->PortCfg.LedCntl.BlinkTimer, 70);
3241 // pAd->PortCfg.CurrentRxAntenna
3242 // 0xff: diversity, 0:antenna A, 1:antenna B
3243 VOID AsicSetRxAnt(
3244 IN PRTMP_ADAPTER pAd)
3246 UCHAR RxValue, TxValue;
3247 ULONG Bbpcsr1;
3249 RTMPCancelTimer(&pAd->PortCfg.RxAnt.RxAntDiversityTimer);
3250 pAd->PortCfg.RxAnt.AvgRssi[0] = 0; // reset Ant-A's RSSI history
3251 pAd->PortCfg.RxAnt.AvgRssi[1] = 0; // reset Ant-B's RSSI history
3252 pAd->PortCfg.RxAnt.PrimaryInUsed = TRUE;
3254 if (pAd->PortCfg.CurrentRxAntenna == 0xff) // Diversity
3256 pAd->PortCfg.RxAnt.PrimaryRxAnt = 1; // assume ant-B
3257 pAd->PortCfg.RxAnt.SecondaryRxAnt = 0; // assume ant-A
3259 else if (pAd->PortCfg.CurrentRxAntenna == 0) // ant-A
3261 pAd->PortCfg.RxAnt.PrimaryRxAnt = 0; // assume ant-A
3262 pAd->PortCfg.RxAnt.SecondaryRxAnt = 1; // assume ant-B
3264 else // ant-B
3266 pAd->PortCfg.RxAnt.PrimaryRxAnt = 1; // assume ant-B
3267 pAd->PortCfg.RxAnt.SecondaryRxAnt = 0; // assume ant-A
3270 DBGPRINT(RT_DEBUG_TRACE,"AntDiv - set RxAnt=%d, primary=%d, second=%d\n",
3271 pAd->PortCfg.CurrentRxAntenna, pAd->PortCfg.RxAnt.PrimaryRxAnt, pAd->PortCfg.RxAnt.SecondaryRxAnt);
3273 // use primary antenna
3274 RTMP_IO_READ32(pAd, BBPCSR1, &Bbpcsr1);
3275 TxValue = pAd->PortCfg.BbpWriteLatch[BBP_Tx_Configure];
3276 RxValue = pAd->PortCfg.BbpWriteLatch[BBP_Rx_Configure];
3277 if (pAd->PortCfg.RxAnt.PrimaryRxAnt == 0) // ant-A
3279 TxValue = (TxValue & 0xFC) | 0x00;
3280 RxValue = (RxValue & 0xFC) | 0x00;
3281 Bbpcsr1 = (Bbpcsr1 & 0xFFFCFFFC) | 0x00000000;
3283 else // ant-B
3285 TxValue = (TxValue & 0xFC) | 0x02;
3286 RxValue = (RxValue & 0xFC) | 0x02;
3287 Bbpcsr1 = (Bbpcsr1 & 0xFFFCFFFC) | 0x00020002;
3289 RTMP_IO_WRITE32(pAd, BBPCSR1, Bbpcsr1);
3290 RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, BBP_Tx_Configure, TxValue);
3291 RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, BBP_Rx_Configure, RxValue);
3295 // switch to secondary RxAnt for a while to collect it's average RSSI
3296 // also set a timeout routine to DO the actual evaluation. If evaluation
3297 // result shows a much better RSSI using secondary RxAnt, then a official
3298 // RX antenna switch is performed.
3299 VOID AsicEvaluateSecondaryRxAnt(
3300 IN PRTMP_ADAPTER pAd)
3302 UCHAR RxValue, TxValue;
3303 ULONG Bbpcsr1;
3305 if (pAd->PortCfg.CurrentRxAntenna != 0xff)
3306 return;
3308 pAd->PortCfg.RxAnt.PrimaryInUsed = FALSE;
3309 // pAd->PortCfg.RxAnt.AvgRssi[pAd->PortCfg.RxAnt.SecondaryRxAnt] = 0;
3311 DBGPRINT(RT_DEBUG_TRACE,"AntDiv - evaluate Ant #%d\n", pAd->PortCfg.RxAnt.SecondaryRxAnt);
3313 // temporarily switch to secondary antenna
3314 RxValue = pAd->PortCfg.BbpWriteLatch[BBP_Rx_Configure];
3315 TxValue = pAd->PortCfg.BbpWriteLatch[BBP_Tx_Configure];
3316 RTMP_IO_READ32(pAd, BBPCSR1, &Bbpcsr1);
3318 if (pAd->PortCfg.RxAnt.SecondaryRxAnt == 0) // ant-A
3320 TxValue = (TxValue & 0xFC) | 0x00;
3321 RxValue = (RxValue & 0xFC) | 0x00;
3322 Bbpcsr1 = (Bbpcsr1 & 0xFFFCFFFC) | 0x00000000;
3324 else // ant-B
3326 TxValue = (TxValue & 0xFC) | 0x02;
3327 RxValue = (RxValue & 0xFC) | 0x02;
3328 Bbpcsr1 = (Bbpcsr1 & 0xFFFCFFFC) | 0x00020002;
3330 RTMP_IO_WRITE32(pAd, BBPCSR1, Bbpcsr1);
3331 RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, BBP_Tx_Configure, TxValue);
3332 RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, BBP_Rx_Configure, RxValue);
3334 // a one-shot timer to end the evalution
3335 if (pAd->MediaState == NdisMediaStateConnected)
3336 RTMPSetTimer(pAd, &pAd->PortCfg.RxAnt.RxAntDiversityTimer, 100);
3337 else
3338 RTMPSetTimer(pAd, &pAd->PortCfg.RxAnt.RxAntDiversityTimer, 300);
3341 // this timeout routine collect AvgRssi[SecondaryRxAnt] and decide if
3342 // SecondaryRxAnt is much better than PrimaryRxAnt
3343 VOID AsicRxAntEvalTimeout(
3344 IN unsigned long data)
3346 RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)data;
3348 if (pAd->PortCfg.RxAnt.PrimaryInUsed == TRUE)
3349 return;
3351 // 1-db or more will we consider to switch antenna
3352 if (pAd->PortCfg.RxAnt.AvgRssi[pAd->PortCfg.RxAnt.SecondaryRxAnt] >
3353 (pAd->PortCfg.RxAnt.AvgRssi[pAd->PortCfg.RxAnt.PrimaryRxAnt]))
3355 UCHAR temp;
3356 // secondary antenna is much better than primary, switch RX antenna
3357 temp = pAd->PortCfg.RxAnt.PrimaryRxAnt;
3358 pAd->PortCfg.RxAnt.PrimaryRxAnt = pAd->PortCfg.RxAnt.SecondaryRxAnt;
3359 pAd->PortCfg.RxAnt.SecondaryRxAnt = temp;
3361 DBGPRINT(RT_DEBUG_TRACE,"AntDiv - Switch to Ant #%d, RSSI[0,1]=<%d, %d>\n",
3362 pAd->PortCfg.RxAnt.PrimaryRxAnt, pAd->PortCfg.RxAnt.AvgRssi[0], pAd->PortCfg.RxAnt.AvgRssi[1]);
3364 else
3366 UCHAR RxValue, TxValue;
3367 ULONG Bbpcsr1;
3369 // end of evaluation, swicth back to primary antenna
3370 RxValue = pAd->PortCfg.BbpWriteLatch[BBP_Rx_Configure];
3371 TxValue = pAd->PortCfg.BbpWriteLatch[BBP_Tx_Configure];
3372 RTMP_IO_READ32(pAd, BBPCSR1, &Bbpcsr1);
3373 if (pAd->PortCfg.RxAnt.PrimaryRxAnt == 0) // ant-A
3375 TxValue = (TxValue & 0xFC) | 0x00;
3376 RxValue = (RxValue & 0xFC) | 0x00;
3377 Bbpcsr1 = (Bbpcsr1 & 0xFFFCFFFC) | 0x00000000;
3379 else // ant-B
3381 TxValue = (TxValue & 0xFC) | 0x02;
3382 RxValue = (RxValue & 0xFC) | 0x02;
3383 Bbpcsr1 = (Bbpcsr1 & 0xFFFCFFFC) | 0x00020002;
3385 RTMP_IO_WRITE32(pAd, BBPCSR1, Bbpcsr1);
3386 RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, BBP_Tx_Configure, TxValue);
3387 RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, BBP_Rx_Configure, RxValue);
3388 DBGPRINT(RT_DEBUG_TRACE,"AntDiv - remain Ant #%d, RSSI[0,1]=<%d, %d>\n",
3389 pAd->PortCfg.RxAnt.PrimaryRxAnt, pAd->PortCfg.RxAnt.AvgRssi[0], pAd->PortCfg.RxAnt.AvgRssi[1]);
3392 // pAd->PortCfg.RxAnt.AvgRssi[0] = 0; // reset Ant-A's RSSI history
3393 // pAd->PortCfg.RxAnt.AvgRssi[1] = 0; // reset Ant-B's RSSI history
3394 pAd->PortCfg.RxAnt.PrimaryInUsed = TRUE;
3398 ==========================================================================
3399 Description:
3400 ==========================================================================
3402 VOID AsicSetSlotTime(
3403 IN PRTMP_ADAPTER pAd,
3404 IN BOOLEAN UseShortSlotTime)
3406 CSR11_STRUC Csr11;
3407 CSR18_STRUC Csr18;
3408 CSR19_STRUC Csr19;
3409 UCHAR PhyMode;
3411 pAd->PortCfg.ShortSlotInUsed = UseShortSlotTime;
3413 PhyMode = pAd->PortCfg.PhyMode;
3414 if (PhyMode == PHY_11ABG_MIXED)
3416 if (pAd->PortCfg.Channel <=14)
3417 PhyMode = PHY_11BG_MIXED;
3418 else
3419 PhyMode = PHY_11A;
3422 RTMP_IO_READ32(pAd, CSR11, &Csr11.word);
3423 if (PhyMode == PHY_11A)
3424 Csr11.field.SlotTime = 9;
3425 else
3426 Csr11.field.SlotTime = (UseShortSlotTime)? 9 : 20;
3427 RTMP_IO_WRITE32(pAd, CSR11, Csr11.word);
3429 RTMP_IO_READ32(pAd, CSR18, &Csr18.word);
3430 Csr18.field.PIFS = Csr18.field.SIFS + Csr11.field.SlotTime;
3431 RTMP_IO_WRITE32(pAd, CSR18, Csr18.word);
3433 Csr19.word = 0;
3434 Csr19.field.DIFS = Csr18.field.PIFS + Csr11.field.SlotTime;
3435 if (PhyMode == PHY_11B)
3436 Csr19.field.EIFS = 364; // SIFS + ACK @1Mbps
3437 else
3438 Csr19.field.EIFS = 60; // roughly = SIFS + ACK @6Mbps
3439 RTMP_IO_WRITE32(pAd, CSR19, Csr19.word);
3441 #if 1
3442 // force using short SLOT time for FAE to demo performance only
3443 if (pAd->PortCfg.EnableTxBurst == 1)
3444 Csr11.field.SlotTime = 9;
3445 RTMP_IO_WRITE32(pAd, CSR11, Csr11.word);
3446 #endif
3451 ==========================================================================
3452 Description:
3453 This routine is used for 2560a only where 2560a still use non-accurate
3454 PCI-clock as TSF 1-usec source. we have to dynamically change tick-per-usec
3455 to avoid ADHOC synchronization issue with SYMBOL 11b card
3456 ==========================================================================
3458 VOID AsicAdjustUsec(
3459 IN PRTMP_ADAPTER pAd)
3461 TIMECSR_STRUC TimeCsr;
3462 UCHAR TickPerUsec = 20;
3463 pAd->PortCfg.PciAdjustmentRound = (pAd->PortCfg.PciAdjustmentRound+1) & 0x03;
3465 RTMP_IO_READ32(pAd, TIMECSR, &TimeCsr.word);
3466 if (pAd->PortCfg.PciAdjustmentRound == 0)
3467 TickPerUsec = 0x21;
3468 else if (pAd->PortCfg.PciAdjustmentRound == 1)
3469 TickPerUsec = 0x21;
3470 else if (pAd->PortCfg.PciAdjustmentRound == 2)
3471 TickPerUsec = 0x20;
3472 else
3473 TickPerUsec = 0x21;
3475 if (TimeCsr.field.UsCnt!= TickPerUsec)
3477 TimeCsr.field.UsCnt= TickPerUsec;
3478 RTMP_IO_WRITE32(pAd, TIMECSR, TimeCsr.word);
3479 DBGPRINT(RT_DEBUG_INFO, "AsicAdjustUsec - change TIMECSR=0x%08x)\n",TimeCsr.word);
3484 ==========================================================================
3485 Description:
3486 danamic tune BBP R17 to find a balance between sensibility and
3487 noise isolation
3488 ==========================================================================
3490 VOID AsicBbpTuning(
3491 IN PRTMP_ADAPTER pAd)
3493 ULONG Value;
3494 UCHAR R17;
3495 ULONG FalseCcaUpperThreshold = pAd->PortCfg.BbpTuning.FalseCcaUpperThreshold << 7;
3496 int dbm = pAd->PortCfg.AvgRssi - RSSI_TO_DBM_OFFSET;
3498 if ((! pAd->PortCfg.BbpTuningEnable) || (pAd->PortCfg.BbpTuning.VgcDelta==0))
3499 return;
3501 R17 = pAd->PortCfg.BbpWriteLatch[17];
3503 if ((pAd->PortCfg.Rt2560Version >= RT2560_VER_D) &&
3504 (pAd->MediaState == NdisMediaStateConnected))
3506 // Rule 0.
3507 // when RSSI is too weak, many signals will become false CCA thus affect R17 tuning.
3508 // so in this case, just stop R17 tuning (be sure R17 remains in <E2PROM-6, BBP_R17_DYNAMIC_UP_BOUND> range)
3509 if ((dbm < -80) && (pAd->Mlme.PeriodicRound > 20))
3511 if (R17 >= BBP_R17_MID_SENSIBILITY)
3513 R17 = pAd->PortCfg.LastR17Value;
3514 RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, 17, R17);
3516 DBGPRINT(RT_DEBUG_INFO, "RSSI = %d dbm, stop R17 at 0x%x\n", dbm, R17);
3517 return;
3519 // Rule 1. "special big-R17 for short-distance" when not SCANNING
3520 else if ((dbm >= RSSI_FOR_LOW_SENSIBILITY) &&
3521 (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE))
3523 if (R17 != BBP_R17_LOW_SENSIBILITY)
3525 R17 = BBP_R17_LOW_SENSIBILITY;
3526 RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, 17, R17);
3528 DBGPRINT(RT_DEBUG_INFO, "RSSI = %d dbm, fixed R17 at 0x%x\n", dbm, R17);
3529 return;
3531 // Rule 2. "special mid-R17 for mid-distance" when not SCANNING
3532 else if ((dbm >= RSSI_FOR_MID_SENSIBILITY) &&
3533 (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE))
3535 if (R17 != BBP_R17_MID_SENSIBILITY)
3537 R17 = BBP_R17_MID_SENSIBILITY;
3538 RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, 17, R17);
3540 DBGPRINT(RT_DEBUG_INFO, "RSSI = %d dbm, fixed R17 at 0x%x\n", dbm, R17);
3541 return;
3543 // Rule 3. leave "short or mid-distance" condition, restore R17 to the
3544 // dynamic tuning range <E2PROM-6, BBP_R17_DYNAMIC_UP_BOUND>
3545 else if (R17 >= BBP_R17_MID_SENSIBILITY)
3547 R17 = pAd->PortCfg.LastR17Value;
3548 RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, 17, R17);
3549 DBGPRINT(RT_DEBUG_INFO, "RSSI = %d dbm, restore R17 to 0x%x\n", dbm, R17);
3550 return;
3554 // Rule 3. otherwise, R17 is currenly in dyanmic tuning range: <E2PROM-6, BBP_R17_DYNAMIC_UP_BOUND>.
3555 // Keep dynamic tuning based on False CCA conter
3557 RTMP_IO_READ32(pAd, CNT3, &Value);
3558 pAd->PrivateInfo.CCAErrCnt = (Value & 0x0000ffff);
3559 DBGPRINT(RT_DEBUG_INFO, "CCA flase alarm = %d, Avg RSSI= %d dbm\n",
3560 pAd->PrivateInfo.CCAErrCnt, dbm);
3562 if ((pAd->PrivateInfo.CCAErrCnt > FalseCcaUpperThreshold) &&
3563 (R17 < pAd->PortCfg.BbpTuning.VgcUpperBound))
3565 R17 += pAd->PortCfg.BbpTuning.VgcDelta;
3566 pAd->PortCfg.LastR17Value = R17;
3567 RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, 17, R17);
3568 DBGPRINT(RT_DEBUG_INFO, "++R17= 0x%x\n", R17);
3570 else if ((pAd->PrivateInfo.CCAErrCnt < pAd->PortCfg.BbpTuning.FalseCcaLowerThreshold) &&
3571 (R17 > pAd->PortCfg.VgcLowerBound))
3573 R17 -= pAd->PortCfg.BbpTuning.VgcDelta;
3574 pAd->PortCfg.LastR17Value = R17;
3575 RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, 17, R17);
3576 DBGPRINT(RT_DEBUG_INFO, "--R17= 0x%x\n", R17);
3580 // stop and restore R17 value upon SITE-SURVEY and LINK-DOWN
3581 VOID AsicRestoreBbpSensibility(
3582 IN PRTMP_ADAPTER pAd)
3584 UCHAR R17;
3586 R17 = pAd->PortCfg.BbpWriteLatch[17];
3587 if (R17 >= BBP_R17_MID_SENSIBILITY)
3589 R17 = pAd->PortCfg.LastR17Value;
3590 RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, 17, R17);
3591 DBGPRINT(RT_DEBUG_TRACE, "AsicRestoreBbpSensibility(set R17= 0x%x)\n", R17);
3596 ========================================================================
3598 Routine Description:
3599 Mlme free the in-used nonpaged memory,
3600 move it to the unused memory link list
3602 Arguments:
3603 pAd Pointer to our adapter
3604 AllocVa Pointer to the base virtual address for free
3606 Return Value:
3607 None
3609 Note:
3611 ========================================================================
3613 VOID MlmeFreeMemory(
3614 IN PRTMP_ADAPTER pAd,
3615 IN PVOID AllocVa)
3617 PMLME_MEMORY_STRUCT pPrevious = NULL;
3618 PMLME_MEMORY_STRUCT pMlmeMemoryStruct = NULL;
3619 UINT Index = 0;
3620 BOOLEAN bIsFound = FALSE;
3621 unsigned long IrqFlags;
3623 DBGPRINT(RT_DEBUG_INFO, "==> MlmeFreeMemory\n");
3624 NdisAcquireSpinLock(&pAd->MemLock);
3625 if (pAd->Mlme.MemHandler.MemRunning)
3627 //Mlme memory handler is busy.
3628 //Move it to the Pending array for later free
3629 pAd->Mlme.MemHandler.PendingCount++;
3630 pAd->Mlme.MemHandler.MemFreePending[pAd->Mlme.MemHandler.PendingHead] = (PULONG) AllocVa;
3631 pAd->Mlme.MemHandler.PendingHead++;
3632 if (pAd->Mlme.MemHandler.PendingHead == MAX_MLME_HANDLER_MEMORY)
3633 pAd->Mlme.MemHandler.PendingHead = 0;
3635 DBGPRINT(RT_DEBUG_TRACE, "Mlme memory Handler Busy!! move free memory to pending list [IN:%d][UN:%d][Pending:%d]\n",
3636 pAd->Mlme.MemHandler.InUseCount, pAd->Mlme.MemHandler.UnUseCount, pAd->Mlme.MemHandler.PendingCount);
3637 DBGPRINT(RT_DEBUG_INFO, "<== MlmeFreeMemory\n");
3638 NdisReleaseSpinLock(&pAd->MemLock);
3639 return;
3641 else
3643 pAd->Mlme.MemHandler.MemRunning = TRUE;
3644 NdisReleaseSpinLock(&pAd->MemLock);
3647 //First check is there have to free memory in the pAd->Mlme.MemHandler.MemFreePending.
3648 while (pAd->Mlme.MemHandler.PendingHead != pAd->Mlme.MemHandler.PendingTail)
3650 bIsFound = FALSE; // Scott
3651 pPrevious = NULL;
3652 pMlmeMemoryStruct = pAd->Mlme.MemHandler.pInUseHead;
3653 Index = pAd->Mlme.MemHandler.PendingTail;
3654 while (pMlmeMemoryStruct)
3656 if (pMlmeMemoryStruct->AllocVa == (PVOID) pAd->Mlme.MemHandler.MemFreePending[pAd->Mlme.MemHandler.PendingTail])
3658 //Found virtual address in the in-used link list
3659 //Remove it from the memory in-used link list, and move it to the unused link list
3660 if (pPrevious == NULL)
3661 pAd->Mlme.MemHandler.pInUseHead = pAd->Mlme.MemHandler.pInUseHead->Next;
3662 else
3663 pPrevious->Next = pMlmeMemoryStruct->Next;
3665 if (pAd->Mlme.MemHandler.pInUseTail == pMlmeMemoryStruct)
3666 pAd->Mlme.MemHandler.pInUseTail = pPrevious;
3668 if ((pAd->Mlme.MemHandler.pUnUseHead == NULL))
3669 { //No head, add it as head
3670 pMlmeMemoryStruct->Next = NULL;
3671 pAd->Mlme.MemHandler.pUnUseHead = pMlmeMemoryStruct;
3672 pAd->Mlme.MemHandler.pUnUseTail = pAd->Mlme.MemHandler.pUnUseHead;
3674 else
3676 //Append it to the tail in pAd->Mlme.MemHandler.pUnUseTail
3677 pMlmeMemoryStruct->Next = NULL;
3678 pAd->Mlme.MemHandler.pUnUseTail->Next = pMlmeMemoryStruct;
3679 pAd->Mlme.MemHandler.pUnUseTail = pAd->Mlme.MemHandler.pUnUseTail->Next;
3681 NdisAcquireSpinLock(&pAd->MemLock);
3682 pAd->Mlme.MemHandler.PendingCount--;
3683 pAd->Mlme.MemHandler.UnUseCount++;
3684 pAd->Mlme.MemHandler.InUseCount--;
3685 pAd->Mlme.MemHandler.MemFreePending[Index] = NULL;
3686 pAd->Mlme.MemHandler.PendingTail++;
3687 if (pAd->Mlme.MemHandler.PendingTail == MAX_MLME_HANDLER_MEMORY)
3688 pAd->Mlme.MemHandler.PendingTail = 0;
3689 NdisReleaseSpinLock(&pAd->MemLock);
3690 bIsFound = TRUE;
3691 break;
3692 } else {
3693 pPrevious = pMlmeMemoryStruct;
3694 pMlmeMemoryStruct = pMlmeMemoryStruct->Next;
3698 if (!bIsFound)
3700 //This shoult not be happened! Just in case!
3701 DBGPRINT(RT_DEBUG_ERROR, "<Warning>Free memory faild!! memory corruption on [Va:0x%x] not found in In-Used link list [IN:%d][UN:%d][Pending:%d]\n",
3702 (UINT)pAd->Mlme.MemHandler.MemFreePending[pAd->Mlme.MemHandler.PendingCount],
3703 pAd->Mlme.MemHandler.InUseCount, pAd->Mlme.MemHandler.UnUseCount, pAd->Mlme.MemHandler.PendingCount);
3704 //lost a memory
3705 NdisAcquireSpinLock(&pAd->MemLock);
3706 pAd->Mlme.MemHandler.PendingCount--;
3707 pAd->Mlme.MemHandler.MemFreePending[Index] = NULL;
3708 pAd->Mlme.MemHandler.PendingTail++;
3709 if (pAd->Mlme.MemHandler.PendingTail == MAX_MLME_HANDLER_MEMORY)
3710 pAd->Mlme.MemHandler.PendingTail = 0;
3711 NdisReleaseSpinLock(&pAd->MemLock);
3712 //This shoult not be happened! Just in case!
3716 pPrevious = NULL;
3717 pMlmeMemoryStruct = pAd->Mlme.MemHandler.pInUseHead;
3718 bIsFound = FALSE;
3719 while (pMlmeMemoryStruct)
3721 if (pMlmeMemoryStruct->AllocVa == AllocVa)
3723 //Found virtual address in the in-used link list
3724 //Remove it from the memory in-used link list, and move it to the unused link list
3725 if (pPrevious == NULL)
3726 pAd->Mlme.MemHandler.pInUseHead = pAd->Mlme.MemHandler.pInUseHead->Next;
3727 else
3728 pPrevious->Next = pMlmeMemoryStruct->Next;
3730 if (pAd->Mlme.MemHandler.pInUseTail == pMlmeMemoryStruct)
3731 pAd->Mlme.MemHandler.pInUseTail = pPrevious;
3733 if (pAd->Mlme.MemHandler.pUnUseHead == NULL)
3735 pMlmeMemoryStruct->Next = NULL;
3736 pAd->Mlme.MemHandler.pUnUseHead = pMlmeMemoryStruct;
3737 pAd->Mlme.MemHandler.pUnUseTail = pMlmeMemoryStruct;
3739 else
3741 pMlmeMemoryStruct->Next = NULL;
3742 pAd->Mlme.MemHandler.pUnUseTail->Next = pMlmeMemoryStruct;
3743 pAd->Mlme.MemHandler.pUnUseTail = pMlmeMemoryStruct;
3746 pAd->Mlme.MemHandler.InUseCount--;
3747 pAd->Mlme.MemHandler.UnUseCount++;
3748 DBGPRINT(RT_DEBUG_INFO, "MlmeFreeMemory Add it to the Unused memory link List[pMlmeMemoryStruct=0x%x][VA=0x%x]\n", (UINT)pMlmeMemoryStruct, (UINT)pMlmeMemoryStruct->AllocVa);
3749 bIsFound = TRUE;
3750 break;
3752 pPrevious = pMlmeMemoryStruct;
3753 pMlmeMemoryStruct = pMlmeMemoryStruct->Next;
3756 if (!bIsFound)
3758 DBGPRINT(RT_DEBUG_TRACE, "(INT=%d) MlmeFreeMemory fail [IN=%d][UN=%d][Pending=%d]\n", in_interrupt(),
3759 pAd->Mlme.MemHandler.InUseCount, pAd->Mlme.MemHandler.UnUseCount, pAd->Mlme.MemHandler.PendingCount);
3762 NdisAcquireSpinLock(&pAd->MemLock);
3763 pAd->Mlme.MemHandler.MemRunning = FALSE;
3764 NdisReleaseSpinLock(&pAd->MemLock);
3766 DBGPRINT(RT_DEBUG_INFO, "<== MlmeFreeMemory [IN:%d][UN:%d][Pending:%d]\n",
3767 pAd->Mlme.MemHandler.InUseCount, pAd->Mlme.MemHandler.UnUseCount, pAd->Mlme.MemHandler.PendingCount);
3771 ========================================================================
3773 Routine Description:
3774 Get an unused nonpaged system-space memory for use
3776 Arguments:
3777 pAd Pointer to our adapter
3778 AllocVa Pointer to the base virtual address for later use
3780 Return Value:
3781 NDIS_STATUS_SUCCESS
3782 NDIS_STATUS_FAILURE
3783 NDIS_STATUS_RESOURCES
3785 Note:
3787 ========================================================================
3789 NDIS_STATUS MlmeAllocateMemory(
3790 IN PRTMP_ADAPTER pAd,
3791 OUT PVOID *AllocVa)
3793 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
3794 PMLME_MEMORY_STRUCT pMlmeMemoryStruct = NULL;
3795 unsigned long IrqFlags;
3797 DBGPRINT(RT_DEBUG_INFO, "==> MlmeAllocateMemory\n");
3798 NdisAcquireSpinLock(&pAd->MemLock);
3799 if (pAd->Mlme.MemHandler.MemRunning)
3801 DBGPRINT(RT_DEBUG_INFO, "Mlme memory Handler Busy!!, MlmeAllocateMemory failed!!\n");
3802 Status = NDIS_STATUS_FAILURE;
3803 DBGPRINT(RT_DEBUG_INFO, "<== MlmeAllocateMemory\n");
3804 NdisReleaseSpinLock(&pAd->MemLock);
3805 return (Status);
3807 else
3809 pAd->Mlme.MemHandler.MemRunning = TRUE;
3810 NdisReleaseSpinLock(&pAd->MemLock);
3813 if (pAd->Mlme.MemHandler.pUnUseHead == NULL)
3814 { //There are no available memory for caller use
3815 Status = NDIS_STATUS_RESOURCES;
3816 NdisAcquireSpinLock(&pAd->MemLock);
3817 pAd->Mlme.MemHandler.MemRunning = FALSE;
3818 NdisReleaseSpinLock(&pAd->MemLock);
3819 DBGPRINT(RT_DEBUG_INFO, "MlmeAllocateMemory, failed!! (There are no available memory in list)\n");
3820 DBGPRINT(RT_DEBUG_INFO, "<== MlmeAllocateMemory\n");
3821 return (Status);
3824 pMlmeMemoryStruct = pAd->Mlme.MemHandler.pUnUseHead;
3825 *AllocVa = pMlmeMemoryStruct->AllocVa; //Saved porint to Pointer the base virtual address of the nonpaged memory for caller use.
3826 //Unused memory point to next available
3827 pAd->Mlme.MemHandler.pUnUseHead = pAd->Mlme.MemHandler.pUnUseHead->Next;
3828 if (pAd->Mlme.MemHandler.pUnUseHead == NULL)
3829 pAd->Mlme.MemHandler.pUnUseTail = NULL;
3830 pAd->Mlme.MemHandler.UnUseCount--;
3832 //Append the unused memory link list to the in-used link list tail
3833 if (pAd->Mlme.MemHandler.pInUseHead == NULL)
3834 {//no head, so current Item assign to In-use Head.
3835 pMlmeMemoryStruct->Next = NULL;
3836 pAd->Mlme.MemHandler.pInUseHead = pMlmeMemoryStruct;
3837 pAd->Mlme.MemHandler.pInUseTail = pMlmeMemoryStruct;
3839 else
3841 pMlmeMemoryStruct->Next = NULL;
3842 pAd->Mlme.MemHandler.pInUseTail->Next = pMlmeMemoryStruct;
3843 pAd->Mlme.MemHandler.pInUseTail = pMlmeMemoryStruct;
3845 pAd->Mlme.MemHandler.InUseCount++;
3846 NdisAcquireSpinLock(&pAd->MemLock);
3847 pAd->Mlme.MemHandler.MemRunning = FALSE;
3848 NdisReleaseSpinLock(&pAd->MemLock);
3849 DBGPRINT(RT_DEBUG_INFO, "MlmeAllocateMemory [pMlmeMemoryStruct=0x%x][VA=0x%x]\n", (UINT)pMlmeMemoryStruct, (UINT)pMlmeMemoryStruct->AllocVa);
3850 DBGPRINT(RT_DEBUG_TRACE, "MlmeAlloc[IN:%d][UN:%d][Pend:%d]\n",
3851 pAd->Mlme.MemHandler.InUseCount, pAd->Mlme.MemHandler.UnUseCount, pAd->Mlme.MemHandler.PendingCount);
3853 return (Status);
3857 ========================================================================
3859 Routine Description:
3860 Allocates resident (nonpaged) system-space memory for MLME send frames
3862 Arguments:
3863 pAd Pointer to our adapter
3864 Number Total nonpaged memory for use
3865 Size Each nonpaged memory size
3867 Return Value:
3868 NDIS_STATUS_SUCCESS
3869 NDIS_STATUS_RESOURCES
3871 Note:
3873 ========================================================================
3875 NDIS_STATUS MlmeInitMemoryHandler(
3876 IN PRTMP_ADAPTER pAd,
3877 IN UINT Number,
3878 IN UINT Size)
3880 PMLME_MEMORY_STRUCT Current = NULL;
3881 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
3882 UINT i;
3884 DBGPRINT(RT_DEBUG_INFO, "==> MlmeInitMemory\n");
3885 pAd->Mlme.MemHandler.MemoryCount = 0;
3886 pAd->Mlme.MemHandler.pInUseHead = NULL;
3887 pAd->Mlme.MemHandler.pInUseTail = NULL;
3888 pAd->Mlme.MemHandler.pUnUseHead = NULL;
3889 pAd->Mlme.MemHandler.pUnUseTail = NULL;
3890 pAd->Mlme.MemHandler.MemRunning = FALSE;
3892 //initial the memory free-pending array all to NULL;
3893 for (i = 0; i < MAX_MLME_HANDLER_MEMORY; i++)
3894 pAd->Mlme.MemHandler.MemFreePending[i] = NULL;
3897 // Available nonpaged memory counts MAX_MLME_HANDLER_MEMORY
3899 if (Number > MAX_MLME_HANDLER_MEMORY)
3900 Number = MAX_MLME_HANDLER_MEMORY;
3902 for (i = 0; i < Number; i++)
3904 //Allocate a nonpaged memory for link list use.
3905 Current = kmalloc(sizeof(MLME_MEMORY_STRUCT), GFP_KERNEL);
3906 if (Current == NULL)
3908 Status = NDIS_STATUS_RESOURCES;
3909 break;
3912 //Allocate a nonpaged memory for mlme use, Current->AllocVa is VirtualAddress pointer
3913 Current->AllocVa = kmalloc(Size, GFP_KERNEL);
3914 if (Current->AllocVa == NULL)
3916 Status = NDIS_STATUS_RESOURCES;
3917 //Free the nonpaged memory of the current link list
3918 kfree((VOID *)Current);
3919 break;
3921 NdisZeroMemory(Current->AllocVa, Size);
3923 pAd->Mlme.MemHandler.MemoryCount++;
3925 //build up the link list
3926 if (pAd->Mlme.MemHandler.pUnUseHead != NULL)
3928 Current->Next = pAd->Mlme.MemHandler.pUnUseHead;
3929 pAd->Mlme.MemHandler.pUnUseHead = Current;
3931 else
3933 Current->Next = NULL;
3934 pAd->Mlme.MemHandler.pUnUseHead = Current;
3937 if (pAd->Mlme.MemHandler.pUnUseTail == NULL)
3938 pAd->Mlme.MemHandler.pUnUseTail = Current;
3942 if (pAd->Mlme.MemHandler.MemoryCount < Number)
3944 Status = NDIS_STATUS_RESOURCES;
3945 DBGPRINT(RT_DEBUG_TRACE, "MlmeInitMemory Initial failed [Require=%d, available=%d]\n", Number, pAd->Mlme.MemHandler.MemoryCount);
3948 pAd->Mlme.MemHandler.InUseCount = 0;
3949 pAd->Mlme.MemHandler.UnUseCount = Number;
3950 pAd->Mlme.MemHandler.PendingCount = 0;
3951 pAd->Mlme.MemHandler.PendingHead = 0;
3952 pAd->Mlme.MemHandler.PendingTail = 0;
3953 MlmePrintMemory(pAd);
3954 DBGPRINT(RT_DEBUG_INFO, "<== MlmeInitMemory\n");
3955 return (Status);
3958 void MlmePrintMemory(IN PRTMP_ADAPTER pAd)
3960 PMLME_MEMORY_STRUCT Current = NULL, Prev = NULL;
3961 UINT i;
3962 #if 0
3963 printk("UnH=0x%08X\n", pAd->Mlme.MemHandler.pUnUseHead);
3964 printk("UnT=0x%08X\n", pAd->Mlme.MemHandler.pUnUseTail);
3965 Current = pAd->Mlme.MemHandler.pUnUseHead;
3966 i=0;
3967 while (Current)
3969 printk("%d: 0x%08X\n", i, Current);
3970 printk("buf=0x%08X\n", Current->AllocVa);
3971 printk("next=0x%08X\n", Current->Next);
3972 Prev=Current;
3973 Current=Current->Next;
3974 i++;
3976 printk("UnUse=%d\n", i);
3978 printk("\n======\n");
3979 printk("InH=0x%08X\n", pAd->Mlme.MemHandler.pInUseHead);
3980 printk("InT=0x%08X\n", pAd->Mlme.MemHandler.pInUseTail);
3981 Current = pAd->Mlme.MemHandler.pInUseHead;
3982 i=0;
3983 while (Current)
3985 printk("%d: 0x%08X\n", i, Current);
3986 printk("buf=0x%08X\n", Current->AllocVa);
3987 printk("next=0x%08X\n", Current->Next);
3988 Prev=Current;
3989 Current=Current->Next;
3990 i++;
3992 printk("InUse=%d\n", i);
3994 printk("\n======\n");
3995 for (i=0; i<MAX_MLME_HANDLER_MEMORY; i++)
3997 printk("%2d: 0x%08X\n", i, pAd->Mlme.MemHandler.MemFreePending[i]);
3999 printk("PCnt=%d\n", pAd->Mlme.MemHandler.PendingCount);
4000 printk("PH=%d\n", pAd->Mlme.MemHandler.PendingHead);
4001 printk("PT=%d\n\n", pAd->Mlme.MemHandler.PendingTail);
4002 printk("\n======\n");
4003 #endif
4004 return;
4008 ========================================================================
4010 Routine Description:
4011 Free Mlme memory handler (link list, nonpaged memory, spin lock)
4013 Arguments:
4014 pAd Pointer to our adapter
4016 Return Value:
4017 None
4018 ========================================================================
4020 VOID MlmeFreeMemoryHandler(
4021 IN PRTMP_ADAPTER pAd)
4023 PMLME_MEMORY_STRUCT pMlmeMemoryStruct = NULL;
4025 //Free nonpaged memory, free it in the *In-used* link list.
4026 while (pAd->Mlme.MemHandler.pInUseHead != NULL)
4028 pMlmeMemoryStruct = pAd->Mlme.MemHandler.pInUseHead;
4029 pAd->Mlme.MemHandler.pInUseHead = pAd->Mlme.MemHandler.pInUseHead->Next;
4030 //Free the virtual address in AllocVa which size is MAX_LEN_OF_MLME_BUFFER
4031 kfree(pMlmeMemoryStruct->AllocVa);
4032 //Free the link list item self
4033 kfree(pMlmeMemoryStruct);
4036 //Free nonpaged memory, free it in the *Unused* link list.
4037 while (pAd->Mlme.MemHandler.pUnUseHead != NULL)
4039 pMlmeMemoryStruct = pAd->Mlme.MemHandler.pUnUseHead;
4040 pAd->Mlme.MemHandler.pUnUseHead = pAd->Mlme.MemHandler.pUnUseHead->Next;
4041 //Free the virtual address in AllocVa which size is MAX_LEN_OF_MLME_BUFFER
4042 kfree(pMlmeMemoryStruct->AllocVa);
4043 //Free the link list item self
4044 kfree(pMlmeMemoryStruct);