/**************************************************************************** * Ralink Tech Inc. * Taiwan, R.O.C. * * (c) Copyright 2010, Ralink Technology, Inc. * * All rights reserved. Ralink's source code is an unpublished work and the * use of a copyright notice does not imply otherwise. This source code * contains confidential trade secret material of Ralink Tech. Any attemp * or participation in deciphering, decoding, reverse engineering or in any * way altering the source code is stricitly prohibited, unless the prior * written consent of Ralink Technology, Inc. is obtained. ***************************************************************************/ /**************************************************************************** Abstract: All related POWER SAVE function body. ***************************************************************************/ #include "rt_config.h" #ifdef MT_PS static VOID MtReadPseRdTabAccessReg( RTMP_ADAPTER *pAd, UCHAR wcid, UINT32 *p_rPseRdTabAccessReg) { *p_rPseRdTabAccessReg = PSE_RTA_RD_KICK_BUSY | PSE_RTA_TAG(wcid); RTMP_IO_WRITE32(pAd, PSE_RTA, *p_rPseRdTabAccessReg); do { RTMP_IO_READ32(pAd,PSE_RTA, p_rPseRdTabAccessReg); } while ( GET_PSE_RTA_RD_KICK_BUSY(*p_rPseRdTabAccessReg) == 1 ); DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_PS, ("%s: *p_rPseRdTabAccessReg = 0x%x\n", __FUNCTION__, *p_rPseRdTabAccessReg)); } VOID MtSetIgnorePsm( RTMP_ADAPTER *pAd, MAC_TABLE_ENTRY *pEntry, UCHAR value) { #ifdef RTMP_PCI_SUPPORT ULONG IrqFlags = 0; #endif /* RTMP_PCI_SUPPORT */ struct wtbl_entry tb_entry; union WTBL_1_DW3 *dw3 = (union WTBL_1_DW3 *)&tb_entry.wtbl_1.wtbl_1_d3.word; NdisZeroMemory(&tb_entry, sizeof(tb_entry)); if (mt_wtbl_get_entry234(pAd, pEntry->wcid, &tb_entry) == FALSE) { DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_PS, ("%s():Cannot found WTBL2/3/4\n",__FUNCTION__)); return; } #ifdef RTMP_PCI_SUPPORT RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags); #endif /* RTMP_PCI_SUPPORT */ pEntry->i_psm = value; RTMP_IO_READ32(pAd, tb_entry.wtbl_addr[0]+12, &dw3->word); dw3->field.du_i_psm = value; /* I_PSM changed by HW automatically is enabled. */ dw3->field.i_psm = value; /* follow PSM value. */ RTMP_IO_WRITE32(pAd, tb_entry.wtbl_addr[0] + 12, dw3->word); #ifdef RTMP_PCI_SUPPORT RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); #endif /* RTMP_PCI_SUPPORT */ } VOID CheckSkipTX( RTMP_ADAPTER *pAd, MAC_TABLE_ENTRY *pEntry) { struct wtbl_entry tb_entry; union WTBL_1_DW3 *dw3 = (union WTBL_1_DW3 *)&tb_entry.wtbl_1.wtbl_1_d3.word; STA_TR_ENTRY *tr_entry; CHAR isChange = FALSE; NdisZeroMemory(&tb_entry, sizeof(tb_entry)); if (mt_wtbl_get_entry234(pAd, pEntry->wcid, &tb_entry) == FALSE) { DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_PS, ("%s():Cannot found WTBL2/3/4\n",__FUNCTION__)); return; } tr_entry = &pAd->MacTab.tr_entry[pEntry->wcid]; RTMP_IO_READ32(pAd, tb_entry.wtbl_addr[0]+12, &dw3->word); if ((tr_entry->ps_state != APPS_RETRIEVE_START_PS) && (dw3->field.skip_tx == 1)) { dw3->field.skip_tx = 0; isChange = TRUE; } if ((tr_entry->ps_state < APPS_RETRIEVE_DONE) && (dw3->field.du_i_psm == 1)) { dw3->field.du_i_psm = 0; dw3->field.i_psm = 0; isChange = TRUE; } if (isChange == TRUE) { pAd->SkipTxRCount++; RTMP_IO_WRITE32(pAd, tb_entry.wtbl_addr[0]+12, dw3->word); } return; } #endif /* MT_PS */ #ifdef MT7603 INT MtPSDummyCR(RTMP_ADAPTER *pAd) { INT value; RTMP_IO_READ32(pAd, 0x817c, &value); value &= 0xff; return value; } #ifdef RTMP_MAC_PCI VOID MtTriggerMCUINT(RTMP_ADAPTER *pAd) { INT value; INT restore_remap_addr; RTMP_IO_READ32(pAd, 0x2504, &restore_remap_addr); RTMP_IO_WRITE32(pAd, 0x2504, 0x81000000); RTMP_IO_READ32(pAd, 0xc00c0, &value); value |= 0x100; RTMP_IO_WRITE32(pAd, 0xc00c0, value); //Trigger INT to MCU, 0x810400c0 RTMP_IO_WRITE32(pAd, 0x2504, restore_remap_addr); } #endif /* RTMP_MAC_PCI */ BOOLEAN MtStartPSRetrieve(RTMP_ADAPTER *pAd, USHORT wcid) { if (MtPSDummyCR(pAd) != 0) { return FALSE; } RTMP_IO_WRITE32(pAd, 0x817c, wcid); #ifdef RTMP_MAC_PCI // MtTriggerMCUINT(pAd); #endif /* RTMP_MAC_PCI */ return TRUE; } #endif /* ======================================================================== Description: This routine frees all packets in PSQ that's destined to a specific DA. BCAST/MCAST in DTIMCount=0 case is also handled here, just like a PS-POLL is received from a WSTA which has MAC address FF:FF:FF:FF:FF:FF ======================================================================== */ VOID MtHandleRxPsPoll(RTMP_ADAPTER *pAd, UCHAR *pAddr, USHORT wcid, BOOLEAN isActive) { #ifdef CONFIG_AP_SUPPORT #if defined(MT_PS) || defined(UAPSD_SUPPORT) MAC_TABLE_ENTRY *pMacEntry; #endif STA_TR_ENTRY *tr_entry; BOOLEAN IsDequeu= FALSE; INT DequeuAC = QID_AC_BE; INT DequeuCOUNT; #ifdef MT_PS INT i, Total_Packet_Number = 0; #endif /* MT_PS */ //struct tx_swq_fifo *fifo_swq; ASSERT(wcid < MAX_LEN_OF_MAC_TABLE); #if defined(MT_PS) || defined(UAPSD_SUPPORT) pMacEntry = &pAd->MacTab.Content[wcid]; #endif tr_entry = &pAd->MacTab.tr_entry[wcid]; if (isActive == FALSE) /* ps poll */ { #ifdef MT_PS if (tr_entry->ps_state == APPS_RETRIEVE_DONE) /*state is finish(sleep)*/ { if (pMacEntry->i_psm == I_PSM_DISABLE) { MT_SET_IGNORE_PSM(pAd, pMacEntry, I_PSM_ENABLE); } } if(tr_entry->ps_state == APPS_RETRIEVE_DONE || tr_entry->ps_state == APPS_RETRIEVE_IDLE) { for (i = 0; i < WMM_QUE_NUM; i++) Total_Packet_Number = Total_Packet_Number + tr_entry->tx_queue[i].Number; if (Total_Packet_Number > 0) { { DBGPRINT(RT_DEBUG_TRACE | DBG_FUNC_PS, ("RtmpHandleRxPsPoll fetch tx queue tr_entry->ps_queue.Number= %x tr_entry->tx_queue[0].Number=%x Total_Packet_Number=%x\n", tr_entry->ps_queue.Number, tr_entry->tx_queue[QID_AC_BE].Number, Total_Packet_Number)); for (i = (WMM_QUE_NUM - 1); i >=0; i--) { if (tr_entry->tx_queue[i].Head) { if (Total_Packet_Number > 1) { RTMP_SET_PACKET_MOREDATA(RTPKT_TO_OSPKT(tr_entry->tx_queue[i].Head), TRUE); } RTMP_SET_PACKET_TXTYPE(RTPKT_TO_OSPKT(tr_entry->tx_queue[i].Head), TX_LEGACY_FRAME); DequeuAC = i; IsDequeu = TRUE; DequeuCOUNT = 1; tr_entry->PsQIdleCount = 0; break; } } } } else /* Recieve ps_poll but no packet==>send NULL Packet */ { BOOLEAN bQosNull = FALSE; DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_PS, ("RtmpHandleRxPsPoll no packet tr_entry->ps_queue.Number= %x tr_entry->tx_queue[0].Number=%x Total_Packet_Number=%x\n" ,tr_entry->ps_queue.Number, tr_entry->tx_queue[QID_AC_BE].Number, Total_Packet_Number)); if (CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_WMM_CAPABLE)) bQosNull = TRUE; RtmpEnqueueNullFrame(pAd, pMacEntry->Addr, tr_entry->CurrTxRate, pMacEntry->Aid, pMacEntry->func_tb_idx, bQosNull, TRUE, 0); } if (Total_Packet_Number >1) { WLAN_MR_TIM_BIT_SET(pAd, tr_entry->func_tb_idx, tr_entry->wcid); } else { WLAN_MR_TIM_BIT_CLEAR(pAd, tr_entry->func_tb_idx, tr_entry->wcid); } } else tr_entry->PsDeQWaitCnt = 0; #else /* Need to check !! @20140212 New architecture has per AC sw-Q for per entry. We should check packets by ACs priority --> 1. VO, 2. VI, 3. BE, 4. BK */ DequeuAC = QID_AC_BE; IsDequeu = TRUE; DequeuCOUNT = 1; tr_entry->PsQIdleCount = 0; #endif /* Ps_poll and ifndef MT_PS */ } else /* Receive Power bit 0 frame */ { WLAN_MR_TIM_BIT_CLEAR(pAd, tr_entry->func_tb_idx, tr_entry->wcid); #ifdef MT_PS if (pMacEntry->i_psm == I_PSM_ENABLE) { MT_SET_IGNORE_PSM(pAd, pMacEntry, I_PSM_DISABLE); } #endif /*Power bit is 1 and ifndef MT_PS */ DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_PS, ("RtmpHandleRxPsPoll null0/1 wcid = %x mt_ps_queue.Number = %d\n", tr_entry->wcid, tr_entry->ps_queue.Number)); DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_PS, ("%s(%d) tx_queue.Number = BE:%d, BK:%d, VI:%d, VO:%d, ps_state:%x, tx_queue.TokenCount = BE:%d, BK:%d, VI:%d, VO:%d\n", __FUNCTION__, __LINE__, tr_entry->tx_queue[QID_AC_BE].Number, tr_entry->tx_queue[QID_AC_BK].Number, tr_entry->tx_queue[QID_AC_VI].Number, tr_entry->tx_queue[QID_AC_VO].Number, tr_entry->ps_state, tr_entry->TokenCount[QID_AC_BE], tr_entry->TokenCount[QID_AC_BK], tr_entry->TokenCount[QID_AC_VI], tr_entry->TokenCount[QID_AC_VO])); #ifdef UAPSD_SUPPORT if (CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_APSD_CAPABLE)) { /* deliver all queued UAPSD packets */ UAPSD_AllPacketDeliver(pAd, pMacEntry); /* end the SP if exists */ UAPSD_MR_ENTRY_RESET(pAd, pMacEntry); } #endif /* UAPSD_SUPPORT */ if (tr_entry->enqCount > 0) { IsDequeu = TRUE; DequeuAC = NUM_OF_TX_RING; if (tr_entry->enqCount > MAX_TX_PROCESS) { DequeuCOUNT = MAX_TX_PROCESS; rtmp_ps_enq(pAd,tr_entry); } else { DequeuCOUNT = tr_entry->enqCount; } } } if (IsDequeu == TRUE) { RTMPDeQueuePacket(pAd, FALSE, (UCHAR)DequeuAC, tr_entry->wcid, DequeuCOUNT); DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_PS, ("RtmpHandleRxPsPoll IsDequeu == TRUE tr_entry->wcid=%x DequeuCOUNT=%d, ps_state=%d\n",tr_entry->wcid, DequeuCOUNT, tr_entry->ps_state)); } return; #endif /* CONFIG_AP_SUPPORT */ } /* ========================================================================== Description: Update the station current power save mode. Calling this routine also prove the specified client is still alive. Otherwise AP will age-out this client once IdleCount exceeds a threshold. ========================================================================== */ BOOLEAN MtPsIndicate(RTMP_ADAPTER *pAd, UCHAR *pAddr, UCHAR wcid, UCHAR Psm) { MAC_TABLE_ENTRY *pEntry; UCHAR old_psmode; STA_TR_ENTRY *tr_entry; if (wcid >= MAX_LEN_OF_MAC_TABLE) { return PWR_ACTIVE; } pEntry = &pAd->MacTab.Content[wcid]; tr_entry = &pAd->MacTab.tr_entry[wcid]; /* Change power save mode first because we will call RTMPDeQueuePacket() in RtmpHandleRxPsPoll(). Or when Psm = PWR_ACTIVE, we will not do Aggregation in RTMPDeQueuePacket(). */ old_psmode = pEntry->PsMode; pEntry->NoDataIdleCount = 0; pEntry->PsMode = Psm; pAd->MacTab.tr_entry[wcid].PsMode = Psm; if ((old_psmode == PWR_SAVE) && (Psm == PWR_ACTIVE)) { /* STA wakes up. */ if(tr_entry->ps_state == APPS_RETRIEVE_DONE) { tr_entry->ps_state = APPS_RETRIEVE_IDLE; DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_PS, ("%s(%d): STA wakes up!\n", __FUNCTION__, __LINE__)); MtHandleRxPsPoll(pAd, pAddr, wcid, TRUE); } else DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_PS, ("%s(%d):wcid=%d, old_psmode=%d, now_psmode=%d, wrong ps_state=%d ???\n", __FUNCTION__, __LINE__, wcid, old_psmode, Psm, tr_entry->ps_state)); } else if ((old_psmode == PWR_ACTIVE) && (Psm == PWR_SAVE)) { /* STA goes to sleep. */ if (tr_entry->ps_state == APPS_RETRIEVE_IDLE) { #ifdef MT_PS DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_PS, ("%s(%d):wcid=%d, old_psmode=%d, now_psmode=%d, ps_state=%d start retrieving!!\n", __FUNCTION__, __LINE__, wcid, old_psmode, Psm, tr_entry->ps_state)); #if defined(MT7603) && defined(RTMP_PCI_SUPPORT) if (MtStartPSRetrieve(pAd, wcid) == TRUE) { tr_entry->ps_state = APPS_RETRIEVE_START_PS; } else { struct tx_swq_fifo *ps_fifo_swq; INT enq_idx; ps_fifo_swq = &pAd->apps_cr_q; enq_idx = ps_fifo_swq->enqIdx; if (ps_fifo_swq->swq[enq_idx] == 0) { ps_fifo_swq->swq[enq_idx] = wcid; INC_RING_INDEX(ps_fifo_swq->enqIdx, TX_SWQ_FIFO_LEN); tr_entry->ps_state = APPS_RETRIEVE_CR_PADDING; } else { INT idx; tr_entry->ps_state = APPS_RETRIEVE_DONE; DBGPRINT(RT_DEBUG_ERROR, ("%s: ERROR!! ps_fifo_swq->deqIdx=%d, ps_fifo_swq->enqIdx=%d\n", __FUNCTION__,ps_fifo_swq->deqIdx,ps_fifo_swq->enqIdx)); for (idx =0; idx < TX_SWQ_FIFO_LEN;idx++) { DBGPRINT(RT_DEBUG_ERROR, (",[%d] =%d\n", idx, ps_fifo_swq->swq[idx])); if ((idx % 16) == 0) DBGPRINT(RT_DEBUG_ERROR, ("\n")); } DBGPRINT(RT_DEBUG_ERROR, ("\n")); } } #else /* !MT7603 && RTMP_PCI_SUPPORT */ RTEnqueueInternalCmd(pAd, CMDTHREAD_PS_RETRIEVE_START, pEntry, sizeof(MAC_TABLE_ENTRY)); #endif /* MT7603 && RTMP_PCI_SUPPORT */ #else /* MT_PS */ tr_entry->ps_state = APPS_RETRIEVE_DONE; #endif /* !MT_PS */ } else DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_PS, ("%s(%d):wcid=%d, old_psmode=%d, now_psmode=%d, wrong ps_state=%d ???\n", __FUNCTION__, __LINE__, wcid, old_psmode, Psm, tr_entry->ps_state)); } else { DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_PS, ("%s(%d): ps state is not changed, do nothing here.\n", __FUNCTION__, __LINE__)); } return old_psmode; } #ifdef MT_PS VOID MtPsRedirectDisableCheck( RTMP_ADAPTER *pAd, UCHAR wcid) { //UINT32 Reg = 0, wlan_idx = 0; //BOOLEAN pfgForce = 0; if (pAd->chipCap.hif_type != HIF_MT) { return; } #if 0 //snowpin test MtReadPseRdTabAccessReg(pAd, wcid, &Reg); pfgForce = ( BOOLEAN ) GET_PSE_RTA_RD_RULE_F(Reg); if (pfgForce) { wlan_idx = (UINT32)wcid; DBGPRINT(RT_DEBUG_ERROR | DBG_FUNC_PS, ("%s(%d): [wlan_idx=0x%x] PS Redirect mode(pfgForce = %d) is enabled. Send PC Clear command to FW.\n", __FUNCTION__, __LINE__, wlan_idx, pfgForce)); RTEnqueueInternalCmd(pAd, CMDTHREAD_PS_CLEAR, (VOID *)&wlan_idx, sizeof(UINT32)); } #endif } VOID MtPsSendToken( RTMP_ADAPTER *pAd, UINT32 WlanIdx) { MAC_TABLE_ENTRY *pEntry = NULL; STA_TR_ENTRY *tr_entry; NDIS_STATUS token_status; struct wtbl_entry tb_entry; union WTBL_1_DW3 *dw3; UINT32 Reg = 0; BOOLEAN pfgForce = 0; unsigned char q_idx; if (pAd->chipCap.hif_type != HIF_MT) { return; } DBGPRINT(RT_DEBUG_ERROR | DBG_FUNC_PS, ("%s(wcid=%d): Driver didn't receive PsRetrieveStartRsp from FW.\n",__FUNCTION__, WlanIdx)); pEntry = &pAd->MacTab.Content[WlanIdx]; tr_entry = &pAd->MacTab.tr_entry[WlanIdx]; NdisZeroMemory(&tb_entry, sizeof(tb_entry)); dw3 = (union WTBL_1_DW3 *)&tb_entry.wtbl_1.wtbl_1_d3.word; if (mt_wtbl_get_entry234(pAd, WlanIdx, &tb_entry) == FALSE) { DBGPRINT(RT_DEBUG_ERROR | DBG_FUNC_PS, ("%s():Cannot found WTBL2/3/4, wcid=%d\n",__FUNCTION__, WlanIdx)); return; } RTMP_IO_READ32(pAd, tb_entry.wtbl_addr[0]+12, &dw3->word); MtReadPseRdTabAccessReg(pAd, pEntry->wcid, &Reg); pfgForce = ( BOOLEAN ) GET_PSE_RTA_RD_RULE_F(Reg); if (pfgForce == 0) { DBGPRINT(RT_DEBUG_WARN | DBG_FUNC_PS, ("%s(ps_state = %d): PS Redirect mode didn't be enabled. Driver doesn't need to send token.\n",__FUNCTION__, tr_entry->ps_state)); DBGPRINT(RT_DEBUG_WARN | DBG_FUNC_PS, ("%s: Reset ps_state to IDLE.\n",__FUNCTION__)); tr_entry->ps_state = APPS_RETRIEVE_IDLE; return; } DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_PS, ("---->%s: Start to send TOKEN frames.\n", __FUNCTION__)); tr_entry->ps_state = APPS_RETRIEVE_GOING; tr_entry->ps_qbitmap = 0; for (q_idx = 0; q_idx < NUM_OF_TX_RING; q_idx++) { token_status = RtmpEnqueueTokenFrame(pAd, &(pEntry->Addr[0]), 0, WlanIdx, 0, q_idx); if (!token_status) tr_entry->ps_qbitmap |= (1 << q_idx); else DBGPRINT(RT_DEBUG_ERROR | DBG_FUNC_PS, ("%s(%d) Fail: Send TOKEN Frame, AC=%d\n", __FUNCTION__, __LINE__, q_idx)); } if (tr_entry->ps_qbitmap == 0) { tr_entry->ps_state = APPS_RETRIEVE_WAIT_EVENT; RTEnqueueInternalCmd(pAd, CMDTHREAD_PS_CLEAR, (VOID *)&WlanIdx, sizeof(UINT32)); DBGPRINT(RT_DEBUG_WARN | DBG_FUNC_PS, ("(ps_state = %d) token enqueue failed for all queues ==> send CMDTHREAD_PS_CLEAR cmd.\n", tr_entry->ps_state)); } } VOID MtEnqTxSwqFromPsQueue(RTMP_ADAPTER *pAd, UCHAR qidx, STA_TR_ENTRY *tr_entry) { ULONG IrqFlags = 0; //struct tx_swq_fifo *fifo_swq; QUEUE_ENTRY *pQEntry; QUEUE_HEADER *pAcPsQue; QUEUE_HEADER *pAcTxQue; #ifdef UAPSD_SUPPORT MAC_TABLE_ENTRY *pEntry = &pAd->MacTab.Content[tr_entry->wcid]; #endif /* UAPSD_SUPPORT */ //fifo_swq = &pAd->tx_swq[qidx]; #if 1 pAcPsQue = &tr_entry->ps_queue; #else pAcPsQue = &tr_entry->mt_ps_queue[qidx]; #endif pAcTxQue = &tr_entry->tx_queue[qidx]; RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags); #ifdef UAPSD_SUPPORT if (UAPSD_MR_IS_UAPSD_AC(pEntry, qidx)) { while(pAcPsQue->Head) { pQEntry = RemoveTailQueue(pAcPsQue); UAPSD_PacketEnqueue(pAd, pEntry, PACKET_TO_QUEUE_ENTRY(pQEntry), qidx, TRUE); } } else #endif /* UAPSD_SUPPORT */ { /*check and insert PS Token queue*/ if(pAcPsQue->Number > 0 && tr_entry->wcid > 0 && tr_entry->wcid < MAX_LEN_OF_TR_TABLE) { rtmp_ps_enq(pAd,tr_entry); DBGPRINT(RT_DEBUG_WARN, ("pAcPsQue->Number=%d,PS:%d\n", pAcPsQue->Number, tr_entry->PsTokenFlag)); } while(pAcPsQue->Head) { pQEntry = RemoveTailQueue(pAcPsQue); if(tr_entry->enqCount > SQ_ENQ_NORMAL_MAX) { RELEASE_NDIS_PACKET(pAd, QUEUE_ENTRY_TO_PACKET(pQEntry), NDIS_STATUS_FAILURE); continue; } InsertHeadQueue(pAcTxQue, pQEntry); TR_ENQ_COUNT_INC(tr_entry); } } RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); return; } VOID MtPsClearErrorHandle(RTMP_ADAPTER *pAd, UINT wcid) { MAC_TABLE_ENTRY *pEntry = NULL; STA_TR_ENTRY *tr_entry; pEntry = &pAd->MacTab.Content[wcid]; tr_entry = &pAd->MacTab.tr_entry[wcid]; if (tr_entry->PsMode == PWR_ACTIVE) { tr_entry->ps_state = APPS_RETRIEVE_IDLE; } else { tr_entry->ps_state = APPS_RETRIEVE_DONE; } if (tr_entry->ps_state == APPS_RETRIEVE_IDLE) { MtHandleRxPsPoll(pAd, &pEntry->Addr[0], wcid, TRUE); } } #endif /* MT_PS */