예제 #1
0
파일: htc_recv.c 프로젝트: KHATEEBNSIT/AP
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;
}
예제 #2
0
/* 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__));

}
예제 #3
0
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__));

}
예제 #4
0
/* 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();
		}
	}
}
예제 #5
0
파일: fwd.c 프로젝트: KHATEEBNSIT/AP
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;
}
예제 #6
0
/* 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); 
}
예제 #7
0
파일: hif_usb.c 프로젝트: KHATEEBNSIT/AP
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;
}
예제 #8
0
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);
}
예제 #9
0
파일: htc_send.c 프로젝트: KHATEEBNSIT/AP
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;
}
예제 #10
0
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__));
}
예제 #11
0
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__));
}