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