void HTCFlushRxHoldQueue(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint) { HTC_PACKET *pPacket; HTC_PACKET_QUEUE container; LOCK_HTC_RX(target); while (1) { pPacket = HTC_PACKET_DEQUEUE(&pEndpoint->RxBufferHoldQueue); if (NULL == pPacket) { break; } UNLOCK_HTC_RX(target); pPacket->Status = A_ECANCELED; pPacket->ActualLength = 0; AR_DEBUG_PRINTF(ATH_DEBUG_RECV, (" Flushing RX packet:%p, length:%d, ep:%d \n", pPacket, pPacket->BufferLength, pPacket->Endpoint)); INIT_HTC_PACKET_QUEUE_AND_ADD(&container,pPacket); /* give the packet back */ DoRecvCompletion(pEndpoint,&container); LOCK_HTC_RX(target); } UNLOCK_HTC_RX(target); }
static void HTCFlushEndpointRX(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint) { HTC_PACKET *pPacket; LOCK_HTC_RX(target); while (1) { pPacket = HTC_PACKET_DEQUEUE(&pEndpoint->RxBuffers); if (NULL == pPacket) { break; } UNLOCK_HTC_RX(target); pPacket->Status = A_ECANCELED; pPacket->ActualLength = 0; AR_DEBUG_PRINTF(ATH_DEBUG_RECV, (" Flushing RX packet:0x%X, length:%d, ep:%d \n", (A_UINT32)pPacket, pPacket->BufferLength, pPacket->Endpoint)); /* give the packet back */ pEndpoint->EpCallBacks.EpRecv(pEndpoint->EpCallBacks.pContext, pPacket); LOCK_HTC_RX(target); } UNLOCK_HTC_RX(target); }
/*flush all queued buffers for surpriseremove case*/ void htc_flush_surprise_remove(HTC_HANDLE HTCHandle) { HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); int i; HTC_ENDPOINT *pEndpoint; #ifdef RX_SG_SUPPORT cdf_nbuf_t netbuf; cdf_nbuf_queue_t *rx_sg_queue = &target->RxSgQueue; #endif AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+htc_flush_surprise_remove \n")); /* cleanup endpoints */ for (i = 0; i < ENDPOINT_MAX; i++) { pEndpoint = &target->EndPoint[i]; htc_flush_rx_hold_queue(target, pEndpoint); htc_flush_endpoint_tx(target, pEndpoint, HTC_TX_PACKET_TAG_ALL); } hif_flush_surprise_remove(target->hif_dev); #ifdef RX_SG_SUPPORT LOCK_HTC_RX(target); while ((netbuf = cdf_nbuf_queue_remove(rx_sg_queue)) != NULL) { cdf_nbuf_free(netbuf); } RESET_RX_SG_CONFIG(target); UNLOCK_HTC_RX(target); #endif reset_endpoint_states(target); AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-htc_flush_surprise_remove \n")); }
/* polling routine to wait for a control packet to be received */ A_STATUS HTCWaitRecvCtrlMessage(HTC_TARGET *target) { // int count = HTC_TARGET_MAX_RESPONSE_POLL; AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("+HTCWaitCtrlMessageRecv\n")); /* Wait for BMI request/response transaction to complete */ while (adf_os_mutex_acquire(target->osdev, &target->CtrlResponseValid)) { } LOCK_HTC_RX(target); /* caller will clear this flag */ target->CtrlResponseProcessing = TRUE; UNLOCK_HTC_RX(target); #if 0 while (count > 0) { LOCK_HTC_RX(target); if (target->CtrlResponseValid) { target->CtrlResponseValid = FALSE; /* caller will clear this flag */ target->CtrlResponseProcessing = TRUE; UNLOCK_HTC_RX(target); break; } UNLOCK_HTC_RX(target); count--; A_MSLEEP(HTC_TARGET_RESPONSE_POLL_MS); } if (count <= 0) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("-HTCWaitCtrlMessageRecv: Timeout!\n")); return A_ECOMM; } #endif AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("-HTCWaitCtrlMessageRecv success\n")); return A_OK; }
A_STATUS HTCAddReceivePktMultiple(HTC_HANDLE HTCHandle, HTC_PACKET_QUEUE *pPktQueue) { HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); HTC_ENDPOINT *pEndpoint; HTC_PACKET *pFirstPacket; A_STATUS status = A_OK; HTC_PACKET *pPacket; pFirstPacket = HTC_GET_PKT_AT_HEAD(pPktQueue); if (NULL == pFirstPacket) { A_ASSERT(FALSE); return A_EINVAL; } AR_DEBUG_ASSERT(pFirstPacket->Endpoint < ENDPOINT_MAX); AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+- HTCAddReceivePktMultiple : endPointId: %d, cnt:%d, length: %d\n", pFirstPacket->Endpoint, HTC_PACKET_QUEUE_DEPTH(pPktQueue), pFirstPacket->BufferLength)); pEndpoint = &target->EndPoint[pFirstPacket->Endpoint]; LOCK_HTC_RX(target); do { if (HTC_STOPPING(target)) { status = A_ERROR; break; } /* store receive packets */ HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint->RxBufferHoldQueue,pPktQueue); } while (FALSE); UNLOCK_HTC_RX(target); if (A_FAILED(status)) { /* walk through queue and mark each one canceled */ HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pPktQueue,pPacket) { pPacket->Status = A_ECANCELED; } HTC_PACKET_QUEUE_ITERATE_END; DoRecvCompletion(pEndpoint,pPktQueue); } return status; }
A_BOOL htc_get_endpoint_statistics(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint, HTC_ENDPOINT_STAT_ACTION Action, HTC_ENDPOINT_STATS *pStats) { #ifdef HTC_EP_STAT_PROFILING HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); A_BOOL clearStats = false; A_BOOL sample = false; switch (Action) { case HTC_EP_STAT_SAMPLE: sample = true; break; case HTC_EP_STAT_SAMPLE_AND_CLEAR: sample = true; clearStats = true; break; case HTC_EP_STAT_CLEAR: clearStats = true; break; default: break; } A_ASSERT(Endpoint < ENDPOINT_MAX); /* lock out TX and RX while we sample and/or clear */ LOCK_HTC_TX(target); LOCK_HTC_RX(target); if (sample) { A_ASSERT(pStats != NULL); /* return the stats to the caller */ A_MEMCPY(pStats, &target->EndPoint[Endpoint].EndPointStats, sizeof(HTC_ENDPOINT_STATS)); } if (clearStats) { /* reset stats */ A_MEMZERO(&target->EndPoint[Endpoint].EndPointStats, sizeof(HTC_ENDPOINT_STATS)); } UNLOCK_HTC_RX(target); UNLOCK_HTC_TX(target); return true; #else return false; #endif }
/* Makes a buffer available to the HTC module */ A_STATUS HTCAddReceivePkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket) { HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); HTC_ENDPOINT *pEndpoint; A_BOOL unblockRecv = FALSE; A_STATUS status = A_OK; AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+- HTCAddReceivePkt: endPointId: %d, buffer: 0x%X, length: %d\n", pPacket->Endpoint, (A_UINT32)pPacket->pBuffer, pPacket->BufferLength)); do { AR_DEBUG_ASSERT(pPacket->Endpoint < ENDPOINT_MAX); pEndpoint = &target->EndPoint[pPacket->Endpoint]; LOCK_HTC_RX(target); if (HTC_STOPPING(target)) { pPacket->Status = A_ECANCELED; status = A_ECANCELED; UNLOCK_HTC_RX(target); pEndpoint->EpCallBacks.EpRecv(pEndpoint->EpCallBacks.pContext, pPacket); break; } /* store receive packet */ HTC_PACKET_ENQUEUE(&pEndpoint->RxBuffers, pPacket); /* check if we are blocked waiting for a new buffer */ if (target->HTCStateFlags & HTC_STATE_WAIT_BUFFERS) { if (target->EpWaitingForBuffers == pPacket->Endpoint) { AR_DEBUG_PRINTF(ATH_DEBUG_RECV,(" receiver was blocked on ep:%d, unblocking.. \n", target->EpWaitingForBuffers)); target->HTCStateFlags &= ~HTC_STATE_WAIT_BUFFERS; target->EpWaitingForBuffers = ENDPOINT_MAX; unblockRecv = TRUE; } } UNLOCK_HTC_RX(target); if (unblockRecv && !HTC_STOPPING(target)) { /* TODO : implement a buffer threshold count? */ DevEnableRecv(&target->Device,DEV_ENABLE_RECV_SYNC); } } while (FALSE); return status; }
void FreeHTCPacketContainer(HTC_TARGET *target, HTC_PACKET *pPacket) { LOCK_HTC_RX(target); if (NULL == target->pHTCPacketStructPool) { target->pHTCPacketStructPool = pPacket; pPacket->ListLink.pNext = NULL; } else { pPacket->ListLink.pNext = (DL_LIST *)target->pHTCPacketStructPool; target->pHTCPacketStructPool = pPacket; } UNLOCK_HTC_RX(target); }
/* stop HTC communications, i.e. stop interrupt reception, and flush all queued buffers */ void htc_stop(HTC_HANDLE HTCHandle) { HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); int i; HTC_ENDPOINT *pEndpoint; #ifdef RX_SG_SUPPORT cdf_nbuf_t netbuf; cdf_nbuf_queue_t *rx_sg_queue = &target->RxSgQueue; #endif AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+htc_stop \n")); /* cleanup endpoints */ for (i = 0; i < ENDPOINT_MAX; i++) { pEndpoint = &target->EndPoint[i]; htc_flush_rx_hold_queue(target, pEndpoint); htc_flush_endpoint_tx(target, pEndpoint, HTC_TX_PACKET_TAG_ALL); if (pEndpoint->ul_is_polled) { cdf_softirq_timer_cancel(&pEndpoint->ul_poll_timer); cdf_softirq_timer_free(&pEndpoint->ul_poll_timer); } } /* Note: htc_flush_endpoint_tx for all endpoints should be called before * hif_stop - otherwise htc_tx_completion_handler called from * hif_send_buffer_cleanup_on_pipe for residual tx frames in HIF layer, * might queue the packet again to HIF Layer - which could cause tx * buffer leak */ hif_stop(target->hif_dev); #ifdef RX_SG_SUPPORT LOCK_HTC_RX(target); while ((netbuf = cdf_nbuf_queue_remove(rx_sg_queue)) != NULL) { cdf_nbuf_free(netbuf); } RESET_RX_SG_CONFIG(target); UNLOCK_HTC_RX(target); #endif reset_endpoint_states(target); AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-htc_stop \n")); }
HTC_PACKET *AllocateHTCPacketContainer(HTC_TARGET *target) { HTC_PACKET *pPacket; LOCK_HTC_RX(target); if (NULL == target->pHTCPacketStructPool) { UNLOCK_HTC_RX(target); return NULL; } pPacket = target->pHTCPacketStructPool; target->pHTCPacketStructPool = (HTC_PACKET *)pPacket->ListLink.pNext; UNLOCK_HTC_RX(target); pPacket->ListLink.pNext = NULL; return pPacket; }
/* stop HTC communications, i.e. stop interrupt reception, and flush all queued buffers */ void HTCStop(HTC_HANDLE HTCHandle) { HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); int i; HTC_ENDPOINT *pEndpoint; #ifdef RX_SG_SUPPORT adf_nbuf_t netbuf; adf_nbuf_queue_t *rx_sg_queue = &target->RxSgQueue; #endif AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCStop \n")); /* cleanup endpoints */ for (i = 0; i < ENDPOINT_MAX; i++) { pEndpoint = &target->EndPoint[i]; HTCFlushRxHoldQueue(target,pEndpoint); HTCFlushEndpointTX(target,pEndpoint,HTC_TX_PACKET_TAG_ALL); } /* Note: HTCFlushEndpointTX for all endpoints should be called before * HIFStop - otherwise HTCTxCompletionHandler called from * hif_send_buffer_cleanup_on_pipe for residual tx frames in HIF layer, * might queue the packet again to HIF Layer - which could cause tx * buffer leak */ HIFStop(target->hif_dev); #ifdef RX_SG_SUPPORT LOCK_HTC_RX(target); while ((netbuf = adf_nbuf_queue_remove(rx_sg_queue)) != NULL) { adf_nbuf_free(netbuf); } RESET_RX_SG_CONFIG(target); UNLOCK_HTC_RX(target); #endif ResetEndpointStates(target); AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCStop \n")); }
/* stop HTC communications, i.e. stop interrupt reception, and flush all queued buffers */ void HTCStop(HTC_HANDLE HTCHandle) { HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCStop \n")); LOCK_HTC_RX(target); /* mark that we are shutting down .. */ target->HTCStateFlags |= HTC_STATE_STOPPING; UNLOCK_HTC_RX(target); /* Masking interrupts is a synchronous operation, when this function returns * all pending HIF I/O has completed, we can safely flush the queues */ DevMaskInterrupts(&target->Device); /* flush all send packets */ HTCFlushSendPkts(target); /* flush all recv buffers */ HTCFlushRecvBuffers(target); ResetEndpointStates(target); AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCStop \n")); }
void HTCUnblockRecv(HTC_HANDLE HTCHandle) { HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); A_BOOL unblockRecv = FALSE; LOCK_HTC_RX(target); /* check if we are blocked waiting for a new buffer */ if (target->HTCStateFlags & HTC_STATE_WAIT_BUFFERS) { AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("HTCUnblockRx : receiver was blocked on ep:%d, unblocking.. \n", target->EpWaitingForBuffers)); target->HTCStateFlags &= ~HTC_STATE_WAIT_BUFFERS; target->EpWaitingForBuffers = ENDPOINT_MAX; unblockRecv = TRUE; } UNLOCK_HTC_RX(target); if (unblockRecv && !HTC_STOPPING(target)) { /* re-enable */ DevEnableRecv(&target->Device,DEV_ENABLE_RECV_ASYNC); } }
A_STATUS HTCRxCompletionHandler( void *Context, adf_nbuf_t netbuf, a_uint8_t pipeID) { A_STATUS status = A_OK; HTC_FRAME_HDR *HtcHdr; HTC_TARGET *target = (HTC_TARGET *)Context; a_uint8_t *netdata; a_uint32_t netlen; HTC_ENDPOINT *pEndpoint; HTC_PACKET *pPacket; A_UINT16 payloadLen; a_uint32_t trailerlen = 0; A_UINT8 htc_ep_id; #ifdef RX_SG_SUPPORT LOCK_HTC_RX(target); if (target->IsRxSgInprogress) { target->CurRxSgTotalLen += adf_nbuf_len(netbuf); adf_nbuf_queue_add(&target->RxSgQueue, netbuf); if (target->CurRxSgTotalLen == target->ExpRxSgTotalLen) { netbuf = RxSgToSingleNetbuf(target); if (netbuf == NULL) { UNLOCK_HTC_RX(target); goto _out; } } else { netbuf = NULL; UNLOCK_HTC_RX(target); goto _out; } } UNLOCK_HTC_RX(target); #endif netdata = adf_nbuf_data(netbuf); netlen = adf_nbuf_len(netbuf); HtcHdr = (HTC_FRAME_HDR *)netdata; do { htc_ep_id = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, ENDPOINTID); pEndpoint = &target->EndPoint[htc_ep_id]; if (htc_ep_id >= ENDPOINT_MAX) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HTC Rx: invalid EndpointID=%d\n",htc_ep_id)); DebugDumpBytes((A_UINT8 *)HtcHdr,sizeof(HTC_FRAME_HDR),"BAD HTC Header"); status = A_ERROR; break; } /* * If this endpoint that received a message from the target has * a to-target HIF pipe whose send completions are polled rather * than interrupt-driven, this is a good point to ask HIF to check * whether it has any completed sends to handle. */ if (pEndpoint->ul_is_polled) { HTCSendCompleteCheck(pEndpoint, 1); } payloadLen = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, PAYLOADLEN); if (netlen < (payloadLen + HTC_HDR_LENGTH)) { #ifdef RX_SG_SUPPORT LOCK_HTC_RX(target); target->IsRxSgInprogress = TRUE; adf_nbuf_queue_init(&target->RxSgQueue); adf_nbuf_queue_add(&target->RxSgQueue, netbuf); target->ExpRxSgTotalLen = (payloadLen + HTC_HDR_LENGTH); target->CurRxSgTotalLen += netlen; UNLOCK_HTC_RX(target); netbuf = NULL; break; #else AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HTC Rx: insufficient length, got:%d expected =%d\n", netlen, payloadLen + HTC_HDR_LENGTH)); DebugDumpBytes((A_UINT8 *)HtcHdr,sizeof(HTC_FRAME_HDR),"BAD RX packet length"); status = A_ERROR; break; #endif } #ifdef HTC_EP_STAT_PROFILING LOCK_HTC_RX(target); INC_HTC_EP_STAT(pEndpoint,RxReceived,1); UNLOCK_HTC_RX(target); #endif //if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { { A_UINT8 temp; /* get flags to check for trailer */ temp = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, FLAGS); if (temp & HTC_FLAGS_RECV_TRAILER) { /* extract the trailer length */ temp = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, CONTROLBYTES0); if ((temp < sizeof(HTC_RECORD_HDR)) || (temp > payloadLen)) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HTCProcessRecvHeader, invalid header (payloadlength should be :%d, CB[0] is:%d) \n", payloadLen, temp)); status = A_EPROTO; break; } trailerlen = temp; /* process trailer data that follows HDR + application payload */ status = HTCProcessTrailer(target, ((A_UINT8 *)HtcHdr + HTC_HDR_LENGTH + payloadLen - temp), temp, htc_ep_id); if (A_FAILED(status)) { break; } } } if (((int)payloadLen - (int)trailerlen) <= 0) { /* zero length packet with trailer data, just drop these */ break; } if (htc_ep_id == ENDPOINT_0) { A_UINT16 message_id; HTC_UNKNOWN_MSG *htc_msg; /* remove HTC header */ adf_nbuf_pull_head(netbuf, HTC_HDR_LENGTH); netdata = adf_nbuf_data(netbuf); netlen = adf_nbuf_len(netbuf); htc_msg = (HTC_UNKNOWN_MSG*)netdata; message_id = HTC_GET_FIELD(htc_msg, HTC_UNKNOWN_MSG, MESSAGEID); switch (message_id) { default: /* handle HTC control message */ if (target->CtrlResponseProcessing) { /* this is a fatal error, target should not be sending unsolicited messages * on the endpoint 0 */ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HTC Rx Ctrl still processing\n")); status = A_ERROR; break; } LOCK_HTC_RX(target); target->CtrlResponseLength = min((int)netlen,HTC_MAX_CONTROL_MESSAGE_LENGTH); A_MEMCPY(target->CtrlResponseBuffer,netdata,target->CtrlResponseLength); UNLOCK_HTC_RX(target); adf_os_mutex_release(target->osdev, &target->CtrlResponseValid); break; case HTC_MSG_SEND_SUSPEND_COMPLETE: target->HTCInitInfo.TargetSendSuspendComplete(target->HTCInitInfo.pContext); break; } adf_nbuf_free(netbuf); netbuf = NULL; break; } /* the current message based HIF architecture allocates net bufs for recv packets * since this layer bridges that HIF to upper layers , which expects HTC packets, * we form the packets here * TODO_FIXME */ pPacket = AllocateHTCPacketContainer(target); if (NULL == pPacket) { status = A_NO_RESOURCE; break; } pPacket->Status = A_OK; pPacket->Endpoint = htc_ep_id; pPacket->pPktContext = netbuf; pPacket->pBuffer = adf_nbuf_data(netbuf) + HTC_HDR_LENGTH; pPacket->ActualLength = netlen - HTC_HEADER_LEN - trailerlen; /* TODO : this is a hack because the driver layer will set the actual length * of the skb again which will just double the length */ //A_NETBUF_TRIM(netbuf,netlen); adf_nbuf_trim_tail(netbuf, netlen); RecvPacketCompletion(target,pEndpoint,pPacket); /* recover the packet container */ FreeHTCPacketContainer(target,pPacket); netbuf = NULL; } while(FALSE); #ifdef RX_SG_SUPPORT _out: #endif if (netbuf != NULL) { adf_nbuf_free(netbuf); } return status; }
/* callback when device layer or lookahead report parsing detects a pending message */ A_STATUS HTCRecvMessagePendingHandler(void *Context, A_UINT32 *LookAhead, A_BOOL *pAsyncProc) { HTC_TARGET *target = (HTC_TARGET *)Context; A_STATUS status = A_OK; HTC_PACKET *pPacket = NULL; HTC_FRAME_HDR *pHdr = NULL; HTC_ENDPOINT *pEndpoint = NULL; A_BOOL asyncProc = FALSE; AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+HTCRecvMessagePendingHandler LookAhead:0x%X \n", *LookAhead)); if (IS_DEV_IRQ_PROCESSING_ASYNC_ALLOWED(&target->Device)) { /* We use async mode to get the packets if the device layer supports it. * The device layer interfaces with HIF in which HIF may have restrictions on * how interrupts are processed */ asyncProc = TRUE; } if (pAsyncProc != NULL) { /* indicate to caller how we decided to process this */ *pAsyncProc = asyncProc; } while (TRUE) { pHdr = (HTC_FRAME_HDR *)LookAhead; if (pHdr->EndpointID >= ENDPOINT_MAX) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Invalid Endpoint in look-ahead: %d \n",pHdr->EndpointID)); /* invalid endpoint */ status = A_EPROTO; break; } if (pHdr->PayloadLen > HTC_MAX_PAYLOAD_LENGTH) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Payload length %d exceeds max HTC : %d !\n", pHdr->PayloadLen, HTC_MAX_PAYLOAD_LENGTH)); status = A_EPROTO; break; } pEndpoint = &target->EndPoint[pHdr->EndpointID]; if (0 == pEndpoint->ServiceID) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Endpoint %d is not connected !\n",pHdr->EndpointID)); /* endpoint isn't even connected */ status = A_EPROTO; break; } if (pEndpoint->EpCallBacks.EpRecvAlloc != NULL) { /* user is using a per-packet allocation callback */ pPacket = pEndpoint->EpCallBacks.EpRecvAlloc(pEndpoint->EpCallBacks.pContext, (HTC_ENDPOINT_ID) pHdr->EndpointID, pHdr->PayloadLen + sizeof(HTC_FRAME_HDR)); /* lock RX, in case this allocation fails, we need to update internal state below */ LOCK_HTC_RX(target); } else { /* user is using a refill handler that can refill multiple HTC buffers */ /* lock RX to get a buffer */ LOCK_HTC_RX(target); /* get a packet from the endpoint recv queue */ pPacket = HTC_PACKET_DEQUEUE(&pEndpoint->RxBuffers); if (NULL == pPacket) { /* check for refill handler */ if (pEndpoint->EpCallBacks.EpRecvRefill != NULL) { UNLOCK_HTC_RX(target); /* call the re-fill handler */ pEndpoint->EpCallBacks.EpRecvRefill(pEndpoint->EpCallBacks.pContext, (HTC_ENDPOINT_ID) pHdr->EndpointID); LOCK_HTC_RX(target); /* check if we have more buffers */ pPacket = HTC_PACKET_DEQUEUE(&pEndpoint->RxBuffers); /* fall through */ } } } if (NULL == pPacket) { /* this is not an error, we simply need to mark that we are waiting for buffers.*/ target->HTCStateFlags |= HTC_STATE_WAIT_BUFFERS; target->EpWaitingForBuffers = (HTC_ENDPOINT_ID) pHdr->EndpointID; status = A_NO_MEMORY; } if (HTC_STOPPING(target)) { status = A_ECANCELED; } UNLOCK_HTC_RX(target); if (A_FAILED(status)) { /* no buffers or stopping */ break; } pPacket->PktInfo.AsRx.IndicationFlags = 0; AR_DEBUG_ASSERT(pPacket->Endpoint == pHdr->EndpointID); /* make sure this message can fit in the endpoint buffer */ if ((pHdr->PayloadLen + HTC_HDR_LENGTH) > pPacket->BufferLength) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Payload Length Error : header reports payload of: %d, endpoint buffer size: %d \n", pHdr->PayloadLen, pPacket->BufferLength)); status = A_EPROTO; break; } pPacket->HTCReserved = *LookAhead; /* set expected look ahead */ /* set the amount of data to fetch */ pPacket->ActualLength = pHdr->PayloadLen + HTC_HDR_LENGTH; if (asyncProc) { /* we use async mode to get the packet if the device layer supports it * set our callback and context */ pPacket->Completion = HTCRecvCompleteHandler; pPacket->pContext = target; } else { /* fully synchronous */ pPacket->Completion = NULL; } /* go fetch the packet */ status = HTCIssueRecv(target, pPacket); if (A_FAILED(status)) { break; } if (asyncProc) { /* we did this asynchronously so we can get out of the loop, the asynch processing * creates a chain of requests to continue processing pending messages in the * context of callbacks */ break; } /* in the sync case, we process the packet, check lookaheads and then repeat */ *LookAhead = 0; status = HTCProcessRecvHeader(target,pPacket,LookAhead); if (A_FAILED(status)) { break; } HTC_RX_STAT_PROFILE(target,pEndpoint,*LookAhead); /* check lookahead to see if we can indicate next packet hint to recv callback */ if (LookAhead != 0) { pHdr = (HTC_FRAME_HDR *)&LookAhead; /* check to see if the "next" packet is from the same endpoint of the completing packet */ if (pHdr->EndpointID == pPacket->Endpoint) { /* check that there is a buffer available to actually fetch it * NOTE: no need to lock RX here , since we are synchronously processing RX * and we are only looking at the queue (not modifying it) */ if (!HTC_QUEUE_EMPTY(&pEndpoint->RxBuffers)) { /* provide a hint that there are more RX packets to fetch */ pPacket->PktInfo.AsRx.IndicationFlags |= HTC_RX_FLAGS_INDICATE_MORE_PKTS; } } } DO_RCV_COMPLETION(target,pPacket,pEndpoint); pPacket = NULL; if (0 == *LookAhead) { break; } /* check whether other OS contexts have queued any WMI command/data for WLAN. * This check is needed only if WLAN Tx and Rx happens in same thread context */ A_CHECK_DRV_TX(); } if (A_NO_MEMORY == status) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (" Endpoint :%d has no buffers, blocking receiver to prevent overrun.. \n", (pHdr != NULL) ? pHdr->EndpointID : 0xFFFF)); /* try to stop receive at the device layer */ DevStopRecv(&target->Device, asyncProc ? DEV_STOP_RECV_ASYNC : DEV_STOP_RECV_SYNC); status = A_OK; } else if (A_FAILED(status)) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Failed to get pending message : LookAhead Value: 0x%X (status = %d) \n", *LookAhead, status)); if (pPacket != NULL) { /* clean up packet on error */ HTC_RECYCLE_RX_PKT(target, pPacket, pEndpoint); } } AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-HTCRecvMessagePendingHandler \n")); return status; }