| /* |
| ************************************************************************* |
| * 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 received 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 promiscuous 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, can't'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 // */ |