adf_nbuf_t RxSgToSingleNetbuf(HTC_TARGET *target) { adf_nbuf_t skb; a_uint8_t *anbdata; a_uint8_t *anbdata_new; a_uint32_t anblen; adf_nbuf_t new_skb = NULL; a_uint32_t sg_queue_len; adf_nbuf_queue_t *rx_sg_queue = &target->RxSgQueue; sg_queue_len = adf_nbuf_queue_len(rx_sg_queue); if (sg_queue_len <= 1) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("RxSgToSingleNetbuf: invalid sg queue len %u\n")); goto _failed; } new_skb = adf_nbuf_alloc(target->ExpRxSgTotalLen, 0, 4, FALSE); if (new_skb == NULL) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("RxSgToSingleNetbuf: can't allocate %u size netbuf\n", target->ExpRxSgTotalLen)); goto _failed; } adf_nbuf_peek_header(new_skb, &anbdata_new, &anblen); skb = adf_nbuf_queue_remove(rx_sg_queue); do { adf_nbuf_peek_header(skb, &anbdata, &anblen); adf_os_mem_copy(anbdata_new, anbdata, adf_nbuf_len(skb)); adf_nbuf_put_tail(new_skb, adf_nbuf_len(skb)); anbdata_new += adf_nbuf_len(skb); adf_nbuf_free(skb); skb = adf_nbuf_queue_remove(rx_sg_queue); } while(skb != NULL); RESET_RX_SG_CONFIG(target); return new_skb; _failed: while ((skb = adf_nbuf_queue_remove(rx_sg_queue)) != NULL) { adf_nbuf_free(skb); } RESET_RX_SG_CONFIG(target); return NULL; }
/* post recv urbs for a given pipe */ static void usb_hif_post_recv_transfers(HIF_USB_PIPE *recv_pipe, int buffer_length) { HIF_URB_CONTEXT *urb_context; a_uint8_t *data; a_uint32_t len; struct urb *urb; int usb_status; AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+%s\n", __func__)); while (1) { urb_context = usb_hif_alloc_urb_from_pipe(recv_pipe); if (NULL == urb_context) break; urb_context->buf = adf_nbuf_alloc(NULL, buffer_length, 0, 4, FALSE); if (NULL == urb_context->buf) { usb_hif_cleanup_recv_urb(urb_context); break; } adf_nbuf_peek_header(urb_context->buf, &data, &len); urb = urb_context->urb; usb_fill_bulk_urb(urb, recv_pipe->device->udev, recv_pipe->usb_pipe_handle, data, buffer_length, usb_hif_usb_recv_complete, urb_context); AR_DEBUG_PRINTF(USB_HIF_DEBUG_BULK_IN, ( "athusb bulk recv submit:%d, 0x%X (ep:0x%2.2X), %d bytes, buf:0x%p\n", recv_pipe->logical_pipe_num, recv_pipe->usb_pipe_handle, recv_pipe->ep_address, buffer_length, urb_context->buf)); usb_hif_enqueue_pending_transfer(recv_pipe, urb_context); usb_status = usb_submit_urb(urb, GFP_ATOMIC); if (usb_status) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("athusb : usb bulk recv failed %d\n", usb_status)); usb_hif_remove_pending_transfer(urb_context); usb_hif_cleanup_recv_urb(urb_context); break; } } AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-%s\n", __func__)); }
void usb_hif_io_comp_work(struct work_struct *work) { HIF_USB_PIPE *pipe = container_of(work, HIF_USB_PIPE, io_complete_work); adf_nbuf_t buf; HIF_DEVICE_USB *device; HTC_FRAME_HDR *HtcHdr; struct hif_usb_softc *sc; A_UINT8 *data; A_UINT32 len; AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+%s\n", __func__)); device = pipe->device; sc = device->sc; while ((buf = skb_dequeue(&pipe->io_comp_queue))) { a_mem_trace(buf); if (pipe->flags & HIF_USB_PIPE_FLAG_TX) { AR_DEBUG_PRINTF(USB_HIF_DEBUG_BULK_OUT, ("+athusb xmit callback " "buf:0x%p\n", buf)); HtcHdr = (HTC_FRAME_HDR *) adf_nbuf_get_frag_vaddr(buf, 0); #ifdef ATH_11AC_TXCOMPACT #error ATH_11AC_TXCOMPACT only support for High Latency mode #else device->htcCallbacks.txCompletionHandler(device-> htcCallbacks. Context, buf, HtcHdr-> EndpointID); #endif AR_DEBUG_PRINTF(USB_HIF_DEBUG_BULK_OUT, ("-athusb xmit callback\n")); } else { AR_DEBUG_PRINTF(USB_HIF_DEBUG_BULK_IN, ("+athusb recv callback buf:" "0x%p\n", buf)); adf_nbuf_peek_header(buf, &data, &len); if (IS_FW_CRASH_DUMP(*((A_UINT32 *) data))) { sc->fw_data = data; sc->fw_data_len = len; device->htcCallbacks.fwEventHandler( device->htcCallbacks.Context, A_USB_ERROR); dev_kfree_skb(buf); } else { device->htcCallbacks.rxCompletionHandler( device->htcCallbacks.Context, buf, pipe->logical_pipe_num); AR_DEBUG_PRINTF(USB_HIF_DEBUG_BULK_IN, ("-athusb recv callback\n")); } } } AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-%s\n", __func__)); }
/* process an incomming control message from the host */ LOCAL void HTCControlSvcProcessMsg(HTC_ENDPOINT_ID EndpointID, adf_nbuf_t hdr_buf, adf_nbuf_t pBuffers, void *arg) { A_BOOL setupComplete = FALSE; a_uint8_t *anbdata; a_uint32_t anblen; HTC_CONTEXT *pHTC = (HTC_CONTEXT *)arg; HTC_UNKNOWN_MSG *pMsg; adf_os_assert(hdr_buf == ADF_NBUF_NULL); /* we assume buffers are aligned such that we can access the message * parameters directly*/ adf_nbuf_peek_header(pBuffers, &anbdata, &anblen); pMsg = (HTC_UNKNOWN_MSG *)anbdata; /* we cannot handle fragmented messages across buffers */ switch ( adf_os_ntohs(pMsg->MessageID) ) { case HTC_MSG_CONNECT_SERVICE_ID: HTCProcessConnectMsg(pHTC, (HTC_CONNECT_SERVICE_MSG *)pMsg); break; case HTC_MSG_CONFIG_PIPE_ID: HTCProcessConfigPipeMsg(pHTC, (HTC_CONFIG_PIPE_MSG *)pMsg); break; case HTC_MSG_SETUP_COMPLETE_ID: /* the host has indicated that it has completed all setup tasks and we can now let the services take over to run the rest of the application */ setupComplete = TRUE; /* can't get this more than once */ break; default: ; } if (pHTC->StateFlags & HTC_STATE_SETUP_COMPLETE) { /* recycle buffer only if we are fully running */ HTC_ReturnBuffers(pHTC, ENDPOINT0,pBuffers); } else { /* supply some head-room again */ adf_nbuf_push_head(pBuffers, HTC_HDR_LENGTH); /* otherwise return the packet back to mbox */ HIF_return_recv_buf(pHTC->hifHandle, pHTC->Endpoints[EndpointID].UpLinkPipeID, pBuffers); } if (setupComplete) { /* mark that setup has completed */ pHTC->StateFlags |= HTC_STATE_SETUP_COMPLETE; if (pHTC->SetupCompleteCb != NULL) { pHTC->SetupCompleteCb(); } } }
hif_status_t fwd_recv(void *context, adf_nbuf_t nbuf, a_uint8_t epid) { fwd_softc_t *sc = (fwd_softc_t *)context; a_uint8_t *pld; a_uint32_t plen, rsp, offset; fwd_rsp_t *h; adf_nbuf_peek_header(nbuf, &pld, &plen); h = (fwd_rsp_t *)pld; rsp = adf_os_ntohl(h->rsp); offset = adf_os_ntohl(h->offset); /*adf_os_timer_cancel(&sc->tmr);*/ switch(rsp) { case FWD_RSP_ACK: if (offset == sc->offset) { // adf_os_printk("ACK for %#x\n", offset); adf_os_print("."); sc->offset += fwd_chunk_len(sc); fwd_send_next(sc); } break; case FWD_RSP_SUCCESS: adf_os_print("done!\n"); hif_boot_done(sc->hif_handle); break; case FWD_RSP_FAILED: if (sc->ntries < FWD_MAX_TRIES) fwd_start_upload(sc); else adf_os_print("FWD: Error: Max retries exceeded\n"); break; default: adf_os_assert(0); } adf_nbuf_free(nbuf); return A_OK; }
/* callback from the mailbox hardware layer when a full message arrives */ LOCAL void HTCMsgRecvHandler(adf_nbuf_t hdr_buf, adf_nbuf_t buffer, void *context) { A_UINT16 totsz; HTC_ENDPOINT *pEndpoint; A_UINT32 eidMask; int eid; a_uint8_t *anbdata; a_uint32_t anblen; HTC_FRAME_HDR *pHTCHdr; HTC_CONTEXT *pHTC = (HTC_CONTEXT *)context; adf_nbuf_t tmp_nbuf; if (hdr_buf == ADF_NBUF_NULL) { /* HTC hdr is not in the hdr_buf */ tmp_nbuf = buffer; } else { tmp_nbuf = hdr_buf; } adf_nbuf_peek_header(tmp_nbuf, &anbdata, &anblen); pHTCHdr = (HTC_FRAME_HDR *)anbdata; totsz = adf_os_ntohs(pHTCHdr->PayloadLen); eid = pHTCHdr->EndpointID; pEndpoint = &pHTC->Endpoints[eid]; eidMask = 1 << eid; if (pHTCHdr->Flags & HTC_FLAGS_CREDIT_REDISTRIBUTION) { /* The pipe id where the credit is redistributed to is carried in Control * Byte 0 */ RedistributeCredit(tmp_nbuf, pHTCHdr->ControlBytes[0]); return; } if (pHTC->StateFlags & HTC_STATE_SETUP_COMPLETE) { /* after setup we keep track of credit consumption to allow us to * adjust thresholds to reduce credit dribbling */ pEndpoint->CreditsConsumed ++; } /* from the design document, we put the endpoint into a "host-needs-credit" state * when we receive a frame with the NEED_CREDIT_UPDATE flag set . * if the host received credits through an opportunistic path, then it can * issue a another frame with this bit cleared, this signals the target to clear * the "host-needs-credit" state */ if (pHTCHdr->Flags & HTC_FLAGS_NEED_CREDIT_UPDATE) { /* the host is running low (or is out) of credits on this * endpoint, update mask */ pHTC->EpHostNeedsCreditMap |= eidMask; /* check and set new threshold since host has reached a low credit situation */ CHECK_AND_ADJUST_CREDIT_THRESHOLD(pEndpoint); } else { /* clear the flag */ pHTC->EpHostNeedsCreditMap &= ~(eidMask); pEndpoint->CreditReturnThreshhold = 0; } /* Adjust the first buffer to point to the start of the actual payload, the first buffer contains the header */ adf_nbuf_pull_head(tmp_nbuf, HTC_HDR_LENGTH); /* NOTE : This callback could re-queue the recv buffers within this calling context. * The callback could also send a response message within the context of this callback * as the result of parsing this message. In either case, if there are * pending credits and the host needs them, a credit report will be sent either through * the response message trailer or a NULL message through HTC_ReturnBuffers(). */ pEndpoint->pService->ProcessRecvMsg(eid, hdr_buf, buffer, pEndpoint->pService->ServiceCtx); /* Calls to HTC_ReturnBuffers drives the endpoint credit reporting state machine. * We do not want to delay credits for too long in the event that the application is * holding onto buffers for excessive periods of time. This gives us "some" better * opportunities to send up credits. */ HTCCheckAndSendCreditReport(pHTC, eidMask, pEndpoint, eid); }
A_STATUS HIFSend(HIF_HANDLE hHIF, a_uint8_t PipeID, adf_nbuf_t hdr_buf, adf_nbuf_t buf) { A_STATUS status = A_OK; HIF_DEVICE_USB *macp = (HIF_DEVICE_USB *)hHIF; adf_nbuf_t sendBuf; a_uint8_t *data = NULL; a_uint32_t len = 0; /* If necessary, link hdr_buf & buf */ if (hdr_buf != NULL) { adf_nbuf_cat(hdr_buf, buf); sendBuf = hdr_buf; } else { sendBuf = buf; } adf_nbuf_peek_header(sendBuf, &data, &len); if ( PipeID == HIF_USB_PIPE_COMMAND ) { #ifdef ATH_WINHTC a_uint8_t *data = NULL; a_uint32_t len; adf_nbuf_peek_header(sendBuf, &data, &len); status = OS_Usb_SubmitCmdOutUrb(macp->os_hdl, data, len, (void*)sendBuf); #else status = ((osdev_t)macp->os_hdl)->os_usb_submitCmdOutUrb(macp->os_hdl, data, len, (void*)sendBuf); #endif } else if ( PipeID == HIF_USB_PIPE_TX ) { #ifdef ATH_WINHTC a_uint8_t *data = NULL; a_uint32_t len; adf_nbuf_peek_header(sendBuf, &data, &len); status = OS_Usb_SubmitTxUrb(macp->os_hdl, data, len, (void*)sendBuf); #else status = ((osdev_t)macp->os_hdl)->os_usb_submitTxUrb(macp->os_hdl, data, len, (void*)sendBuf, &(((osdev_t)macp->os_hdl)->TxPipe)); #endif } else if ( PipeID == HIF_USB_PIPE_HP_TX ) { #ifdef ATH_WINHTC a_uint8_t *data = NULL; a_uint32_t len; adf_nbuf_peek_header(sendBuf, &data, &len); status = OS_Usb_SubmitTxUrb(macp->os_hdl, data, len, (void*)sendBuf); #else status = ((osdev_t)macp->os_hdl)->os_usb_submitTxUrb(macp->os_hdl, data, len, (void*)sendBuf, &(((osdev_t)macp->os_hdl)->HPTxPipe)); #endif } else { adf_os_print("Unknown pipe %d\n", PipeID); adf_nbuf_free(sendBuf); } return status; }
static void WMIRecvMessageHandler(HTC_ENDPOINT_ID EndPt, adf_nbuf_t hdr_buf, adf_nbuf_t pHTCBuf, void *arg) { void *pContext; WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)arg; WMI_DISPATCH_TABLE *pCurrentTable; WMI_DISPATCH_ENTRY*pCurrentEntry; WMI_CMD_HANDLER pCmdHandler; A_UINT8* pCmdBuffer; int i; A_UINT16 cmd; A_UINT16 seq; int length; a_uint8_t *anbdata; a_uint32_t anblen; WMI_CMD_HDR *cmdHdr; adf_os_assert(hdr_buf == ADF_NBUF_NULL); do { length = adf_nbuf_len(pHTCBuf); if (length < sizeof(WMI_CMD_HDR)) { break; } adf_nbuf_peek_header(pHTCBuf, &anbdata, &anblen); pCurrentTable = pWMI->pDispatchHead; length = length - sizeof(WMI_CMD_HDR); cmdHdr = (WMI_CMD_HDR *)anbdata; cmd = adf_os_ntohs(cmdHdr->commandId); seq = adf_os_ntohs(cmdHdr->seqNo); pCmdBuffer = anbdata + sizeof(WMI_CMD_HDR); pCmdHandler = NULL; while (pCurrentTable != NULL) { pContext = pCurrentTable->pContext; pCurrentEntry = pCurrentTable->pTable; /* scan table entries */ for (i = 0; i < pCurrentTable->NumberOfEntries; i++, pCurrentEntry++) { if (pCurrentEntry->CmdID == cmd) { /* found a match */ pCmdHandler = pCurrentEntry->pCmdHandler; /* optionally check length */ if ((pCurrentEntry->CheckLength != 0) && (length < pCurrentEntry->CheckLength)) { /* do not process command */ pCmdHandler = NULL; } /* end search */ break; } } if (pCmdHandler != NULL) { /* found a handler */ break; } /* scan next table */ pCurrentTable = pCurrentTable->pNext; } if (NULL == pCmdHandler) { break; } /* if we get here, we have a command handler to dispatch */ /* call dispatch function */ pCmdHandler(pContext, cmd, seq, pCmdBuffer, length); } while (FALSE); /* Invalidate the buffer (including HTC header). Note : we only need to invalidate up to the portion * that was used (cache invalidate will also round up to the nearest cache line). * The rest of the buffer should still be coherent. * */ HTC_ReturnBuffers(pWMI->HtcHandle, EndPt, pHTCBuf); }
hif_status_t HTCTxCompletionHandler(void *Context, adf_nbuf_t netbuf) { HTC_TARGET *target = (HTC_TARGET *)Context; //adf_os_handle_t os_hdl = target->os_handle; a_uint8_t *netdata; a_uint32_t netlen; HTC_FRAME_HDR *HtcHdr; a_uint8_t EpID; HTC_ENDPOINT *pEndpoint; #ifndef HTC_HOST_CREDIT_DIST a_int32_t i; #endif adf_nbuf_peek_header(netbuf, &netdata, &netlen); HtcHdr = (HTC_FRAME_HDR *)netdata; EpID = HtcHdr->EndpointID; pEndpoint = &target->EndPoint[EpID]; if (EpID == ENDPOINT0) { adf_nbuf_free(netbuf); } else { /* gather tx completion counts */ //HTC_AGGRNUM_REC *pAggrNumRec; //LOCK_HTC_TX(target); //pAggrNumRec = HTC_GET_REC_AT_HEAD(&pEndpoint->AggrNumRecQueue); //aggrNum = pAggrNumRec->AggrNum; //UNLOCK_HTC_TX(target); //if ((++pEndpoint->CompletedTxCnt) == aggrNum) { //pEndpoint->CompletedTxCnt = 0; #if 0 LOCK_HTC_TX(target); /* Dequeue from endpoint and then enqueue to target */ pAggrNumRec = HTC_AGGRNUMREC_DEQUEUE(&pEndpoint->AggrNumRecQueue); HTC_AGGRNUMREC_ENQUEUE(&target->FreeAggrNumRecQueue, pAggrNumRec); UNLOCK_HTC_TX(target); #endif /* remove HTC header */ adf_nbuf_pull_head(netbuf, HTC_HDR_LENGTH); #if 1 /* freeing the net buffer instead of handing this buffer to upper layer driver */ /* nofity upper layer */ if (pEndpoint->EpCallBacks.EpTxComplete) { /* give the packet to the upper layer */ pEndpoint->EpCallBacks.EpTxComplete(/*dev*/pEndpoint->EpCallBacks.pContext, netbuf, EpID/*aggrNum*/); } else { adf_nbuf_free(netbuf); } #else adf_nbuf_free(netbuf); #endif //} } #ifndef HTC_HOST_CREDIT_DIST /* Check whether there is any pending buffer needed */ /* to be sent */ if (pEndpoint->UL_PipeID == 1) { if (HTCNeedReschedule(target, pEndpoint) == A_OK) { for (i = ENDPOINT_MAX - 1; i >= 0; i--) { pEndpoint = &target->EndPoint[i]; if (HTCGetTxBufCnt(target, pEndpoint) > 0) { HTCTrySend(target, NULL, ADF_NBUF_NULL, ADF_NBUF_NULL); break; } } } } #endif return HIF_OK; }
static void usb_hif_usb_recv_bundle_complete(struct urb *urb) { HIF_URB_CONTEXT *urb_context = (HIF_URB_CONTEXT *) urb->context; A_STATUS status = A_OK; adf_nbuf_t buf = NULL; HIF_USB_PIPE *pipe = urb_context->pipe; A_UINT8 *netdata, *netdata_new; A_UINT32 netlen, netlen_new; HTC_FRAME_HDR *HtcHdr; A_UINT16 payloadLen; adf_nbuf_t new_skb = NULL; AR_DEBUG_PRINTF(USB_HIF_DEBUG_BULK_IN, ( "+%s: recv pipe: %d, stat:%d,len:%d urb:0x%p\n", __func__, pipe->logical_pipe_num, urb->status, urb->actual_length, urb)); /* this urb is not pending anymore */ usb_hif_remove_pending_transfer(urb_context); do { if (urb->status != 0) { status = A_ECOMM; switch (urb->status) { case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: /* NOTE: no need to spew these errors when * device is removed * or urb is killed due to driver shutdown */ status = A_ECANCELED; break; default: AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ( "%s recv pipe: %d (ep:0x%2.2X), failed:%d\n", __func__, pipe->logical_pipe_num, pipe->ep_address, urb->status)); break; } break; } if (urb->actual_length == 0) break; buf = urb_context->buf; if (AR_DEBUG_LVL_CHECK(USB_HIF_DEBUG_DUMP_DATA)) { A_UINT8 *data; A_UINT32 len; adf_nbuf_peek_header(buf, &data, &len); DebugDumpBytes(data, len, "hif recv data"); } adf_nbuf_peek_header(buf, &netdata, &netlen); netlen = urb->actual_length; do { #if defined(AR6004_1_0_ALIGN_WAR) A_UINT8 extra_pad; A_UINT16 act_frame_len; #endif A_UINT16 frame_len; /* Hack into HTC header for bundle processing */ HtcHdr = (HTC_FRAME_HDR *) netdata; if (HtcHdr->EndpointID >= ENDPOINT_MAX) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("athusb: Rx: invalid EndpointID=%d\n", HtcHdr->EndpointID)); break; } payloadLen = HtcHdr->PayloadLen; payloadLen = A_LE2CPU16(payloadLen); #if defined(AR6004_1_0_ALIGN_WAR) act_frame_len = (HTC_HDR_LENGTH + payloadLen); if (HtcHdr->EndpointID == 0 || HtcHdr->EndpointID == 1) { /* assumption: target won't pad on HTC endpoint * 0 & 1. */ extra_pad = 0; } else { extra_pad = A_GET_UINT8_FIELD((A_UINT8 *) HtcHdr, HTC_FRAME_HDR, ControlBytes[1]); } #endif if (payloadLen > HIF_USB_RX_BUFFER_SIZE) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("athusb: payloadLen too long %u\n", payloadLen)); break; } #if defined(AR6004_1_0_ALIGN_WAR) frame_len = (act_frame_len + extra_pad); #else frame_len = (HTC_HDR_LENGTH + payloadLen); #endif if (netlen >= frame_len) { /* allocate a new skb and copy */ #if defined(AR6004_1_0_ALIGN_WAR) new_skb = adf_nbuf_alloc(NULL, act_frame_len, 0, 4, FALSE); if (new_skb == NULL) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ( "athusb: allocate skb (len=%u) failed\n", act_frame_len)); break; } adf_nbuf_peek_header(new_skb, &netdata_new, &netlen_new); adf_os_mem_copy(netdata_new, netdata, act_frame_len); adf_nbuf_put_tail(new_skb, act_frame_len); #else new_skb = adf_nbuf_alloc(NULL, frame_len, 0, 4, FALSE); if (new_skb == NULL) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ( "athusb: allocate skb (len=%u) failed\n", frame_len)); break; } adf_nbuf_peek_header(new_skb, &netdata_new, &netlen_new); adf_os_mem_copy(netdata_new, netdata, frame_len); adf_nbuf_put_tail(new_skb, frame_len); #endif skb_queue_tail(&pipe->io_comp_queue, new_skb); new_skb = NULL; netdata += frame_len; netlen -= frame_len; } else { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ( "athusb: subframe length %d not fitted into bundle packet length %d\n" , netlen, frame_len)); break; } } while (netlen); schedule_work(&pipe->io_complete_work); } while (FALSE); if (urb_context->buf == NULL) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("athusb: buffer in urb_context is NULL\n")); } /* reset urb_context->buf ==> seems not necessary */ usb_hif_free_urb_to_pipe(urb_context->pipe, urb_context); if (A_SUCCESS(status)) { if (pipe->urb_cnt >= pipe->urb_cnt_thresh) { /* our free urbs are piling up, post more transfers */ usb_hif_post_recv_bundle_transfers(pipe, 0 /* pass zero for not allocating urb-buffer again */ ); } } AR_DEBUG_PRINTF(USB_HIF_DEBUG_BULK_IN, ("-%s\n", __func__)); }
static void usb_hif_usb_recv_complete(struct urb *urb) { HIF_URB_CONTEXT *urb_context = (HIF_URB_CONTEXT *) urb->context; A_STATUS status = A_OK; adf_nbuf_t buf = NULL; HIF_USB_PIPE *pipe = urb_context->pipe; AR_DEBUG_PRINTF(USB_HIF_DEBUG_BULK_IN, ( "+%s: recv pipe: %d, stat:%d,len:%d urb:0x%p\n", __func__, pipe->logical_pipe_num, urb->status, urb->actual_length, urb)); /* this urb is not pending anymore */ usb_hif_remove_pending_transfer(urb_context); do { if (urb->status != 0) { status = A_ECOMM; switch (urb->status) { #ifdef RX_SG_SUPPORT case -EOVERFLOW: urb->actual_length = HIF_USB_RX_BUFFER_SIZE; status = A_OK; break; #endif case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: /* NOTE: no need to spew these errors when * device is removed * or urb is killed due to driver shutdown */ status = A_ECANCELED; break; default: AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ( "%s recv pipe: %d (ep:0x%2.2X), failed:%d\n", __func__, pipe->logical_pipe_num, pipe->ep_address, urb->status)); break; } break; } if (urb->actual_length == 0) break; buf = urb_context->buf; /* we are going to pass it up */ urb_context->buf = NULL; adf_nbuf_put_tail(buf, urb->actual_length); if (AR_DEBUG_LVL_CHECK(USB_HIF_DEBUG_DUMP_DATA)) { A_UINT8 *data; A_UINT32 len; adf_nbuf_peek_header(buf, &data, &len); DebugDumpBytes(data, len, "hif recv data"); } /* note: queue implements a lock */ skb_queue_tail(&pipe->io_comp_queue, buf); schedule_work(&pipe->io_complete_work); } while (FALSE); usb_hif_cleanup_recv_urb(urb_context); if (A_SUCCESS(status)) { if (pipe->urb_cnt >= pipe->urb_cnt_thresh) { /* our free urbs are piling up, post more transfers */ usb_hif_post_recv_transfers(pipe, HIF_USB_RX_BUFFER_SIZE); } } AR_DEBUG_PRINTF(USB_HIF_DEBUG_BULK_IN, ("-%s\n", __func__)); }