diff options
Diffstat (limited to 'drivers/staging/rt2860/common/cmm_data_usb.c')
-rw-r--r-- | drivers/staging/rt2860/common/cmm_data_usb.c | 951 |
1 files changed, 951 insertions, 0 deletions
diff --git a/drivers/staging/rt2860/common/cmm_data_usb.c b/drivers/staging/rt2860/common/cmm_data_usb.c new file mode 100644 index 00000000000..7c56c2f5198 --- /dev/null +++ b/drivers/staging/rt2860/common/cmm_data_usb.c @@ -0,0 +1,951 @@ +/* + ************************************************************************* + * 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. + +*/ + +#ifdef RTMP_MAC_USB + +#include "../rt_config.h" + +/* + We can do copy the frame into pTxContext when match following conditions. + => + => + => +*/ +static inline int RtmpUSBCanDoWrite(struct rt_rtmp_adapter *pAd, + u8 QueIdx, + struct rt_ht_tx_context *pHTTXContext) +{ + int 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; +} + +u16 RtmpUSB_WriteSubTxResource(struct rt_rtmp_adapter *pAd, + struct rt_tx_blk *pTxBlk, + IN BOOLEAN bIsLast, u16 * FreeNumber) +{ + + /* Dummy function. Should be removed in the future. */ + return 0; + +} + +u16 RtmpUSB_WriteFragTxResource(struct rt_rtmp_adapter *pAd, + struct rt_tx_blk *pTxBlk, + u8 fragNum, u16 * FreeNumber) +{ + struct rt_ht_tx_context *pHTTXContext; + u16 hwHdrLen; /* The hwHdrLen consist of 802.11 header length plus the header padding length. */ + u32 fillOffset; + struct rt_txinfo *pTxInfo; + struct rt_txwi *pTxWI; + u8 *pWirelessPacket = NULL; + u8 QueIdx; + int Status; + unsigned long IrqFlags; + u32 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((u8 *)(&pTxBlk->HeaderBuf[0]), TXINFO_SIZE); + pTxInfo = (struct rt_txinfo *)(&pTxBlk->HeaderBuf[0]); + pTxWI = (struct rt_txwi *) (&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, (u16)(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); + 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); + +} + +u16 RtmpUSB_WriteSingleTxResource(struct rt_rtmp_adapter *pAd, + struct rt_tx_blk *pTxBlk, + IN BOOLEAN bIsLast, + u16 * FreeNumber) +{ + struct rt_ht_tx_context *pHTTXContext; + u16 hwHdrLen; + u32 fillOffset; + struct rt_txinfo *pTxInfo; + struct rt_txwi *pTxWI; + u8 *pWirelessPacket; + u8 QueIdx; + unsigned long IrqFlags; + int Status; + u32 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 = (struct rt_txinfo *)(&pTxBlk->HeaderBuf[0]); + pTxWI = (struct rt_txwi *) (&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 */ + RTMPWriteTxInfo(pAd, pTxInfo, (u16)(USBDMApktLen), FALSE, + FIFO_EDCA, FALSE /*NextValid */ , FALSE); + + if ((pHTTXContext->CurWritePosition + 3906 + pTxBlk->Priv) > + MAX_TXBULK_LIMIT) { + pTxInfo->SwUseLastRound = 1; + bTxQLastRound = TRUE; + } + NdisMoveMemory(pWirelessPacket, pTxBlk->HeaderBuf, + TXINFO_SIZE + TXWI_SIZE + hwHdrLen); + 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); + +} + +u16 RtmpUSB_WriteMultiTxResource(struct rt_rtmp_adapter *pAd, + struct rt_tx_blk *pTxBlk, + u8 frameNum, u16 * FreeNumber) +{ + struct rt_ht_tx_context *pHTTXContext; + u16 hwHdrLen; /* The hwHdrLen consist of 802.11 header length plus the header padding length. */ + u32 fillOffset; + struct rt_txinfo *pTxInfo; + struct rt_txwi *pTxWI; + u8 *pWirelessPacket = NULL; + u8 QueIdx; + int Status; + unsigned long IrqFlags; + /*u32 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 = (struct rt_txinfo *)(&pTxBlk->HeaderBuf[0]); + pTxWI = (struct rt_txwi *) (&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, (u16)(pTxBlk->Priv), + FALSE, FIFO_EDCA, FALSE /*NextValid */ , + FALSE); + + /* Copy it. */ + NdisMoveMemory(pWirelessPacket, pTxBlk->HeaderBuf, + pTxBlk->Priv); + 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(struct rt_rtmp_adapter *pAd, + struct rt_tx_blk *pTxBlk, + u16 totalMPDUSize, u16 TxIdx) +{ + u8 QueIdx; + struct rt_ht_tx_context *pHTTXContext; + u32 fillOffset; + struct rt_txinfo *pTxInfo; + struct rt_txwi *pTxWI; + u32 USBDMApktLen, padding; + unsigned long IrqFlags; + u8 *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 = (u8 *)(&pHTTXContext->SavedPad[0]); + else + pWirelessPacket = + (u8 *)(&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 = (struct rt_txinfo *)(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 = (struct rt_txwi *) (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(struct rt_rtmp_adapter *pAd, + u8 QueIdx, u16 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(struct rt_rtmp_adapter *pAd, + struct rt_tx_blk *pTxBlk, u8 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(struct rt_rtmp_adapter *pAd, + u8 QueIdx, + void *pPacket, + u8 *pSrcBufVA, u32 SrcBufLen) +{ + struct rt_txinfo *pTxInfo; + unsigned long BulkOutSize; + u8 padLen; + u8 *pDest; + unsigned long SwIdx = pAd->MgmtRing.TxCpuIdx; + struct rt_tx_context *pMLMEContext = + (struct rt_tx_context *)pAd->MgmtRing.Cell[SwIdx].AllocVa; + unsigned long IrqFlags; + + pTxInfo = (struct rt_txinfo *)(pSrcBufVA); + + /* Build our URB for USBD */ + BulkOutSize = SrcBufLen; + BulkOutSize = (BulkOutSize + 3) & (~3); + RTMPWriteTxInfo(pAd, pTxInfo, (u16)(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 = (u8 *)(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 = + (struct rt_tx_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(struct rt_rtmp_adapter *pAd, + u8 QueIdx, + u8 * pNullFrame, u32 frameLen) +{ + if (pAd->NullContext.InUse == FALSE) { + struct rt_tx_context *pNullContext; + struct rt_txinfo *pTxInfo; + struct rt_txwi * pTxWI; + u8 *pWirelessPkt; + + pNullContext = &(pAd->NullContext); + + /* Set the in use bit */ + pNullContext->InUse = TRUE; + pWirelessPkt = + (u8 *)& pNullContext->TransferBuffer->field. + WirelessPacket[0]; + + RTMPZeroMemory(&pWirelessPkt[0], 100); + pTxInfo = (struct rt_txinfo *)& pWirelessPkt[0]; + RTMPWriteTxInfo(pAd, pTxInfo, + (u16)(sizeof(struct rt_header_802_11) + TXWI_SIZE), + TRUE, EpToQueue[MGMTPIPEIDX], FALSE, FALSE); + pTxInfo->QSEL = FIFO_EDCA; + pTxWI = (struct rt_txwi *) & pWirelessPkt[TXINFO_SIZE]; + RTMPWriteTxWI(pAd, pTxWI, FALSE, FALSE, FALSE, FALSE, TRUE, + FALSE, 0, BSSID_WCID, (sizeof(struct rt_header_802_11)), 0, + 0, (u8)pAd->CommonCfg.MlmeTransmit.field.MCS, + IFS_HTTXOP, FALSE, &pAd->CommonCfg.MlmeTransmit); + + RTMPMoveMemory(&pWirelessPkt[TXWI_SIZE + TXINFO_SIZE], + &pAd->NullFrame, sizeof(struct rt_header_802_11)); + 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); + } + +} + +/* +======================================================================== +Routine Description: + Get a received packet. + +Arguments: + pAd device control block + pSaveRxD receive descriptor information + *pbReschedule need reschedule flag + *pRxPending pending received packet flag + +Return Value: + the recieved packet + +Note: +======================================================================== +*/ +void *GetPacketFromRxRing(struct rt_rtmp_adapter *pAd, + OUT PRT28XX_RXD_STRUC pSaveRxD, + OUT BOOLEAN * pbReschedule, + IN u32 * pRxPending) +{ + struct rt_rx_context *pRxContext; + void *pSkb; + u8 *pData; + unsigned long ThisFrameLen; + unsigned long RxBufferLength; + struct rt_rxwi * pRxWI; + + pRxContext = &pAd->RxContext[pAd->NextRxBulkInReadIndex]; + if ((pRxContext->Readable == FALSE) || (pRxContext->InUse == TRUE)) + return NULL; + + RxBufferLength = pRxContext->BulkInOffset - pAd->ReadPosition; + if (RxBufferLength < + (RT2870_RXDMALEN_FIELD_SIZE + sizeof(struct rt_rxwi) + + sizeof(struct rt_rxinfo))) { + goto label_null; + } + + pData = &pRxContext->TransferBuffer[pAd->ReadPosition]; /* 4KB */ + /* The RXDMA field is 4 bytes, now just use the first 2 bytes. The Length including the (RXWI + MSDU + Padding) */ + ThisFrameLen = *pData + (*(pData + 1) << 8); + if (ThisFrameLen == 0) { + DBGPRINT(RT_DEBUG_TRACE, + ("BIRIdx(%d): RXDMALen is zero.[%ld], BulkInBufLen = %ld)\n", + pAd->NextRxBulkInReadIndex, ThisFrameLen, + pRxContext->BulkInOffset)); + goto label_null; + } + if ((ThisFrameLen & 0x3) != 0) { + DBGPRINT(RT_DEBUG_ERROR, + ("BIRIdx(%d): RXDMALen not multiple of 4.[%ld], BulkInBufLen = %ld)\n", + pAd->NextRxBulkInReadIndex, ThisFrameLen, + pRxContext->BulkInOffset)); + goto label_null; + } + + if ((ThisFrameLen + 8) > RxBufferLength) /* 8 for (RT2870_RXDMALEN_FIELD_SIZE + sizeof(struct rt_rxinfo)) */ + { + DBGPRINT(RT_DEBUG_TRACE, + ("BIRIdx(%d):FrameLen(0x%lx) outranges. BulkInLen=0x%lx, remaining RxBufLen=0x%lx, ReadPos=0x%lx\n", + pAd->NextRxBulkInReadIndex, ThisFrameLen, + pRxContext->BulkInOffset, RxBufferLength, + pAd->ReadPosition)); + + /* error frame. finish this loop */ + goto label_null; + } + /* skip USB frame length field */ + pData += RT2870_RXDMALEN_FIELD_SIZE; + pRxWI = (struct rt_rxwi *) pData; + if (pRxWI->MPDUtotalByteCount > ThisFrameLen) { + DBGPRINT(RT_DEBUG_ERROR, + ("%s():pRxWIMPDUtotalByteCount(%d) large than RxDMALen(%ld)\n", + __FUNCTION__, pRxWI->MPDUtotalByteCount, + ThisFrameLen)); + goto label_null; + } + /* allocate a rx packet */ + pSkb = dev_alloc_skb(ThisFrameLen); + if (pSkb == NULL) { + DBGPRINT(RT_DEBUG_ERROR, + ("%s():Cannot Allocate sk buffer for this Bulk-In buffer!\n", + __FUNCTION__)); + goto label_null; + } + /* copy the rx packet */ + memcpy(skb_put(pSkb, ThisFrameLen), pData, ThisFrameLen); + RTPKT_TO_OSPKT(pSkb)->dev = get_netdev_from_bssid(pAd, BSS0); + RTMP_SET_PACKET_SOURCE(OSPKT_TO_RTPKT(pSkb), PKTSRC_NDIS); + + /* copy RxD */ + *pSaveRxD = *(struct rt_rxinfo *) (pData + ThisFrameLen); + + /* update next packet read position. */ + pAd->ReadPosition += (ThisFrameLen + RT2870_RXDMALEN_FIELD_SIZE + RXINFO_SIZE); /* 8 for (RT2870_RXDMALEN_FIELD_SIZE + sizeof(struct rt_rxinfo)) */ + + return pSkb; + +label_null: + + return NULL; +} + +/* + ======================================================================== + + 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: + + ======================================================================== +*/ +int RTMPCheckRxError(struct rt_rtmp_adapter *pAd, + struct rt_header_802_11 * pHeader, + struct rt_rxwi * pRxWI, IN PRT28XX_RXD_STRUC pRxINFO) +{ + struct rt_cipher_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) { + + if (((pRxINFO->CipherErr & 1) == 1) + && pAd->CommonCfg.bWirelessEvent && INFRA_ON(pAd)) + RTMPSendWirelessEvent(pAd, IW_ICV_ERROR_EVENT_FLAG, + pAd->MacTab.Content[BSSID_WCID]. + Addr, BSS0, 0); + + if (((pRxINFO->CipherErr & 2) == 2) + && pAd->CommonCfg.bWirelessEvent && INFRA_ON(pAd)) + RTMPSendWirelessEvent(pAd, IW_MIC_ERROR_EVENT_FLAG, + pAd->MacTab.Content[BSSID_WCID]. + Addr, BSS0, 0); + /* */ + /* 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 RtmpUsbStaAsicForceWakeupTimeout(void *SystemSpecific1, + void *FunctionContext, + void *SystemSpecific2, + void *SystemSpecific3) +{ + struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)FunctionContext; + + if (pAd && pAd->Mlme.AutoWakeupTimerRunning) { + AsicSendCommandToMcu(pAd, 0x31, 0xff, 0x00, 0x02); + + OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE); + pAd->Mlme.AutoWakeupTimerRunning = FALSE; + } +} + +void RT28xxUsbStaAsicForceWakeup(struct rt_rtmp_adapter *pAd, IN BOOLEAN bFromTx) +{ + BOOLEAN Canceled; + + if (pAd->Mlme.AutoWakeupTimerRunning) + RTMPCancelTimer(&pAd->Mlme.AutoWakeupTimer, &Canceled); + + AsicSendCommandToMcu(pAd, 0x31, 0xff, 0x00, 0x02); + + OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE); +} + +void RT28xxUsbStaAsicSleepThenAutoWakeup(struct rt_rtmp_adapter *pAd, + u16 TbttNumToNextWakeUp) +{ + + /* we have decided to SLEEP, so at least do it for a BEACON period. */ + if (TbttNumToNextWakeUp == 0) + TbttNumToNextWakeUp = 1; + + RTMPSetTimer(&pAd->Mlme.AutoWakeupTimer, AUTO_WAKEUP_TIMEOUT); + pAd->Mlme.AutoWakeupTimerRunning = TRUE; + + AsicSendCommandToMcu(pAd, 0x30, 0xff, 0xff, 0x02); /* send POWER-SAVE command to MCU. Timeout 40us. */ + + OPSTATUS_SET_FLAG(pAd, fOP_STATUS_DOZE); + +} + +#endif /* RTMP_MAC_USB // */ |