Beispiel #1
0
A_STATUS HTCStart(HTC_HANDLE HTCHandle)
{
    adf_nbuf_t netbuf;
    A_STATUS   status = A_OK;
    HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
    HTC_SETUP_COMPLETE_MSG *SetupComp;

    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCStart Enter\n"));
    do {
         
        HTCConfigTargetHIFPipe(HTCHandle);

#ifdef HTC_HOST_CREDIT_DIST
        adf_os_assert(target->InitCredits != NULL);
        adf_os_assert(target->EpCreditDistributionListHead != NULL);
        adf_os_assert(target->EpCreditDistributionListHead->pNext != NULL);

        /* call init credits callback to do the distribution , 
         * NOTE: the first entry in the distribution list is ENDPOINT_0, so
         * we pass the start of the list after this one. */
        target->InitCredits(target->pCredDistContext, 
                            target->EpCreditDistributionListHead->pNext,
                            target->TargetCredits);

#if 1
        adf_os_timer_init(target->os_handle, &target->host_htc_credit_debug_timer, host_htc_credit_show, target);
        adf_os_timer_start(&target->host_htc_credit_debug_timer, 10000);
#endif
#endif

        /* allocate a buffer to send */
        //netbuf = adf_nbuf_alloc(anet, sizeof(HTC_SETUP_COMPLETE_MSG), HTC_HDR_LENGTH, 0);
        netbuf = adf_nbuf_alloc(50, HTC_HDR_LENGTH, 0);

        if (netbuf == ADF_NBUF_NULL) {
            status = A_NO_MEMORY;
            break;
        }

        /* assemble setup complete message */
        SetupComp = (HTC_SETUP_COMPLETE_MSG *)adf_nbuf_put_tail(netbuf, sizeof(HTC_SETUP_COMPLETE_MSG));
        SetupComp->MessageID = adf_os_htons(HTC_MSG_SETUP_COMPLETE_ID);

        /* assemble the HTC header and send to HIF layer */
        status = HTCIssueSend(target, 
                              ADF_NBUF_NULL, 
                              netbuf, 
                              0, 
                              sizeof(HTC_SETUP_COMPLETE_MSG),
                              ENDPOINT0);
        
        if (A_FAILED(status)) {
            break;    
        }

    } while (FALSE);

    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCStart Exit\n"));
    return status;
}
Beispiel #2
0
A_STATUS ConfigPipeCredits(HTC_TARGET *target, a_uint8_t pipeID, a_uint8_t credits)
{
    A_STATUS status = A_OK;
    adf_nbuf_t netbuf;
    HTC_CONFIG_PIPE_MSG *CfgPipeCdt;


    do {
        /* allocate a buffer to send */
        //netbuf = adf_nbuf_alloc(anet, sizeof(HTC_CONFIG_PIPE_MSG), HTC_HDR_LENGTH, 0);
        netbuf = adf_nbuf_alloc(50, HTC_HDR_LENGTH, 0);

        if (netbuf == ADF_NBUF_NULL) {
            status = A_NO_MEMORY;
            break;
        }

        /* assemble config pipe message */
        CfgPipeCdt = (HTC_CONFIG_PIPE_MSG *)adf_nbuf_put_tail(netbuf, sizeof(HTC_CONFIG_PIPE_MSG));
        CfgPipeCdt->MessageID = adf_os_htons(HTC_MSG_CONFIG_PIPE_ID);
        CfgPipeCdt->PipeID = pipeID;
        CfgPipeCdt->CreditCount = credits;

        /* assemble the HTC header and send to HIF layer */
        
#ifndef MAGPIE_SINGLE_CPU_CASE
        htc_spin_prep(&target->spin);
#endif
        status = HTCIssueSend(target, 
                              ADF_NBUF_NULL,
                              netbuf, 
                              0, 
                              sizeof(HTC_CONFIG_PIPE_MSG),
                              ENDPOINT0);
        
        if (A_FAILED(status)) {
            break;    
        }
        
        htc_spin( &target->spin );
        
        if (target->cfg_pipe_rsp_stat == HTC_CONFIGPIPE_SUCCESS) {
            status = A_OK;
        }
        else {
            status = A_ERROR;
        }

    } while(FALSE);

    return status;
    
}
Beispiel #3
0
A_STATUS HTCSendSetupComplete(HTC_TARGET *target)
{
    HTC_PACKET             *pSendPacket = NULL;
    A_STATUS                status;
    HTC_SETUP_COMPLETE_MSG *pSetupComplete;

    do {
        /* allocate a packet to send to the target */
        pSendPacket = HTC_ALLOC_CONTROL_TX(target);

        if (NULL == pSendPacket) {
            status = A_NO_MEMORY;
            break;
        }

        /* assemble setup complete message */
        pSetupComplete = (HTC_SETUP_COMPLETE_MSG *)pSendPacket->pBuffer;
        A_MEMZERO(pSetupComplete,sizeof(HTC_SETUP_COMPLETE_MSG));
        pSetupComplete->MessageID = HTC_MSG_SETUP_COMPLETE_ID;

        SET_HTC_PACKET_INFO_TX(pSendPacket,
                               NULL,
                               (A_UINT8 *)pSetupComplete,
                               sizeof(HTC_SETUP_COMPLETE_MSG),
                               ENDPOINT_0,
                               HTC_SERVICE_TX_PACKET_TAG);

        /* we want synchronous operation */
        pSendPacket->Completion = NULL;
        /* send the message */
        status = HTCIssueSend(target,pSendPacket,0);

    } while (FALSE);

    if (pSendPacket != NULL) {
        HTC_FREE_CONTROL_TX(target,pSendPacket);
    }

    return status;
}
A_STATUS HTCSendSetupComplete(HTC_TARGET *target)
{
    HTC_PACKET             *pSendPacket = NULL;
    A_STATUS                status;

    do {
           /* allocate a packet to send to the target */
        pSendPacket = HTC_ALLOC_CONTROL_TX(target);

        if (NULL == pSendPacket) {
            status = A_NO_MEMORY;
            break;
        }

        if (target->HTCTargetVersion >= HTC_VERSION_2P1) {
            HTC_SETUP_COMPLETE_EX_MSG *pSetupCompleteEx;
            A_UINT32                  setupFlags = 0;
                   
            pSetupCompleteEx = (HTC_SETUP_COMPLETE_EX_MSG *)pSendPacket->pBuffer;
            A_MEMZERO(pSetupCompleteEx, sizeof(HTC_SETUP_COMPLETE_EX_MSG));
            pSetupCompleteEx->MessageID = HTC_MSG_SETUP_COMPLETE_EX_ID;   
            if (target->MaxMsgPerBundle > 0) {
                    /* host can do HTC bundling, indicate this to the target */
                setupFlags |= HTC_SETUP_COMPLETE_FLAGS_ENABLE_BUNDLE_RECV; 
                pSetupCompleteEx->MaxMsgsPerBundledRecv = target->MaxMsgPerBundle;
            }    
            A_MEMCPY(&pSetupCompleteEx->SetupFlags, &setupFlags, sizeof(pSetupCompleteEx->SetupFlags));            
            SET_HTC_PACKET_INFO_TX(pSendPacket,
                                   NULL,
                                   (A_UINT8 *)pSetupCompleteEx,
                                   sizeof(HTC_SETUP_COMPLETE_EX_MSG),
                                   ENDPOINT_0,
                                   HTC_SERVICE_TX_PACKET_TAG);
      
        }  else {            
            HTC_SETUP_COMPLETE_MSG *pSetupComplete;
                /* assemble setup complete message */
            pSetupComplete = (HTC_SETUP_COMPLETE_MSG *)pSendPacket->pBuffer;
            A_MEMZERO(pSetupComplete, sizeof(HTC_SETUP_COMPLETE_MSG));
            pSetupComplete->MessageID = HTC_MSG_SETUP_COMPLETE_ID;   
            SET_HTC_PACKET_INFO_TX(pSendPacket,
                                   NULL,
                                   (A_UINT8 *)pSetupComplete,
                                   sizeof(HTC_SETUP_COMPLETE_MSG),
                                   ENDPOINT_0,
                                   HTC_SERVICE_TX_PACKET_TAG);
        }

            /* we want synchronous operation */
        pSendPacket->Completion = NULL;
        HTC_PREPARE_SEND_PKT(pSendPacket,0,0,0);
            /* send the message */
        status = HTCIssueSend(target,pSendPacket);

    } while (FALSE);

    if (pSendPacket != NULL) {
        HTC_FREE_CONTROL_TX(target,pSendPacket);
    }

    return status;
}
A_STATUS HTCConnectService(HTC_HANDLE               HTCHandle,
                           HTC_SERVICE_CONNECT_REQ  *pConnectReq,
                           HTC_SERVICE_CONNECT_RESP *pConnectResp)
{
    HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
    A_STATUS                            status = A_OK;
    HTC_PACKET                          *pRecvPacket = NULL;
    HTC_PACKET                          *pSendPacket = NULL;
    HTC_CONNECT_SERVICE_RESPONSE_MSG    *pResponseMsg;
    HTC_CONNECT_SERVICE_MSG             *pConnectMsg;
    HTC_ENDPOINT_ID                     assignedEndpoint = ENDPOINT_MAX;
    HTC_ENDPOINT                        *pEndpoint;
    unsigned int                        maxMsgSize = 0;

    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCConnectService, target:0x%X SvcID:0x%X \n",
               (A_UINT32)target, pConnectReq->ServiceID));

    do {

        AR_DEBUG_ASSERT(pConnectReq->ServiceID != 0);

        if (HTC_CTRL_RSVD_SVC == pConnectReq->ServiceID) {
                /* special case for pseudo control service */
            assignedEndpoint = ENDPOINT_0;
            maxMsgSize = HTC_MAX_CONTROL_MESSAGE_LENGTH;
        } else {
                /* allocate a packet to send to the target */
            pSendPacket = HTC_ALLOC_CONTROL_TX(target);

            if (NULL == pSendPacket) {
                AR_DEBUG_ASSERT(FALSE);
                status = A_NO_MEMORY;
                break;
            }
                /* assemble connect service message */
            pConnectMsg = (HTC_CONNECT_SERVICE_MSG *)pSendPacket->pBuffer;
            AR_DEBUG_ASSERT(pConnectMsg != NULL);
            A_MEMZERO(pConnectMsg,sizeof(HTC_CONNECT_SERVICE_MSG));
            pConnectMsg->MessageID = HTC_MSG_CONNECT_SERVICE_ID;
            pConnectMsg->ServiceID = pConnectReq->ServiceID;
            pConnectMsg->ConnectionFlags = pConnectReq->ConnectionFlags;
                /* check caller if it wants to transfer meta data */
            if ((pConnectReq->pMetaData != NULL) &&
                (pConnectReq->MetaDataLength <= HTC_SERVICE_META_DATA_MAX_LENGTH)) {
                    /* copy meta data into message buffer (after header ) */
                A_MEMCPY((A_UINT8 *)pConnectMsg + sizeof(HTC_CONNECT_SERVICE_MSG),
                         pConnectReq->pMetaData,
                         pConnectReq->MetaDataLength);
                pConnectMsg->ServiceMetaLength = pConnectReq->MetaDataLength;
            }

            SET_HTC_PACKET_INFO_TX(pSendPacket,
                                   NULL,
                                   (A_UINT8 *)pConnectMsg,
                                   sizeof(HTC_CONNECT_SERVICE_MSG) + pConnectMsg->ServiceMetaLength,
                                   ENDPOINT_0,
                                   HTC_SERVICE_TX_PACKET_TAG);

                /* we want synchronous operation */
            pSendPacket->Completion = NULL;
            HTC_PREPARE_SEND_PKT(pSendPacket,0,0,0);
            status = HTCIssueSend(target,pSendPacket);

            if (A_FAILED(status)) {
                break;
            }

                /* wait for response */
            status = HTCWaitforControlMessage(target, &pRecvPacket);

            if (A_FAILED(status)) {
                break;
            }
                /* we controlled the buffer creation so it has to be properly aligned */
            pResponseMsg = (HTC_CONNECT_SERVICE_RESPONSE_MSG *)pRecvPacket->pBuffer;

            if ((pResponseMsg->MessageID != HTC_MSG_CONNECT_SERVICE_RESPONSE_ID) ||
                (pRecvPacket->ActualLength < sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG))) {
                    /* this message is not valid */
                AR_DEBUG_ASSERT(FALSE);
                status = A_EPROTO;
                break;
            }

            pConnectResp->ConnectRespCode = pResponseMsg->Status;
                /* check response status */
            if (pResponseMsg->Status != HTC_SERVICE_SUCCESS) {
                AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
                    (" Target failed service 0x%X connect request (status:%d)\n",
                                pResponseMsg->ServiceID, pResponseMsg->Status));
                status = A_EPROTO;
                break;
            }

            assignedEndpoint = (HTC_ENDPOINT_ID) pResponseMsg->EndpointID;
            maxMsgSize = pResponseMsg->MaxMsgSize;

            if ((pConnectResp->pMetaData != NULL) &&
                (pResponseMsg->ServiceMetaLength > 0) &&
                (pResponseMsg->ServiceMetaLength <= HTC_SERVICE_META_DATA_MAX_LENGTH)) {
                    /* caller supplied a buffer and the target responded with data */
                int copyLength = min((int)pConnectResp->BufferLength, (int)pResponseMsg->ServiceMetaLength);
                    /* copy the meta data */
                A_MEMCPY(pConnectResp->pMetaData,
                         ((A_UINT8 *)pResponseMsg) + sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG),
                         copyLength);
                pConnectResp->ActualLength = copyLength;
            }

        }

            /* the rest of these are parameter checks so set the error status */
        status = A_EPROTO;

        if (assignedEndpoint >= ENDPOINT_MAX) {
            AR_DEBUG_ASSERT(FALSE);
            break;
        }

        if (0 == maxMsgSize) {
            AR_DEBUG_ASSERT(FALSE);
            break;
        }

        pEndpoint = &target->EndPoint[assignedEndpoint];
        pEndpoint->Id = assignedEndpoint;
        if (pEndpoint->ServiceID != 0) {
            /* endpoint already in use! */
            AR_DEBUG_ASSERT(FALSE);
            break;
        }

            /* return assigned endpoint to caller */
        pConnectResp->Endpoint = assignedEndpoint;
        pConnectResp->MaxMsgLength = maxMsgSize;

            /* setup the endpoint */
        pEndpoint->ServiceID = pConnectReq->ServiceID; /* this marks the endpoint in use */
        pEndpoint->MaxTxQueueDepth = pConnectReq->MaxSendQueueDepth;
        pEndpoint->MaxMsgLength = maxMsgSize;
            /* copy all the callbacks */
        pEndpoint->EpCallBacks = pConnectReq->EpCallbacks;
            /* set the credit distribution info for this endpoint, this information is
             * passed back to the credit distribution callback function */
        pEndpoint->CreditDist.ServiceID = pConnectReq->ServiceID;
        pEndpoint->CreditDist.pHTCReserved = pEndpoint;
        pEndpoint->CreditDist.Endpoint = assignedEndpoint;
        pEndpoint->CreditDist.TxCreditSize = target->TargetCreditSize;
        
        if (pConnectReq->MaxSendMsgSize != 0) {
                /* override TxCreditsPerMaxMsg calculation, this optimizes the credit-low indications
                 * since the host will actually issue smaller messages in the Send path */
            if (pConnectReq->MaxSendMsgSize > maxMsgSize) {
                    /* can't be larger than the maximum the target can support */
                AR_DEBUG_ASSERT(FALSE);
                break;       
            }
            pEndpoint->CreditDist.TxCreditsPerMaxMsg = pConnectReq->MaxSendMsgSize / target->TargetCreditSize;
        } else {
            pEndpoint->CreditDist.TxCreditsPerMaxMsg = maxMsgSize / target->TargetCreditSize;
        }
        
        if (0 == pEndpoint->CreditDist.TxCreditsPerMaxMsg) {
            pEndpoint->CreditDist.TxCreditsPerMaxMsg = 1;
        }
        
            /* save local connection flags */
        pEndpoint->LocalConnectionFlags = pConnectReq->LocalConnectionFlags;
        
        status = A_OK;

    } while (FALSE);

    if (pSendPacket != NULL) {
        HTC_FREE_CONTROL_TX(target,pSendPacket);
    }

    if (pRecvPacket != NULL) {
        HTC_FREE_CONTROL_RX(target,pRecvPacket);
    }

    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCConnectService \n"));

    return status;
}
Beispiel #6
0
A_STATUS HTCSendPkt(HTC_HANDLE hHTC,
                    adf_nbuf_t hdr_buf,
                    adf_nbuf_t buf,
                    HTC_ENDPOINT_ID Ep)
{
    HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(hHTC);
    A_STATUS status = A_OK;
    HTC_ENDPOINT *pEndpoint;

#ifndef ATH_HTC_TX_SCHED
    do {
	    if (Ep >= ENDPOINT_MAX) {
            adf_os_print("Ep %u is invalid!\n", Ep);
            if (hdr_buf) {
                adf_nbuf_free(hdr_buf);
            }
            if (buf) {
                adf_nbuf_free(buf);
            }
		    status = A_EPROTO;
		    break;
	    }

	    pEndpoint = &target->EndPoint[Ep];

#if 0
        LOCK_HTC_TX(target);
        /* record number of buffers in corresponding endpoint */
        if ((pAggrNumRec = HTC_AGGRNUMREC_DEQUEUE(&target->FreeAggrNumRecQueue)) == NULL) {
            adf_os_print("%s no more free aggr record\n", __FUNCTION__);
            status = A_NO_RESOURCE;
            UNLOCK_HTC_TX(target);
            break;
        }
        pAggrNumRec->AggrNum = num;
        pAggrNumRec->bufArray = bufArray;

        /* buffers were supplied to be queued */
        HTC_AGGRNUMREC_ENQUEUE(&pEndpoint->AggrNumRecQueue, pAggrNumRec);
        UNLOCK_HTC_TX(target);
#endif

        status = HTCTrySend(target, pEndpoint, hdr_buf, buf);

    //    adf_os_print("return value of HTCTrySend: %u\n", status);

    } while(FALSE);
#else
	a_uint16_t payloadLen;
    a_uint8_t SendFlags = 0;

    pEndpoint = &target->EndPoint[Ep];
    if ( HIFGetFreeQueueNumber(target->hif_dev, pEndpoint->UL_PipeID) == 0 )
            return -1 ;

    if(hdr_buf != NULL)
        payloadLen = (a_uint16_t) (adf_nbuf_len(hdr_buf) + adf_nbuf_len(buf));
    else
        payloadLen = (a_uint16_t) adf_nbuf_len(buf)  ;

#ifdef HTC_HOST_CREDIT_DIST
    /* check if credits are enough for sending this packet */
#ifdef WMI_RETRY
    if((Ep != 1 ) && (Ep != 2)) 
#endif
    {
        status = HTCCheckCredits(target, HTC_HDR_LENGTH + payloadLen, pEndpoint, &SendFlags);
        if (A_FAILED(status)) {
            //adf_os_print("credits are not enough for sending the message!\n");
            return status;
        }
    }
#endif
    status = HTCIssueSend(target, hdr_buf, buf, SendFlags, payloadLen, Ep);

    if (A_FAILED(status)) {
        HTCReclaimCredits(target, HTC_HDR_LENGTH + payloadLen, pEndpoint);
        return -1 ;
    }

#endif
    return status;
}
Beispiel #7
0
A_STATUS HTCTrySend(HTC_TARGET      *target, 
                    HTC_ENDPOINT    *pEndpoint, 
                    adf_nbuf_t      hdr_buf,
                    adf_nbuf_t      buf)
{
    a_uint8_t SendFlags = 0;
    a_uint16_t payloadLen;
    a_uint8_t EpID;
    A_STATUS status = A_OK;
#if 0 
    a_uint32_t creditsRequired, remainder;
#endif
    a_int32_t i;
    
    if ( (pEndpoint) 
         && (buf != ADF_NBUF_NULL) ) 
    {
        /* packet was supplied to be queued */
        status = HTCTxEnqueuePkts(target, pEndpoint, hdr_buf, buf);

        if (A_FAILED(status)) {
            if (buf)     { adf_nbuf_free(buf);     }
            if (hdr_buf) { adf_nbuf_free(hdr_buf); }
            //adf_os_print("%s: Not enough queue spaces for enqueuing, epid = %d, enqueue fail cnt = %d\n", 
            //              __func__, 
            //              pEndpoint->CreditDist.Endpoint, ++(pEndpoint->stat_enqfail));
        }
    }

    /* now drain the TX queue for transmission as long as we have enough credits */

    LOCK_HTC_TX(target);

    for (i = ENDPOINT_MAX - 1; i >= 0; i--) {
        a_uint32_t availableTxCnt = 0xFFFFFFFF;
        a_uint8_t  isDataService = 0;

        pEndpoint = &target->EndPoint[i];
        EpID = pEndpoint->CreditDist.Endpoint;

        if (pEndpoint->ServiceID == 0)
            continue;

        /* calculate available tx count base on the de-queue level */
        if ((pEndpoint->ServiceID == WMI_DATA_BE_SVC)
            || (pEndpoint->ServiceID == WMI_DATA_BK_SVC)
            || (pEndpoint->ServiceID == WMI_DATA_VI_SVC)
            || (pEndpoint->ServiceID == WMI_DATA_VO_SVC)) {
            isDataService = 1;
            if (pEndpoint->tqi_dqlevel < 4) {
                availableTxCnt  = 4- pEndpoint->tqi_dqlevel;
            } else {
                availableTxCnt = 1;
            }
            //adf_os_print("%s: epid = %d, i = %d, dqlevel = %d, txcnt = %d\n", __FUNCTION__, EpID, i, pEndpoint->tqi_dqlevel, availableTxCnt);
        }

        while (availableTxCnt-- > 0) {
            adf_nbuf_t tmpbuf, tmp_hdr_buf;
            a_uint16_t tmplen, tmp_hdr_len;
            a_uint16_t freeQNum, maxQNum, toNext;
            
            if (pEndpoint->TxBufCnt == 0) {
                break;
            }
            
            if ( (freeQNum = HIFGetFreeQueueNumber(target->hif_dev, pEndpoint->UL_PipeID)) == 0 ) {
                //adf_os_print("%s: USB TxQ full, epid = %d, pipe id = %d, count = %d\n", 
                //              __func__, EpID, pEndpoint->UL_PipeID, ++(pEndpoint->stat_usbqfull));
                break;
            }

            if (isDataService) {
                toNext = 0;
                maxQNum = HIFGetMaxQueueNumber(target->hif_dev, pEndpoint->UL_PipeID);
                //adf_os_print("%s: epid = %d, freeQNum = %d, maxQNum = %d, availableTxCnt = %d\n", __FUNCTION__, EpID, freeQNum, maxQNum, availableTxCnt);
                switch (pEndpoint->tqi_dqlevel) {
                case 0:
                    if (freeQNum == 0) {toNext = 1;}
                        break;
                case 1:
                    if (freeQNum <= maxQNum/2) {toNext = 1;}        //4/8
                        break;
                case 2:
                    if (freeQNum <= (maxQNum*5)/8) {toNext = 1;}    //5/8
                        break;
                case 3:
                default:
                    if (freeQNum <= (maxQNum*3)/4) {toNext = 1;}    //6/8
                        break;
                }

                if (toNext == 1) {
                //    adf_os_print("%s: To Next Endpoint, epid = %d, freeQNum = %d, maxQNum = %d\n", __FUNCTION__, EpID, freeQNum, maxQNum);
                    break;
                }
            }

            /* get packet at head, but don't remove it */
            tmp_hdr_buf = pEndpoint->HtcTxQueue[pEndpoint->TxQHead].hdr_buf;
            tmp_hdr_len = pEndpoint->HtcTxQueue[pEndpoint->TxQHead].hdr_bufLen;
            tmpbuf = pEndpoint->HtcTxQueue[pEndpoint->TxQHead].buf;
            tmplen = pEndpoint->HtcTxQueue[pEndpoint->TxQHead].bufLen;

    #if 0 
    
            /* figure out how many credits this message requires */
            creditsRequired = (tmplen + tmp_hdr_len + HTC_HDR_LENGTH) / target->TargetCreditSize;
            remainder = (tmplen + tmp_hdr_len + HTC_HDR_LENGTH) % target->TargetCreditSize;
    
            if (remainder) {
                creditsRequired++;
            }
    
            adf_os_print("creditsRequired: %u, tmplen + HTC_HDR_LENGTH: %u, target->TargetCreditSize: %u, pEndpoint->CreditDist.TxCredits: %u\n", creditsRequired, tmplen + HTC_HDR_LENGTH, target->TargetCreditSize, pEndpoint->CreditDist.TxCredits);
    
            /* not enough credits */
            if (pEndpoint->CreditDist.TxCredits < creditsRequired) {
    
                /* set how many credits we need  */
                pEndpoint->CreditDist.TxCreditsSeek = creditsRequired - pEndpoint->CreditDist.TxCredits;
    
                DO_DISTRIBUTION(target,
                                HTC_CREDIT_DIST_SEEK_CREDITS,
                                "Seek Credits",
                                &pEndpoint->CreditDist);
    
                pEndpoint->CreditDist.TxCreditsSeek = 0;
    
                if (pEndpoint->CreditDist.TxCredits < creditsRequired) {
                    /* still not enough credits to send, leave packet in the queue */
					status = A_CREDIT_UNAVAILABLE;                    
					break;
                }
            }
    
            pEndpoint->CreditDist.TxCredits -= creditsRequired;
    
            //adf_os_print("pEndpoint->CreditDist.TxCreditsPerMaxMsg: %u\n", pEndpoint->CreditDist.TxCreditsPerMaxMsg);
    
            /* check if we need credits back from the target */
            if (pEndpoint->CreditDist.TxCredits < pEndpoint->CreditDist.TxCreditsPerMaxMsg) {
                /* we are getting low on credits, see if we can ask for more from the distribution function */
                pEndpoint->CreditDist.TxCreditsSeek = pEndpoint->CreditDist.TxCreditsPerMaxMsg - pEndpoint->CreditDist.TxCredits;
    
                DO_DISTRIBUTION(target,
                                HTC_CREDIT_DIST_SEEK_CREDITS,
                                "Seek Credits",
                                &pEndpoint->CreditDist);
    
                pEndpoint->CreditDist.TxCreditsSeek = 0;
    
                if (pEndpoint->CreditDist.TxCredits < pEndpoint->CreditDist.TxCreditsPerMaxMsg) {
                    /* tell the target we need credits ASAP! */
                    SendFlags |= HTC_FLAGS_NEED_CREDIT_UPDATE;
                    adf_os_print("SendFlags: %u\n", SendFlags);
                }
    
    #endif   
    
                payloadLen = tmp_hdr_len + tmplen;
    
                /* now we can fully dequeue */
                pEndpoint->TxQHead = (pEndpoint->TxQHead + 1) % HTC_TX_QUEUE_SIZE;
                pEndpoint->TxBufCnt--;
    
                UNLOCK_HTC_TX(target);

                status = HTCIssueSend(target, tmp_hdr_buf, tmpbuf, SendFlags, payloadLen, EpID);

                LOCK_HTC_TX(target);

                if (A_FAILED(status)) {
                    adf_os_print("%s: Fail to send pkt to HIF, cnt = %d, usesendfail = %d\n", 
                           __func__, EpID, ++(pEndpoint->stat_usbsendfail));
#if 0
        			/* reclaim the credit due to failure to send */
            		HTCReclaimCredits(target, HTC_HDR_LENGTH + payloadLen, pEndpoint);
#endif        
                    if (tmpbuf)      { adf_nbuf_free(tmpbuf);      }
                    if (tmp_hdr_buf) { adf_nbuf_free(tmp_hdr_buf); }
                    break;
                }
    
    #if 0 
            }
    #endif
        }
    } /* for (i = ENDPOINT_MAX - 1; i >= 0; i--) */
    
    UNLOCK_HTC_TX(target);
#if 0 
       return status;
#else 
       return A_OK;
#endif  
}