1 /****************************************************************************
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"
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
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 };
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}
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}
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
[] = {
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}
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}
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 ==========================================================================
249 initialize the MLME task and its data structure (queue, spinlock,
250 timer, state machines).
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
)
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
)
305 RTMPInitTimer(pAd
, &pAd
->PortCfg
.LedCntl
.BlinkTimer
, AsicLedPeriodicExec
);
307 RTMPSetTimer(pAd
, &pAd
->PortCfg
.LedCntl
.BlinkTimer
, 70);
310 // software-based RX Antenna diversity
311 RTMPInitTimer(pAd
, &pAd
->PortCfg
.RxAnt
.RxAntDiversityTimer
, AsicRxAntEvalTimeout
);
314 DBGPRINT(RT_DEBUG_TRACE
, "<-- MLME Initialize\n");
321 ==========================================================================
323 main loop of the MLME
325 Mlme has to be initialized, and there are something inside the queue
327 This function is invoked from MPSetInformation and MPReceive;
328 This task guarantee only one MlmeHandler will run.
329 ==========================================================================
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
);
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
);
363 case AUTH_STATE_MACHINE
:
364 StateMachinePerformAction(pAd
, &pAd
->Mlme
.AuthMachine
, Elem
);
366 case AUTH_RSP_STATE_MACHINE
:
367 StateMachinePerformAction(pAd
, &pAd
->Mlme
.AuthRspMachine
, Elem
);
369 case SYNC_STATE_MACHINE
:
370 StateMachinePerformAction(pAd
, &pAd
->Mlme
.SyncMachine
, Elem
);
372 case MLME_CNTL_STATE_MACHINE
:
373 MlmeCntlMachinePerformAction(pAd
, &pAd
->Mlme
.CntlMachine
, Elem
);
375 case WPA_PSK_STATE_MACHINE
:
376 StateMachinePerformAction(pAd
, &pAd
->Mlme
.WpaPskMachine
, Elem
);
379 DBGPRINT(RT_DEBUG_TRACE
, "ERROR: Illegal machine in MlmeHandler()\n");
384 Elem
->Occupied
= FALSE
;
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
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 ==========================================================================
403 Destructor of MLME (Destroy queue, state machine, spin lock and timer)
405 Adapter - NIC Adapter pointer
407 The MLME task will no longer work properly
408 ==========================================================================
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
);
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
);
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 ==========================================================================
478 This routine is executed periodically to -
479 1. Decide if it's a right time to turn on PwrMgmt bit of all
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
;
496 if (RTMP_TEST_FLAG(pAd
, fRTMP_ADAPTER_RADIO_OFF
))
498 RTMPSetTimer(pAd
, &pAd
->Mlme
.PeriodicTimer
, MLME_TASK_EXEC_INTV
);
502 if (RTMP_TEST_FLAG(pAd
, fRTMP_ADAPTER_RESET_IN_PROGRESS
))
504 RTMPSetTimer(pAd
, &pAd
->Mlme
.PeriodicTimer
, MLME_TASK_EXEC_INTV
);
510 if (pAd
->RalinkCounters
.MgmtRingFullCount
>= 2)
512 RTMP_SET_FLAG(pAd
, fRTMP_ADAPTER_HARDWARE_ERROR
);
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
);
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
)
535 else if ((pAd
->MediaState
== NdisMediaStateConnected
) && (pAd
->Mlme
.PeriodicRound
<= 20))
539 if (pAd
->MediaState
== NdisMediaStateConnected
)
541 // update channel quality for Roaming and UI LinkQuality display
542 MlmeCheckChannelQuality(pAd
, Now32
);
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
);
554 // perform dynamic tx rate switching based on past TX history
555 MlmeCheckDynamicTxRateSwitching(pAd
);
558 AsicAdjustTxPower(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
;
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
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
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
;
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
)
684 pAd
->PortCfg
.LastScanTime
= Now32
;
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");
700 if (RTMP_TEST_FLAG(pAd
, fRTMP_ADAPTER_INTERRUPT_ACTIVE
))
701 NICCheckForHang(pAd
);
703 RTMPSetTimer(pAd
, &pAd
->Mlme
.PeriodicTimer
, MLME_TASK_EXEC_INTV
);
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
,
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
,
746 sizeof(NDIS_802_11_SSID
),
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
,
771 sizeof(NDIS_802_11_SSID
),
776 DBGPRINT(RT_DEBUG_TRACE
, "pAd->Mlme.CntlMachine.CurrState=%d\n", pAd
->Mlme
.CntlMachine
.CurrState
); // Scott
780 ==========================================================================
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.
786 ==========================================================================
788 VOID
MlmeCheckForRoaming(
789 IN PRTMP_ADAPTER pAd
,
793 BSS_TABLE
*pBssTab
= &pAd
->Mlme
.CntlAux
.SsidBssTab
;
794 BSS_TABLE
*pRoamTab
= &pAd
->Mlme
.CntlAux
.RoamTab
;
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
);
836 ==========================================================================
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.
844 PortCfg.ChannelQuality - 0..100
845 ==========================================================================
847 VOID
MlmeCheckChannelQuality(
848 IN PRTMP_ADAPTER pAd
,
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
869 TxPER
= (TxFailCnt
* 100) / TxCnt
;
870 TxPRR
= ((TxRetryCnt
+ TxFailCnt
) * 100) / TxCnt
;
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
;
897 RxPER
= 0; // don't take RxPER into ChannelQuality consideration if too few sample
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
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 ==========================================================================
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}
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
;
955 BOOLEAN fUpgradeQuality
= FALSE
;
956 USHORT
*pRateUpPER
, *pRateDownPER
;
958 pAd
->DrsCounters
.CurrTxRateStableTime
++;
959 CurrRate
= pAd
->PortCfg
.TxRate
;
962 if (pAd
->PortCfg
.EnableAutoRateSwitching
== FALSE
)
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
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
);
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
];
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];
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
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):");
1091 DBGPRINT(RT_DEBUG_TRACE
,"DRS:");
1094 /*printk("Qty[%d]=%d PER=%d%% %d-sec, Qty[%d]=%d, Pty=%d\n",
1095 RateIdToMbps[CurrRate], pAd->DrsCounters.TxQuality[CurrRate],
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.
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
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
;
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))
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
))
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
;
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
&&
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
))
1186 if (DownRate
<= RATE_2
) break; // never goes lower than 5.5 Mbps TX rate
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
;
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
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;
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 ==========================================================================
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.
1249 1. change pAd->PortCfg.Psm to PWR_SAVE or leave it untouched
1250 ==========================================================================
1252 VOID
MlmeCheckForPsmChange(
1253 IN PRTMP_ADAPTER pAd
,
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
;
1281 IN PRTMP_ADAPTER pAd
,
1284 TXCSR7_STRUC txcsr7
;
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
);
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
;
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
,
1337 UCHAR Rate
, MaxDesire
= RATE_1
, MaxSupport
= RATE_1
;
1338 ULONG BasicRateBitmap
= 0;
1339 UCHAR CurrBasicRate
= RATE_1
;
1341 // find max desired rate
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
1376 pAd
->PortCfg
.EnableAutoRateSwitching
= FALSE
;
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;
1389 case 4: Rate
= RATE_2
;
1390 if (pAd
->PortCfg
.SupportedRates
[i
] & 0x80)
1391 BasicRateBitmap
|= 0x0002;
1395 if (pAd
->PortCfg
.SupportedRates
[i
] & 0x80)
1396 BasicRateBitmap
|= 0x0004;
1400 if (pAd
->PortCfg
.SupportedRates
[i
] & 0x80)
1401 BasicRateBitmap
|= 0x0008;
1405 // if (pAd->PortCfg.SupportedRates[i] & 0x80)
1406 BasicRateBitmap
|= 0x0010;
1410 if (pAd
->PortCfg
.SupportedRates
[i
] & 0x80)
1411 BasicRateBitmap
|= 0x0020;
1415 // if (pAd->PortCfg.SupportedRates[i] & 0x80)
1416 BasicRateBitmap
|= 0x0040;
1420 if (pAd
->PortCfg
.SupportedRates
[i
] & 0x80)
1421 BasicRateBitmap
|= 0x0080;
1425 // if (pAd->PortCfg.SupportedRates[i] & 0x80)
1426 BasicRateBitmap
|= 0x0100;
1430 if (pAd
->PortCfg
.SupportedRates
[i
] & 0x80)
1431 BasicRateBitmap
|= 0x0200;
1435 if (pAd
->PortCfg
.SupportedRates
[i
] & 0x80)
1436 BasicRateBitmap
|= 0x0400;
1440 if (pAd
->PortCfg
.SupportedRates
[i
] & 0x80)
1441 BasicRateBitmap
|= 0x0800;
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
;
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
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
1479 short dbm
= pAd
->PortCfg
.AvgRssi
- RSSI_TO_DBM_OFFSET
;
1480 if (bLinkUp
== TRUE
)
1481 pAd
->PortCfg
.TxRate
= RATE_24
;
1483 pAd
->PortCfg
.TxRate
= pAd
->PortCfg
.MaxTxRate
;
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
]);
1492 pAd
->PortCfg
.TxRate
= pAd
->PortCfg
.MaxTxRate
;
1494 switch (pAd
->PortCfg
.PhyMode
) {
1495 case PHY_11BG_MIXED
:
1497 pAd
->PortCfg
.MlmeRate
= RATE_2
;
1499 pAd
->PortCfg
.RtsRate
= RATE_11
;
1501 pAd
->PortCfg
.RtsRate
= RATE_2
;
1505 pAd
->PortCfg
.MlmeRate
= RATE_6
;
1506 pAd
->PortCfg
.RtsRate
= RATE_6
;
1508 case PHY_11ABG_MIXED
:
1509 if (pAd
->PortCfg
.Channel
<= 14)
1511 pAd
->PortCfg
.MlmeRate
= RATE_2
;
1512 pAd
->PortCfg
.RtsRate
= RATE_2
;
1516 pAd
->PortCfg
.MlmeRate
= RATE_6
;
1517 pAd
->PortCfg
.RtsRate
= RATE_6
;
1521 pAd
->PortCfg
.MlmeRate
= RATE_2
;
1522 pAd
->PortCfg
.RtsRate
= RATE_2
;
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
);
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
))
1543 RTMP_IO_WRITE32(pAd
, TXCSR0
, 0x08);
1545 RTMP_IO_WRITE32(pAd
, RXCSR0
, 0x01);
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
);
1559 IN PRTMP_ADAPTER pAd
)
1562 RTMP_IO_WRITE32(pAd
, PWRCSR0
, 0x3f3b3100);
1565 RTMP_IO_WRITE32(pAd
, TXCSR0
, 0x08);
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 // ===========================================================================================
1585 // ===========================================================================================
1588 /*! \brief initialize BSS table
1589 * \param p_tab pointer to the table
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
1612 * \note search by sequential search
1614 ULONG
BssTableSearch(
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
))
1628 return (ULONG
)BSS_NOT_FOUND
;
1631 VOID
BssTableDeleteEntry(
1632 IN OUT BSS_TABLE
*Tab
,
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
));
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};
1661 IN PRTMP_ADAPTER pAd
,
1662 OUT BSS_ENTRY
*pBss
,
1667 IN USHORT BeaconPeriod
,
1669 IN CF_PARM
*pCfParm
,
1671 IN USHORT CapabilityInfo
,
1674 IN BOOLEAN ExtendedRateIeExist
,
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
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
;
1696 pBss
->BssType
= BssType
;
1697 pBss
->BeaconPeriod
= BeaconPeriod
;
1698 if (BssType
== BSS_INFRA
)
1702 pBss
->CfpCount
= pCfParm
->CfpCount
;
1703 pBss
->CfpPeriod
= pCfParm
->CfpPeriod
;
1704 pBss
->CfpMaxDuration
= pCfParm
->CfpMaxDuration
;
1705 pBss
->CfpDurRemaining
= pCfParm
->CfpDurRemaining
;
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
;
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
);
1738 // No SSN ID, if security is on, this is WEP algorithm
1740 pBss
->WepStatus
= Ndis802_11WEPEnabled
;
1741 // No SSN ID, security is also off.
1743 pBss
->WepStatus
= Ndis802_11WEPDisabled
;
1748 * \brief insert an entry into the bss table
1749 * \param p_tab The BSS table
1750 * \param Bssid BSSID
1752 * \param ssid_len Length of SSID
1754 * \param beacon_period
1761 * \param channel_idx
1765 * \note If SSID is identical, the old entry will be replaced by the new one
1767 ULONG
BssTableSetEntry(
1768 IN PRTMP_ADAPTER pAd
,
1774 IN USHORT BeaconPeriod
,
1778 IN USHORT CapabilityInfo
,
1781 IN BOOLEAN ExtendedRateIeExist
,
1784 IN LARGE_INTEGER TimeStamp
,
1785 IN PNDIS_802_11_VARIABLE_IEs pVIE
)
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
;
1795 BssEntrySet(pAd
, &Tab
->BssEntry
[Idx
], Bssid
, Ssid
, SsidLen
, BssType
, BeaconPeriod
,
1796 CfExist
, CfParm
, AtimWin
, CapabilityInfo
, Rates
, RatesLen
, ExtendedRateIeExist
,
1797 ChannelNo
, Rssi
, TimeStamp
, pVIE
);
1802 BssEntrySet(pAd
, &Tab
->BssEntry
[Idx
], Bssid
, Ssid
, SsidLen
, BssType
, BeaconPeriod
,
1803 CfExist
, CfParm
, AtimWin
, CapabilityInfo
, Rates
, RatesLen
, ExtendedRateIeExist
,
1804 ChannelNo
, Rssi
, TimeStamp
, pVIE
);
1810 VOID
BssTableSsidSort(
1811 IN PRTMP_ADAPTER pAd
,
1812 OUT BSS_TABLE
*OutTab
,
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
)
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!!
1839 // copy matching BSS from InTab to OutTab
1840 NdisMoveMemory(pOutBss
, pInBss
, sizeof(BSS_ENTRY
));
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
)
1853 // copy matching BSS from InTab to OutTab
1854 NdisMoveMemory(pOutBss
, pInBss
, sizeof(BSS_ENTRY
));
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
)
1869 // copy matching BSS from InTab to OutTab
1870 NdisMoveMemory(pOutBss
, pInBss
, sizeof(BSS_ENTRY
));
1875 if (OutTab
->BssNr
>= MAX_LEN_OF_BSS_TABLE
)
1880 BssTableSortByRssi(OutTab
);
1883 VOID
BssTableSortByRssi(
1884 IN OUT BSS_TABLE
*OutTab
)
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(
1906 PBEACON_EID_STRUCT pEid
;
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
;
1925 if (*pTmp
== 4) // AES
1926 return (Ndis802_11Encryption3Enabled
);
1927 else if (*pTmp
== 2) // TKIP
1928 return (Ndis802_11Encryption2Enabled
);
1930 return (Ndis802_11WEPDisabled
);
1933 // ===========================================================================================
1935 // ===========================================================================================
1937 /*! \brief generates a random mac address value for IBSS BSSID
1938 * \param Addr the bssid location
1943 VOID
MacAddrRandomBssid(
1944 IN PRTMP_ADAPTER pAd
,
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
1962 * \pre the station has the following information in the pAd->PortCfg
1966 * \note this function initializes the following field
1968 VOID
MgtMacHeaderInit(
1969 IN PRTMP_ADAPTER pAd
,
1976 NdisZeroMemory(Hdr
, sizeof(MACHDR
));
1977 Hdr
->Type
= BTYPE_MGMT
;
1978 Hdr
->SubType
= Subtype
;
1980 COPY_MAC_ADDR(&Hdr
->Addr1
, Ds
);
1981 COPY_MAC_ADDR(&Hdr
->Addr2
, &pAd
->CurrentAddress
);
1982 COPY_MAC_ADDR(&Hdr
->Addr3
, Bssid
);
1985 // ===========================================================================================
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
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!!!
1999 * Size of the buffer
2001 * MakeOutgoingFrame(Buffer, output_length, 2, &fc, 2, &dur, 6, p_addr1, 6,p_addr2, END_OF_ARGS);
2002 ****************************************************************************/
2003 ULONG
MakeOutgoingFrame(
2005 OUT ULONG
*FrameLen
, ...)
2012 // calculates the total length
2014 va_start(Args
, FrameLen
);
2017 leng
= va_arg(Args
, int);
2018 if (leng
== END_OF_ARGS
)
2022 p
= va_arg(Args
, PVOID
);
2023 NdisMoveMemory(&Buffer
[TotLeng
], p
, leng
);
2024 TotLeng
= TotLeng
+ leng
;
2027 va_end(Args
); /* clean up */
2028 *FrameLen
= TotLeng
;
2032 // ===========================================================================================
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
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
)
2048 NdisAllocateSpinLock(&Queue
->Lock
);
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
2075 * \note The message has to be initialized
2077 BOOLEAN
MlmeEnqueue(
2078 OUT MLME_QUEUE
*Queue
,
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
);
2094 if (MlmeQueueFull(Queue
))
2096 DBGPRINT(RT_DEBUG_ERROR
, "MlmeEnqueue full, msg dropped and may corrupt MLME\n");
2100 NdisAcquireSpinLock(&(Queue
->Lock
));
2104 if (Queue
->Tail
== MAX_LEN_OF_MLME_QUEUE
)
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
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)
2130 BOOLEAN
MlmeEnqueueForRecv(
2131 IN PRTMP_ADAPTER pAd
,
2132 OUT MLME_QUEUE
*Queue
,
2133 IN ULONG TimeStampHigh
,
2134 IN ULONG TimeStampLow
,
2140 MACFRAME
*Fr
= (MACFRAME
*)Msg
;
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
);
2151 if (MlmeQueueFull(Queue
))
2153 DBGPRINT(RT_DEBUG_ERROR
, "MlmeEnqueueForRecv (queue full error) \n");
2157 if (!MsgTypeSubst(Fr
, &Machine
, &MsgType
))
2159 DBGPRINT(RT_DEBUG_ERROR
, "MlmeEnqueueForRecv (drop mgmt->subtype=%d)\n",Fr
->Hdr
.SubType
);
2163 // OK, we got all the informations, it is time to put things into queue
2164 NdisAcquireSpinLock(&(Queue
->Lock
));
2168 if (Queue
->Tail
== MAX_LEN_OF_MLME_QUEUE
)
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
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
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
]);
2207 if (Queue
->Head
== MAX_LEN_OF_MLME_QUEUE
)
2211 NdisReleaseSpinLock(&(Queue
->Lock
));
2212 DBGPRINT(RT_DEBUG_INFO
, "MlmeDequeue, num=%d\n",Queue
->Num
);
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
);
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
;
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
2287 BOOLEAN
MlmeQueueEmpty(
2288 IN MLME_QUEUE
*Queue
)
2291 unsigned long IrqFlags
;
2293 NdisAcquireSpinLock(&(Queue
->Lock
));
2294 Ans
= (Queue
->Num
== 0);
2295 NdisReleaseSpinLock(&(Queue
->Lock
));
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
2306 BOOLEAN
MlmeQueueFull(
2307 IN MLME_QUEUE
*Queue
)
2310 unsigned long IrqFlags
;
2312 NdisAcquireSpinLock(&(Queue
->Lock
));
2313 Ans
= (Queue
->Num
== MAX_LEN_OF_MLME_QUEUE
);
2314 NdisReleaseSpinLock(&(Queue
->Lock
));
2319 /*! \brief The destructor of MLME Queue
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
));
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
2346 BOOLEAN
MsgTypeSubst(
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
;
2368 case SUBTYPE_ASSOC_RSP
:
2369 *Machine
= ASSOC_STATE_MACHINE
;
2370 *MsgType
= MT2_PEER_ASSOC_RSP
;
2372 case SUBTYPE_REASSOC_REQ
:
2373 *Machine
= ASSOC_STATE_MACHINE
;
2374 *MsgType
= MT2_PEER_REASSOC_REQ
;
2376 case SUBTYPE_REASSOC_RSP
:
2377 *Machine
= ASSOC_STATE_MACHINE
;
2378 *MsgType
= MT2_PEER_REASSOC_RSP
;
2380 case SUBTYPE_PROBE_REQ
:
2381 *Machine
= SYNC_STATE_MACHINE
;
2382 *MsgType
= MT2_PEER_PROBE_REQ
;
2384 case SUBTYPE_PROBE_RSP
:
2385 *Machine
= SYNC_STATE_MACHINE
;
2386 *MsgType
= MT2_PEER_PROBE_RSP
;
2388 case SUBTYPE_BEACON
:
2389 *Machine
= SYNC_STATE_MACHINE
;
2390 *MsgType
= MT2_PEER_BEACON
;
2393 *Machine
= SYNC_STATE_MACHINE
;
2394 *MsgType
= MT2_PEER_ATIM
;
2396 case SUBTYPE_DISASSOC
:
2397 *Machine
= ASSOC_STATE_MACHINE
;
2398 *MsgType
= MT2_PEER_DISASSOC_REQ
;
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
;
2418 case SUBTYPE_DEAUTH
:
2419 *Machine
= AUTH_RSP_STATE_MACHINE
;
2420 *MsgType
= MT2_PEER_DEAUTH
;
2430 // ===========================================================================================
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
2446 VOID
StateMachineInit(
2447 IN STATE_MACHINE
*S
,
2448 IN STATE_MACHINE_FUNC Trans
[],
2451 IN STATE_MACHINE_FUNC DefFunc
,
2457 // set number of states and messages
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
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
2486 VOID
StateMachineSetAction(
2487 IN STATE_MACHINE
*S
,
2490 IN STATE_MACHINE_FUNC Func
)
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
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
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 ==========================================================================
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 ==========================================================================
2536 IN PRTMP_ADAPTER pAd
,
2537 IN MLME_QUEUE_ELEM
*Elem
)
2540 if ((Elem
->MsgType
== MT2_PEER_BEACON
) ||
2541 (Elem
->MsgType
== MT2_PEER_PROBE_REQ
) ||
2542 (Elem
->MsgType
== MT2_PEER_PROBE_RSP
))
2546 DBGPRINT(RT_DEBUG_TRACE
, ("Warn:>>Drop Msg=%d<<\n",Elem
->MsgType
));
2551 // ===========================================================================================
2553 // ===========================================================================================
2556 ==========================================================================
2558 ==========================================================================
2561 IN PRTMP_ADAPTER pAd
,
2565 pAd
->Mlme
.ShiftReg
= 1;
2567 pAd
->Mlme
.ShiftReg
= Seed
;
2571 ==========================================================================
2573 ==========================================================================
2576 IN PRTMP_ADAPTER pAd
)
2583 for (i
= 0; i
< 8; i
++)
2585 if (pAd
->Mlme
.ShiftReg
& 0x00000001)
2587 pAd
->Mlme
.ShiftReg
= ((pAd
->Mlme
.ShiftReg
^ LFSR_MASK
) >> 1) | 0x80000000;
2592 pAd
->Mlme
.ShiftReg
= pAd
->Mlme
.ShiftReg
>> 1;
2595 R
= (R
<< 1) | Result
;
2602 ==========================================================================
2604 ==========================================================================
2606 VOID
AsicSwitchChannel(
2607 IN PRTMP_ADAPTER pAd
,
2613 // TODO: need to update E2PROM format to add 802.11a channel's TX power calibration values
2615 R3
= pAd
->PortCfg
.ChannelTxPower
[Channel
- 1];
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
2627 else if (pAd
->PortCfg
.TxPowerPercentage
> 30) // 31 ~ 60%, treat as 50% in terms of mW
2629 else if (pAd
->PortCfg
.TxPowerPercentage
> 15) // 16 ~ 30%, treat as 25% in terms of mW
2631 else if (pAd
->PortCfg
.TxPowerPercentage
> 9) // 10 ~ 15%, treat as 12.5% in terms of mW
2633 else // 0 ~ 9 %, treat as 6.25% in terms of mW
2636 R3
= R3
<< 9; // shift TX power control to correct RF R3 bit position
2638 switch (pAd
->PortCfg
.RfType
)
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
;
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
;
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
;
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
;
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
;
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
;
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 ==========================================================================
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
,
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
);
2802 // Scott:2004-11-29 r70 |= 0x08; // turn on Japan filter bit
2803 r70
= 0x4E; // turn on Japan filter bit
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
)
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
);
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
);
2844 ==========================================================================
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
;
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
))
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.
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
2925 R3
= (R3
< (ULONG
) (TxPowerRef
+ 5)) ? (R3
+ 1) : R3
;
2928 DBGPRINT(RT_DEBUG_INFO
,"TSSI(R1)=%d, ++TxPwr=%d\n", R1
, R3
);
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
2948 else if (pAd
->PortCfg
.TxPowerPercentage
> 30) // 31 ~ 60%, treat as 50% in terms of mW
2950 else if (pAd
->PortCfg
.TxPowerPercentage
> 15) // 16 ~ 30%, treat as 25% in terms of mW
2952 else if (pAd
->PortCfg
.TxPowerPercentage
> 9) // 10 ~ 15%, treat as 12.5% in terms of mW
2954 else // 0 ~ 9 %, treat as MIN(~3%) in terms of mW
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
)
2962 if (R3
> 31) R3
= 31;
2966 // compare the desired R3.TxPwr value with current R3, if not equal
2968 CurrTxPwr
= (pAd
->PortCfg
.LatchRfRegs
.R3
>> 9) & 0x0000001f;
2969 if (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 ==========================================================================
2983 put PHY to sleep here, and set next wakeup timer
2984 ==========================================================================
2986 VOID
AsicSleepThenAutoWakeup(
2987 IN PRTMP_ADAPTER pAd
,
2988 IN USHORT TbttNumToNextWakeUp
)
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
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
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 ==========================================================================
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");
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
)
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
3052 Csr20
.field
.AutoWake
= 0;
3053 RTMP_IO_WRITE32(pAd
, CSR20
, Csr20
.word
);
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 ==========================================================================
3067 ==========================================================================
3070 IN PRTMP_ADAPTER pAd
,
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 ==========================================================================
3088 ==========================================================================
3090 VOID
AsicDisableSync(
3091 IN PRTMP_ADAPTER pAd
)
3093 // TIMECSR_STRUC TimeCsr;
3094 DBGPRINT(RT_DEBUG_TRACE
, "--->Disable TSF synchronization\n");
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);
3100 RTMP_IO_WRITE32(pAd
, CSR14
, 0x00000000);
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
);
3116 ==========================================================================
3118 ==========================================================================
3120 VOID
AsicEnableBssSync(
3121 IN PRTMP_ADAPTER pAd
)
3126 BCNCSR1_STRUC Bcncsr1
;
3129 DBGPRINT(RT_DEBUG_TRACE
, "--->AsicEnableBssSync(INFRA mode)\n");
3131 RTMP_IO_WRITE32(pAd
, CSR14
, 0x00000000);
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
);
3139 Csr13
.field
.CfpPeriod
= pAd
->PortCfg
.CfpDurRemain
<< 4; // ASIC register in units of 1/16 TU
3140 RTMP_IO_WRITE32(pAd
, CSR13
, Csr13
.word
);
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
3152 Csr14
.field
.TsfCount
= 1;
3153 Csr14
.field
.TsfSync
= 1; // sync TSF in INFRASTRUCTURE mode
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 ==========================================================================
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
3173 ==========================================================================
3175 VOID
AsicEnableIbssSync(
3176 IN PRTMP_ADAPTER pAd
)
3181 // BCNCSR_STRUC Bcncsr;
3182 BCNCSR1_STRUC Bcncsr1
;
3184 DBGPRINT(RT_DEBUG_TRACE
, "--->AsicEnableIbssSync(ADHOC mode)\n");
3186 RTMP_IO_WRITE32(pAd
, CSR14
, 0x00000000);
3189 Csr12
.field
.BeaconInterval
= pAd
->PortCfg
.BeaconPeriod
<< 4; // ASIC register in units of 1/16 TU
3190 RTMP_IO_WRITE32(pAd
, CSR12
, Csr12
.word
);
3193 Csr13
.field
.AtimwDuration
= pAd
->PortCfg
.AtimWin
<< 4; // ASIC register in units of 1/16 TU
3194 RTMP_IO_WRITE32(pAd
, CSR13
, Csr13
.word
);
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]);
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
);
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
3244 IN PRTMP_ADAPTER pAd
)
3246 UCHAR RxValue
, TxValue
;
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
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;
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
;
3305 if (pAd
->PortCfg
.CurrentRxAntenna
!= 0xff)
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;
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);
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
)
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
]))
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]);
3366 UCHAR RxValue
, TxValue
;
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;
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 ==========================================================================
3400 ==========================================================================
3402 VOID
AsicSetSlotTime(
3403 IN PRTMP_ADAPTER pAd
,
3404 IN BOOLEAN UseShortSlotTime
)
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
;
3422 RTMP_IO_READ32(pAd
, CSR11
, &Csr11
.word
);
3423 if (PhyMode
== PHY_11A
)
3424 Csr11
.field
.SlotTime
= 9;
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
);
3434 Csr19
.field
.DIFS
= Csr18
.field
.PIFS
+ Csr11
.field
.SlotTime
;
3435 if (PhyMode
== PHY_11B
)
3436 Csr19
.field
.EIFS
= 364; // SIFS + ACK @1Mbps
3438 Csr19
.field
.EIFS
= 60; // roughly = SIFS + ACK @6Mbps
3439 RTMP_IO_WRITE32(pAd
, CSR19
, Csr19
.word
);
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
);
3451 ==========================================================================
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)
3468 else if (pAd
->PortCfg
.PciAdjustmentRound
== 1)
3470 else if (pAd
->PortCfg
.PciAdjustmentRound
== 2)
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 ==========================================================================
3486 danamic tune BBP R17 to find a balance between sensibility and
3488 ==========================================================================
3491 IN PRTMP_ADAPTER pAd
)
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))
3501 R17
= pAd
->PortCfg
.BbpWriteLatch
[17];
3503 if ((pAd
->PortCfg
.Rt2560Version
>= RT2560_VER_D
) &&
3504 (pAd
->MediaState
== NdisMediaStateConnected
))
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
);
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
);
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
);
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
);
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
)
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
3603 pAd Pointer to our adapter
3604 AllocVa Pointer to the base virtual address for free
3611 ========================================================================
3613 VOID
MlmeFreeMemory(
3614 IN PRTMP_ADAPTER pAd
,
3617 PMLME_MEMORY_STRUCT pPrevious
= NULL
;
3618 PMLME_MEMORY_STRUCT pMlmeMemoryStruct
= NULL
;
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
);
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
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
;
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
;
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
);
3693 pPrevious
= pMlmeMemoryStruct
;
3694 pMlmeMemoryStruct
= pMlmeMemoryStruct
->Next
;
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
);
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!
3717 pMlmeMemoryStruct
= pAd
->Mlme
.MemHandler
.pInUseHead
;
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
;
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
;
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
);
3752 pPrevious
= pMlmeMemoryStruct
;
3753 pMlmeMemoryStruct
= pMlmeMemoryStruct
->Next
;
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
3777 pAd Pointer to our adapter
3778 AllocVa Pointer to the base virtual address for later use
3783 NDIS_STATUS_RESOURCES
3787 ========================================================================
3789 NDIS_STATUS
MlmeAllocateMemory(
3790 IN PRTMP_ADAPTER pAd
,
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
);
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");
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
;
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
);
3857 ========================================================================
3859 Routine Description:
3860 Allocates resident (nonpaged) system-space memory for MLME send frames
3863 pAd Pointer to our adapter
3864 Number Total nonpaged memory for use
3865 Size Each nonpaged memory size
3869 NDIS_STATUS_RESOURCES
3873 ========================================================================
3875 NDIS_STATUS
MlmeInitMemoryHandler(
3876 IN PRTMP_ADAPTER pAd
,
3880 PMLME_MEMORY_STRUCT Current
= NULL
;
3881 NDIS_STATUS Status
= NDIS_STATUS_SUCCESS
;
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
;
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
);
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
;
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");
3958 void MlmePrintMemory(IN PRTMP_ADAPTER pAd
)
3960 PMLME_MEMORY_STRUCT Current
= NULL
, Prev
= NULL
;
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
;
3969 printk("%d: 0x%08X\n", i
, Current
);
3970 printk("buf=0x%08X\n", Current
->AllocVa
);
3971 printk("next=0x%08X\n", Current
->Next
);
3973 Current
=Current
->Next
;
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
;
3985 printk("%d: 0x%08X\n", i
, Current
);
3986 printk("buf=0x%08X\n", Current
->AllocVa
);
3987 printk("next=0x%08X\n", Current
->Next
);
3989 Current
=Current
->Next
;
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");
4008 ========================================================================
4010 Routine Description:
4011 Free Mlme memory handler (link list, nonpaged memory, spin lock)
4014 pAd Pointer to our adapter
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
);