Commit | Line | Data |
---|---|---|
c55519ff GKH |
1 | /* |
2 | ************************************************************************* | |
3 | * Ralink Tech Inc. | |
4 | * 5F., No.36, Taiyuan St., Jhubei City, | |
5 | * Hsinchu County 302, | |
6 | * Taiwan, R.O.C. | |
7 | * | |
8 | * (c) Copyright 2002-2007, Ralink Technology, Inc. | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify * | |
11 | * it under the terms of the GNU General Public License as published by * | |
12 | * the Free Software Foundation; either version 2 of the License, or * | |
13 | * (at your option) any later version. * | |
14 | * * | |
15 | * This program is distributed in the hope that it will be useful, * | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | |
18 | * GNU General Public License for more details. * | |
19 | * * | |
20 | * You should have received a copy of the GNU General Public License * | |
21 | * along with this program; if not, write to the * | |
22 | * Free Software Foundation, Inc., * | |
23 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * | |
24 | * * | |
25 | ************************************************************************* | |
26 | */ | |
ca97b838 | 27 | |
c55519ff GKH |
28 | /* |
29 | All functions in this file must be USB-depended, or you should out your function | |
30 | in other files. | |
31 | ||
32 | */ | |
ca97b838 BZ |
33 | |
34 | #ifdef RTMP_MAC_USB | |
35 | ||
ca97b838 | 36 | #include "../rt_config.h" |
c55519ff | 37 | |
c55519ff GKH |
38 | /* |
39 | We can do copy the frame into pTxContext when match following conditions. | |
40 | => | |
41 | => | |
42 | => | |
43 | */ | |
62eb734b | 44 | static inline int RtmpUSBCanDoWrite(struct rt_rtmp_adapter *pAd, |
51126deb | 45 | u8 QueIdx, |
62eb734b | 46 | struct rt_ht_tx_context *pHTTXContext) |
c55519ff | 47 | { |
51126deb | 48 | int canWrite = NDIS_STATUS_RESOURCES; |
96b3c83d BZ |
49 | |
50 | if (((pHTTXContext->CurWritePosition) < | |
51 | pHTTXContext->NextBulkOutPosition) | |
52 | && (pHTTXContext->CurWritePosition + LOCAL_TXBUF_SIZE) > | |
53 | pHTTXContext->NextBulkOutPosition) { | |
54 | DBGPRINT(RT_DEBUG_ERROR, ("RtmpUSBCanDoWrite c1!\n")); | |
55 | RTUSB_SET_BULK_FLAG(pAd, | |
56 | (fRTUSB_BULK_OUT_DATA_NORMAL << QueIdx)); | |
57 | } else if ((pHTTXContext->CurWritePosition == 8) | |
58 | && (pHTTXContext->NextBulkOutPosition < LOCAL_TXBUF_SIZE)) { | |
59 | DBGPRINT(RT_DEBUG_ERROR, ("RtmpUSBCanDoWrite c2!\n")); | |
60 | RTUSB_SET_BULK_FLAG(pAd, | |
61 | (fRTUSB_BULK_OUT_DATA_NORMAL << QueIdx)); | |
62 | } else if (pHTTXContext->bCurWriting == TRUE) { | |
63 | DBGPRINT(RT_DEBUG_ERROR, ("RtmpUSBCanDoWrite c3!\n")); | |
64 | } else { | |
c55519ff GKH |
65 | canWrite = NDIS_STATUS_SUCCESS; |
66 | } | |
67 | ||
c55519ff GKH |
68 | return canWrite; |
69 | } | |
70 | ||
62eb734b BZ |
71 | u16 RtmpUSB_WriteSubTxResource(struct rt_rtmp_adapter *pAd, |
72 | struct rt_tx_blk *pTxBlk, | |
51126deb | 73 | IN BOOLEAN bIsLast, u16 * FreeNumber) |
c55519ff GKH |
74 | { |
75 | ||
ec278fa2 | 76 | /* Dummy function. Should be removed in the future. */ |
c55519ff GKH |
77 | return 0; |
78 | ||
79 | } | |
80 | ||
62eb734b BZ |
81 | u16 RtmpUSB_WriteFragTxResource(struct rt_rtmp_adapter *pAd, |
82 | struct rt_tx_blk *pTxBlk, | |
51126deb | 83 | u8 fragNum, u16 * FreeNumber) |
c55519ff | 84 | { |
62eb734b | 85 | struct rt_ht_tx_context *pHTTXContext; |
51126deb BZ |
86 | u16 hwHdrLen; /* The hwHdrLen consist of 802.11 header length plus the header padding length. */ |
87 | u32 fillOffset; | |
62eb734b BZ |
88 | struct rt_txinfo *pTxInfo; |
89 | struct rt_txwi *pTxWI; | |
51126deb BZ |
90 | u8 *pWirelessPacket = NULL; |
91 | u8 QueIdx; | |
92 | int Status; | |
96b3c83d | 93 | unsigned long IrqFlags; |
51126deb | 94 | u32 USBDMApktLen = 0, DMAHdrLen, padding; |
96b3c83d | 95 | BOOLEAN TxQLastRound = FALSE; |
c55519ff | 96 | |
ec278fa2 BZ |
97 | /* */ |
98 | /* get Tx Ring Resource & Dma Buffer address */ | |
99 | /* */ | |
c55519ff | 100 | QueIdx = pTxBlk->QueIdx; |
96b3c83d | 101 | pHTTXContext = &pAd->TxContext[QueIdx]; |
c55519ff GKH |
102 | |
103 | RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); | |
104 | ||
96b3c83d | 105 | pHTTXContext = &pAd->TxContext[QueIdx]; |
c55519ff GKH |
106 | fillOffset = pHTTXContext->CurWritePosition; |
107 | ||
96b3c83d | 108 | if (fragNum == 0) { |
ec278fa2 | 109 | /* Check if we have enough space for this bulk-out batch. */ |
c55519ff | 110 | Status = RtmpUSBCanDoWrite(pAd, QueIdx, pHTTXContext); |
96b3c83d | 111 | if (Status == NDIS_STATUS_SUCCESS) { |
c55519ff GKH |
112 | pHTTXContext->bCurWriting = TRUE; |
113 | ||
ec278fa2 | 114 | /* Reserve space for 8 bytes padding. */ |
96b3c83d BZ |
115 | if ((pHTTXContext->ENextBulkOutPosition == |
116 | pHTTXContext->CurWritePosition)) { | |
c55519ff GKH |
117 | pHTTXContext->ENextBulkOutPosition += 8; |
118 | pHTTXContext->CurWritePosition += 8; | |
119 | fillOffset += 8; | |
120 | } | |
121 | pTxBlk->Priv = 0; | |
96b3c83d BZ |
122 | pHTTXContext->CurWriteRealPos = |
123 | pHTTXContext->CurWritePosition; | |
124 | } else { | |
125 | RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], | |
126 | IrqFlags); | |
127 | ||
128 | RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, | |
129 | NDIS_STATUS_FAILURE); | |
130 | return (Status); | |
c55519ff | 131 | } |
96b3c83d | 132 | } else { |
ec278fa2 | 133 | /* For sub-sequent frames of this bulk-out batch. Just copy it to our bulk-out buffer. */ |
96b3c83d BZ |
134 | Status = |
135 | ((pHTTXContext->bCurWriting == | |
136 | TRUE) ? NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE); | |
137 | if (Status == NDIS_STATUS_SUCCESS) { | |
c55519ff | 138 | fillOffset += pTxBlk->Priv; |
96b3c83d BZ |
139 | } else { |
140 | RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], | |
141 | IrqFlags); | |
c55519ff | 142 | |
96b3c83d BZ |
143 | RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, |
144 | NDIS_STATUS_FAILURE); | |
145 | return (Status); | |
c55519ff GKH |
146 | } |
147 | } | |
148 | ||
51126deb | 149 | NdisZeroMemory((u8 *)(&pTxBlk->HeaderBuf[0]), TXINFO_SIZE); |
62eb734b BZ |
150 | pTxInfo = (struct rt_txinfo *)(&pTxBlk->HeaderBuf[0]); |
151 | pTxWI = (struct rt_txwi *) (&pTxBlk->HeaderBuf[TXINFO_SIZE]); | |
c55519ff | 152 | |
96b3c83d BZ |
153 | pWirelessPacket = |
154 | &pHTTXContext->TransferBuffer->field.WirelessPacket[fillOffset]; | |
c55519ff | 155 | |
ec278fa2 BZ |
156 | /* copy TXWI + WLAN Header + LLC into DMA Header Buffer */ |
157 | /*hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4); */ | |
c55519ff GKH |
158 | hwHdrLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen; |
159 | ||
ec278fa2 | 160 | /* Build our URB for USBD */ |
c55519ff GKH |
161 | DMAHdrLen = TXWI_SIZE + hwHdrLen; |
162 | USBDMApktLen = DMAHdrLen + pTxBlk->SrcBufLen; | |
ec278fa2 | 163 | padding = (4 - (USBDMApktLen % 4)) & 0x03; /* round up to 4 byte alignment */ |
c55519ff GKH |
164 | USBDMApktLen += padding; |
165 | ||
166 | pTxBlk->Priv += (TXINFO_SIZE + USBDMApktLen); | |
167 | ||
ec278fa2 | 168 | /* For TxInfo, the length of USBDMApktLen = TXWI_SIZE + 802.11 header + payload */ |
51126deb | 169 | RTMPWriteTxInfo(pAd, pTxInfo, (u16)(USBDMApktLen), FALSE, FIFO_EDCA, |
96b3c83d | 170 | FALSE /*NextValid */ , FALSE); |
c55519ff | 171 | |
96b3c83d | 172 | if (fragNum == pTxBlk->TotalFragNum) { |
c55519ff | 173 | pTxInfo->USBDMATxburst = 0; |
96b3c83d BZ |
174 | if ((pHTTXContext->CurWritePosition + pTxBlk->Priv + 3906) > |
175 | MAX_TXBULK_LIMIT) { | |
c55519ff GKH |
176 | pTxInfo->SwUseLastRound = 1; |
177 | TxQLastRound = TRUE; | |
178 | } | |
96b3c83d | 179 | } else { |
c55519ff GKH |
180 | pTxInfo->USBDMATxburst = 1; |
181 | } | |
182 | ||
96b3c83d BZ |
183 | NdisMoveMemory(pWirelessPacket, pTxBlk->HeaderBuf, |
184 | TXINFO_SIZE + TXWI_SIZE + hwHdrLen); | |
c55519ff GKH |
185 | pWirelessPacket += (TXINFO_SIZE + TXWI_SIZE + hwHdrLen); |
186 | pHTTXContext->CurWriteRealPos += (TXINFO_SIZE + TXWI_SIZE + hwHdrLen); | |
187 | ||
188 | RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); | |
189 | ||
190 | NdisMoveMemory(pWirelessPacket, pTxBlk->pSrcBufData, pTxBlk->SrcBufLen); | |
191 | ||
ec278fa2 | 192 | /* Zero the last padding. */ |
c55519ff GKH |
193 | pWirelessPacket += pTxBlk->SrcBufLen; |
194 | NdisZeroMemory(pWirelessPacket, padding + 8); | |
195 | ||
96b3c83d | 196 | if (fragNum == pTxBlk->TotalFragNum) { |
c55519ff GKH |
197 | RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); |
198 | ||
ec278fa2 | 199 | /* Update the pHTTXContext->CurWritePosition. 3906 used to prevent the NextBulkOut is a A-RALINK/A-MSDU Frame. */ |
c55519ff GKH |
200 | pHTTXContext->CurWritePosition += pTxBlk->Priv; |
201 | if (TxQLastRound == TRUE) | |
202 | pHTTXContext->CurWritePosition = 8; | |
203 | pHTTXContext->CurWriteRealPos = pHTTXContext->CurWritePosition; | |
204 | ||
ec278fa2 | 205 | /* Finally, set bCurWriting as FALSE */ |
96b3c83d | 206 | pHTTXContext->bCurWriting = FALSE; |
c55519ff GKH |
207 | |
208 | RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); | |
209 | ||
ec278fa2 | 210 | /* succeed and release the skb buffer */ |
c55519ff GKH |
211 | RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_SUCCESS); |
212 | } | |
213 | ||
96b3c83d | 214 | return (Status); |
c55519ff GKH |
215 | |
216 | } | |
217 | ||
62eb734b BZ |
218 | u16 RtmpUSB_WriteSingleTxResource(struct rt_rtmp_adapter *pAd, |
219 | struct rt_tx_blk *pTxBlk, | |
96b3c83d | 220 | IN BOOLEAN bIsLast, |
51126deb | 221 | u16 * FreeNumber) |
c55519ff | 222 | { |
62eb734b | 223 | struct rt_ht_tx_context *pHTTXContext; |
51126deb BZ |
224 | u16 hwHdrLen; |
225 | u32 fillOffset; | |
62eb734b BZ |
226 | struct rt_txinfo *pTxInfo; |
227 | struct rt_txwi *pTxWI; | |
51126deb BZ |
228 | u8 *pWirelessPacket; |
229 | u8 QueIdx; | |
96b3c83d | 230 | unsigned long IrqFlags; |
51126deb BZ |
231 | int Status; |
232 | u32 USBDMApktLen = 0, DMAHdrLen, padding; | |
96b3c83d | 233 | BOOLEAN bTxQLastRound = FALSE; |
c55519ff | 234 | |
ec278fa2 BZ |
235 | /* For USB, didn't need PCI_MAP_SINGLE() */ |
236 | /*SrcBufPA = PCI_MAP_SINGLE(pAd, (char *) pTxBlk->pSrcBufData, pTxBlk->SrcBufLen, PCI_DMA_TODEVICE); */ | |
c55519ff | 237 | |
ec278fa2 BZ |
238 | /* */ |
239 | /* get Tx Ring Resource & Dma Buffer address */ | |
240 | /* */ | |
c55519ff GKH |
241 | QueIdx = pTxBlk->QueIdx; |
242 | ||
243 | RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); | |
96b3c83d | 244 | pHTTXContext = &pAd->TxContext[QueIdx]; |
c55519ff GKH |
245 | fillOffset = pHTTXContext->CurWritePosition; |
246 | ||
ec278fa2 | 247 | /* Check ring full. */ |
c55519ff | 248 | Status = RtmpUSBCanDoWrite(pAd, QueIdx, pHTTXContext); |
96b3c83d | 249 | if (Status == NDIS_STATUS_SUCCESS) { |
c55519ff GKH |
250 | pHTTXContext->bCurWriting = TRUE; |
251 | ||
62eb734b BZ |
252 | pTxInfo = (struct rt_txinfo *)(&pTxBlk->HeaderBuf[0]); |
253 | pTxWI = (struct rt_txwi *) (&pTxBlk->HeaderBuf[TXINFO_SIZE]); | |
c55519ff | 254 | |
ec278fa2 | 255 | /* Reserve space for 8 bytes padding. */ |
96b3c83d BZ |
256 | if ((pHTTXContext->ENextBulkOutPosition == |
257 | pHTTXContext->CurWritePosition)) { | |
c55519ff GKH |
258 | pHTTXContext->ENextBulkOutPosition += 8; |
259 | pHTTXContext->CurWritePosition += 8; | |
260 | fillOffset += 8; | |
261 | } | |
262 | pHTTXContext->CurWriteRealPos = pHTTXContext->CurWritePosition; | |
263 | ||
96b3c83d BZ |
264 | pWirelessPacket = |
265 | &pHTTXContext->TransferBuffer->field. | |
266 | WirelessPacket[fillOffset]; | |
c55519ff | 267 | |
ec278fa2 BZ |
268 | /* copy TXWI + WLAN Header + LLC into DMA Header Buffer */ |
269 | /*hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4); */ | |
c55519ff GKH |
270 | hwHdrLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen; |
271 | ||
ec278fa2 | 272 | /* Build our URB for USBD */ |
c55519ff GKH |
273 | DMAHdrLen = TXWI_SIZE + hwHdrLen; |
274 | USBDMApktLen = DMAHdrLen + pTxBlk->SrcBufLen; | |
ec278fa2 | 275 | padding = (4 - (USBDMApktLen % 4)) & 0x03; /* round up to 4 byte alignment */ |
c55519ff GKH |
276 | USBDMApktLen += padding; |
277 | ||
278 | pTxBlk->Priv = (TXINFO_SIZE + USBDMApktLen); | |
279 | ||
ec278fa2 | 280 | /* For TxInfo, the length of USBDMApktLen = TXWI_SIZE + 802.11 header + payload */ |
51126deb | 281 | RTMPWriteTxInfo(pAd, pTxInfo, (u16)(USBDMApktLen), FALSE, |
96b3c83d | 282 | FIFO_EDCA, FALSE /*NextValid */ , FALSE); |
c55519ff | 283 | |
96b3c83d BZ |
284 | if ((pHTTXContext->CurWritePosition + 3906 + pTxBlk->Priv) > |
285 | MAX_TXBULK_LIMIT) { | |
c55519ff GKH |
286 | pTxInfo->SwUseLastRound = 1; |
287 | bTxQLastRound = TRUE; | |
288 | } | |
96b3c83d BZ |
289 | NdisMoveMemory(pWirelessPacket, pTxBlk->HeaderBuf, |
290 | TXINFO_SIZE + TXWI_SIZE + hwHdrLen); | |
c55519ff GKH |
291 | pWirelessPacket += (TXINFO_SIZE + TXWI_SIZE + hwHdrLen); |
292 | ||
ec278fa2 BZ |
293 | /* We unlock it here to prevent the first 8 bytes maybe over-writed issue. */ |
294 | /* 1. First we got CurWritePosition but the first 8 bytes still not write to the pTxcontext. */ | |
295 | /* 2. An interrupt break our routine and handle bulk-out complete. */ | |
296 | /* 3. In the bulk-out compllete, it need to do another bulk-out, */ | |
297 | /* if the ENextBulkOutPosition is just the same as CurWritePosition, it will save the first 8 bytes from CurWritePosition, */ | |
298 | /* but the payload still not copyed. the pTxContext->SavedPad[] will save as allzero. and set the bCopyPad = TRUE. */ | |
299 | /* 4. Interrupt complete. */ | |
300 | /* 5. Our interrupted routine go back and fill the first 8 bytes to pTxContext. */ | |
301 | /* 6. Next time when do bulk-out, it found the bCopyPad==TRUE and will copy the SavedPad[] to pTxContext->NextBulkOutPosition. */ | |
302 | /* and the packet will wrong. */ | |
96b3c83d BZ |
303 | pHTTXContext->CurWriteRealPos += |
304 | (TXINFO_SIZE + TXWI_SIZE + hwHdrLen); | |
c55519ff GKH |
305 | RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); |
306 | ||
96b3c83d BZ |
307 | NdisMoveMemory(pWirelessPacket, pTxBlk->pSrcBufData, |
308 | pTxBlk->SrcBufLen); | |
c55519ff GKH |
309 | pWirelessPacket += pTxBlk->SrcBufLen; |
310 | NdisZeroMemory(pWirelessPacket, padding + 8); | |
311 | ||
312 | RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); | |
313 | ||
314 | pHTTXContext->CurWritePosition += pTxBlk->Priv; | |
315 | if (bTxQLastRound) | |
316 | pHTTXContext->CurWritePosition = 8; | |
317 | pHTTXContext->CurWriteRealPos = pHTTXContext->CurWritePosition; | |
318 | ||
96b3c83d | 319 | pHTTXContext->bCurWriting = FALSE; |
c55519ff GKH |
320 | } |
321 | ||
c55519ff GKH |
322 | RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); |
323 | ||
ec278fa2 | 324 | /* succeed and release the skb buffer */ |
c55519ff GKH |
325 | RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_SUCCESS); |
326 | ||
96b3c83d | 327 | return (Status); |
c55519ff GKH |
328 | |
329 | } | |
330 | ||
62eb734b BZ |
331 | u16 RtmpUSB_WriteMultiTxResource(struct rt_rtmp_adapter *pAd, |
332 | struct rt_tx_blk *pTxBlk, | |
51126deb | 333 | u8 frameNum, u16 * FreeNumber) |
c55519ff | 334 | { |
62eb734b | 335 | struct rt_ht_tx_context *pHTTXContext; |
51126deb BZ |
336 | u16 hwHdrLen; /* The hwHdrLen consist of 802.11 header length plus the header padding length. */ |
337 | u32 fillOffset; | |
62eb734b BZ |
338 | struct rt_txinfo *pTxInfo; |
339 | struct rt_txwi *pTxWI; | |
51126deb BZ |
340 | u8 *pWirelessPacket = NULL; |
341 | u8 QueIdx; | |
342 | int Status; | |
96b3c83d | 343 | unsigned long IrqFlags; |
51126deb | 344 | /*u32 USBDMApktLen = 0, DMAHdrLen, padding; */ |
c55519ff | 345 | |
ec278fa2 BZ |
346 | /* */ |
347 | /* get Tx Ring Resource & Dma Buffer address */ | |
348 | /* */ | |
c55519ff | 349 | QueIdx = pTxBlk->QueIdx; |
96b3c83d | 350 | pHTTXContext = &pAd->TxContext[QueIdx]; |
c55519ff GKH |
351 | |
352 | RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); | |
353 | ||
96b3c83d | 354 | if (frameNum == 0) { |
ec278fa2 | 355 | /* Check if we have enough space for this bulk-out batch. */ |
c55519ff | 356 | Status = RtmpUSBCanDoWrite(pAd, QueIdx, pHTTXContext); |
96b3c83d | 357 | if (Status == NDIS_STATUS_SUCCESS) { |
c55519ff GKH |
358 | pHTTXContext->bCurWriting = TRUE; |
359 | ||
62eb734b BZ |
360 | pTxInfo = (struct rt_txinfo *)(&pTxBlk->HeaderBuf[0]); |
361 | pTxWI = (struct rt_txwi *) (&pTxBlk->HeaderBuf[TXINFO_SIZE]); | |
c55519ff | 362 | |
ec278fa2 | 363 | /* Reserve space for 8 bytes padding. */ |
96b3c83d BZ |
364 | if ((pHTTXContext->ENextBulkOutPosition == |
365 | pHTTXContext->CurWritePosition)) { | |
c55519ff GKH |
366 | |
367 | pHTTXContext->CurWritePosition += 8; | |
368 | pHTTXContext->ENextBulkOutPosition += 8; | |
369 | } | |
370 | fillOffset = pHTTXContext->CurWritePosition; | |
96b3c83d BZ |
371 | pHTTXContext->CurWriteRealPos = |
372 | pHTTXContext->CurWritePosition; | |
c55519ff | 373 | |
96b3c83d BZ |
374 | pWirelessPacket = |
375 | &pHTTXContext->TransferBuffer->field. | |
376 | WirelessPacket[fillOffset]; | |
c55519ff | 377 | |
ec278fa2 BZ |
378 | /* */ |
379 | /* Copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer */ | |
380 | /* */ | |
c55519ff | 381 | if (pTxBlk->TxFrameType == TX_AMSDU_FRAME) |
ec278fa2 | 382 | /*hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen-LENGTH_AMSDU_SUBFRAMEHEAD, 4)+LENGTH_AMSDU_SUBFRAMEHEAD; */ |
96b3c83d BZ |
383 | hwHdrLen = |
384 | pTxBlk->MpduHeaderLen - | |
385 | LENGTH_AMSDU_SUBFRAMEHEAD + | |
386 | pTxBlk->HdrPadLen + | |
387 | LENGTH_AMSDU_SUBFRAMEHEAD; | |
c55519ff | 388 | else if (pTxBlk->TxFrameType == TX_RALINK_FRAME) |
ec278fa2 | 389 | /*hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen-LENGTH_ARALINK_HEADER_FIELD, 4)+LENGTH_ARALINK_HEADER_FIELD; */ |
96b3c83d BZ |
390 | hwHdrLen = |
391 | pTxBlk->MpduHeaderLen - | |
392 | LENGTH_ARALINK_HEADER_FIELD + | |
393 | pTxBlk->HdrPadLen + | |
394 | LENGTH_ARALINK_HEADER_FIELD; | |
c55519ff | 395 | else |
ec278fa2 | 396 | /*hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4); */ |
96b3c83d BZ |
397 | hwHdrLen = |
398 | pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen; | |
c55519ff | 399 | |
ec278fa2 | 400 | /* Update the pTxBlk->Priv. */ |
c55519ff GKH |
401 | pTxBlk->Priv = TXINFO_SIZE + TXWI_SIZE + hwHdrLen; |
402 | ||
ec278fa2 | 403 | /* pTxInfo->USBDMApktLen now just a temp value and will to correct latter. */ |
51126deb | 404 | RTMPWriteTxInfo(pAd, pTxInfo, (u16)(pTxBlk->Priv), |
96b3c83d BZ |
405 | FALSE, FIFO_EDCA, FALSE /*NextValid */ , |
406 | FALSE); | |
c55519ff | 407 | |
ec278fa2 | 408 | /* Copy it. */ |
96b3c83d BZ |
409 | NdisMoveMemory(pWirelessPacket, pTxBlk->HeaderBuf, |
410 | pTxBlk->Priv); | |
c55519ff GKH |
411 | pHTTXContext->CurWriteRealPos += pTxBlk->Priv; |
412 | pWirelessPacket += pTxBlk->Priv; | |
413 | } | |
ec278fa2 | 414 | } else { /* For sub-sequent frames of this bulk-out batch. Just copy it to our bulk-out buffer. */ |
96b3c83d BZ |
415 | |
416 | Status = | |
417 | ((pHTTXContext->bCurWriting == | |
418 | TRUE) ? NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE); | |
419 | if (Status == NDIS_STATUS_SUCCESS) { | |
420 | fillOffset = | |
421 | (pHTTXContext->CurWritePosition + pTxBlk->Priv); | |
422 | pWirelessPacket = | |
423 | &pHTTXContext->TransferBuffer->field. | |
424 | WirelessPacket[fillOffset]; | |
c55519ff | 425 | |
ec278fa2 | 426 | /*hwHdrLen = pTxBlk->MpduHeaderLen; */ |
96b3c83d BZ |
427 | NdisMoveMemory(pWirelessPacket, pTxBlk->HeaderBuf, |
428 | pTxBlk->MpduHeaderLen); | |
c55519ff GKH |
429 | pWirelessPacket += (pTxBlk->MpduHeaderLen); |
430 | pTxBlk->Priv += pTxBlk->MpduHeaderLen; | |
ec278fa2 | 431 | } else { /* It should not happened now unless we are going to shutdown. */ |
96b3c83d BZ |
432 | DBGPRINT(RT_DEBUG_ERROR, |
433 | ("WriteMultiTxResource():bCurWriting is FALSE when handle sub-sequent frames.\n")); | |
c55519ff GKH |
434 | Status = NDIS_STATUS_FAILURE; |
435 | } | |
436 | } | |
437 | ||
ec278fa2 BZ |
438 | /* We unlock it here to prevent the first 8 bytes maybe over-write issue. */ |
439 | /* 1. First we got CurWritePosition but the first 8 bytes still not write to the pTxContext. */ | |
440 | /* 2. An interrupt break our routine and handle bulk-out complete. */ | |
441 | /* 3. In the bulk-out compllete, it need to do another bulk-out, */ | |
442 | /* if the ENextBulkOutPosition is just the same as CurWritePosition, it will save the first 8 bytes from CurWritePosition, */ | |
443 | /* but the payload still not copyed. the pTxContext->SavedPad[] will save as allzero. and set the bCopyPad = TRUE. */ | |
444 | /* 4. Interrupt complete. */ | |
445 | /* 5. Our interrupted routine go back and fill the first 8 bytes to pTxContext. */ | |
446 | /* 6. Next time when do bulk-out, it found the bCopyPad==TRUE and will copy the SavedPad[] to pTxContext->NextBulkOutPosition. */ | |
447 | /* and the packet will wrong. */ | |
c55519ff GKH |
448 | RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); |
449 | ||
96b3c83d BZ |
450 | if (Status != NDIS_STATUS_SUCCESS) { |
451 | DBGPRINT(RT_DEBUG_ERROR, | |
452 | ("WriteMultiTxResource: CWPos = %ld, NBOutPos = %ld.\n", | |
453 | pHTTXContext->CurWritePosition, | |
454 | pHTTXContext->NextBulkOutPosition)); | |
c55519ff GKH |
455 | goto done; |
456 | } | |
ec278fa2 | 457 | /* Copy the frame content into DMA buffer and update the pTxBlk->Priv */ |
c55519ff GKH |
458 | NdisMoveMemory(pWirelessPacket, pTxBlk->pSrcBufData, pTxBlk->SrcBufLen); |
459 | pWirelessPacket += pTxBlk->SrcBufLen; | |
460 | pTxBlk->Priv += pTxBlk->SrcBufLen; | |
461 | ||
462 | done: | |
ec278fa2 | 463 | /* Release the skb buffer here */ |
c55519ff GKH |
464 | RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_SUCCESS); |
465 | ||
96b3c83d | 466 | return (Status); |
c55519ff GKH |
467 | |
468 | } | |
469 | ||
62eb734b BZ |
470 | void RtmpUSB_FinalWriteTxResource(struct rt_rtmp_adapter *pAd, |
471 | struct rt_tx_blk *pTxBlk, | |
51126deb | 472 | u16 totalMPDUSize, u16 TxIdx) |
c55519ff | 473 | { |
51126deb | 474 | u8 QueIdx; |
62eb734b | 475 | struct rt_ht_tx_context *pHTTXContext; |
51126deb | 476 | u32 fillOffset; |
62eb734b BZ |
477 | struct rt_txinfo *pTxInfo; |
478 | struct rt_txwi *pTxWI; | |
51126deb | 479 | u32 USBDMApktLen, padding; |
96b3c83d | 480 | unsigned long IrqFlags; |
51126deb | 481 | u8 *pWirelessPacket; |
c55519ff GKH |
482 | |
483 | QueIdx = pTxBlk->QueIdx; | |
96b3c83d | 484 | pHTTXContext = &pAd->TxContext[QueIdx]; |
c55519ff GKH |
485 | |
486 | RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); | |
487 | ||
96b3c83d | 488 | if (pHTTXContext->bCurWriting == TRUE) { |
c55519ff | 489 | fillOffset = pHTTXContext->CurWritePosition; |
96b3c83d BZ |
490 | if (((pHTTXContext->ENextBulkOutPosition == |
491 | pHTTXContext->CurWritePosition) | |
492 | || ((pHTTXContext->ENextBulkOutPosition - 8) == | |
493 | pHTTXContext->CurWritePosition)) | |
494 | && (pHTTXContext->bCopySavePad == TRUE)) | |
51126deb | 495 | pWirelessPacket = (u8 *)(&pHTTXContext->SavedPad[0]); |
c55519ff | 496 | else |
96b3c83d | 497 | pWirelessPacket = |
51126deb | 498 | (u8 *)(&pHTTXContext->TransferBuffer->field. |
96b3c83d | 499 | WirelessPacket[fillOffset]); |
c55519ff | 500 | |
ec278fa2 BZ |
501 | /* */ |
502 | /* Update TxInfo->USBDMApktLen , */ | |
503 | /* the length = TXWI_SIZE + 802.11_hdr + 802.11_hdr_pad + payload_of_all_batch_frames + Bulk-Out-padding */ | |
504 | /* */ | |
62eb734b | 505 | pTxInfo = (struct rt_txinfo *)(pWirelessPacket); |
c55519ff | 506 | |
ec278fa2 | 507 | /* Calculate the bulk-out padding */ |
c55519ff | 508 | USBDMApktLen = pTxBlk->Priv - TXINFO_SIZE; |
ec278fa2 | 509 | padding = (4 - (USBDMApktLen % 4)) & 0x03; /* round up to 4 byte alignment */ |
c55519ff GKH |
510 | USBDMApktLen += padding; |
511 | ||
512 | pTxInfo->USBDMATxPktLen = USBDMApktLen; | |
513 | ||
ec278fa2 BZ |
514 | /* */ |
515 | /* Update TXWI->MPDUtotalByteCount , */ | |
516 | /* the length = 802.11 header + payload_of_all_batch_frames */ | |
62eb734b | 517 | pTxWI = (struct rt_txwi *) (pWirelessPacket + TXINFO_SIZE); |
c55519ff GKH |
518 | pTxWI->MPDUtotalByteCount = totalMPDUSize; |
519 | ||
ec278fa2 BZ |
520 | /* */ |
521 | /* Update the pHTTXContext->CurWritePosition */ | |
522 | /* */ | |
c55519ff | 523 | pHTTXContext->CurWritePosition += (TXINFO_SIZE + USBDMApktLen); |
ec278fa2 | 524 | if ((pHTTXContext->CurWritePosition + 3906) > MAX_TXBULK_LIMIT) { /* Add 3906 for prevent the NextBulkOut packet size is a A-RALINK/A-MSDU Frame. */ |
c55519ff GKH |
525 | pHTTXContext->CurWritePosition = 8; |
526 | pTxInfo->SwUseLastRound = 1; | |
527 | } | |
528 | pHTTXContext->CurWriteRealPos = pHTTXContext->CurWritePosition; | |
529 | ||
ec278fa2 BZ |
530 | /* */ |
531 | /* Zero the last padding. */ | |
532 | /* */ | |
96b3c83d BZ |
533 | pWirelessPacket = |
534 | (&pHTTXContext->TransferBuffer->field. | |
535 | WirelessPacket[fillOffset + pTxBlk->Priv]); | |
c55519ff GKH |
536 | NdisZeroMemory(pWirelessPacket, padding + 8); |
537 | ||
ec278fa2 | 538 | /* Finally, set bCurWriting as FALSE */ |
c55519ff GKH |
539 | pHTTXContext->bCurWriting = FALSE; |
540 | ||
ec278fa2 | 541 | } else { /* It should not happened now unless we are going to shutdown. */ |
96b3c83d BZ |
542 | DBGPRINT(RT_DEBUG_ERROR, |
543 | ("FinalWriteTxResource():bCurWriting is FALSE when handle last frames.\n")); | |
c55519ff GKH |
544 | } |
545 | ||
546 | RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); | |
547 | ||
548 | } | |
549 | ||
62eb734b | 550 | void RtmpUSBDataLastTxIdx(struct rt_rtmp_adapter *pAd, |
51126deb | 551 | u8 QueIdx, u16 TxIdx) |
c55519ff | 552 | { |
ec278fa2 | 553 | /* DO nothing for USB. */ |
c55519ff GKH |
554 | } |
555 | ||
c55519ff GKH |
556 | /* |
557 | When can do bulk-out: | |
558 | 1. TxSwFreeIdx < TX_RING_SIZE; | |
559 | It means has at least one Ring entity is ready for bulk-out, kick it out. | |
560 | 2. If TxSwFreeIdx == TX_RING_SIZE | |
561 | Check if the CurWriting flag is FALSE, if it's FALSE, we can do kick out. | |
562 | ||
563 | */ | |
62eb734b BZ |
564 | void RtmpUSBDataKickOut(struct rt_rtmp_adapter *pAd, |
565 | struct rt_tx_blk *pTxBlk, u8 QueIdx) | |
c55519ff GKH |
566 | { |
567 | RTUSB_SET_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << QueIdx)); | |
568 | RTUSBKickBulkOut(pAd); | |
569 | ||
570 | } | |
571 | ||
c55519ff GKH |
572 | /* |
573 | Must be run in Interrupt context | |
574 | This function handle RT2870 specific TxDesc and cpu index update and kick the packet out. | |
575 | */ | |
62eb734b | 576 | int RtmpUSBMgmtKickOut(struct rt_rtmp_adapter *pAd, |
51126deb | 577 | u8 QueIdx, |
8a10a546 | 578 | void *pPacket, |
51126deb | 579 | u8 *pSrcBufVA, u32 SrcBufLen) |
c55519ff | 580 | { |
62eb734b | 581 | struct rt_txinfo *pTxInfo; |
51126deb BZ |
582 | unsigned long BulkOutSize; |
583 | u8 padLen; | |
584 | u8 *pDest; | |
585 | unsigned long SwIdx = pAd->MgmtRing.TxCpuIdx; | |
62eb734b BZ |
586 | struct rt_tx_context *pMLMEContext = |
587 | (struct rt_tx_context *)pAd->MgmtRing.Cell[SwIdx].AllocVa; | |
96b3c83d | 588 | unsigned long IrqFlags; |
c55519ff | 589 | |
62eb734b | 590 | pTxInfo = (struct rt_txinfo *)(pSrcBufVA); |
c55519ff | 591 | |
ec278fa2 | 592 | /* Build our URB for USBD */ |
c55519ff GKH |
593 | BulkOutSize = SrcBufLen; |
594 | BulkOutSize = (BulkOutSize + 3) & (~3); | |
51126deb | 595 | RTMPWriteTxInfo(pAd, pTxInfo, (u16)(BulkOutSize - TXINFO_SIZE), |
96b3c83d | 596 | TRUE, EpToQueue[MGMTPIPEIDX], FALSE, FALSE); |
c55519ff | 597 | |
ec278fa2 | 598 | BulkOutSize += 4; /* Always add 4 extra bytes at every packet. */ |
c55519ff | 599 | |
ec278fa2 | 600 | /* If BulkOutSize is multiple of BulkOutMaxPacketSize, add extra 4 bytes again. */ |
c55519ff GKH |
601 | if ((BulkOutSize % pAd->BulkOutMaxPacketSize) == 0) |
602 | BulkOutSize += 4; | |
603 | ||
604 | padLen = BulkOutSize - SrcBufLen; | |
605 | ASSERT((padLen <= RTMP_PKT_TAIL_PADDING)); | |
606 | ||
ec278fa2 | 607 | /* Now memzero all extra padding bytes. */ |
51126deb | 608 | pDest = (u8 *)(pSrcBufVA + SrcBufLen); |
c55519ff GKH |
609 | skb_put(GET_OS_PKT_TYPE(pPacket), padLen); |
610 | NdisZeroMemory(pDest, padLen); | |
611 | ||
612 | RTMP_IRQ_LOCK(&pAd->MLMEBulkOutLock, IrqFlags); | |
613 | ||
614 | pAd->MgmtRing.Cell[pAd->MgmtRing.TxCpuIdx].pNdisPacket = pPacket; | |
96b3c83d | 615 | pMLMEContext->TransferBuffer = |
62eb734b | 616 | (struct rt_tx_buffer *)(GET_OS_PKT_DATAPTR(pPacket)); |
c55519ff | 617 | |
ec278fa2 | 618 | /* Length in TxInfo should be 8 less than bulkout size. */ |
c55519ff GKH |
619 | pMLMEContext->BulkOutSize = BulkOutSize; |
620 | pMLMEContext->InUse = TRUE; | |
621 | pMLMEContext->bWaitingBulkOut = TRUE; | |
622 | ||
ec278fa2 BZ |
623 | /*for debug */ |
624 | /*hex_dump("RtmpUSBMgmtKickOut", &pMLMEContext->TransferBuffer->field.WirelessPacket[0], (pMLMEContext->BulkOutSize > 16 ? 16 : pMLMEContext->BulkOutSize)); */ | |
c55519ff | 625 | |
ec278fa2 BZ |
626 | /*pAd->RalinkCounters.KickTxCount++; */ |
627 | /*pAd->RalinkCounters.OneSecTxDoneCount++; */ | |
c55519ff | 628 | |
ec278fa2 BZ |
629 | /*if (pAd->MgmtRing.TxSwFreeIdx == MGMT_RING_SIZE) */ |
630 | /* needKickOut = TRUE; */ | |
c55519ff | 631 | |
ec278fa2 | 632 | /* Decrease the TxSwFreeIdx and Increase the TX_CTX_IDX */ |
c55519ff GKH |
633 | pAd->MgmtRing.TxSwFreeIdx--; |
634 | INC_RING_INDEX(pAd->MgmtRing.TxCpuIdx, MGMT_RING_SIZE); | |
635 | ||
636 | RTMP_IRQ_UNLOCK(&pAd->MLMEBulkOutLock, IrqFlags); | |
637 | ||
638 | RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_MLME); | |
ec278fa2 | 639 | /*if (needKickOut) */ |
c55519ff GKH |
640 | RTUSBKickBulkOut(pAd); |
641 | ||
642 | return 0; | |
643 | } | |
644 | ||
62eb734b | 645 | void RtmpUSBNullFrameKickOut(struct rt_rtmp_adapter *pAd, |
51126deb BZ |
646 | u8 QueIdx, |
647 | u8 * pNullFrame, u32 frameLen) | |
c55519ff | 648 | { |
96b3c83d | 649 | if (pAd->NullContext.InUse == FALSE) { |
62eb734b BZ |
650 | struct rt_tx_context *pNullContext; |
651 | struct rt_txinfo *pTxInfo; | |
652 | struct rt_txwi * pTxWI; | |
51126deb | 653 | u8 *pWirelessPkt; |
c55519ff GKH |
654 | |
655 | pNullContext = &(pAd->NullContext); | |
656 | ||
ec278fa2 | 657 | /* Set the in use bit */ |
c55519ff | 658 | pNullContext->InUse = TRUE; |
96b3c83d | 659 | pWirelessPkt = |
51126deb | 660 | (u8 *)& pNullContext->TransferBuffer->field. |
96b3c83d | 661 | WirelessPacket[0]; |
c55519ff GKH |
662 | |
663 | RTMPZeroMemory(&pWirelessPkt[0], 100); | |
62eb734b | 664 | pTxInfo = (struct rt_txinfo *)& pWirelessPkt[0]; |
96b3c83d | 665 | RTMPWriteTxInfo(pAd, pTxInfo, |
62eb734b | 666 | (u16)(sizeof(struct rt_header_802_11) + TXWI_SIZE), |
96b3c83d | 667 | TRUE, EpToQueue[MGMTPIPEIDX], FALSE, FALSE); |
c55519ff | 668 | pTxInfo->QSEL = FIFO_EDCA; |
62eb734b | 669 | pTxWI = (struct rt_txwi *) & pWirelessPkt[TXINFO_SIZE]; |
96b3c83d | 670 | RTMPWriteTxWI(pAd, pTxWI, FALSE, FALSE, FALSE, FALSE, TRUE, |
62eb734b | 671 | FALSE, 0, BSSID_WCID, (sizeof(struct rt_header_802_11)), 0, |
51126deb | 672 | 0, (u8)pAd->CommonCfg.MlmeTransmit.field.MCS, |
96b3c83d | 673 | IFS_HTTXOP, FALSE, &pAd->CommonCfg.MlmeTransmit); |
ca97b838 | 674 | |
96b3c83d | 675 | RTMPMoveMemory(&pWirelessPkt[TXWI_SIZE + TXINFO_SIZE], |
62eb734b | 676 | &pAd->NullFrame, sizeof(struct rt_header_802_11)); |
96b3c83d BZ |
677 | pAd->NullContext.BulkOutSize = |
678 | TXINFO_SIZE + TXWI_SIZE + sizeof(pAd->NullFrame) + 4; | |
c55519ff | 679 | |
ec278fa2 BZ |
680 | /* Fill out frame length information for global Bulk out arbitor */ |
681 | /*pNullContext->BulkOutSize = TransferBufferLength; */ | |
96b3c83d BZ |
682 | DBGPRINT(RT_DEBUG_TRACE, |
683 | ("SYNC - send NULL Frame @%d Mbps...\n", | |
684 | RateIdToMbps[pAd->CommonCfg.TxRate])); | |
c55519ff GKH |
685 | RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NULL); |
686 | ||
ec278fa2 | 687 | /* Kick bulk out */ |
c55519ff GKH |
688 | RTUSBKickBulkOut(pAd); |
689 | } | |
690 | ||
691 | } | |
692 | ||
ca97b838 BZ |
693 | /* |
694 | ======================================================================== | |
695 | Routine Description: | |
696 | Get a received packet. | |
697 | ||
698 | Arguments: | |
699 | pAd device control block | |
700 | pSaveRxD receive descriptor information | |
701 | *pbReschedule need reschedule flag | |
702 | *pRxPending pending received packet flag | |
703 | ||
704 | Return Value: | |
25985edc | 705 | the received packet |
ca97b838 BZ |
706 | |
707 | Note: | |
708 | ======================================================================== | |
709 | */ | |
62eb734b | 710 | void *GetPacketFromRxRing(struct rt_rtmp_adapter *pAd, |
96b3c83d BZ |
711 | OUT PRT28XX_RXD_STRUC pSaveRxD, |
712 | OUT BOOLEAN * pbReschedule, | |
51126deb | 713 | IN u32 * pRxPending) |
ca97b838 | 714 | { |
62eb734b | 715 | struct rt_rx_context *pRxContext; |
8a10a546 | 716 | void *pSkb; |
51126deb BZ |
717 | u8 *pData; |
718 | unsigned long ThisFrameLen; | |
719 | unsigned long RxBufferLength; | |
62eb734b | 720 | struct rt_rxwi * pRxWI; |
ca97b838 BZ |
721 | |
722 | pRxContext = &pAd->RxContext[pAd->NextRxBulkInReadIndex]; | |
723 | if ((pRxContext->Readable == FALSE) || (pRxContext->InUse == TRUE)) | |
724 | return NULL; | |
725 | ||
726 | RxBufferLength = pRxContext->BulkInOffset - pAd->ReadPosition; | |
96b3c83d | 727 | if (RxBufferLength < |
62eb734b BZ |
728 | (RT2870_RXDMALEN_FIELD_SIZE + sizeof(struct rt_rxwi) + |
729 | sizeof(struct rt_rxinfo))) { | |
ca97b838 BZ |
730 | goto label_null; |
731 | } | |
732 | ||
96b3c83d | 733 | pData = &pRxContext->TransferBuffer[pAd->ReadPosition]; /* 4KB */ |
ec278fa2 | 734 | /* The RXDMA field is 4 bytes, now just use the first 2 bytes. The Length including the (RXWI + MSDU + Padding) */ |
96b3c83d BZ |
735 | ThisFrameLen = *pData + (*(pData + 1) << 8); |
736 | if (ThisFrameLen == 0) { | |
737 | DBGPRINT(RT_DEBUG_TRACE, | |
738 | ("BIRIdx(%d): RXDMALen is zero.[%ld], BulkInBufLen = %ld)\n", | |
739 | pAd->NextRxBulkInReadIndex, ThisFrameLen, | |
740 | pRxContext->BulkInOffset)); | |
ca97b838 BZ |
741 | goto label_null; |
742 | } | |
96b3c83d BZ |
743 | if ((ThisFrameLen & 0x3) != 0) { |
744 | DBGPRINT(RT_DEBUG_ERROR, | |
745 | ("BIRIdx(%d): RXDMALen not multiple of 4.[%ld], BulkInBufLen = %ld)\n", | |
746 | pAd->NextRxBulkInReadIndex, ThisFrameLen, | |
747 | pRxContext->BulkInOffset)); | |
ca97b838 BZ |
748 | goto label_null; |
749 | } | |
750 | ||
62eb734b | 751 | if ((ThisFrameLen + 8) > RxBufferLength) /* 8 for (RT2870_RXDMALEN_FIELD_SIZE + sizeof(struct rt_rxinfo)) */ |
ca97b838 | 752 | { |
96b3c83d BZ |
753 | DBGPRINT(RT_DEBUG_TRACE, |
754 | ("BIRIdx(%d):FrameLen(0x%lx) outranges. BulkInLen=0x%lx, remaining RxBufLen=0x%lx, ReadPos=0x%lx\n", | |
755 | pAd->NextRxBulkInReadIndex, ThisFrameLen, | |
756 | pRxContext->BulkInOffset, RxBufferLength, | |
757 | pAd->ReadPosition)); | |
ca97b838 | 758 | |
ec278fa2 | 759 | /* error frame. finish this loop */ |
ca97b838 BZ |
760 | goto label_null; |
761 | } | |
ec278fa2 | 762 | /* skip USB frame length field */ |
ca97b838 | 763 | pData += RT2870_RXDMALEN_FIELD_SIZE; |
62eb734b | 764 | pRxWI = (struct rt_rxwi *) pData; |
96b3c83d BZ |
765 | if (pRxWI->MPDUtotalByteCount > ThisFrameLen) { |
766 | DBGPRINT(RT_DEBUG_ERROR, | |
767 | ("%s():pRxWIMPDUtotalByteCount(%d) large than RxDMALen(%ld)\n", | |
768 | __FUNCTION__, pRxWI->MPDUtotalByteCount, | |
769 | ThisFrameLen)); | |
ca97b838 BZ |
770 | goto label_null; |
771 | } | |
ec278fa2 | 772 | /* allocate a rx packet */ |
ca97b838 | 773 | pSkb = dev_alloc_skb(ThisFrameLen); |
96b3c83d BZ |
774 | if (pSkb == NULL) { |
775 | DBGPRINT(RT_DEBUG_ERROR, | |
776 | ("%s():Cannot Allocate sk buffer for this Bulk-In buffer!\n", | |
777 | __FUNCTION__)); | |
ca97b838 BZ |
778 | goto label_null; |
779 | } | |
ec278fa2 | 780 | /* copy the rx packet */ |
ca97b838 BZ |
781 | memcpy(skb_put(pSkb, ThisFrameLen), pData, ThisFrameLen); |
782 | RTPKT_TO_OSPKT(pSkb)->dev = get_netdev_from_bssid(pAd, BSS0); | |
783 | RTMP_SET_PACKET_SOURCE(OSPKT_TO_RTPKT(pSkb), PKTSRC_NDIS); | |
784 | ||
ec278fa2 | 785 | /* copy RxD */ |
62eb734b | 786 | *pSaveRxD = *(struct rt_rxinfo *) (pData + ThisFrameLen); |
ca97b838 | 787 | |
ec278fa2 | 788 | /* update next packet read position. */ |
62eb734b | 789 | pAd->ReadPosition += (ThisFrameLen + RT2870_RXDMALEN_FIELD_SIZE + RXINFO_SIZE); /* 8 for (RT2870_RXDMALEN_FIELD_SIZE + sizeof(struct rt_rxinfo)) */ |
ca97b838 BZ |
790 | |
791 | return pSkb; | |
792 | ||
793 | label_null: | |
794 | ||
795 | return NULL; | |
796 | } | |
797 | ||
c55519ff GKH |
798 | /* |
799 | ======================================================================== | |
800 | ||
801 | Routine Description: | |
802 | Check Rx descriptor, return NDIS_STATUS_FAILURE if any error dound | |
803 | ||
804 | Arguments: | |
805 | pRxD Pointer to the Rx descriptor | |
806 | ||
807 | Return Value: | |
808 | NDIS_STATUS_SUCCESS No err | |
809 | NDIS_STATUS_FAILURE Error | |
810 | ||
811 | Note: | |
812 | ||
813 | ======================================================================== | |
814 | */ | |
62eb734b BZ |
815 | int RTMPCheckRxError(struct rt_rtmp_adapter *pAd, |
816 | struct rt_header_802_11 * pHeader, | |
817 | struct rt_rxwi * pRxWI, IN PRT28XX_RXD_STRUC pRxINFO) | |
c55519ff | 818 | { |
62eb734b | 819 | struct rt_cipher_key *pWpaKey; |
51126deb | 820 | int dBm; |
c55519ff GKH |
821 | |
822 | if (pAd->bPromiscuous == TRUE) | |
96b3c83d BZ |
823 | return (NDIS_STATUS_SUCCESS); |
824 | if (pRxINFO == NULL) | |
825 | return (NDIS_STATUS_FAILURE); | |
c55519ff | 826 | |
ec278fa2 | 827 | /* Phy errors & CRC errors */ |
96b3c83d | 828 | if (pRxINFO->Crc) { |
ec278fa2 | 829 | /* Check RSSI for Noise Hist statistic collection. */ |
51126deb | 830 | dBm = (int)(pRxWI->RSSI0) - pAd->BbpRssiToDbmDelta; |
c55519ff GKH |
831 | if (dBm <= -87) |
832 | pAd->StaCfg.RPIDensity[0] += 1; | |
833 | else if (dBm <= -82) | |
834 | pAd->StaCfg.RPIDensity[1] += 1; | |
835 | else if (dBm <= -77) | |
836 | pAd->StaCfg.RPIDensity[2] += 1; | |
837 | else if (dBm <= -72) | |
838 | pAd->StaCfg.RPIDensity[3] += 1; | |
839 | else if (dBm <= -67) | |
840 | pAd->StaCfg.RPIDensity[4] += 1; | |
841 | else if (dBm <= -62) | |
842 | pAd->StaCfg.RPIDensity[5] += 1; | |
843 | else if (dBm <= -57) | |
844 | pAd->StaCfg.RPIDensity[6] += 1; | |
845 | else if (dBm > -57) | |
846 | pAd->StaCfg.RPIDensity[7] += 1; | |
847 | ||
96b3c83d | 848 | return (NDIS_STATUS_FAILURE); |
c55519ff | 849 | } |
ec278fa2 | 850 | /* Add Rx size to channel load counter, we should ignore error counts */ |
96b3c83d | 851 | pAd->StaCfg.CLBusyBytes += (pRxWI->MPDUtotalByteCount + 14); |
c55519ff | 852 | |
25985edc | 853 | /* Drop ToDs promiscuous frame, it is opened due to CCX 2 channel load statistics */ |
96b3c83d | 854 | if (pHeader->FC.ToDs) { |
c55519ff GKH |
855 | DBGPRINT_RAW(RT_DEBUG_ERROR, ("Err;FC.ToDs\n")); |
856 | return NDIS_STATUS_FAILURE; | |
857 | } | |
ec278fa2 | 858 | /* Paul 04-03 for OFDM Rx length issue */ |
96b3c83d | 859 | if (pRxWI->MPDUtotalByteCount > MAX_AGGREGATION_SIZE) { |
c55519ff GKH |
860 | DBGPRINT_RAW(RT_DEBUG_ERROR, ("received packet too long\n")); |
861 | return NDIS_STATUS_FAILURE; | |
862 | } | |
25985edc | 863 | /* Drop not U2M frames, can't's drop here because we will drop beacon in this case */ |
ec278fa2 BZ |
864 | /* I am kind of doubting the U2M bit operation */ |
865 | /* if (pRxD->U2M == 0) */ | |
866 | /* return(NDIS_STATUS_FAILURE); */ | |
c55519ff | 867 | |
ec278fa2 | 868 | /* drop decyption fail frame */ |
96b3c83d BZ |
869 | if (pRxINFO->Decrypted && pRxINFO->CipherErr) { |
870 | ||
871 | if (((pRxINFO->CipherErr & 1) == 1) | |
872 | && pAd->CommonCfg.bWirelessEvent && INFRA_ON(pAd)) | |
873 | RTMPSendWirelessEvent(pAd, IW_ICV_ERROR_EVENT_FLAG, | |
874 | pAd->MacTab.Content[BSSID_WCID]. | |
875 | Addr, BSS0, 0); | |
876 | ||
877 | if (((pRxINFO->CipherErr & 2) == 2) | |
878 | && pAd->CommonCfg.bWirelessEvent && INFRA_ON(pAd)) | |
879 | RTMPSendWirelessEvent(pAd, IW_MIC_ERROR_EVENT_FLAG, | |
880 | pAd->MacTab.Content[BSSID_WCID]. | |
881 | Addr, BSS0, 0); | |
ec278fa2 BZ |
882 | /* */ |
883 | /* MIC Error */ | |
884 | /* */ | |
96b3c83d | 885 | if ((pRxINFO->CipherErr == 2) && pRxINFO->MyBss) { |
c55519ff GKH |
886 | pWpaKey = &pAd->SharedKey[BSS0][pRxWI->KeyIndex]; |
887 | RTMPReportMicError(pAd, pWpaKey); | |
96b3c83d | 888 | DBGPRINT_RAW(RT_DEBUG_ERROR, ("Rx MIC Value error\n")); |
c55519ff GKH |
889 | } |
890 | ||
891 | if (pRxINFO->Decrypted && | |
96b3c83d BZ |
892 | (pAd->SharedKey[BSS0][pRxWI->KeyIndex].CipherAlg == |
893 | CIPHER_AES) | |
894 | && (pHeader->Sequence == pAd->FragFrame.Sequence)) { | |
ec278fa2 BZ |
895 | /* */ |
896 | /* Acceptable since the First FragFrame no CipherErr problem. */ | |
897 | /* */ | |
96b3c83d | 898 | return (NDIS_STATUS_SUCCESS); |
c55519ff GKH |
899 | } |
900 | ||
96b3c83d | 901 | return (NDIS_STATUS_FAILURE); |
c55519ff GKH |
902 | } |
903 | ||
96b3c83d | 904 | return (NDIS_STATUS_SUCCESS); |
c55519ff GKH |
905 | } |
906 | ||
51126deb BZ |
907 | void RtmpUsbStaAsicForceWakeupTimeout(void *SystemSpecific1, |
908 | void *FunctionContext, | |
909 | void *SystemSpecific2, | |
910 | void *SystemSpecific3) | |
ca97b838 | 911 | { |
62eb734b | 912 | struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)FunctionContext; |
ca97b838 | 913 | |
96b3c83d | 914 | if (pAd && pAd->Mlme.AutoWakeupTimerRunning) { |
ca97b838 BZ |
915 | AsicSendCommandToMcu(pAd, 0x31, 0xff, 0x00, 0x02); |
916 | ||
917 | OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE); | |
918 | pAd->Mlme.AutoWakeupTimerRunning = FALSE; | |
919 | } | |
920 | } | |
921 | ||
62eb734b | 922 | void RT28xxUsbStaAsicForceWakeup(struct rt_rtmp_adapter *pAd, IN BOOLEAN bFromTx) |
c55519ff | 923 | { |
96b3c83d | 924 | BOOLEAN Canceled; |
c55519ff | 925 | |
ca97b838 BZ |
926 | if (pAd->Mlme.AutoWakeupTimerRunning) |
927 | RTMPCancelTimer(&pAd->Mlme.AutoWakeupTimer, &Canceled); | |
c55519ff | 928 | |
ffbc7b85 | 929 | AsicSendCommandToMcu(pAd, 0x31, 0xff, 0x00, 0x02); |
c55519ff GKH |
930 | |
931 | OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE); | |
932 | } | |
933 | ||
62eb734b | 934 | void RT28xxUsbStaAsicSleepThenAutoWakeup(struct rt_rtmp_adapter *pAd, |
51126deb | 935 | u16 TbttNumToNextWakeUp) |
c55519ff | 936 | { |
ca97b838 | 937 | |
ec278fa2 | 938 | /* we have decided to SLEEP, so at least do it for a BEACON period. */ |
c55519ff GKH |
939 | if (TbttNumToNextWakeUp == 0) |
940 | TbttNumToNextWakeUp = 1; | |
941 | ||
ca97b838 BZ |
942 | RTMPSetTimer(&pAd->Mlme.AutoWakeupTimer, AUTO_WAKEUP_TIMEOUT); |
943 | pAd->Mlme.AutoWakeupTimerRunning = TRUE; | |
c55519ff | 944 | |
ec278fa2 | 945 | AsicSendCommandToMcu(pAd, 0x30, 0xff, 0xff, 0x02); /* send POWER-SAVE command to MCU. Timeout 40us. */ |
c55519ff GKH |
946 | |
947 | OPSTATUS_SET_FLAG(pAd, fOP_STATUS_DOZE); | |
948 | ||
949 | } | |
c55519ff | 950 | |
ec278fa2 | 951 | #endif /* RTMP_MAC_USB // */ |