Merge branch 'for-linus' of git://neil.brown.name/md
[sfrench/cifs-2.6.git] / drivers / staging / rt3070 / 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                 //PS packets use HCCA queue when dequeue from PS unicast queue (WiFi WPA2 MA9_DT1 for Marvell B STA)
299 #ifdef CONFIG_STA_SUPPORT
300                 IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
301                 RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(USBDMApktLen), FALSE, FIFO_EDCA, FALSE /*NextValid*/,  FALSE);
302 #endif // CONFIG_STA_SUPPORT //
303
304                 if ((pHTTXContext->CurWritePosition + 3906 + pTxBlk->Priv) > MAX_TXBULK_LIMIT)
305                 {
306                         pTxInfo->SwUseLastRound = 1;
307                         bTxQLastRound = TRUE;
308                 }
309                 NdisMoveMemory(pWirelessPacket, pTxBlk->HeaderBuf, TXINFO_SIZE + TXWI_SIZE + hwHdrLen);
310 #ifdef RT_BIG_ENDIAN
311                 RTMPFrameEndianChange(pAd, (PUCHAR)(pWirelessPacket + TXINFO_SIZE + TXWI_SIZE), DIR_WRITE, FALSE);
312 #endif // RT_BIG_ENDIAN //
313                 pWirelessPacket += (TXINFO_SIZE + TXWI_SIZE + hwHdrLen);
314
315                 // We unlock it here to prevent the first 8 bytes maybe over-writed issue.
316                 //      1. First we got CurWritePosition but the first 8 bytes still not write to the pTxcontext.
317                 //      2. An interrupt break our routine and handle bulk-out complete.
318                 //      3. In the bulk-out compllete, it need to do another bulk-out,
319                 //                      if the ENextBulkOutPosition is just the same as CurWritePosition, it will save the first 8 bytes from CurWritePosition,
320                 //                      but the payload still not copyed. the pTxContext->SavedPad[] will save as allzero. and set the bCopyPad = TRUE.
321                 //      4. Interrupt complete.
322                 //  5. Our interrupted routine go back and fill the first 8 bytes to pTxContext.
323                 //      6. Next time when do bulk-out, it found the bCopyPad==TRUE and will copy the SavedPad[] to pTxContext->NextBulkOutPosition.
324                 //              and the packet will wrong.
325                 pHTTXContext->CurWriteRealPos += (TXINFO_SIZE + TXWI_SIZE + hwHdrLen);
326                 RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags);
327
328                 NdisMoveMemory(pWirelessPacket, pTxBlk->pSrcBufData, pTxBlk->SrcBufLen);
329                 pWirelessPacket += pTxBlk->SrcBufLen;
330                 NdisZeroMemory(pWirelessPacket, padding + 8);
331
332                 RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags);
333
334                 pHTTXContext->CurWritePosition += pTxBlk->Priv;
335                 if (bTxQLastRound)
336                         pHTTXContext->CurWritePosition = 8;
337                 pHTTXContext->CurWriteRealPos = pHTTXContext->CurWritePosition;
338
339         pHTTXContext->bCurWriting = FALSE;
340         }
341
342
343         RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags);
344
345
346         // succeed and release the skb buffer
347         RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_SUCCESS);
348
349         return(Status);
350
351 }
352
353
354 USHORT RtmpUSB_WriteMultiTxResource(
355         IN      PRTMP_ADAPTER   pAd,
356         IN      TX_BLK                  *pTxBlk,
357         IN      UCHAR                   frameNum,
358         OUT     USHORT                  *FreeNumber)
359 {
360         HT_TX_CONTEXT   *pHTTXContext;
361         USHORT                  hwHdrLen;       // The hwHdrLen consist of 802.11 header length plus the header padding length.
362         UINT32                  fillOffset;
363         TXINFO_STRUC    *pTxInfo;
364         TXWI_STRUC              *pTxWI;
365         PUCHAR                  pWirelessPacket = NULL;
366         UCHAR                   QueIdx;
367         NDIS_STATUS             Status;
368         unsigned long   IrqFlags;
369         //UINT32                        USBDMApktLen = 0, DMAHdrLen, padding;
370
371         //
372         // get Tx Ring Resource & Dma Buffer address
373         //
374         QueIdx = pTxBlk->QueIdx;
375         pHTTXContext  = &pAd->TxContext[QueIdx];
376
377         RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags);
378
379         if(frameNum == 0)
380         {
381                 // Check if we have enough space for this bulk-out batch.
382                 Status = RtmpUSBCanDoWrite(pAd, QueIdx, pHTTXContext);
383                 if (Status == NDIS_STATUS_SUCCESS)
384                 {
385                         pHTTXContext->bCurWriting = TRUE;
386
387                         pTxInfo = (PTXINFO_STRUC)(&pTxBlk->HeaderBuf[0]);
388                         pTxWI= (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]);
389
390
391                         // Reserve space for 8 bytes padding.
392                         if ((pHTTXContext->ENextBulkOutPosition == pHTTXContext->CurWritePosition))
393                         {
394
395                                 pHTTXContext->CurWritePosition += 8;
396                                 pHTTXContext->ENextBulkOutPosition += 8;
397                         }
398                         fillOffset = pHTTXContext->CurWritePosition;
399                         pHTTXContext->CurWriteRealPos = pHTTXContext->CurWritePosition;
400
401                         pWirelessPacket = &pHTTXContext->TransferBuffer->field.WirelessPacket[fillOffset];
402
403                         //
404                         // Copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer
405                         //
406                         if (pTxBlk->TxFrameType == TX_AMSDU_FRAME)
407                                 //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen-LENGTH_AMSDU_SUBFRAMEHEAD, 4)+LENGTH_AMSDU_SUBFRAMEHEAD;
408                                 hwHdrLen = pTxBlk->MpduHeaderLen-LENGTH_AMSDU_SUBFRAMEHEAD + pTxBlk->HdrPadLen + LENGTH_AMSDU_SUBFRAMEHEAD;
409                         else if (pTxBlk->TxFrameType == TX_RALINK_FRAME)
410                                 //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen-LENGTH_ARALINK_HEADER_FIELD, 4)+LENGTH_ARALINK_HEADER_FIELD;
411                                 hwHdrLen = pTxBlk->MpduHeaderLen-LENGTH_ARALINK_HEADER_FIELD + pTxBlk->HdrPadLen + LENGTH_ARALINK_HEADER_FIELD;
412                         else
413                                 //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4);
414                                 hwHdrLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen;
415
416                         // Update the pTxBlk->Priv.
417                         pTxBlk->Priv = TXINFO_SIZE + TXWI_SIZE + hwHdrLen;
418
419                         //      pTxInfo->USBDMApktLen now just a temp value and will to correct latter.
420                         RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(pTxBlk->Priv), FALSE, FIFO_EDCA, FALSE /*NextValid*/,  FALSE);
421
422                         // Copy it.
423                         NdisMoveMemory(pWirelessPacket, pTxBlk->HeaderBuf, pTxBlk->Priv);
424 #ifdef RT_BIG_ENDIAN
425                         RTMPFrameEndianChange(pAd, (PUCHAR)(pWirelessPacket+ TXINFO_SIZE + TXWI_SIZE), DIR_WRITE, FALSE);
426 #endif // RT_BIG_ENDIAN //
427                         pHTTXContext->CurWriteRealPos += pTxBlk->Priv;
428                         pWirelessPacket += pTxBlk->Priv;
429                 }
430         }
431         else
432         {       // For sub-sequent frames of this bulk-out batch. Just copy it to our bulk-out buffer.
433
434                 Status = ((pHTTXContext->bCurWriting == TRUE) ? NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE);
435                 if (Status == NDIS_STATUS_SUCCESS)
436                 {
437                         fillOffset =  (pHTTXContext->CurWritePosition + pTxBlk->Priv);
438                         pWirelessPacket = &pHTTXContext->TransferBuffer->field.WirelessPacket[fillOffset];
439
440                         //hwHdrLen = pTxBlk->MpduHeaderLen;
441                         NdisMoveMemory(pWirelessPacket, pTxBlk->HeaderBuf, pTxBlk->MpduHeaderLen);
442                         pWirelessPacket += (pTxBlk->MpduHeaderLen);
443                         pTxBlk->Priv += pTxBlk->MpduHeaderLen;
444                 }
445                 else
446                 {       // It should not happened now unless we are going to shutdown.
447                         DBGPRINT(RT_DEBUG_ERROR, ("WriteMultiTxResource():bCurWriting is FALSE when handle sub-sequent frames.\n"));
448                         Status = NDIS_STATUS_FAILURE;
449                 }
450         }
451
452
453         // We unlock it here to prevent the first 8 bytes maybe over-write issue.
454         //      1. First we got CurWritePosition but the first 8 bytes still not write to the pTxContext.
455         //      2. An interrupt break our routine and handle bulk-out complete.
456         //      3. In the bulk-out compllete, it need to do another bulk-out,
457         //                      if the ENextBulkOutPosition is just the same as CurWritePosition, it will save the first 8 bytes from CurWritePosition,
458         //                      but the payload still not copyed. the pTxContext->SavedPad[] will save as allzero. and set the bCopyPad = TRUE.
459         //      4. Interrupt complete.
460         //  5. Our interrupted routine go back and fill the first 8 bytes to pTxContext.
461         //      6. Next time when do bulk-out, it found the bCopyPad==TRUE and will copy the SavedPad[] to pTxContext->NextBulkOutPosition.
462         //              and the packet will wrong.
463         RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags);
464
465         if (Status != NDIS_STATUS_SUCCESS)
466         {
467                 DBGPRINT(RT_DEBUG_ERROR,("WriteMultiTxResource: CWPos = %ld, NBOutPos = %ld.\n", pHTTXContext->CurWritePosition, pHTTXContext->NextBulkOutPosition));
468                 goto done;
469         }
470
471         // Copy the frame content into DMA buffer and update the pTxBlk->Priv
472         NdisMoveMemory(pWirelessPacket, pTxBlk->pSrcBufData, pTxBlk->SrcBufLen);
473         pWirelessPacket += pTxBlk->SrcBufLen;
474         pTxBlk->Priv += pTxBlk->SrcBufLen;
475
476 done:
477         // Release the skb buffer here
478         RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_SUCCESS);
479
480         return(Status);
481
482 }
483
484
485 VOID RtmpUSB_FinalWriteTxResource(
486         IN      PRTMP_ADAPTER   pAd,
487         IN      TX_BLK                  *pTxBlk,
488         IN      USHORT                  totalMPDUSize,
489         IN      USHORT                  TxIdx)
490 {
491         UCHAR                   QueIdx;
492         HT_TX_CONTEXT   *pHTTXContext;
493         UINT32                  fillOffset;
494         TXINFO_STRUC    *pTxInfo;
495         TXWI_STRUC              *pTxWI;
496         UINT32                  USBDMApktLen, padding;
497         unsigned long   IrqFlags;
498         PUCHAR                  pWirelessPacket;
499
500         QueIdx = pTxBlk->QueIdx;
501         pHTTXContext  = &pAd->TxContext[QueIdx];
502
503         RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags);
504
505         if (pHTTXContext->bCurWriting == TRUE)
506         {
507                 fillOffset = pHTTXContext->CurWritePosition;
508                 if (((pHTTXContext->ENextBulkOutPosition == pHTTXContext->CurWritePosition) || ((pHTTXContext->ENextBulkOutPosition-8) == pHTTXContext->CurWritePosition))
509                         && (pHTTXContext->bCopySavePad == TRUE))
510                         pWirelessPacket = (PUCHAR)(&pHTTXContext->SavedPad[0]);
511                 else
512                         pWirelessPacket = (PUCHAR)(&pHTTXContext->TransferBuffer->field.WirelessPacket[fillOffset]);
513
514                 //
515                 // Update TxInfo->USBDMApktLen ,
516                 //              the length = TXWI_SIZE + 802.11_hdr + 802.11_hdr_pad + payload_of_all_batch_frames + Bulk-Out-padding
517                 //
518                 pTxInfo = (PTXINFO_STRUC)(pWirelessPacket);
519
520                 // Calculate the bulk-out padding
521                 USBDMApktLen = pTxBlk->Priv - TXINFO_SIZE;
522                 padding = (4 - (USBDMApktLen % 4)) & 0x03;      // round up to 4 byte alignment
523                 USBDMApktLen += padding;
524
525                 pTxInfo->USBDMATxPktLen = USBDMApktLen;
526
527                 //
528                 // Update TXWI->MPDUtotalByteCount ,
529                 //              the length = 802.11 header + payload_of_all_batch_frames
530                 pTxWI= (PTXWI_STRUC)(pWirelessPacket + TXINFO_SIZE);
531                 pTxWI->MPDUtotalByteCount = totalMPDUSize;
532
533                 //
534                 // Update the pHTTXContext->CurWritePosition
535                 //
536                 pHTTXContext->CurWritePosition += (TXINFO_SIZE + USBDMApktLen);
537                 if ((pHTTXContext->CurWritePosition + 3906)> MAX_TXBULK_LIMIT)
538                 {       // Add 3906 for prevent the NextBulkOut packet size is a A-RALINK/A-MSDU Frame.
539                         pHTTXContext->CurWritePosition = 8;
540                         pTxInfo->SwUseLastRound = 1;
541                 }
542                 pHTTXContext->CurWriteRealPos = pHTTXContext->CurWritePosition;
543
544
545                 //
546                 //      Zero the last padding.
547                 //
548                 pWirelessPacket = (&pHTTXContext->TransferBuffer->field.WirelessPacket[fillOffset + pTxBlk->Priv]);
549                 NdisZeroMemory(pWirelessPacket, padding + 8);
550
551                 // Finally, set bCurWriting as FALSE
552                 pHTTXContext->bCurWriting = FALSE;
553
554         }
555         else
556         {       // It should not happened now unless we are going to shutdown.
557                 DBGPRINT(RT_DEBUG_ERROR, ("FinalWriteTxResource():bCurWriting is FALSE when handle last frames.\n"));
558         }
559
560         RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags);
561
562 }
563
564
565 VOID RtmpUSBDataLastTxIdx(
566         IN      PRTMP_ADAPTER   pAd,
567         IN      UCHAR                   QueIdx,
568         IN      USHORT                  TxIdx)
569 {
570         // DO nothing for USB.
571 }
572
573
574 /*
575         When can do bulk-out:
576                 1. TxSwFreeIdx < TX_RING_SIZE;
577                         It means has at least one Ring entity is ready for bulk-out, kick it out.
578                 2. If TxSwFreeIdx == TX_RING_SIZE
579                         Check if the CurWriting flag is FALSE, if it's FALSE, we can do kick out.
580
581 */
582 VOID RtmpUSBDataKickOut(
583         IN      PRTMP_ADAPTER   pAd,
584         IN      TX_BLK                  *pTxBlk,
585         IN      UCHAR                   QueIdx)
586 {
587         RTUSB_SET_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << QueIdx));
588         RTUSBKickBulkOut(pAd);
589
590 }
591
592
593 /*
594         Must be run in Interrupt context
595         This function handle RT2870 specific TxDesc and cpu index update and kick the packet out.
596  */
597 int RtmpUSBMgmtKickOut(
598         IN RTMP_ADAPTER         *pAd,
599         IN UCHAR                        QueIdx,
600         IN PNDIS_PACKET         pPacket,
601         IN PUCHAR                       pSrcBufVA,
602         IN UINT                         SrcBufLen)
603 {
604         PTXINFO_STRUC   pTxInfo;
605         ULONG                   BulkOutSize;
606         UCHAR                   padLen;
607         PUCHAR                  pDest;
608         ULONG                   SwIdx = pAd->MgmtRing.TxCpuIdx;
609         PTX_CONTEXT             pMLMEContext = (PTX_CONTEXT)pAd->MgmtRing.Cell[SwIdx].AllocVa;
610         unsigned long   IrqFlags;
611
612
613         pTxInfo = (PTXINFO_STRUC)(pSrcBufVA);
614
615         // Build our URB for USBD
616         BulkOutSize = SrcBufLen;
617         BulkOutSize = (BulkOutSize + 3) & (~3);
618         RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(BulkOutSize - TXINFO_SIZE), TRUE, EpToQueue[MGMTPIPEIDX], FALSE,  FALSE);
619
620         BulkOutSize += 4; // Always add 4 extra bytes at every packet.
621
622         // If BulkOutSize is multiple of BulkOutMaxPacketSize, add extra 4 bytes again.
623         if ((BulkOutSize % pAd->BulkOutMaxPacketSize) == 0)
624                 BulkOutSize += 4;
625
626         padLen = BulkOutSize - SrcBufLen;
627         ASSERT((padLen <= RTMP_PKT_TAIL_PADDING));
628
629         // Now memzero all extra padding bytes.
630         pDest = (PUCHAR)(pSrcBufVA + SrcBufLen);
631         skb_put(GET_OS_PKT_TYPE(pPacket), padLen);
632         NdisZeroMemory(pDest, padLen);
633
634         RTMP_IRQ_LOCK(&pAd->MLMEBulkOutLock, IrqFlags);
635
636         pAd->MgmtRing.Cell[pAd->MgmtRing.TxCpuIdx].pNdisPacket = pPacket;
637         pMLMEContext->TransferBuffer = (PTX_BUFFER)(GET_OS_PKT_DATAPTR(pPacket));
638
639         // Length in TxInfo should be 8 less than bulkout size.
640         pMLMEContext->BulkOutSize = BulkOutSize;
641         pMLMEContext->InUse = TRUE;
642         pMLMEContext->bWaitingBulkOut = TRUE;
643
644
645         //for debug
646         //hex_dump("RtmpUSBMgmtKickOut", &pMLMEContext->TransferBuffer->field.WirelessPacket[0], (pMLMEContext->BulkOutSize > 16 ? 16 : pMLMEContext->BulkOutSize));
647
648         //pAd->RalinkCounters.KickTxCount++;
649         //pAd->RalinkCounters.OneSecTxDoneCount++;
650
651         //if (pAd->MgmtRing.TxSwFreeIdx == MGMT_RING_SIZE)
652         //      needKickOut = TRUE;
653
654         // Decrease the TxSwFreeIdx and Increase the TX_CTX_IDX
655         pAd->MgmtRing.TxSwFreeIdx--;
656         INC_RING_INDEX(pAd->MgmtRing.TxCpuIdx, MGMT_RING_SIZE);
657
658         RTMP_IRQ_UNLOCK(&pAd->MLMEBulkOutLock, IrqFlags);
659
660         RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_MLME);
661         //if (needKickOut)
662         RTUSBKickBulkOut(pAd);
663
664         return 0;
665 }
666
667
668 VOID RtmpUSBNullFrameKickOut(
669         IN RTMP_ADAPTER *pAd,
670         IN UCHAR                QueIdx,
671         IN UCHAR                *pNullFrame,
672         IN UINT32               frameLen)
673 {
674         if (pAd->NullContext.InUse == FALSE)
675         {
676                 PTX_CONTEXT             pNullContext;
677                 PTXINFO_STRUC   pTxInfo;
678                 PTXWI_STRUC             pTxWI;
679                 PUCHAR                  pWirelessPkt;
680
681                 pNullContext = &(pAd->NullContext);
682
683                 // Set the in use bit
684                 pNullContext->InUse = TRUE;
685                 pWirelessPkt = (PUCHAR)&pNullContext->TransferBuffer->field.WirelessPacket[0];
686
687                 RTMPZeroMemory(&pWirelessPkt[0], 100);
688                 pTxInfo = (PTXINFO_STRUC)&pWirelessPkt[0];
689                 RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(sizeof(HEADER_802_11)+TXWI_SIZE), TRUE, EpToQueue[MGMTPIPEIDX], FALSE,  FALSE);
690                 pTxInfo->QSEL = FIFO_EDCA;
691                 pTxWI = (PTXWI_STRUC)&pWirelessPkt[TXINFO_SIZE];
692                 RTMPWriteTxWI(pAd, pTxWI,  FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, 0, BSSID_WCID, (sizeof(HEADER_802_11)),
693                         0, 0, (UCHAR)pAd->CommonCfg.MlmeTransmit.field.MCS, IFS_HTTXOP, FALSE, &pAd->CommonCfg.MlmeTransmit);
694 #ifdef RT_BIG_ENDIAN
695                 RTMPWIEndianChange((PUCHAR)pTxWI, TYPE_TXWI);
696 #endif // RT_BIG_ENDIAN //
697
698                 RTMPMoveMemory(&pWirelessPkt[TXWI_SIZE+TXINFO_SIZE], &pAd->NullFrame, sizeof(HEADER_802_11));
699 #ifdef RT_BIG_ENDIAN
700                 RTMPFrameEndianChange(pAd, (PUCHAR)&pWirelessPkt[TXINFO_SIZE + TXWI_SIZE], DIR_WRITE, FALSE);
701 #endif // RT_BIG_ENDIAN //
702                 pAd->NullContext.BulkOutSize =  TXINFO_SIZE + TXWI_SIZE + sizeof(pAd->NullFrame) + 4;
703
704                 // Fill out frame length information for global Bulk out arbitor
705                 //pNullContext->BulkOutSize = TransferBufferLength;
706                 DBGPRINT(RT_DEBUG_TRACE, ("SYNC - send NULL Frame @%d Mbps...\n", RateIdToMbps[pAd->CommonCfg.TxRate]));
707                 RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NULL);
708
709                 // Kick bulk out
710                 RTUSBKickBulkOut(pAd);
711         }
712
713 }
714
715 #ifdef CONFIG_STA_SUPPORT
716 /*
717         ========================================================================
718
719         Routine Description:
720                 Check Rx descriptor, return NDIS_STATUS_FAILURE if any error dound
721
722         Arguments:
723                 pRxD            Pointer to the Rx descriptor
724
725         Return Value:
726                 NDIS_STATUS_SUCCESS             No err
727                 NDIS_STATUS_FAILURE             Error
728
729         Note:
730
731         ========================================================================
732 */
733 NDIS_STATUS     RTMPCheckRxError(
734         IN      PRTMP_ADAPTER   pAd,
735         IN      PHEADER_802_11  pHeader,
736         IN      PRXWI_STRUC     pRxWI,
737         IN      PRT28XX_RXD_STRUC       pRxINFO)
738 {
739         PCIPHER_KEY pWpaKey;
740         INT     dBm;
741
742         if (pAd->bPromiscuous == TRUE)
743                 return(NDIS_STATUS_SUCCESS);
744         if(pRxINFO == NULL)
745                 return(NDIS_STATUS_FAILURE);
746
747         // Phy errors & CRC errors
748         if (pRxINFO->Crc)
749         {
750                 // Check RSSI for Noise Hist statistic collection.
751                 dBm = (INT) (pRxWI->RSSI0) - pAd->BbpRssiToDbmDelta;
752                 if (dBm <= -87)
753                         pAd->StaCfg.RPIDensity[0] += 1;
754                 else if (dBm <= -82)
755                         pAd->StaCfg.RPIDensity[1] += 1;
756                 else if (dBm <= -77)
757                         pAd->StaCfg.RPIDensity[2] += 1;
758                 else if (dBm <= -72)
759                         pAd->StaCfg.RPIDensity[3] += 1;
760                 else if (dBm <= -67)
761                         pAd->StaCfg.RPIDensity[4] += 1;
762                 else if (dBm <= -62)
763                         pAd->StaCfg.RPIDensity[5] += 1;
764                 else if (dBm <= -57)
765                         pAd->StaCfg.RPIDensity[6] += 1;
766                 else if (dBm > -57)
767                         pAd->StaCfg.RPIDensity[7] += 1;
768
769                 return(NDIS_STATUS_FAILURE);
770         }
771
772         // Add Rx size to channel load counter, we should ignore error counts
773         pAd->StaCfg.CLBusyBytes += (pRxWI->MPDUtotalByteCount+ 14);
774
775         // Drop ToDs promiscous frame, it is opened due to CCX 2 channel load statistics
776         if (pHeader->FC.ToDs)
777         {
778                 DBGPRINT_RAW(RT_DEBUG_ERROR, ("Err;FC.ToDs\n"));
779                 return NDIS_STATUS_FAILURE;
780         }
781
782         // Paul 04-03 for OFDM Rx length issue
783         if (pRxWI->MPDUtotalByteCount > MAX_AGGREGATION_SIZE)
784         {
785                 DBGPRINT_RAW(RT_DEBUG_ERROR, ("received packet too long\n"));
786                 return NDIS_STATUS_FAILURE;
787         }
788
789         // Drop not U2M frames, cant's drop here because we will drop beacon in this case
790         // I am kind of doubting the U2M bit operation
791         // if (pRxD->U2M == 0)
792         //      return(NDIS_STATUS_FAILURE);
793
794         // drop decyption fail frame
795         if (pRxINFO->Decrypted && pRxINFO->CipherErr)
796         {
797
798                 //
799                 // MIC Error
800                 //
801                 if ((pRxINFO->CipherErr == 2) && pRxINFO->MyBss)
802                 {
803                         pWpaKey = &pAd->SharedKey[BSS0][pRxWI->KeyIndex];
804                         RTMPReportMicError(pAd, pWpaKey);
805                         DBGPRINT_RAW(RT_DEBUG_ERROR,("Rx MIC Value error\n"));
806                 }
807
808                 if (pRxINFO->Decrypted &&
809                         (pAd->SharedKey[BSS0][pRxWI->KeyIndex].CipherAlg == CIPHER_AES) &&
810                         (pHeader->Sequence == pAd->FragFrame.Sequence))
811                 {
812                         //
813                         // Acceptable since the First FragFrame no CipherErr problem.
814                         //
815                         return(NDIS_STATUS_SUCCESS);
816                 }
817
818                 return(NDIS_STATUS_FAILURE);
819         }
820
821         return(NDIS_STATUS_SUCCESS);
822 }
823
824 VOID RT28xxUsbStaAsicForceWakeup(
825         IN PRTMP_ADAPTER pAd,
826         IN BOOLEAN       bFromTx)
827 {
828     AUTO_WAKEUP_STRUC   AutoWakeupCfg;
829
830         AutoWakeupCfg.word = 0;
831         RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
832
833         AsicSendCommandToMcu(pAd, 0x31, 0xff, 0x00, 0x02);
834
835         OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
836 }
837
838 VOID RT28xxUsbStaAsicSleepThenAutoWakeup(
839         IN PRTMP_ADAPTER pAd,
840         IN USHORT TbttNumToNextWakeUp)
841 {
842         AUTO_WAKEUP_STRUC       AutoWakeupCfg;
843
844         // we have decided to SLEEP, so at least do it for a BEACON period.
845         if (TbttNumToNextWakeUp == 0)
846                 TbttNumToNextWakeUp = 1;
847
848         AutoWakeupCfg.word = 0;
849         RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
850
851         AutoWakeupCfg.field.NumofSleepingTbtt = TbttNumToNextWakeUp - 1;
852         AutoWakeupCfg.field.EnableAutoWakeup = 1;
853         AutoWakeupCfg.field.AutoLeadTime = 5;
854         RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
855
856         AsicSendCommandToMcu(pAd, 0x30, 0xff, 0xff, 0x02);   // send POWER-SAVE command to MCU. Timeout 40us.
857
858         OPSTATUS_SET_FLAG(pAd, fOP_STATUS_DOZE);
859
860 }
861 #endif // CONFIG_STA_SUPPORT //
862
863 VOID RT28xxUsbMlmeRadioOn(
864         IN PRTMP_ADAPTER pAd)
865 {
866     DBGPRINT(RT_DEBUG_TRACE,("RT28xxUsbMlmeRadioOn()\n"));
867
868         if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
869                 return;
870
871 #ifdef CONFIG_STA_SUPPORT
872         IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
873         {
874         AsicSendCommandToMcu(pAd, 0x31, 0xff, 0x00, 0x02);
875                 RTMPusecDelay(10000);
876         }
877 #endif // CONFIG_STA_SUPPORT //
878         NICResetFromError(pAd);
879
880         // Enable Tx/Rx
881         RTMPEnableRxTx(pAd);
882
883 #ifdef RT3070
884         if (IS_RT3071(pAd))
885         {
886                 RT30xxReverseRFSleepModeSetup(pAd);
887         }
888 #endif // RT3070 //
889
890         // Clear Radio off flag
891         RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
892
893 #ifdef CONFIG_STA_SUPPORT
894         IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
895                 RTUSBBulkReceive(pAd);
896 #endif // CONFIG_STA_SUPPORT //
897
898         // Set LED
899         RTMPSetLED(pAd, LED_RADIO_ON);
900 }
901
902 VOID RT28xxUsbMlmeRadioOFF(
903         IN PRTMP_ADAPTER pAd)
904 {
905         WPDMA_GLO_CFG_STRUC     GloCfg;
906         UINT32  Value, i;
907
908         DBGPRINT(RT_DEBUG_TRACE,("RT28xxUsbMlmeRadioOFF()\n"));
909
910         if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
911                 return;
912
913         // Set LED
914         RTMPSetLED(pAd, LED_RADIO_OFF);
915         // Set Radio off flag
916         RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
917
918 #ifdef CONFIG_STA_SUPPORT
919         IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
920         {
921                 // Link down first if any association exists
922                 if (INFRA_ON(pAd) || ADHOC_ON(pAd))
923                         LinkDown(pAd, FALSE);
924                 RTMPusecDelay(10000);
925
926                 //==========================================
927                 // Clean up old bss table
928                 BssTableInit(&pAd->ScanTab);
929         }
930 #endif // CONFIG_STA_SUPPORT //
931
932
933         if (pAd->CommonCfg.BBPCurrentBW == BW_40)
934         {
935                 // Must using 40MHz.
936                 AsicTurnOffRFClk(pAd, pAd->CommonCfg.CentralChannel);
937         }
938         else
939         {
940                 // Must using 20MHz.
941                 AsicTurnOffRFClk(pAd, pAd->CommonCfg.Channel);
942         }
943
944         // Disable Tx/Rx DMA
945         RTUSBReadMACRegister(pAd, WPDMA_GLO_CFG, &GloCfg.word);    // disable DMA
946         GloCfg.field.EnableTxDMA = 0;
947         GloCfg.field.EnableRxDMA = 0;
948         RTUSBWriteMACRegister(pAd, WPDMA_GLO_CFG, GloCfg.word);    // abort all TX rings
949
950         // Waiting for DMA idle
951         i = 0;
952         do
953         {
954                 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word);
955                 if ((GloCfg.field.TxDMABusy == 0) && (GloCfg.field.RxDMABusy == 0))
956                         break;
957
958                 RTMPusecDelay(1000);
959         }while (i++ < 100);
960
961         // Disable MAC Tx/Rx
962         RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value);
963         Value &= (0xfffffff3);
964         RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value);
965
966         // MAC_SYS_CTRL => value = 0x0 => 40mA
967         //RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0);
968
969         // PWR_PIN_CFG => value = 0x0 => 40mA
970         //RTMP_IO_WRITE32(pAd, PWR_PIN_CFG, 0);
971
972         // TX_PIN_CFG => value = 0x0 => 20mA
973         //RTMP_IO_WRITE32(pAd, TX_PIN_CFG, 0);
974
975 #ifdef CONFIG_STA_SUPPORT
976         IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
977                 AsicSendCommandToMcu(pAd, 0x30, 0xff, 0xff, 0x02);
978 #endif // CONFIG_STA_SUPPORT //
979 }
980