/* ************************************************************************* * Ralink Tech Inc. * 5F., No.36, Taiyuan St., Jhubei City, * Hsinchu County 302, * Taiwan, R.O.C. * * (c) Copyright 2002-2007, Ralink Technology, Inc. * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * ************************************************************************* */ /* All functions in this file must be USB-depended, or you should out your function in other files. */ #include "../rt_config.h" /* We can do copy the frame into pTxContext when match following conditions. => => => */ static inline NDIS_STATUS RtmpUSBCanDoWrite( IN RTMP_ADAPTER *pAd, IN UCHAR QueIdx, IN HT_TX_CONTEXT *pHTTXContext) { NDIS_STATUS canWrite = NDIS_STATUS_RESOURCES; if (((pHTTXContext->CurWritePosition) < pHTTXContext->NextBulkOutPosition) && (pHTTXContext->CurWritePosition + LOCAL_TXBUF_SIZE) > pHTTXContext->NextBulkOutPosition) { DBGPRINT(RT_DEBUG_ERROR,("RtmpUSBCanDoWrite c1!\n")); RTUSB_SET_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << QueIdx)); } else if ((pHTTXContext->CurWritePosition == 8) && (pHTTXContext->NextBulkOutPosition < LOCAL_TXBUF_SIZE)) { DBGPRINT(RT_DEBUG_ERROR,("RtmpUSBCanDoWrite c2!\n")); RTUSB_SET_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << QueIdx)); } else if (pHTTXContext->bCurWriting == TRUE) { DBGPRINT(RT_DEBUG_ERROR,("RtmpUSBCanDoWrite c3!\n")); } else { canWrite = NDIS_STATUS_SUCCESS; } return canWrite; } USHORT RtmpUSB_WriteSubTxResource( IN PRTMP_ADAPTER pAd, IN TX_BLK *pTxBlk, IN BOOLEAN bIsLast, OUT USHORT *FreeNumber) { // Dummy function. Should be removed in the future. return 0; } USHORT RtmpUSB_WriteFragTxResource( IN PRTMP_ADAPTER pAd, IN TX_BLK *pTxBlk, IN UCHAR fragNum, OUT USHORT *FreeNumber) { HT_TX_CONTEXT *pHTTXContext; USHORT hwHdrLen; // The hwHdrLen consist of 802.11 header length plus the header padding length. UINT32 fillOffset; TXINFO_STRUC *pTxInfo; TXWI_STRUC *pTxWI; PUCHAR pWirelessPacket = NULL; UCHAR QueIdx; NDIS_STATUS Status; unsigned long IrqFlags; UINT32 USBDMApktLen = 0, DMAHdrLen, padding; BOOLEAN TxQLastRound = FALSE; // // get Tx Ring Resource & Dma Buffer address // QueIdx = pTxBlk->QueIdx; pHTTXContext = &pAd->TxContext[QueIdx]; RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); pHTTXContext = &pAd->TxContext[QueIdx]; fillOffset = pHTTXContext->CurWritePosition; if(fragNum == 0) { // Check if we have enough space for this bulk-out batch. Status = RtmpUSBCanDoWrite(pAd, QueIdx, pHTTXContext); if (Status == NDIS_STATUS_SUCCESS) { pHTTXContext->bCurWriting = TRUE; // Reserve space for 8 bytes padding. if ((pHTTXContext->ENextBulkOutPosition == pHTTXContext->CurWritePosition)) { pHTTXContext->ENextBulkOutPosition += 8; pHTTXContext->CurWritePosition += 8; fillOffset += 8; } pTxBlk->Priv = 0; pHTTXContext->CurWriteRealPos = pHTTXContext->CurWritePosition; } else { RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); return(Status); } } else { // For sub-sequent frames of this bulk-out batch. Just copy it to our bulk-out buffer. Status = ((pHTTXContext->bCurWriting == TRUE) ? NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE); if (Status == NDIS_STATUS_SUCCESS) { fillOffset += pTxBlk->Priv; } else { RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); return(Status); } } NdisZeroMemory((PUCHAR)(&pTxBlk->HeaderBuf[0]), TXINFO_SIZE); pTxInfo = (PTXINFO_STRUC)(&pTxBlk->HeaderBuf[0]); pTxWI= (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]); pWirelessPacket = &pHTTXContext->TransferBuffer->field.WirelessPacket[fillOffset]; // copy TXWI + WLAN Header + LLC into DMA Header Buffer //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4); hwHdrLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen; // Build our URB for USBD DMAHdrLen = TXWI_SIZE + hwHdrLen; USBDMApktLen = DMAHdrLen + pTxBlk->SrcBufLen; padding = (4 - (USBDMApktLen % 4)) & 0x03; // round up to 4 byte alignment USBDMApktLen += padding; pTxBlk->Priv += (TXINFO_SIZE + USBDMApktLen); // For TxInfo, the length of USBDMApktLen = TXWI_SIZE + 802.11 header + payload RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(USBDMApktLen), FALSE, FIFO_EDCA, FALSE /*NextValid*/, FALSE); if (fragNum == pTxBlk->TotalFragNum) { pTxInfo->USBDMATxburst = 0; if ((pHTTXContext->CurWritePosition + pTxBlk->Priv + 3906)> MAX_TXBULK_LIMIT) { pTxInfo->SwUseLastRound = 1; TxQLastRound = TRUE; } } else { pTxInfo->USBDMATxburst = 1; } NdisMoveMemory(pWirelessPacket, pTxBlk->HeaderBuf, TXINFO_SIZE + TXWI_SIZE + hwHdrLen); #ifdef RT_BIG_ENDIAN RTMPFrameEndianChange(pAd, (PUCHAR)(pWirelessPacket + TXINFO_SIZE + TXWI_SIZE), DIR_WRITE, FALSE); #endif // RT_BIG_ENDIAN // pWirelessPacket += (TXINFO_SIZE + TXWI_SIZE + hwHdrLen); pHTTXContext->CurWriteRealPos += (TXINFO_SIZE + TXWI_SIZE + hwHdrLen); RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); NdisMoveMemory(pWirelessPacket, pTxBlk->pSrcBufData, pTxBlk->SrcBufLen); // Zero the last padding. pWirelessPacket += pTxBlk->SrcBufLen; NdisZeroMemory(pWirelessPacket, padding + 8); if (fragNum == pTxBlk->TotalFragNum) { RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); // Update the pHTTXContext->CurWritePosition. 3906 used to prevent the NextBulkOut is a A-RALINK/A-MSDU Frame. pHTTXContext->CurWritePosition += pTxBlk->Priv; if (TxQLastRound == TRUE) pHTTXContext->CurWritePosition = 8; pHTTXContext->CurWriteRealPos = pHTTXContext->CurWritePosition; // Finally, set bCurWriting as FALSE pHTTXContext->bCurWriting = FALSE; RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); // succeed and release the skb buffer RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_SUCCESS); } return(Status); } USHORT RtmpUSB_WriteSingleTxResource( IN PRTMP_ADAPTER pAd, IN TX_BLK *pTxBlk, IN BOOLEAN bIsLast, OUT USHORT *FreeNumber) { HT_TX_CONTEXT *pHTTXContext; USHORT hwHdrLen; UINT32 fillOffset; TXINFO_STRUC *pTxInfo; TXWI_STRUC *pTxWI; PUCHAR pWirelessPacket; UCHAR QueIdx; unsigned long IrqFlags; NDIS_STATUS Status; UINT32 USBDMApktLen = 0, DMAHdrLen, padding; BOOLEAN bTxQLastRound = FALSE; // For USB, didn't need PCI_MAP_SINGLE() //SrcBufPA = PCI_MAP_SINGLE(pAd, (char *) pTxBlk->pSrcBufData, pTxBlk->SrcBufLen, PCI_DMA_TODEVICE); // // get Tx Ring Resource & Dma Buffer address // QueIdx = pTxBlk->QueIdx; RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); pHTTXContext = &pAd->TxContext[QueIdx]; fillOffset = pHTTXContext->CurWritePosition; // Check ring full. Status = RtmpUSBCanDoWrite(pAd, QueIdx, pHTTXContext); if(Status == NDIS_STATUS_SUCCESS) { pHTTXContext->bCurWriting = TRUE; pTxInfo = (PTXINFO_STRUC)(&pTxBlk->HeaderBuf[0]); pTxWI= (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]); // Reserve space for 8 bytes padding. if ((pHTTXContext->ENextBulkOutPosition == pHTTXContext->CurWritePosition)) { pHTTXContext->ENextBulkOutPosition += 8; pHTTXContext->CurWritePosition += 8; fillOffset += 8; } pHTTXContext->CurWriteRealPos = pHTTXContext->CurWritePosition; pWirelessPacket = &pHTTXContext->TransferBuffer->field.WirelessPacket[fillOffset]; // copy TXWI + WLAN Header + LLC into DMA Header Buffer //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4); hwHdrLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen; // Build our URB for USBD DMAHdrLen = TXWI_SIZE + hwHdrLen; USBDMApktLen = DMAHdrLen + pTxBlk->SrcBufLen; padding = (4 - (USBDMApktLen % 4)) & 0x03; // round up to 4 byte alignment USBDMApktLen += padding; pTxBlk->Priv = (TXINFO_SIZE + USBDMApktLen); // For TxInfo, the length of USBDMApktLen = TXWI_SIZE + 802.11 header + payload //PS packets use HCCA queue when dequeue from PS unicast queue (WiFi WPA2 MA9_DT1 for Marvell B STA) #ifdef CONFIG_STA_SUPPORT IF_DEV_CONFIG_OPMODE_ON_STA(pAd) RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(USBDMApktLen), FALSE, FIFO_EDCA, FALSE /*NextValid*/, FALSE); #endif // CONFIG_STA_SUPPORT // if ((pHTTXContext->CurWritePosition + 3906 + pTxBlk->Priv) > MAX_TXBULK_LIMIT) { pTxInfo->SwUseLastRound = 1; bTxQLastRound = TRUE; } NdisMoveMemory(pWirelessPacket, pTxBlk->HeaderBuf, TXINFO_SIZE + TXWI_SIZE + hwHdrLen); #ifdef RT_BIG_ENDIAN RTMPFrameEndianChange(pAd, (PUCHAR)(pWirelessPacket + TXINFO_SIZE + TXWI_SIZE), DIR_WRITE, FALSE); #endif // RT_BIG_ENDIAN // pWirelessPacket += (TXINFO_SIZE + TXWI_SIZE + hwHdrLen); // We unlock it here to prevent the first 8 bytes maybe over-writed issue. // 1. First we got CurWritePosition but the first 8 bytes still not write to the pTxcontext. // 2. An interrupt break our routine and handle bulk-out complete. // 3. In the bulk-out compllete, it need to do another bulk-out, // if the ENextBulkOutPosition is just the same as CurWritePosition, it will save the first 8 bytes from CurWritePosition, // but the payload still not copyed. the pTxContext->SavedPad[] will save as allzero. and set the bCopyPad = TRUE. // 4. Interrupt complete. // 5. Our interrupted routine go back and fill the first 8 bytes to pTxContext. // 6. Next time when do bulk-out, it found the bCopyPad==TRUE and will copy the SavedPad[] to pTxContext->NextBulkOutPosition. // and the packet will wrong. pHTTXContext->CurWriteRealPos += (TXINFO_SIZE + TXWI_SIZE + hwHdrLen); RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); NdisMoveMemory(pWirelessPacket, pTxBlk->pSrcBufData, pTxBlk->SrcBufLen); pWirelessPacket += pTxBlk->SrcBufLen; NdisZeroMemory(pWirelessPacket, padding + 8); RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); pHTTXContext->CurWritePosition += pTxBlk->Priv; if (bTxQLastRound) pHTTXContext->CurWritePosition = 8; pHTTXContext->CurWriteRealPos = pHTTXContext->CurWritePosition; pHTTXContext->bCurWriting = FALSE; } RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); // succeed and release the skb buffer RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_SUCCESS); return(Status); } USHORT RtmpUSB_WriteMultiTxResource( IN PRTMP_ADAPTER pAd, IN TX_BLK *pTxBlk, IN UCHAR frameNum, OUT USHORT *FreeNumber) { HT_TX_CONTEXT *pHTTXContext; USHORT hwHdrLen; // The hwHdrLen consist of 802.11 header length plus the header padding length. UINT32 fillOffset; TXINFO_STRUC *pTxInfo; TXWI_STRUC *pTxWI; PUCHAR pWirelessPacket = NULL; UCHAR QueIdx; NDIS_STATUS Status; unsigned long IrqFlags; //UINT32 USBDMApktLen = 0, DMAHdrLen, padding; // // get Tx Ring Resource & Dma Buffer address // QueIdx = pTxBlk->QueIdx; pHTTXContext = &pAd->TxContext[QueIdx]; RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); if(frameNum == 0) { // Check if we have enough space for this bulk-out batch. Status = RtmpUSBCanDoWrite(pAd, QueIdx, pHTTXContext); if (Status == NDIS_STATUS_SUCCESS) { pHTTXContext->bCurWriting = TRUE; pTxInfo = (PTXINFO_STRUC)(&pTxBlk->HeaderBuf[0]); pTxWI= (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]); // Reserve space for 8 bytes padding. if ((pHTTXContext->ENextBulkOutPosition == pHTTXContext->CurWritePosition)) { pHTTXContext->CurWritePosition += 8; pHTTXContext->ENextBulkOutPosition += 8; } fillOffset = pHTTXContext->CurWritePosition; pHTTXContext->CurWriteRealPos = pHTTXContext->CurWritePosition; pWirelessPacket = &pHTTXContext->TransferBuffer->field.WirelessPacket[fillOffset]; // // Copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer // if (pTxBlk->TxFrameType == TX_AMSDU_FRAME) //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen-LENGTH_AMSDU_SUBFRAMEHEAD, 4)+LENGTH_AMSDU_SUBFRAMEHEAD; hwHdrLen = pTxBlk->MpduHeaderLen-LENGTH_AMSDU_SUBFRAMEHEAD + pTxBlk->HdrPadLen + LENGTH_AMSDU_SUBFRAMEHEAD; else if (pTxBlk->TxFrameType == TX_RALINK_FRAME) //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen-LENGTH_ARALINK_HEADER_FIELD, 4)+LENGTH_ARALINK_HEADER_FIELD; hwHdrLen = pTxBlk->MpduHeaderLen-LENGTH_ARALINK_HEADER_FIELD + pTxBlk->HdrPadLen + LENGTH_ARALINK_HEADER_FIELD; else //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4); hwHdrLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen; // Update the pTxBlk->Priv. pTxBlk->Priv = TXINFO_SIZE + TXWI_SIZE + hwHdrLen; // pTxInfo->USBDMApktLen now just a temp value and will to correct latter. RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(pTxBlk->Priv), FALSE, FIFO_EDCA, FALSE /*NextValid*/, FALSE); // Copy it. NdisMoveMemory(pWirelessPacket, pTxBlk->HeaderBuf, pTxBlk->Priv); #ifdef RT_BIG_ENDIAN RTMPFrameEndianChange(pAd, (PUCHAR)(pWirelessPacket+ TXINFO_SIZE + TXWI_SIZE), DIR_WRITE, FALSE); #endif // RT_BIG_ENDIAN // pHTTXContext->CurWriteRealPos += pTxBlk->Priv; pWirelessPacket += pTxBlk->Priv; } } else { // For sub-sequent frames of this bulk-out batch. Just copy it to our bulk-out buffer. Status = ((pHTTXContext->bCurWriting == TRUE) ? NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE); if (Status == NDIS_STATUS_SUCCESS) { fillOffset = (pHTTXContext->CurWritePosition + pTxBlk->Priv); pWirelessPacket = &pHTTXContext->TransferBuffer->field.WirelessPacket[fillOffset]; //hwHdrLen = pTxBlk->MpduHeaderLen; NdisMoveMemory(pWirelessPacket, pTxBlk->HeaderBuf, pTxBlk->MpduHeaderLen); pWirelessPacket += (pTxBlk->MpduHeaderLen); pTxBlk->Priv += pTxBlk->MpduHeaderLen; } else { // It should not happened now unless we are going to shutdown. DBGPRINT(RT_DEBUG_ERROR, ("WriteMultiTxResource():bCurWriting is FALSE when handle sub-sequent frames.\n")); Status = NDIS_STATUS_FAILURE; } } // We unlock it here to prevent the first 8 bytes maybe over-write issue. // 1. First we got CurWritePosition but the first 8 bytes still not write to the pTxContext. // 2. An interrupt break our routine and handle bulk-out complete. // 3. In the bulk-out compllete, it need to do another bulk-out, // if the ENextBulkOutPosition is just the same as CurWritePosition, it will save the first 8 bytes from CurWritePosition, // but the payload still not copyed. the pTxContext->SavedPad[] will save as allzero. and set the bCopyPad = TRUE. // 4. Interrupt complete. // 5. Our interrupted routine go back and fill the first 8 bytes to pTxContext. // 6. Next time when do bulk-out, it found the bCopyPad==TRUE and will copy the SavedPad[] to pTxContext->NextBulkOutPosition. // and the packet will wrong. RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); if (Status != NDIS_STATUS_SUCCESS) { DBGPRINT(RT_DEBUG_ERROR,("WriteMultiTxResource: CWPos = %ld, NBOutPos = %ld.\n", pHTTXContext->CurWritePosition, pHTTXContext->NextBulkOutPosition)); goto done; } // Copy the frame content into DMA buffer and update the pTxBlk->Priv NdisMoveMemory(pWirelessPacket, pTxBlk->pSrcBufData, pTxBlk->SrcBufLen); pWirelessPacket += pTxBlk->SrcBufLen; pTxBlk->Priv += pTxBlk->SrcBufLen; done: // Release the skb buffer here RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_SUCCESS); return(Status); } VOID RtmpUSB_FinalWriteTxResource( IN PRTMP_ADAPTER pAd, IN TX_BLK *pTxBlk, IN USHORT totalMPDUSize, IN USHORT TxIdx) { UCHAR QueIdx; HT_TX_CONTEXT *pHTTXContext; UINT32 fillOffset; TXINFO_STRUC *pTxInfo; TXWI_STRUC *pTxWI; UINT32 USBDMApktLen, padding; unsigned long IrqFlags; PUCHAR pWirelessPacket; QueIdx = pTxBlk->QueIdx; pHTTXContext = &pAd->TxContext[QueIdx]; RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); if (pHTTXContext->bCurWriting == TRUE) { fillOffset = pHTTXContext->CurWritePosition; if (((pHTTXContext->ENextBulkOutPosition == pHTTXContext->CurWritePosition) || ((pHTTXContext->ENextBulkOutPosition-8) == pHTTXContext->CurWritePosition)) && (pHTTXContext->bCopySavePad == TRUE)) pWirelessPacket = (PUCHAR)(&pHTTXContext->SavedPad[0]); else pWirelessPacket = (PUCHAR)(&pHTTXContext->TransferBuffer->field.WirelessPacket[fillOffset]); // // Update TxInfo->USBDMApktLen , // the length = TXWI_SIZE + 802.11_hdr + 802.11_hdr_pad + payload_of_all_batch_frames + Bulk-Out-padding // pTxInfo = (PTXINFO_STRUC)(pWirelessPacket); // Calculate the bulk-out padding USBDMApktLen = pTxBlk->Priv - TXINFO_SIZE; padding = (4 - (USBDMApktLen % 4)) & 0x03; // round up to 4 byte alignment USBDMApktLen += padding; pTxInfo->USBDMATxPktLen = USBDMApktLen; // // Update TXWI->MPDUtotalByteCount , // the length = 802.11 header + payload_of_all_batch_frames pTxWI= (PTXWI_STRUC)(pWirelessPacket + TXINFO_SIZE); pTxWI->MPDUtotalByteCount = totalMPDUSize; // // Update the pHTTXContext->CurWritePosition // pHTTXContext->CurWritePosition += (TXINFO_SIZE + USBDMApktLen); if ((pHTTXContext->CurWritePosition + 3906)> MAX_TXBULK_LIMIT) { // Add 3906 for prevent the NextBulkOut packet size is a A-RALINK/A-MSDU Frame. pHTTXContext->CurWritePosition = 8; pTxInfo->SwUseLastRound = 1; } pHTTXContext->CurWriteRealPos = pHTTXContext->CurWritePosition; // // Zero the last padding. // pWirelessPacket = (&pHTTXContext->TransferBuffer->field.WirelessPacket[fillOffset + pTxBlk->Priv]); NdisZeroMemory(pWirelessPacket, padding + 8); // Finally, set bCurWriting as FALSE pHTTXContext->bCurWriting = FALSE; } else { // It should not happened now unless we are going to shutdown. DBGPRINT(RT_DEBUG_ERROR, ("FinalWriteTxResource():bCurWriting is FALSE when handle last frames.\n")); } RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); } VOID RtmpUSBDataLastTxIdx( IN PRTMP_ADAPTER pAd, IN UCHAR QueIdx, IN USHORT TxIdx) { // DO nothing for USB. } /* When can do bulk-out: 1. TxSwFreeIdx < TX_RING_SIZE; It means has at least one Ring entity is ready for bulk-out, kick it out. 2. If TxSwFreeIdx == TX_RING_SIZE Check if the CurWriting flag is FALSE, if it's FALSE, we can do kick out. */ VOID RtmpUSBDataKickOut( IN PRTMP_ADAPTER pAd, IN TX_BLK *pTxBlk, IN UCHAR QueIdx) { RTUSB_SET_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << QueIdx)); RTUSBKickBulkOut(pAd); } /* Must be run in Interrupt context This function handle RT2870 specific TxDesc and cpu index update and kick the packet out. */ int RtmpUSBMgmtKickOut( IN RTMP_ADAPTER *pAd, IN UCHAR QueIdx, IN PNDIS_PACKET pPacket, IN PUCHAR pSrcBufVA, IN UINT SrcBufLen) { PTXINFO_STRUC pTxInfo; ULONG BulkOutSize; UCHAR padLen; PUCHAR pDest; ULONG SwIdx = pAd->MgmtRing.TxCpuIdx; PTX_CONTEXT pMLMEContext = (PTX_CONTEXT)pAd->MgmtRing.Cell[SwIdx].AllocVa; unsigned long IrqFlags; pTxInfo = (PTXINFO_STRUC)(pSrcBufVA); // Build our URB for USBD BulkOutSize = SrcBufLen; BulkOutSize = (BulkOutSize + 3) & (~3); RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(BulkOutSize - TXINFO_SIZE), TRUE, EpToQueue[MGMTPIPEIDX], FALSE, FALSE); BulkOutSize += 4; // Always add 4 extra bytes at every packet. // If BulkOutSize is multiple of BulkOutMaxPacketSize, add extra 4 bytes again. if ((BulkOutSize % pAd->BulkOutMaxPacketSize) == 0) BulkOutSize += 4; padLen = BulkOutSize - SrcBufLen; ASSERT((padLen <= RTMP_PKT_TAIL_PADDING)); // Now memzero all extra padding bytes. pDest = (PUCHAR)(pSrcBufVA + SrcBufLen); skb_put(GET_OS_PKT_TYPE(pPacket), padLen); NdisZeroMemory(pDest, padLen); RTMP_IRQ_LOCK(&pAd->MLMEBulkOutLock, IrqFlags); pAd->MgmtRing.Cell[pAd->MgmtRing.TxCpuIdx].pNdisPacket = pPacket; pMLMEContext->TransferBuffer = (PTX_BUFFER)(GET_OS_PKT_DATAPTR(pPacket)); // Length in TxInfo should be 8 less than bulkout size. pMLMEContext->BulkOutSize = BulkOutSize; pMLMEContext->InUse = TRUE; pMLMEContext->bWaitingBulkOut = TRUE; //for debug //hex_dump("RtmpUSBMgmtKickOut", &pMLMEContext->TransferBuffer->field.WirelessPacket[0], (pMLMEContext->BulkOutSize > 16 ? 16 : pMLMEContext->BulkOutSize)); //pAd->RalinkCounters.KickTxCount++; //pAd->RalinkCounters.OneSecTxDoneCount++; //if (pAd->MgmtRing.TxSwFreeIdx == MGMT_RING_SIZE) // needKickOut = TRUE; // Decrease the TxSwFreeIdx and Increase the TX_CTX_IDX pAd->MgmtRing.TxSwFreeIdx--; INC_RING_INDEX(pAd->MgmtRing.TxCpuIdx, MGMT_RING_SIZE); RTMP_IRQ_UNLOCK(&pAd->MLMEBulkOutLock, IrqFlags); RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_MLME); //if (needKickOut) RTUSBKickBulkOut(pAd); return 0; } VOID RtmpUSBNullFrameKickOut( IN RTMP_ADAPTER *pAd, IN UCHAR QueIdx, IN UCHAR *pNullFrame, IN UINT32 frameLen) { if (pAd->NullContext.InUse == FALSE) { PTX_CONTEXT pNullContext; PTXINFO_STRUC pTxInfo; PTXWI_STRUC pTxWI; PUCHAR pWirelessPkt; pNullContext = &(pAd->NullContext); // Set the in use bit pNullContext->InUse = TRUE; pWirelessPkt = (PUCHAR)&pNullContext->TransferBuffer->field.WirelessPacket[0]; RTMPZeroMemory(&pWirelessPkt[0], 100); pTxInfo = (PTXINFO_STRUC)&pWirelessPkt[0]; RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(sizeof(HEADER_802_11)+TXWI_SIZE), TRUE, EpToQueue[MGMTPIPEIDX], FALSE, FALSE); pTxInfo->QSEL = FIFO_EDCA; pTxWI = (PTXWI_STRUC)&pWirelessPkt[TXINFO_SIZE]; RTMPWriteTxWI(pAd, pTxWI, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, 0, BSSID_WCID, (sizeof(HEADER_802_11)), 0, 0, (UCHAR)pAd->CommonCfg.MlmeTransmit.field.MCS, IFS_HTTXOP, FALSE, &pAd->CommonCfg.MlmeTransmit); #ifdef RT_BIG_ENDIAN RTMPWIEndianChange((PUCHAR)pTxWI, TYPE_TXWI); #endif // RT_BIG_ENDIAN // RTMPMoveMemory(&pWirelessPkt[TXWI_SIZE+TXINFO_SIZE], &pAd->NullFrame, sizeof(HEADER_802_11)); #ifdef RT_BIG_ENDIAN RTMPFrameEndianChange(pAd, (PUCHAR)&pWirelessPkt[TXINFO_SIZE + TXWI_SIZE], DIR_WRITE, FALSE); #endif // RT_BIG_ENDIAN // pAd->NullContext.BulkOutSize = TXINFO_SIZE + TXWI_SIZE + sizeof(pAd->NullFrame) + 4; // Fill out frame length information for global Bulk out arbitor //pNullContext->BulkOutSize = TransferBufferLength; DBGPRINT(RT_DEBUG_TRACE, ("SYNC - send NULL Frame @%d Mbps...\n", RateIdToMbps[pAd->CommonCfg.TxRate])); RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NULL); // Kick bulk out RTUSBKickBulkOut(pAd); } } #ifdef CONFIG_STA_SUPPORT /* ======================================================================== Routine Description: Check Rx descriptor, return NDIS_STATUS_FAILURE if any error dound Arguments: pRxD Pointer to the Rx descriptor Return Value: NDIS_STATUS_SUCCESS No err NDIS_STATUS_FAILURE Error Note: ======================================================================== */ NDIS_STATUS RTMPCheckRxError( IN PRTMP_ADAPTER pAd, IN PHEADER_802_11 pHeader, IN PRXWI_STRUC pRxWI, IN PRT28XX_RXD_STRUC pRxINFO) { PCIPHER_KEY pWpaKey; INT dBm; if (pAd->bPromiscuous == TRUE) return(NDIS_STATUS_SUCCESS); if(pRxINFO == NULL) return(NDIS_STATUS_FAILURE); // Phy errors & CRC errors if (pRxINFO->Crc) { // Check RSSI for Noise Hist statistic collection. dBm = (INT) (pRxWI->RSSI0) - pAd->BbpRssiToDbmDelta; if (dBm <= -87) pAd->StaCfg.RPIDensity[0] += 1; else if (dBm <= -82) pAd->StaCfg.RPIDensity[1] += 1; else if (dBm <= -77) pAd->StaCfg.RPIDensity[2] += 1; else if (dBm <= -72) pAd->StaCfg.RPIDensity[3] += 1; else if (dBm <= -67) pAd->StaCfg.RPIDensity[4] += 1; else if (dBm <= -62) pAd->StaCfg.RPIDensity[5] += 1; else if (dBm <= -57) pAd->StaCfg.RPIDensity[6] += 1; else if (dBm > -57) pAd->StaCfg.RPIDensity[7] += 1; return(NDIS_STATUS_FAILURE); } // Add Rx size to channel load counter, we should ignore error counts pAd->StaCfg.CLBusyBytes += (pRxWI->MPDUtotalByteCount+ 14); // Drop ToDs promiscous frame, it is opened due to CCX 2 channel load statistics if (pHeader->FC.ToDs) { DBGPRINT_RAW(RT_DEBUG_ERROR, ("Err;FC.ToDs\n")); return NDIS_STATUS_FAILURE; } // Paul 04-03 for OFDM Rx length issue if (pRxWI->MPDUtotalByteCount > MAX_AGGREGATION_SIZE) { DBGPRINT_RAW(RT_DEBUG_ERROR, ("received packet too long\n")); return NDIS_STATUS_FAILURE; } // Drop not U2M frames, cant's drop here because we will drop beacon in this case // I am kind of doubting the U2M bit operation // if (pRxD->U2M == 0) // return(NDIS_STATUS_FAILURE); // drop decyption fail frame if (pRxINFO->Decrypted && pRxINFO->CipherErr) { // // MIC Error // if ((pRxINFO->CipherErr == 2) && pRxINFO->MyBss) { pWpaKey = &pAd->SharedKey[BSS0][pRxWI->KeyIndex]; RTMPReportMicError(pAd, pWpaKey); DBGPRINT_RAW(RT_DEBUG_ERROR,("Rx MIC Value error\n")); } if (pRxINFO->Decrypted && (pAd->SharedKey[BSS0][pRxWI->KeyIndex].CipherAlg == CIPHER_AES) && (pHeader->Sequence == pAd->FragFrame.Sequence)) { // // Acceptable since the First FragFrame no CipherErr problem. // return(NDIS_STATUS_SUCCESS); } return(NDIS_STATUS_FAILURE); } return(NDIS_STATUS_SUCCESS); } VOID RT28xxUsbStaAsicForceWakeup( IN PRTMP_ADAPTER pAd, IN BOOLEAN bFromTx) { AUTO_WAKEUP_STRUC AutoWakeupCfg; AutoWakeupCfg.word = 0; RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word); AsicSendCommandToMcu(pAd, 0x31, 0xff, 0x00, 0x02); OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE); } VOID RT28xxUsbStaAsicSleepThenAutoWakeup( IN PRTMP_ADAPTER pAd, IN USHORT TbttNumToNextWakeUp) { AUTO_WAKEUP_STRUC AutoWakeupCfg; // we have decided to SLEEP, so at least do it for a BEACON period. if (TbttNumToNextWakeUp == 0) TbttNumToNextWakeUp = 1; AutoWakeupCfg.word = 0; RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word); AutoWakeupCfg.field.NumofSleepingTbtt = TbttNumToNextWakeUp - 1; AutoWakeupCfg.field.EnableAutoWakeup = 1; AutoWakeupCfg.field.AutoLeadTime = 5; RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word); AsicSendCommandToMcu(pAd, 0x30, 0xff, 0xff, 0x02); // send POWER-SAVE command to MCU. Timeout 40us. OPSTATUS_SET_FLAG(pAd, fOP_STATUS_DOZE); } #endif // CONFIG_STA_SUPPORT // VOID RT28xxUsbMlmeRadioOn( IN PRTMP_ADAPTER pAd) { DBGPRINT(RT_DEBUG_TRACE,("RT28xxUsbMlmeRadioOn()\n")); if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) return; #ifdef CONFIG_STA_SUPPORT IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { AsicSendCommandToMcu(pAd, 0x31, 0xff, 0x00, 0x02); RTMPusecDelay(10000); } #endif // CONFIG_STA_SUPPORT // NICResetFromError(pAd); // Enable Tx/Rx RTMPEnableRxTx(pAd); #ifdef RT3070 if (IS_RT3071(pAd)) { RT30xxReverseRFSleepModeSetup(pAd); } #endif // RT3070 // // Clear Radio off flag RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF); #ifdef CONFIG_STA_SUPPORT IF_DEV_CONFIG_OPMODE_ON_STA(pAd) RTUSBBulkReceive(pAd); #endif // CONFIG_STA_SUPPORT // // Set LED RTMPSetLED(pAd, LED_RADIO_ON); } VOID RT28xxUsbMlmeRadioOFF( IN PRTMP_ADAPTER pAd) { WPDMA_GLO_CFG_STRUC GloCfg; UINT32 Value, i; DBGPRINT(RT_DEBUG_TRACE,("RT28xxUsbMlmeRadioOFF()\n")); if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) return; // Set LED RTMPSetLED(pAd, LED_RADIO_OFF); // Set Radio off flag RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF); #ifdef CONFIG_STA_SUPPORT IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { // Link down first if any association exists if (INFRA_ON(pAd) || ADHOC_ON(pAd)) LinkDown(pAd, FALSE); RTMPusecDelay(10000); //========================================== // Clean up old bss table BssTableInit(&pAd->ScanTab); } #endif // CONFIG_STA_SUPPORT // if (pAd->CommonCfg.BBPCurrentBW == BW_40) { // Must using 40MHz. AsicTurnOffRFClk(pAd, pAd->CommonCfg.CentralChannel); } else { // Must using 20MHz. AsicTurnOffRFClk(pAd, pAd->CommonCfg.Channel); } // Disable Tx/Rx DMA RTUSBReadMACRegister(pAd, WPDMA_GLO_CFG, &GloCfg.word); // disable DMA GloCfg.field.EnableTxDMA = 0; GloCfg.field.EnableRxDMA = 0; RTUSBWriteMACRegister(pAd, WPDMA_GLO_CFG, GloCfg.word); // abort all TX rings // Waiting for DMA idle i = 0; do { RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word); if ((GloCfg.field.TxDMABusy == 0) && (GloCfg.field.RxDMABusy == 0)) break; RTMPusecDelay(1000); }while (i++ < 100); // Disable MAC Tx/Rx RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); Value &= (0xfffffff3); RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); // MAC_SYS_CTRL => value = 0x0 => 40mA //RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0); // PWR_PIN_CFG => value = 0x0 => 40mA //RTMP_IO_WRITE32(pAd, PWR_PIN_CFG, 0); // TX_PIN_CFG => value = 0x0 => 20mA //RTMP_IO_WRITE32(pAd, TX_PIN_CFG, 0); #ifdef CONFIG_STA_SUPPORT IF_DEV_CONFIG_OPMODE_ON_STA(pAd) AsicSendCommandToMcu(pAd, 0x30, 0xff, 0xff, 0x02); #endif // CONFIG_STA_SUPPORT // }