| /* |
| ************************************************************************* |
| * 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 PCI-depended, or you should out your function |
| in other files. |
| |
| */ |
| #include "../rt_config.h" |
| |
| u16 RtmpPCI_WriteTxResource(struct rt_rtmp_adapter *pAd, |
| struct rt_tx_blk *pTxBlk, |
| IN BOOLEAN bIsLast, u16 * FreeNumber) |
| { |
| |
| u8 *pDMAHeaderBufVA; |
| u16 TxIdx, RetTxIdx; |
| struct rt_txd * pTxD; |
| u32 BufBasePaLow; |
| struct rt_rtmp_tx_ring *pTxRing; |
| u16 hwHeaderLen; |
| |
| /* */ |
| /* get Tx Ring Resource */ |
| /* */ |
| pTxRing = &pAd->TxRing[pTxBlk->QueIdx]; |
| TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx; |
| pDMAHeaderBufVA = (u8 *)pTxRing->Cell[TxIdx].DmaBuf.AllocVa; |
| BufBasePaLow = |
| RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa); |
| |
| /* copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer */ |
| if (pTxBlk->TxFrameType == TX_AMSDU_FRAME) { |
| /*hwHeaderLen = ROUND_UP(pTxBlk->MpduHeaderLen-LENGTH_AMSDU_SUBFRAMEHEAD, 4)+LENGTH_AMSDU_SUBFRAMEHEAD; */ |
| hwHeaderLen = |
| pTxBlk->MpduHeaderLen - LENGTH_AMSDU_SUBFRAMEHEAD + |
| pTxBlk->HdrPadLen + LENGTH_AMSDU_SUBFRAMEHEAD; |
| } else { |
| /*hwHeaderLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4); */ |
| hwHeaderLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen; |
| } |
| NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, |
| TXINFO_SIZE + TXWI_SIZE + hwHeaderLen); |
| |
| pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket; |
| pTxRing->Cell[TxIdx].pNextNdisPacket = NULL; |
| |
| /* */ |
| /* build Tx Descriptor */ |
| /* */ |
| |
| pTxD = (struct rt_txd *) pTxRing->Cell[TxIdx].AllocVa; |
| NdisZeroMemory(pTxD, TXD_SIZE); |
| |
| pTxD->SDPtr0 = BufBasePaLow; |
| pTxD->SDLen0 = TXINFO_SIZE + TXWI_SIZE + hwHeaderLen; /* include padding */ |
| pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE); |
| pTxD->SDLen1 = pTxBlk->SrcBufLen; |
| pTxD->LastSec0 = 0; |
| pTxD->LastSec1 = (bIsLast) ? 1 : 0; |
| |
| RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA); |
| |
| RetTxIdx = TxIdx; |
| /* */ |
| /* Update Tx index */ |
| /* */ |
| INC_RING_INDEX(TxIdx, TX_RING_SIZE); |
| pTxRing->TxCpuIdx = TxIdx; |
| |
| *FreeNumber -= 1; |
| |
| return RetTxIdx; |
| } |
| |
| u16 RtmpPCI_WriteSingleTxResource(struct rt_rtmp_adapter *pAd, |
| struct rt_tx_blk *pTxBlk, |
| IN BOOLEAN bIsLast, |
| u16 * FreeNumber) |
| { |
| |
| u8 *pDMAHeaderBufVA; |
| u16 TxIdx, RetTxIdx; |
| struct rt_txd * pTxD; |
| u32 BufBasePaLow; |
| struct rt_rtmp_tx_ring *pTxRing; |
| u16 hwHeaderLen; |
| |
| /* */ |
| /* get Tx Ring Resource */ |
| /* */ |
| pTxRing = &pAd->TxRing[pTxBlk->QueIdx]; |
| TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx; |
| pDMAHeaderBufVA = (u8 *)pTxRing->Cell[TxIdx].DmaBuf.AllocVa; |
| BufBasePaLow = |
| RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa); |
| |
| /* copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer */ |
| /*hwHeaderLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4); */ |
| hwHeaderLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen; |
| |
| NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, |
| TXINFO_SIZE + TXWI_SIZE + hwHeaderLen); |
| |
| pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket; |
| pTxRing->Cell[TxIdx].pNextNdisPacket = NULL; |
| |
| /* */ |
| /* build Tx Descriptor */ |
| /* */ |
| pTxD = (struct rt_txd *) pTxRing->Cell[TxIdx].AllocVa; |
| NdisZeroMemory(pTxD, TXD_SIZE); |
| |
| pTxD->SDPtr0 = BufBasePaLow; |
| pTxD->SDLen0 = TXINFO_SIZE + TXWI_SIZE + hwHeaderLen; /* include padding */ |
| pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE); |
| pTxD->SDLen1 = pTxBlk->SrcBufLen; |
| pTxD->LastSec0 = 0; |
| pTxD->LastSec1 = (bIsLast) ? 1 : 0; |
| |
| RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA); |
| |
| RetTxIdx = TxIdx; |
| /* */ |
| /* Update Tx index */ |
| /* */ |
| INC_RING_INDEX(TxIdx, TX_RING_SIZE); |
| pTxRing->TxCpuIdx = TxIdx; |
| |
| *FreeNumber -= 1; |
| |
| return RetTxIdx; |
| } |
| |
| u16 RtmpPCI_WriteMultiTxResource(struct rt_rtmp_adapter *pAd, |
| struct rt_tx_blk *pTxBlk, |
| u8 frameNum, u16 * FreeNumber) |
| { |
| BOOLEAN bIsLast; |
| u8 *pDMAHeaderBufVA; |
| u16 TxIdx, RetTxIdx; |
| struct rt_txd * pTxD; |
| u32 BufBasePaLow; |
| struct rt_rtmp_tx_ring *pTxRing; |
| u16 hwHdrLen; |
| u32 firstDMALen; |
| |
| bIsLast = ((frameNum == (pTxBlk->TotalFrameNum - 1)) ? 1 : 0); |
| |
| /* */ |
| /* get Tx Ring Resource */ |
| /* */ |
| pTxRing = &pAd->TxRing[pTxBlk->QueIdx]; |
| TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx; |
| pDMAHeaderBufVA = (u8 *)pTxRing->Cell[TxIdx].DmaBuf.AllocVa; |
| BufBasePaLow = |
| RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa); |
| |
| if (frameNum == 0) { |
| /* 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; |
| |
| firstDMALen = TXINFO_SIZE + TXWI_SIZE + hwHdrLen; |
| } else { |
| firstDMALen = pTxBlk->MpduHeaderLen; |
| } |
| |
| NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, firstDMALen); |
| |
| pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket; |
| pTxRing->Cell[TxIdx].pNextNdisPacket = NULL; |
| |
| /* */ |
| /* build Tx Descriptor */ |
| /* */ |
| pTxD = (struct rt_txd *) pTxRing->Cell[TxIdx].AllocVa; |
| NdisZeroMemory(pTxD, TXD_SIZE); |
| |
| pTxD->SDPtr0 = BufBasePaLow; |
| pTxD->SDLen0 = firstDMALen; /* include padding */ |
| pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE); |
| pTxD->SDLen1 = pTxBlk->SrcBufLen; |
| pTxD->LastSec0 = 0; |
| pTxD->LastSec1 = (bIsLast) ? 1 : 0; |
| |
| RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA); |
| |
| RetTxIdx = TxIdx; |
| /* */ |
| /* Update Tx index */ |
| /* */ |
| INC_RING_INDEX(TxIdx, TX_RING_SIZE); |
| pTxRing->TxCpuIdx = TxIdx; |
| |
| *FreeNumber -= 1; |
| |
| return RetTxIdx; |
| |
| } |
| |
| void RtmpPCI_FinalWriteTxResource(struct rt_rtmp_adapter *pAd, |
| struct rt_tx_blk *pTxBlk, |
| u16 totalMPDUSize, u16 FirstTxIdx) |
| { |
| |
| struct rt_txwi * pTxWI; |
| struct rt_rtmp_tx_ring *pTxRing; |
| |
| /* */ |
| /* get Tx Ring Resource */ |
| /* */ |
| pTxRing = &pAd->TxRing[pTxBlk->QueIdx]; |
| pTxWI = (struct rt_txwi *) pTxRing->Cell[FirstTxIdx].DmaBuf.AllocVa; |
| pTxWI->MPDUtotalByteCount = totalMPDUSize; |
| |
| } |
| |
| void RtmpPCIDataLastTxIdx(struct rt_rtmp_adapter *pAd, |
| u8 QueIdx, u16 LastTxIdx) |
| { |
| struct rt_txd * pTxD; |
| struct rt_rtmp_tx_ring *pTxRing; |
| |
| /* */ |
| /* get Tx Ring Resource */ |
| /* */ |
| pTxRing = &pAd->TxRing[QueIdx]; |
| |
| /* */ |
| /* build Tx Descriptor */ |
| /* */ |
| pTxD = (struct rt_txd *) pTxRing->Cell[LastTxIdx].AllocVa; |
| |
| pTxD->LastSec1 = 1; |
| |
| } |
| |
| u16 RtmpPCI_WriteFragTxResource(struct rt_rtmp_adapter *pAd, |
| struct rt_tx_blk *pTxBlk, |
| u8 fragNum, u16 * FreeNumber) |
| { |
| u8 *pDMAHeaderBufVA; |
| u16 TxIdx, RetTxIdx; |
| struct rt_txd * pTxD; |
| u32 BufBasePaLow; |
| struct rt_rtmp_tx_ring *pTxRing; |
| u16 hwHeaderLen; |
| u32 firstDMALen; |
| |
| /* */ |
| /* Get Tx Ring Resource */ |
| /* */ |
| pTxRing = &pAd->TxRing[pTxBlk->QueIdx]; |
| TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx; |
| pDMAHeaderBufVA = (u8 *)pTxRing->Cell[TxIdx].DmaBuf.AllocVa; |
| BufBasePaLow = |
| RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa); |
| |
| /* */ |
| /* Copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer */ |
| /* */ |
| /*hwHeaderLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4); */ |
| hwHeaderLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen; |
| |
| firstDMALen = TXINFO_SIZE + TXWI_SIZE + hwHeaderLen; |
| NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, firstDMALen); |
| |
| /* */ |
| /* Build Tx Descriptor */ |
| /* */ |
| pTxD = (struct rt_txd *) pTxRing->Cell[TxIdx].AllocVa; |
| NdisZeroMemory(pTxD, TXD_SIZE); |
| |
| if (fragNum == pTxBlk->TotalFragNum) { |
| pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket; |
| pTxRing->Cell[TxIdx].pNextNdisPacket = NULL; |
| } |
| |
| pTxD->SDPtr0 = BufBasePaLow; |
| pTxD->SDLen0 = firstDMALen; /* include padding */ |
| pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE); |
| pTxD->SDLen1 = pTxBlk->SrcBufLen; |
| pTxD->LastSec0 = 0; |
| pTxD->LastSec1 = 1; |
| |
| RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA); |
| |
| RetTxIdx = TxIdx; |
| pTxBlk->Priv += pTxBlk->SrcBufLen; |
| |
| /* */ |
| /* Update Tx index */ |
| /* */ |
| INC_RING_INDEX(TxIdx, TX_RING_SIZE); |
| pTxRing->TxCpuIdx = TxIdx; |
| |
| *FreeNumber -= 1; |
| |
| return RetTxIdx; |
| |
| } |
| |
| /* |
| Must be run in Interrupt context |
| This function handle PCI specific TxDesc and cpu index update and kick the packet out. |
| */ |
| int RtmpPCIMgmtKickOut(struct rt_rtmp_adapter *pAd, |
| u8 QueIdx, |
| void *pPacket, |
| u8 *pSrcBufVA, u32 SrcBufLen) |
| { |
| struct rt_txd * pTxD; |
| unsigned long SwIdx = pAd->MgmtRing.TxCpuIdx; |
| |
| pTxD = (struct rt_txd *) pAd->MgmtRing.Cell[SwIdx].AllocVa; |
| |
| pAd->MgmtRing.Cell[SwIdx].pNdisPacket = pPacket; |
| pAd->MgmtRing.Cell[SwIdx].pNextNdisPacket = NULL; |
| |
| RTMPWriteTxDescriptor(pAd, pTxD, TRUE, FIFO_MGMT); |
| pTxD->LastSec0 = 1; |
| pTxD->LastSec1 = 1; |
| pTxD->DMADONE = 0; |
| pTxD->SDLen1 = 0; |
| pTxD->SDPtr0 = |
| PCI_MAP_SINGLE(pAd, pSrcBufVA, SrcBufLen, 0, PCI_DMA_TODEVICE); |
| pTxD->SDLen0 = SrcBufLen; |
| |
| /*================================================================== */ |
| /* DBGPRINT_RAW(RT_DEBUG_TRACE, ("MLMEHardTransmit\n")); |
| for (i = 0; i < (TXWI_SIZE+24); i++) |
| { |
| |
| DBGPRINT_RAW(RT_DEBUG_TRACE, ("%x:", *(pSrcBufVA+i))); |
| if ( i%4 == 3) |
| DBGPRINT_RAW(RT_DEBUG_TRACE, (" :: ")); |
| if ( i%16 == 15) |
| DBGPRINT_RAW(RT_DEBUG_TRACE, ("\n ")); |
| } |
| DBGPRINT_RAW(RT_DEBUG_TRACE, ("\n "));*/ |
| /*======================================================================= */ |
| |
| pAd->RalinkCounters.KickTxCount++; |
| pAd->RalinkCounters.OneSecTxDoneCount++; |
| |
| /* Increase TX_CTX_IDX, but write to register later. */ |
| INC_RING_INDEX(pAd->MgmtRing.TxCpuIdx, MGMT_RING_SIZE); |
| |
| RTMP_IO_WRITE32(pAd, TX_MGMTCTX_IDX, pAd->MgmtRing.TxCpuIdx); |
| |
| return 0; |
| } |
| |
| /* |
| ======================================================================== |
| |
| 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 pRxD) |
| { |
| struct rt_cipher_key *pWpaKey; |
| int dBm; |
| |
| /* Phy errors & CRC errors */ |
| if ( /*(pRxD->PhyErr) || */ (pRxD->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 += (pRxD->SDL0 + 14); |
| |
| /* Drop ToDs promiscuous frame, it is opened due to CCX 2 channel load statistics */ |
| if (pHeader != NULL) { |
| if (pHeader->FC.ToDs) { |
| 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 (pRxD->CipherErr) { |
| if (pRxD->CipherErr == 2) { |
| DBGPRINT_RAW(RT_DEBUG_TRACE, |
| ("pRxD ERROR: ICV ok but MICErr ")); |
| } else if (pRxD->CipherErr == 1) { |
| DBGPRINT_RAW(RT_DEBUG_TRACE, ("pRxD ERROR: ICV Err ")); |
| } else if (pRxD->CipherErr == 3) |
| DBGPRINT_RAW(RT_DEBUG_TRACE, |
| ("pRxD ERROR: Key not valid ")); |
| |
| if (((pRxD->CipherErr & 1) == 1) |
| && pAd->CommonCfg.bWirelessEvent && INFRA_ON(pAd)) |
| RTMPSendWirelessEvent(pAd, IW_ICV_ERROR_EVENT_FLAG, |
| pAd->MacTab.Content[BSSID_WCID]. |
| Addr, BSS0, 0); |
| |
| DBGPRINT_RAW(RT_DEBUG_TRACE, |
| (" %d (len=%d, Mcast=%d, MyBss=%d, Wcid=%d, KeyId=%d)\n", |
| pRxD->CipherErr, pRxD->SDL0, |
| pRxD->Mcast | pRxD->Bcast, pRxD->MyBss, |
| pRxWI->WirelessCliID, |
| /* CipherName[pRxD->CipherAlg], */ |
| pRxWI->KeyIndex)); |
| |
| /* */ |
| /* MIC Error */ |
| /* */ |
| if (pRxD->CipherErr == 2) { |
| pWpaKey = &pAd->SharedKey[BSS0][pRxWI->KeyIndex]; |
| if (pAd->StaCfg.WpaSupplicantUP) |
| WpaSendMicFailureToWpaSupplicant(pAd, |
| (pWpaKey-> |
| Type == |
| PAIRWISEKEY) ? |
| TRUE : FALSE); |
| else |
| RTMPReportMicError(pAd, pWpaKey); |
| |
| if (((pRxD->CipherErr & 2) == 2) |
| && pAd->CommonCfg.bWirelessEvent && INFRA_ON(pAd)) |
| RTMPSendWirelessEvent(pAd, |
| IW_MIC_ERROR_EVENT_FLAG, |
| pAd->MacTab. |
| Content[BSSID_WCID].Addr, |
| BSS0, 0); |
| |
| DBGPRINT_RAW(RT_DEBUG_ERROR, ("Rx MIC Value error\n")); |
| } |
| |
| if (pHeader == NULL) |
| return (NDIS_STATUS_SUCCESS); |
| /*if ((pRxD->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); |
| } |
| |
| BOOLEAN RTMPFreeTXDUponTxDmaDone(struct rt_rtmp_adapter *pAd, u8 QueIdx) |
| { |
| struct rt_rtmp_tx_ring *pTxRing; |
| struct rt_txd * pTxD; |
| void *pPacket; |
| u8 FREE = 0; |
| struct rt_txd TxD, *pOriTxD; |
| /*unsigned long IrqFlags; */ |
| BOOLEAN bReschedule = FALSE; |
| |
| ASSERT(QueIdx < NUM_OF_TX_RING); |
| pTxRing = &pAd->TxRing[QueIdx]; |
| |
| RTMP_IO_READ32(pAd, TX_DTX_IDX0 + QueIdx * RINGREG_DIFF, |
| &pTxRing->TxDmaIdx); |
| while (pTxRing->TxSwFreeIdx != pTxRing->TxDmaIdx) { |
| /* RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags); */ |
| |
| /* static rate also need NICUpdateFifoStaCounters() function. */ |
| /*if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED)) */ |
| NICUpdateFifoStaCounters(pAd); |
| |
| /* Note : If (pAd->ate.bQATxStart == TRUE), we will never reach here. */ |
| FREE++; |
| pTxD = |
| (struct rt_txd *) (pTxRing->Cell[pTxRing->TxSwFreeIdx].AllocVa); |
| pOriTxD = pTxD; |
| NdisMoveMemory(&TxD, pTxD, sizeof(struct rt_txd)); |
| pTxD = &TxD; |
| |
| pTxD->DMADONE = 0; |
| |
| { |
| pPacket = |
| pTxRing->Cell[pTxRing->TxSwFreeIdx].pNdisPacket; |
| if (pPacket) { |
| PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, |
| pTxD->SDLen1, |
| PCI_DMA_TODEVICE); |
| RELEASE_NDIS_PACKET(pAd, pPacket, |
| NDIS_STATUS_SUCCESS); |
| } |
| /*Always assign pNdisPacket as NULL after clear */ |
| pTxRing->Cell[pTxRing->TxSwFreeIdx].pNdisPacket = NULL; |
| |
| pPacket = |
| pTxRing->Cell[pTxRing->TxSwFreeIdx].pNextNdisPacket; |
| |
| ASSERT(pPacket == NULL); |
| if (pPacket) { |
| PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, |
| pTxD->SDLen1, |
| PCI_DMA_TODEVICE); |
| RELEASE_NDIS_PACKET(pAd, pPacket, |
| NDIS_STATUS_SUCCESS); |
| } |
| /*Always assign pNextNdisPacket as NULL after clear */ |
| pTxRing->Cell[pTxRing->TxSwFreeIdx].pNextNdisPacket = |
| NULL; |
| } |
| |
| pAd->RalinkCounters.TransmittedByteCount += |
| (pTxD->SDLen1 + pTxD->SDLen0); |
| pAd->RalinkCounters.OneSecDmaDoneCount[QueIdx]++; |
| INC_RING_INDEX(pTxRing->TxSwFreeIdx, TX_RING_SIZE); |
| /* get tx_tdx_idx again */ |
| RTMP_IO_READ32(pAd, TX_DTX_IDX0 + QueIdx * RINGREG_DIFF, |
| &pTxRing->TxDmaIdx); |
| NdisMoveMemory(pOriTxD, pTxD, sizeof(struct rt_txd)); |
| |
| /* RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); */ |
| } |
| |
| return bReschedule; |
| |
| } |
| |
| /* |
| ======================================================================== |
| |
| Routine Description: |
| Process TX Rings DMA Done interrupt, running in DPC level |
| |
| Arguments: |
| Adapter Pointer to our adapter |
| |
| Return Value: |
| None |
| |
| IRQL = DISPATCH_LEVEL |
| |
| ======================================================================== |
| */ |
| BOOLEAN RTMPHandleTxRingDmaDoneInterrupt(struct rt_rtmp_adapter *pAd, |
| INT_SOURCE_CSR_STRUC TxRingBitmap) |
| { |
| /* u8 Count = 0; */ |
| unsigned long IrqFlags; |
| BOOLEAN bReschedule = FALSE; |
| |
| /* Make sure Tx ring resource won't be used by other threads */ |
| /*NdisAcquireSpinLock(&pAd->TxRingLock); */ |
| |
| RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags); |
| |
| if (TxRingBitmap.field.Ac0DmaDone) |
| bReschedule = RTMPFreeTXDUponTxDmaDone(pAd, QID_AC_BE); |
| |
| if (TxRingBitmap.field.Ac3DmaDone) |
| bReschedule |= RTMPFreeTXDUponTxDmaDone(pAd, QID_AC_VO); |
| |
| if (TxRingBitmap.field.Ac2DmaDone) |
| bReschedule |= RTMPFreeTXDUponTxDmaDone(pAd, QID_AC_VI); |
| |
| if (TxRingBitmap.field.Ac1DmaDone) |
| bReschedule |= RTMPFreeTXDUponTxDmaDone(pAd, QID_AC_BK); |
| |
| /* Make sure to release Tx ring resource */ |
| /*NdisReleaseSpinLock(&pAd->TxRingLock); */ |
| RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); |
| |
| /* Dequeue outgoing frames from TxSwQueue[] and process it */ |
| RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); |
| |
| return bReschedule; |
| } |
| |
| /* |
| ======================================================================== |
| |
| Routine Description: |
| Process MGMT ring DMA done interrupt, running in DPC level |
| |
| Arguments: |
| pAd Pointer to our adapter |
| |
| Return Value: |
| None |
| |
| IRQL = DISPATCH_LEVEL |
| |
| Note: |
| |
| ======================================================================== |
| */ |
| void RTMPHandleMgmtRingDmaDoneInterrupt(struct rt_rtmp_adapter *pAd) |
| { |
| struct rt_txd * pTxD; |
| void *pPacket; |
| /* int i; */ |
| u8 FREE = 0; |
| struct rt_rtmp_mgmt_ring *pMgmtRing = &pAd->MgmtRing; |
| |
| NdisAcquireSpinLock(&pAd->MgmtRingLock); |
| |
| RTMP_IO_READ32(pAd, TX_MGMTDTX_IDX, &pMgmtRing->TxDmaIdx); |
| while (pMgmtRing->TxSwFreeIdx != pMgmtRing->TxDmaIdx) { |
| FREE++; |
| pTxD = |
| (struct rt_txd *) (pMgmtRing->Cell[pAd->MgmtRing.TxSwFreeIdx]. |
| AllocVa); |
| pTxD->DMADONE = 0; |
| pPacket = pMgmtRing->Cell[pMgmtRing->TxSwFreeIdx].pNdisPacket; |
| |
| if (pPacket) { |
| PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr0, pTxD->SDLen0, |
| PCI_DMA_TODEVICE); |
| RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); |
| } |
| pMgmtRing->Cell[pMgmtRing->TxSwFreeIdx].pNdisPacket = NULL; |
| |
| pPacket = |
| pMgmtRing->Cell[pMgmtRing->TxSwFreeIdx].pNextNdisPacket; |
| if (pPacket) { |
| PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, pTxD->SDLen1, |
| PCI_DMA_TODEVICE); |
| RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); |
| } |
| pMgmtRing->Cell[pMgmtRing->TxSwFreeIdx].pNextNdisPacket = NULL; |
| INC_RING_INDEX(pMgmtRing->TxSwFreeIdx, MGMT_RING_SIZE); |
| |
| } |
| NdisReleaseSpinLock(&pAd->MgmtRingLock); |
| |
| } |
| |
| /* |
| ======================================================================== |
| |
| Routine Description: |
| Arguments: |
| Adapter Pointer to our adapter. Dequeue all power safe delayed braodcast frames after beacon. |
| |
| IRQL = DISPATCH_LEVEL |
| |
| ======================================================================== |
| */ |
| void RTMPHandleTBTTInterrupt(struct rt_rtmp_adapter *pAd) |
| { |
| { |
| if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) { |
| } |
| } |
| } |
| |
| /* |
| ======================================================================== |
| |
| Routine Description: |
| Arguments: |
| pAd Pointer to our adapter. Rewrite beacon content before next send-out. |
| |
| IRQL = DISPATCH_LEVEL |
| |
| ======================================================================== |
| */ |
| void RTMPHandlePreTBTTInterrupt(struct rt_rtmp_adapter *pAd) |
| { |
| { |
| if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) { |
| DBGPRINT(RT_DEBUG_TRACE, |
| ("RTMPHandlePreTBTTInterrupt...\n")); |
| } |
| } |
| |
| } |
| |
| void RTMPHandleRxCoherentInterrupt(struct rt_rtmp_adapter *pAd) |
| { |
| WPDMA_GLO_CFG_STRUC GloCfg; |
| |
| if (pAd == NULL) { |
| DBGPRINT(RT_DEBUG_TRACE, ("====> pAd is NULL, return.\n")); |
| return; |
| } |
| |
| DBGPRINT(RT_DEBUG_TRACE, ("==> RTMPHandleRxCoherentInterrupt \n")); |
| |
| RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word); |
| |
| GloCfg.field.EnTXWriteBackDDONE = 0; |
| GloCfg.field.EnableRxDMA = 0; |
| GloCfg.field.EnableTxDMA = 0; |
| RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word); |
| |
| RTMPRingCleanUp(pAd, QID_AC_BE); |
| RTMPRingCleanUp(pAd, QID_AC_BK); |
| RTMPRingCleanUp(pAd, QID_AC_VI); |
| RTMPRingCleanUp(pAd, QID_AC_VO); |
| RTMPRingCleanUp(pAd, QID_MGMT); |
| RTMPRingCleanUp(pAd, QID_RX); |
| |
| RTMPEnableRxTx(pAd); |
| |
| DBGPRINT(RT_DEBUG_TRACE, ("<== RTMPHandleRxCoherentInterrupt \n")); |
| } |
| |
| void *GetPacketFromRxRing(struct rt_rtmp_adapter *pAd, |
| OUT PRT28XX_RXD_STRUC pSaveRxD, |
| OUT BOOLEAN * pbReschedule, |
| IN u32 * pRxPending) |
| { |
| struct rt_rxd * pRxD; |
| void *pRxPacket = NULL; |
| void *pNewPacket; |
| void *AllocVa; |
| dma_addr_t AllocPa; |
| BOOLEAN bReschedule = FALSE; |
| struct rt_rtmp_dmacb *pRxCell; |
| |
| RTMP_SEM_LOCK(&pAd->RxRingLock); |
| |
| if (*pRxPending == 0) { |
| /* Get how may packets had been received */ |
| RTMP_IO_READ32(pAd, RX_DRX_IDX, &pAd->RxRing.RxDmaIdx); |
| |
| if (pAd->RxRing.RxSwReadIdx == pAd->RxRing.RxDmaIdx) { |
| /* no more rx packets */ |
| bReschedule = FALSE; |
| goto done; |
| } |
| /* get rx pending count */ |
| if (pAd->RxRing.RxDmaIdx > pAd->RxRing.RxSwReadIdx) |
| *pRxPending = |
| pAd->RxRing.RxDmaIdx - pAd->RxRing.RxSwReadIdx; |
| else |
| *pRxPending = |
| pAd->RxRing.RxDmaIdx + RX_RING_SIZE - |
| pAd->RxRing.RxSwReadIdx; |
| |
| } |
| |
| pRxCell = &pAd->RxRing.Cell[pAd->RxRing.RxSwReadIdx]; |
| |
| /* Point to Rx indexed rx ring descriptor */ |
| pRxD = (struct rt_rxd *) pRxCell->AllocVa; |
| |
| if (pRxD->DDONE == 0) { |
| *pRxPending = 0; |
| /* DMAIndx had done but DDONE bit not ready */ |
| bReschedule = TRUE; |
| goto done; |
| } |
| |
| /* return rx descriptor */ |
| NdisMoveMemory(pSaveRxD, pRxD, RXD_SIZE); |
| |
| pNewPacket = |
| RTMP_AllocateRxPacketBuffer(pAd, RX_BUFFER_AGGRESIZE, FALSE, |
| &AllocVa, &AllocPa); |
| |
| if (pNewPacket) { |
| /* unmap the rx buffer */ |
| PCI_UNMAP_SINGLE(pAd, pRxCell->DmaBuf.AllocPa, |
| pRxCell->DmaBuf.AllocSize, PCI_DMA_FROMDEVICE); |
| pRxPacket = pRxCell->pNdisPacket; |
| |
| pRxCell->DmaBuf.AllocSize = RX_BUFFER_AGGRESIZE; |
| pRxCell->pNdisPacket = (void *)pNewPacket; |
| pRxCell->DmaBuf.AllocVa = AllocVa; |
| pRxCell->DmaBuf.AllocPa = AllocPa; |
| /* update SDP0 to new buffer of rx packet */ |
| pRxD->SDP0 = AllocPa; |
| } else { |
| /*DBGPRINT(RT_DEBUG_TRACE,("No Rx Buffer\n")); */ |
| pRxPacket = NULL; |
| bReschedule = TRUE; |
| } |
| |
| pRxD->DDONE = 0; |
| |
| /* had handled one rx packet */ |
| *pRxPending = *pRxPending - 1; |
| |
| /* update rx descriptor and kick rx */ |
| INC_RING_INDEX(pAd->RxRing.RxSwReadIdx, RX_RING_SIZE); |
| |
| pAd->RxRing.RxCpuIdx = |
| (pAd->RxRing.RxSwReadIdx == |
| 0) ? (RX_RING_SIZE - 1) : (pAd->RxRing.RxSwReadIdx - 1); |
| RTMP_IO_WRITE32(pAd, RX_CRX_IDX, pAd->RxRing.RxCpuIdx); |
| |
| done: |
| RTMP_SEM_UNLOCK(&pAd->RxRingLock); |
| *pbReschedule = bReschedule; |
| return pRxPacket; |
| } |
| |
| int MlmeHardTransmitTxRing(struct rt_rtmp_adapter *pAd, |
| u8 QueIdx, void *pPacket) |
| { |
| struct rt_packet_info PacketInfo; |
| u8 *pSrcBufVA; |
| u32 SrcBufLen; |
| struct rt_txd * pTxD; |
| struct rt_header_802_11 * pHeader_802_11; |
| BOOLEAN bAckRequired, bInsertTimestamp; |
| unsigned long SrcBufPA; |
| /*u8 TxBufIdx; */ |
| u8 MlmeRate; |
| unsigned long SwIdx = pAd->TxRing[QueIdx].TxCpuIdx; |
| struct rt_txwi * pFirstTxWI; |
| /*unsigned long i; */ |
| /*HTTRANSMIT_SETTING MlmeTransmit; //Rate for this MGMT frame. */ |
| unsigned long FreeNum; |
| struct rt_mac_table_entry *pMacEntry = NULL; |
| |
| RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pSrcBufVA, &SrcBufLen); |
| |
| if (pSrcBufVA == NULL) { |
| /* The buffer shouldn't be NULL */ |
| return NDIS_STATUS_FAILURE; |
| } |
| /* Make sure MGMT ring resource won't be used by other threads */ |
| /*NdisAcquireSpinLock(&pAd->TxRingLock); */ |
| |
| FreeNum = GET_TXRING_FREENO(pAd, QueIdx); |
| |
| if (FreeNum == 0) { |
| /*NdisReleaseSpinLock(&pAd->TxRingLock); */ |
| return NDIS_STATUS_FAILURE; |
| } |
| |
| SwIdx = pAd->TxRing[QueIdx].TxCpuIdx; |
| |
| pTxD = (struct rt_txd *) pAd->TxRing[QueIdx].Cell[SwIdx].AllocVa; |
| |
| if (pAd->TxRing[QueIdx].Cell[SwIdx].pNdisPacket) { |
| DBGPRINT(RT_DEBUG_OFF, ("MlmeHardTransmit Error\n")); |
| /*NdisReleaseSpinLock(&pAd->TxRingLock); */ |
| return NDIS_STATUS_FAILURE; |
| } |
| |
| { |
| /* outgoing frame always wakeup PHY to prevent frame lost */ |
| /* if (pAd->StaCfg.Psm == PWR_SAVE) */ |
| if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) |
| AsicForceWakeup(pAd, TRUE); |
| } |
| pFirstTxWI = (struct rt_txwi *) pSrcBufVA; |
| |
| pHeader_802_11 = (struct rt_header_802_11 *) (pSrcBufVA + TXWI_SIZE); |
| if (pHeader_802_11->Addr1[0] & 0x01) { |
| MlmeRate = pAd->CommonCfg.BasicMlmeRate; |
| } else { |
| MlmeRate = pAd->CommonCfg.MlmeRate; |
| } |
| |
| if ((pHeader_802_11->FC.Type == BTYPE_DATA) && |
| (pHeader_802_11->FC.SubType == SUBTYPE_QOS_NULL)) { |
| pMacEntry = MacTableLookup(pAd, pHeader_802_11->Addr1); |
| } |
| /* Verify Mlme rate for a / g bands. */ |
| if ((pAd->LatchRfRegs.Channel > 14) && (MlmeRate < RATE_6)) /* 11A band */ |
| MlmeRate = RATE_6; |
| |
| /* */ |
| /* Should not be hard code to set PwrMgmt to 0 (PWR_ACTIVE) */ |
| /* Snice it's been set to 0 while on MgtMacHeaderInit */ |
| /* By the way this will cause frame to be send on PWR_SAVE failed. */ |
| /* */ |
| /* */ |
| /* In WMM-UAPSD, mlme frame should be set psm as power saving but probe request frame */ |
| /* Data-Null packets also pass through MMRequest in RT2860, however, we hope control the psm bit to pass APSD */ |
| if (pHeader_802_11->FC.Type != BTYPE_DATA) { |
| if ((pHeader_802_11->FC.SubType == SUBTYPE_PROBE_REQ) |
| || !(pAd->CommonCfg.bAPSDCapable |
| && pAd->CommonCfg.APEdcaParm.bAPSDCapable)) { |
| pHeader_802_11->FC.PwrMgmt = PWR_ACTIVE; |
| } else { |
| pHeader_802_11->FC.PwrMgmt = |
| pAd->CommonCfg.bAPSDForcePowerSave; |
| } |
| } |
| |
| bInsertTimestamp = FALSE; |
| if (pHeader_802_11->FC.Type == BTYPE_CNTL) /* must be PS-POLL */ |
| { |
| bAckRequired = FALSE; |
| } else /* BTYPE_MGMT or BTYPE_DATA(must be NULL frame) */ |
| { |
| if (pHeader_802_11->Addr1[0] & 0x01) /* MULTICAST, BROADCAST */ |
| { |
| bAckRequired = FALSE; |
| pHeader_802_11->Duration = 0; |
| } else { |
| bAckRequired = TRUE; |
| pHeader_802_11->Duration = |
| RTMPCalcDuration(pAd, MlmeRate, 14); |
| if (pHeader_802_11->FC.SubType == SUBTYPE_PROBE_RSP) { |
| bInsertTimestamp = TRUE; |
| } |
| } |
| } |
| pHeader_802_11->Sequence = pAd->Sequence++; |
| if (pAd->Sequence > 0xfff) |
| pAd->Sequence = 0; |
| /* Before radar detection done, mgmt frame can not be sent but probe req */ |
| /* Because we need to use probe req to trigger driver to send probe req in passive scan */ |
| if ((pHeader_802_11->FC.SubType != SUBTYPE_PROBE_REQ) |
| && (pAd->CommonCfg.bIEEE80211H == 1) |
| && (pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE)) { |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("MlmeHardTransmit --> radar detect not in normal mode!\n")); |
| /*NdisReleaseSpinLock(&pAd->TxRingLock); */ |
| return (NDIS_STATUS_FAILURE); |
| } |
| /* */ |
| /* fill scatter-and-gather buffer list into TXD. Internally created NDIS PACKET */ |
| /* should always has only one ohysical buffer, and the whole frame size equals */ |
| /* to the first scatter buffer size */ |
| /* */ |
| |
| /* Initialize TX Descriptor */ |
| /* For inter-frame gap, the number is for this frame and next frame */ |
| /* For MLME rate, we will fix as 2Mb to match other vendor's implement */ |
| /* pAd->CommonCfg.MlmeTransmit.field.MODE = 1; */ |
| |
| /* management frame doesn't need encryption. so use RESERVED_WCID no matter u are sending to specific wcid or not. */ |
| /* Only beacon use Nseq=TRUE. So here we use Nseq=FALSE. */ |
| if (pMacEntry == NULL) { |
| RTMPWriteTxWI(pAd, pFirstTxWI, FALSE, FALSE, bInsertTimestamp, |
| FALSE, bAckRequired, FALSE, 0, RESERVED_WCID, |
| (SrcBufLen - TXWI_SIZE), PID_MGMT, 0, |
| (u8)pAd->CommonCfg.MlmeTransmit.field.MCS, |
| IFS_BACKOFF, FALSE, &pAd->CommonCfg.MlmeTransmit); |
| } else { |
| RTMPWriteTxWI(pAd, pFirstTxWI, FALSE, FALSE, |
| bInsertTimestamp, FALSE, bAckRequired, FALSE, |
| 0, pMacEntry->Aid, (SrcBufLen - TXWI_SIZE), |
| pMacEntry->MaxHTPhyMode.field.MCS, 0, |
| (u8)pMacEntry->MaxHTPhyMode.field.MCS, |
| IFS_BACKOFF, FALSE, &pMacEntry->MaxHTPhyMode); |
| } |
| |
| pAd->TxRing[QueIdx].Cell[SwIdx].pNdisPacket = pPacket; |
| pAd->TxRing[QueIdx].Cell[SwIdx].pNextNdisPacket = NULL; |
| /* pFirstTxWI->MPDUtotalByteCount = SrcBufLen - TXWI_SIZE; */ |
| SrcBufPA = |
| PCI_MAP_SINGLE(pAd, pSrcBufVA, SrcBufLen, 0, PCI_DMA_TODEVICE); |
| |
| RTMPWriteTxDescriptor(pAd, pTxD, TRUE, FIFO_EDCA); |
| pTxD->LastSec0 = 1; |
| pTxD->LastSec1 = 1; |
| pTxD->SDLen0 = SrcBufLen; |
| pTxD->SDLen1 = 0; |
| pTxD->SDPtr0 = SrcBufPA; |
| pTxD->DMADONE = 0; |
| |
| pAd->RalinkCounters.KickTxCount++; |
| pAd->RalinkCounters.OneSecTxDoneCount++; |
| |
| /* Increase TX_CTX_IDX, but write to register later. */ |
| INC_RING_INDEX(pAd->TxRing[QueIdx].TxCpuIdx, TX_RING_SIZE); |
| |
| RTMP_IO_WRITE32(pAd, TX_CTX_IDX0 + QueIdx * 0x10, |
| pAd->TxRing[QueIdx].TxCpuIdx); |
| |
| /* Make sure to release MGMT ring resource */ |
| /* NdisReleaseSpinLock(&pAd->TxRingLock); */ |
| |
| return NDIS_STATUS_SUCCESS; |
| } |
| |
| int MlmeDataHardTransmit(struct rt_rtmp_adapter *pAd, |
| u8 QueIdx, void *pPacket) |
| { |
| if ((pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE) |
| ) { |
| return NDIS_STATUS_FAILURE; |
| } |
| |
| return MlmeHardTransmitTxRing(pAd, QueIdx, pPacket); |
| } |
| |
| /* |
| ======================================================================== |
| |
| Routine Description: |
| Calculates the duration which is required to transmit out frames |
| with given size and specified rate. |
| |
| Arguments: |
| pTxD Pointer to transmit descriptor |
| Ack Setting for Ack requirement bit |
| Fragment Setting for Fragment bit |
| RetryMode Setting for retry mode |
| Ifs Setting for IFS gap |
| Rate Setting for transmit rate |
| Service Setting for service |
| Length Frame length |
| TxPreamble Short or Long preamble when using CCK rates |
| QueIdx - 0-3, according to 802.11e/d4.4 June/2003 |
| |
| Return Value: |
| None |
| |
| IRQL = PASSIVE_LEVEL |
| IRQL = DISPATCH_LEVEL |
| |
| ======================================================================== |
| */ |
| void RTMPWriteTxDescriptor(struct rt_rtmp_adapter *pAd, |
| struct rt_txd * pTxD, |
| IN BOOLEAN bWIV, u8 QueueSEL) |
| { |
| /* */ |
| /* Always use Long preamble before verifiation short preamble functionality works well. */ |
| /* Todo: remove the following line if short preamble functionality works */ |
| /* */ |
| OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); |
| |
| pTxD->WIV = (bWIV) ? 1 : 0; |
| pTxD->QSEL = (QueueSEL); |
| /*RT2860c?? fixed using EDCA queue for test... We doubt Queue1 has problem. 2006-09-26 Jan */ |
| /*pTxD->QSEL= FIFO_EDCA; */ |
| pTxD->DMADONE = 0; |
| } |