/* ======================================================================== Routine Description: Arguments: Return Value: IRQL = Note: ======================================================================== */ VOID RTUSBRejectPendingPackets( IN PRTMP_ADAPTER pAd) { UCHAR Index; PQUEUE_ENTRY pEntry; PNDIS_PACKET pPacket; PQUEUE_HEADER pQueue; #ifdef RELEASE_EXCLUDE DBGPRINT_RAW(RT_DEBUG_INFO, ("--->RejectPendingPackets\n")); #endif // RELEASE_EXCLUDE // for (Index = 0; Index < 4; Index++) { NdisAcquireSpinLock(&pAd->TxSwQueueLock[Index]); while (pAd->TxSwQueue[Index].Head != NULL) { pQueue = (PQUEUE_HEADER) &(pAd->TxSwQueue[Index]); pEntry = RemoveHeadQueue(pQueue); pPacket = QUEUE_ENTRY_TO_PACKET(pEntry); RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); } NdisReleaseSpinLock(&pAd->TxSwQueueLock[Index]); } #ifdef RELEASE_EXCLUDE DBGPRINT_RAW(RT_DEBUG_INFO, ("<---RejectPendingPackets\n")); #endif // RELEASE_EXCLUDE // }
VOID TxSwQDepthAdjust(IN RTMP_ADAPTER *pAd, IN UINT32 qLen) { ULONG IrqFlags; INT qIdx; QUEUE_HEADER *pTxQ, *pEntry; PNDIS_PACKET pPacket; RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags); pAd->TxSwQMaxLen = qLen; for (qIdx = 0; qIdx < NUM_OF_TX_RING; qIdx++) { pTxQ = &pAd->TxSwQueue[qIdx]; while(pTxQ->Number >= pAd->TxSwQMaxLen) { pEntry = RemoveHeadQueue(pTxQ); if (pEntry) { pPacket = QUEUE_ENTRY_TO_PACKET(pEntry); RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); } else break; } } RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); DBGPRINT(RT_DEBUG_OFF, ("%s():Set TxSwQMaxLen as %d\n", __FUNCTION__, pAd->TxSwQMaxLen)); }
/* ========================================================================== Description: This routine is used to clean up a specified power-saving queue. It's used whenever a wireless client is deleted. ========================================================================== */ VOID RtmpCleanupPsQueue(RTMP_ADAPTER *pAd, QUEUE_HEADER *pQueue) { QUEUE_ENTRY *pQEntry; PNDIS_PACKET pPacket; DBGPRINT(RT_DEBUG_TRACE, ("RtmpCleanupPsQueue (0x%08lx)...\n", (ULONG)pQueue)); while (pQueue->Head) { DBGPRINT(RT_DEBUG_TRACE, ("RtmpCleanupPsQueue %ld...\n",pQueue->Number)); pQEntry = RemoveHeadQueue(pQueue); /*pPacket = CONTAINING_RECORD(pEntry, NDIS_PACKET, MiniportReservedEx); */ pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); DBGPRINT(RT_DEBUG_TRACE, ("RtmpCleanupPsQueue pkt = %lx...\n", (ULONG)pPacket)); } }
/* ======================================================================== Routine Description: Arguments: Return Value: IRQL = Note: ======================================================================== */ void RTUSBRejectPendingPackets(struct rt_rtmp_adapter *pAd) { u8 Index; struct rt_queue_entry *pEntry; void *pPacket; struct rt_queue_header *pQueue; for (Index = 0; Index < 4; Index++) { NdisAcquireSpinLock(&pAd->TxSwQueueLock[Index]); while (pAd->TxSwQueue[Index].Head != NULL) { pQueue = (struct rt_queue_header *)& (pAd->TxSwQueue[Index]); pEntry = RemoveHeadQueue(pQueue); pPacket = QUEUE_ENTRY_TO_PACKET(pEntry); RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); } NdisReleaseSpinLock(&pAd->TxSwQueueLock[Index]); } }
/* ======================================================================== Routine Description: Arguments: Return Value: IRQL = Note: ======================================================================== */ VOID RTUSBRejectPendingPackets( IN PRTMP_ADAPTER pAd) { UCHAR Index; PQUEUE_ENTRY pEntry; PNDIS_PACKET pPacket; PQUEUE_HEADER pQueue; for (Index = 0; Index < 4; Index++) { NdisAcquireSpinLock(&pAd->TxSwQueueLock[Index]); while (pAd->TxSwQueue[Index].Head != NULL) { pQueue = (PQUEUE_HEADER) &(pAd->TxSwQueue[Index]); pEntry = RemoveHeadQueue(pQueue); pPacket = QUEUE_ENTRY_TO_PACKET(pEntry); RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); } NdisReleaseSpinLock(&pAd->TxSwQueueLock[Index]); } }
/* ======================================================================== 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 RtmpHandleRxPsPoll(RTMP_ADAPTER *pAd, UCHAR *pAddr, USHORT wcid, BOOLEAN isActive) { QUEUE_ENTRY *pQEntry; MAC_TABLE_ENTRY *pMacEntry; unsigned long IrqFlags; /* DBGPRINT(RT_DEBUG_TRACE, ("rcv PS-POLL (AID=%d) from %02x:%02x:%02x:%02x:%02x:%02x\n", Aid, PRINT_MAC(pAddr))); */ pMacEntry = &pAd->MacTab.Content[wcid]; if (RTMPEqualMemory(pMacEntry->Addr, pAddr, MAC_ADDR_LEN)) { #ifdef DROP_MASK_SUPPORT /* Disable Drop Mask */ set_drop_mask_per_client(pAd, pMacEntry, 2, 0); #endif /* DROP_MASK_SUPPORT */ #ifdef PS_ENTRY_MAITENANCE pMacEntry->continuous_ps_count = 0; #endif /* PS_ENTRY_MAITENANCE */ /* Sta is change to Power Active stat. Reset ContinueTxFailCnt */ pMacEntry->ContinueTxFailCnt = 0; #ifdef UAPSD_SUPPORT if (UAPSD_MR_IS_ALL_AC_UAPSD(isActive, pMacEntry)) { /* IEEE802.11e spec. 11.2.1.7 Receive operation for STAs in PS mode during the CP When a non-AP QSTA that is using U-APSD and has all ACs delivery-enabled detects that the bit corresponding to its AID is set in the TIM, the non-AP QSTA shall issue a trigger frame or a PS-Poll frame to retrieve the buffered MSDU or management frames. WMM Spec. v1.1a 070601 3.6.2 U-APSD STA Operation 3.6.2.3 In case one or more ACs are not delivery-enabled ACs, the WMM STA may retrieve MSDUs and MMPDUs belonging to those ACs by sending PS-Polls to the WMM AP. In case all ACs are delivery enabled ACs, WMM STA should only use trigger frames to retrieve MSDUs and MMPDUs belonging to those ACs, and it should not send PS-Poll frames. Different definitions in IEEE802.11e and WMM spec. But we follow the WiFi WMM Spec. */ DBGPRINT(RT_DEBUG_TRACE, ("All AC are UAPSD, can not use PS-Poll\n")); return; /* all AC are U-APSD, can not use PS-Poll */ } #endif /* UAPSD_SUPPORT */ RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags); if (isActive == FALSE) { if (pMacEntry->PsQueue.Head) { #ifdef UAPSD_SUPPORT UINT32 NumOfOldPsPkt; NumOfOldPsPkt = pAd->TxSwQueue[QID_AC_BE].Number; #endif /* UAPSD_SUPPORT */ pQEntry = RemoveHeadQueue(&pMacEntry->PsQueue); if ( pMacEntry->PsQueue.Number >=1 ) RTMP_SET_PACKET_MOREDATA(RTPKT_TO_OSPKT(pQEntry), TRUE); InsertTailQueueAc(pAd, pMacEntry, &pAd->TxSwQueue[QID_AC_BE], pQEntry); #ifdef UAPSD_SUPPORT /* we need to call RTMPDeQueuePacket() immediately as below */ if (NumOfOldPsPkt != pAd->TxSwQueue[QID_AC_BE].Number) { if (RTMP_GET_PACKET_DHCP(RTPKT_TO_OSPKT(pQEntry)) || RTMP_GET_PACKET_EAPOL(RTPKT_TO_OSPKT(pQEntry)) || RTMP_GET_PACKET_WAI(RTPKT_TO_OSPKT(pQEntry))) { /* These packets will use 1M/6M rate to send. If you use 1M(2.4G)/6M(5G) to send, no statistics count in NICUpdateFifoStaCounters(). So we can not count it for UAPSD; Or the SP will not closed until timeout. */ } else UAPSD_MR_MIX_PS_POLL_RCV(pAd, pMacEntry); } #endif /* UAPSD_SUPPORT */ } else { /* or transmit a (QoS) Null Frame; In addtion, in Station Keep Alive mechanism, we need to send a QoS Null frame to detect the station live status. */ BOOLEAN bQosNull = FALSE; if (CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_WMM_CAPABLE)) bQosNull = TRUE; RtmpEnqueueNullFrame(pAd, pMacEntry->Addr, pMacEntry->CurrTxRate, pMacEntry->Aid, pMacEntry->apidx, bQosNull, TRUE, 0); } } else { #ifdef UAPSD_SUPPORT /* deliver all queued UAPSD packets */ UAPSD_AllPacketDeliver(pAd, pMacEntry); /* end the SP if exists */ UAPSD_MR_ENTRY_RESET(pAd, pMacEntry); #endif /* UAPSD_SUPPORT */ while(pMacEntry->PsQueue.Head) { pQEntry = RemoveHeadQueue(&pMacEntry->PsQueue); InsertTailQueueAc(pAd, pMacEntry, &pAd->TxSwQueue[QID_AC_BE], pQEntry); } } if ((pMacEntry->Aid > 0) && (pMacEntry->Aid < MAX_LEN_OF_MAC_TABLE) && (pMacEntry->PsQueue.Number == 0)) { /* clear corresponding TIM bit because no any PS packet */ #ifdef CONFIG_AP_SUPPORT if(pMacEntry->wdev->wdev_type == WDEV_TYPE_AP) { WLAN_MR_TIM_BIT_CLEAR(pAd, pMacEntry->apidx, pMacEntry->Aid); } #endif /* CONFIG_AP_SUPPORT */ pMacEntry->PsQIdleCount = 0; } RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); /* Dequeue outgoing frames from TxSwQueue0..3 queue and process it TODO: 2004-12-27 it's not a good idea to handle "More Data" bit here. because the RTMPDeQueue process doesn't guarantee to de-queue the desired MSDU from the corresponding TxSwQueue/PsQueue when QOS in-used. We should consider "HardTransmt" this MPDU using MGMT queue or things like that. */ RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); } else { DBGPRINT(RT_DEBUG_ERROR,("rcv PS-POLL (AID=%d not match) from %02x:%02x:%02x:%02x:%02x:%02x\n", pMacEntry->Aid, PRINT_MAC(pAddr))); } }
VOID RTMPFreeTxRxRingMemory( IN PRTMP_ADAPTER pAd) { int index, num , j; PRTMP_TX_RING pTxRing; PTXD_STRUC pTxD; PNDIS_PACKET pPacket; unsigned int IrqFlags; POS_COOKIE pObj =(POS_COOKIE) pAd->OS_Cookie; DBGPRINT(RT_DEBUG_TRACE, ("--> RTMPFreeTxRxRingMemory\n")); for (index=0; index <NUM_OF_TX_RING; index++) { PQUEUE_ENTRY pEntry; PNDIS_PACKET pPacket; PQUEUE_HEADER pQueue; RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags); pQueue = &pAd->TxSwQueue[index]; while (pQueue->Head) { pEntry = RemoveHeadQueue(pQueue); pPacket = QUEUE_ENTRY_TO_PACKET(pEntry); RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); } RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); } for (index=0;index< NUM_OF_TX_RING;index++) { pTxRing = &pAd->TxRing[index]; for (j=0; j< TX_RING_SIZE; j++) { pTxD = (PTXD_STRUC) (pTxRing->Cell[j].AllocVa); pPacket = pTxRing->Cell[j].pNdisPacket; if (pPacket) { PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr0, pTxD->SDLen0, PCI_DMA_TODEVICE); RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); } pTxRing->Cell[j].pNdisPacket = NULL; pPacket = pTxRing->Cell[j].pNextNdisPacket; if (pPacket) { PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, pTxD->SDLen1, PCI_DMA_TODEVICE); RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); } pTxRing->Cell[pTxRing->TxSwFreeIdx].pNextNdisPacket = NULL; } } for (index = RX_RING_SIZE - 1 ; index >= 0; index--) { if ((pAd->RxRing.Cell[index].DmaBuf.AllocVa) && (pAd->RxRing.Cell[index].pNdisPacket)) { PCI_UNMAP_SINGLE(pObj->pci_dev, pAd->RxRing.Cell[index].DmaBuf.AllocPa, pAd->RxRing.Cell[index].DmaBuf.AllocSize, PCI_DMA_FROMDEVICE); RELEASE_NDIS_PACKET(pAd, pAd->RxRing.Cell[index].pNdisPacket, NDIS_STATUS_SUCCESS); } } NdisZeroMemory(pAd->RxRing.Cell, RX_RING_SIZE * sizeof(RTMP_DMACB)); if (pAd->RxDescRing.AllocVa) { PCI_FREE_CONSISTENT(pObj->pci_dev, pAd->RxDescRing.AllocSize, pAd->RxDescRing.AllocVa, pAd->RxDescRing.AllocPa); } NdisZeroMemory(&pAd->RxDescRing, sizeof(RTMP_DMABUF)); if (pAd->MgmtDescRing.AllocVa) { PCI_FREE_CONSISTENT(pObj->pci_dev, pAd->MgmtDescRing.AllocSize, pAd->MgmtDescRing.AllocVa, pAd->MgmtDescRing.AllocPa); } NdisZeroMemory(&pAd->MgmtDescRing, sizeof(RTMP_DMABUF)); for (num = 0; num < NUM_OF_TX_RING; num++) { if (pAd->TxBufSpace[num].AllocVa) { PCI_FREE_CONSISTENT(pObj->pci_dev, pAd->TxBufSpace[num].AllocSize, pAd->TxBufSpace[num].AllocVa, pAd->TxBufSpace[num].AllocPa); } NdisZeroMemory(&pAd->TxBufSpace[num], sizeof(RTMP_DMABUF)); if (pAd->TxDescRing[num].AllocVa) { PCI_FREE_CONSISTENT(pObj->pci_dev, pAd->TxDescRing[num].AllocSize, pAd->TxDescRing[num].AllocVa, pAd->TxDescRing[num].AllocPa); } NdisZeroMemory(&pAd->TxDescRing[num], sizeof(RTMP_DMABUF)); } if (pAd->FragFrame.pFragPacket) RELEASE_NDIS_PACKET(pAd, pAd->FragFrame.pFragPacket, NDIS_STATUS_SUCCESS); DBGPRINT(RT_DEBUG_TRACE, ("<-- RTMPFreeTxRxRingMemory\n")); }
VOID RTMPRingCleanUp( IN PRTMP_ADAPTER pAd, IN UCHAR RingType) { PTXD_STRUC pTxD; PRXD_STRUC pRxD; PQUEUE_ENTRY pEntry; PNDIS_PACKET pPacket; int i; PRTMP_TX_RING pTxRing; unsigned long IrqFlags; DBGPRINT(RT_DEBUG_TRACE,("RTMPRingCleanUp(RingIdx=%d, Pending-NDIS=%ld)\n", RingType, pAd->RalinkCounters.PendingNdisPacketCount)); switch (RingType) { case QID_AC_BK: case QID_AC_BE: case QID_AC_VI: case QID_AC_VO: case QID_HCCA: RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags); pTxRing = &pAd->TxRing[RingType]; for (i=0; i<TX_RING_SIZE; i++) { pTxD = (PTXD_STRUC) pTxRing->Cell[i].AllocVa; pPacket = (PNDIS_PACKET) pTxRing->Cell[i].pNdisPacket; if (pPacket) { RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); pTxRing->Cell[i].pNdisPacket = NULL; } pPacket = (PNDIS_PACKET) pTxRing->Cell[i].pNextNdisPacket; if (pPacket) { RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); pTxRing->Cell[i].pNextNdisPacket = NULL; } } RTMP_IO_READ32(pAd, TX_DTX_IDX0 + RingType * 0x10, &pTxRing->TxDmaIdx); pTxRing->TxSwFreeIdx = pTxRing->TxDmaIdx; pTxRing->TxCpuIdx = pTxRing->TxDmaIdx; RTMP_IO_WRITE32(pAd, TX_CTX_IDX0 + RingType * 0x10, pTxRing->TxCpuIdx); RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags); while (pAd->TxSwQueue[RingType].Head != NULL) { pEntry = RemoveHeadQueue(&pAd->TxSwQueue[RingType]); pPacket = QUEUE_ENTRY_TO_PACKET(pEntry); RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); DBGPRINT(RT_DEBUG_TRACE,("Release 1 NDIS packet from s/w backlog queue\n")); } RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); break; case QID_MGMT: NdisAcquireSpinLock(&pAd->MgmtRingLock); for (i=0; i<MGMT_RING_SIZE; i++) { pTxD = (PTXD_STRUC) pAd->MgmtRing.Cell[i].AllocVa; pPacket = (PNDIS_PACKET) pAd->MgmtRing.Cell[i].pNdisPacket; if (pPacket) { PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr0, pTxD->SDLen0, PCI_DMA_TODEVICE); RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); } pAd->MgmtRing.Cell[i].pNdisPacket = NULL; pPacket = (PNDIS_PACKET) pAd->MgmtRing.Cell[i].pNextNdisPacket; if (pPacket) { PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, pTxD->SDLen1, PCI_DMA_TODEVICE); RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); } pAd->MgmtRing.Cell[i].pNextNdisPacket = NULL; } RTMP_IO_READ32(pAd, TX_MGMTDTX_IDX, &pAd->MgmtRing.TxDmaIdx); pAd->MgmtRing.TxSwFreeIdx = pAd->MgmtRing.TxDmaIdx; pAd->MgmtRing.TxCpuIdx = pAd->MgmtRing.TxDmaIdx; RTMP_IO_WRITE32(pAd, TX_MGMTCTX_IDX, pAd->MgmtRing.TxCpuIdx); NdisReleaseSpinLock(&pAd->MgmtRingLock); pAd->RalinkCounters.MgmtRingFullCount = 0; break; case QID_RX: NdisAcquireSpinLock(&pAd->RxRingLock); for (i=0; i<RX_RING_SIZE; i++) { pRxD = (PRXD_STRUC) pAd->RxRing.Cell[i].AllocVa; pRxD->DDONE = 0 ; } RTMP_IO_READ32(pAd, RX_DRX_IDX, &pAd->RxRing.RxDmaIdx); pAd->RxRing.RxSwReadIdx = pAd->RxRing.RxDmaIdx; pAd->RxRing.RxCpuIdx = ((pAd->RxRing.RxDmaIdx == 0) ? (RX_RING_SIZE-1) : (pAd->RxRing.RxDmaIdx-1)); RTMP_IO_WRITE32(pAd, RX_CRX_IDX, pAd->RxRing.RxCpuIdx); NdisReleaseSpinLock(&pAd->RxRingLock); break; default: break; } }
void tbtt_tasklet(unsigned long data) { //#define MAX_TX_IN_TBTT (16) #ifdef CONFIG_AP_SUPPORT PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) data; #ifdef RTMP_MAC_PCI if (pAd->OpMode == OPMODE_AP) { #ifdef AP_QLOAD_SUPPORT /* update channel utilization */ QBSS_LoadUpdate(pAd, 0); #endif // AP_QLOAD_SUPPORT // } #endif // RTMP_MAC_PCI // if (pAd->OpMode == OPMODE_AP) { // // step 7 - if DTIM, then move backlogged bcast/mcast frames from PSQ to TXQ whenever DtimCount==0 #ifdef RTMP_MAC_PCI // NOTE: This updated BEACON frame will be sent at "next" TBTT instead of at cureent TBTT. The reason is // because ASIC already fetch the BEACON content down to TX FIFO before driver can make any // modification. To compenstate this effect, the actual time to deilver PSQ frames will be // at the time that we wrapping around DtimCount from 0 to DtimPeriod-1 if (pAd->ApCfg.DtimCount == 0) #endif // RTMP_MAC_PCI // { PQUEUE_ENTRY pEntry; BOOLEAN bPS = FALSE; UINT count = 0; unsigned long IrqFlags; // NdisAcquireSpinLock(&pAd->MacTabLock); // NdisAcquireSpinLock(&pAd->TxSwQueueLock); RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags); while (pAd->MacTab.McastPsQueue.Head) { bPS = TRUE; if (pAd->TxSwQueue[QID_AC_BE].Number <= (MAX_PACKETS_IN_QUEUE + MAX_PACKETS_IN_MCAST_PS_QUEUE)) { pEntry = RemoveHeadQueue(&pAd->MacTab.McastPsQueue); //if(pAd->MacTab.McastPsQueue.Number) if (count) { RTMP_SET_PACKET_MOREDATA(pEntry, TRUE); } InsertHeadQueue(&pAd->TxSwQueue[QID_AC_BE], pEntry); count++; } else { break; } } RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); // NdisReleaseSpinLock(&pAd->TxSwQueueLock); // NdisReleaseSpinLock(&pAd->MacTabLock); if (pAd->MacTab.McastPsQueue.Number == 0) { UINT bss_index; /* clear MCAST/BCAST backlog bit for all BSS */ for(bss_index=BSS0; bss_index<pAd->ApCfg.BssidNum; bss_index++) WLAN_MR_TIM_BCMC_CLEAR(bss_index); /* End of for */ } pAd->MacTab.PsQIdleCount = 0; // Dequeue outgoing framea from TxSwQueue0..3 queue and process it if (bPS == TRUE) { RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, /*MAX_TX_IN_TBTT*/MAX_PACKETS_IN_MCAST_PS_QUEUE); } } } #endif // CONFIG_AP_SUPPORT // }