⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usbhcdohcilib.c

📁 VxWorks BSP for S3C2510A
💻 C
📖 第 1 页 / 共 5 页
字号:
		pTd->tdi.psw [i] = TO_LITTLEW (psw);

		isochOffset += isochLen;
		}

	    /*
	     * Packet status words need to be swapped before sending on
	     * some particular controllers.
	     * By default USB_BUFFER_SWAP is a no-op, but it can be
	     * overridden in BSP stubs as necessary.
	     */

	    USB_BUFFER_SWAP ((pVOID *) &pTd->tdi.psw [0],
			     frameCount * sizeof (UINT16));

	    bfrEnd = curBfrPtr + isochOffset - 1;

	    pWork->bfrOffset += isochOffset;


	    /* Initialize remaining fields in isochronous TD. */

	    control |= OHCI_TICTL_FC_FMT (frameCount);
	    control |= OHCI_TICTL_SF_FMT (pWork->isochNext);
	    pWork->isochNext = FINDEX (pWork->isochNext + frameCount);

	    pTd->tdi.control = TO_LITTLEL (control);
	    pTd->tdi.bp0 = TO_LITTLEL (curBfrPtr & OHCI_PAGE_MASK);
	    pTd->tdi.be = TO_LITTLEL (bfrEnd);
	    }
	else
	    {
	    /* General TD */

	    control |= OHCI_TGCTL_BFR_RND | OHCI_TGCTL_TOGGLE_USETD;

	    /* If this transfer does not complete the BFR_LIST entry, then
	     * truncate it to an even number of frames. 
	     */

	    if (maxLen > pPipe->maxPacketSize &&
		pWork->bfrOffset + maxLen != pBfrList->bfrLen)
		{
		maxLen = (maxLen / pPipe->maxPacketSize) * pPipe->maxPacketSize;
		}

	    if (maxLen == 0)
		{
		pWork->zeroLenMapped = TRUE;
		curBfrPtr = bfrEnd = 0;
		}
	    else
		{
		bfrEnd = curBfrPtr + maxLen - 1;
		}

	    pWork->bfrOffset += maxLen;


	    /* The last BFR_LIST entry for a control transfer (the status
	     * packet) is alwasy DATA1. 
	     */

	    if (pPipe->transferType == USB_XFRTYPE_CONTROL &&
		pWork->bfrNo == pIrp->bfrCount - 1)
		{
		control |= OHCI_TGCTL_TOGGLE_DATA1;
		}
	    else
		{
		control |= (pIrp->dataToggle == USB_DATA0) ? 
						OHCI_TGCTL_TOGGLE_DATA0 :
						OHCI_TGCTL_TOGGLE_DATA1;
		}

	    pTd->tdg.control = TO_LITTLEL (control);
	    pTd->tdg.cbp = TO_LITTLEL (curBfrPtr);
	    pTd->tdg.be = TO_LITTLEL (bfrEnd);
	    }

	pTd->sw.curBfrPtr = curBfrPtr;


	/* Link the TD back to the workspace for the IRP. */

	pTd->sw.pWork = pWork;


	/* Store the time required to execute this TD */

	pHost->nanoseconds += nanoseconds;
	pTd->sw.nanoseconds = nanoseconds;


	/* Append TD to the end of the ED's TD queue. 
	 *
	 * NOTE: pTd->tdg.nextTd == pTd->tdi.nextTd. */

	pciPtrToNextFree = TO_LITTLEL (TO_PCIPTR (&pPipe->pTds [pPipe->freeTdIndex]));

	pTd->tdg.nextTd = pciPtrToNextFree;

	DMA_FLUSH (pTd, sizeof (OHCI_TD_ISO)+sizeof(OHCI_TD_GEN));

	pPipe->pEd->ed.tdTail = pciPtrToNextFree;
	DMA_FLUSH (&pPipe->pEd->ed.tdTail, sizeof (pPipe->pEd->ed.tdTail));


	/* If necessary, notify the HC that new a new transfer is ready. */

	switch (pPipe->transferType)
	    {
	    case USB_XFRTYPE_CONTROL:

		HC_SET_BITS (OHCI_HC_COMMAND_STATUS, OHCI_CS_CLF);
		break;

	    case USB_XFRTYPE_BULK:

		HC_SET_BITS (OHCI_HC_COMMAND_STATUS, OHCI_CS_BLF);
		break;
	    }
	}
    }


/***************************************************************************
*
* scheduleOtherIrps - schedules other IRPs if TDs are available on a pipe
*
* RETURNS: N/A
*/

LOCAL VOID scheduleOtherIrps
    (
    pHCD_HOST pHost,
    pHCD_PIPE pPipe
    )

    {
    pUSB_IRP pIrp;
    pUSB_IRP pNextIrp;
    pIRP_WORKSPACE pWork;

    pIrp = usbListFirst (&pHost->busIrps);

    while (pIrp != NULL && pPipe->freeTdCount > 0)
	{
	pNextIrp = usbListNext (&pIrp->hcdLink);

	pWork = (pIRP_WORKSPACE) pIrp->hcdPtr;

	if (pWork->pPipe == pPipe)
	    assignTds (pHost, pPipe, pIrp, pWork);

	pIrp = pNextIrp;
	}
    }


/***************************************************************************
*
* releaseTd - Update an IRP based on a completed IRP.
*
* Sets <result> field in <pIrp> to OK or S_usbHcdLib_xxx if IRP completed.
*
* NOTE: Automatically reschedules TDs.
*
* RETURNS: N/A
*/

LOCAL VOID releaseTd
    (
    pHCD_HOST pHost,
    pHCD_PIPE pPipe,
    pUSB_IRP pIrp,
    pIRP_WORKSPACE pWork,
    pTD_WRAPPER pTd
    )

    {
    pUSB_BFR_LIST pBfrList;
    UINT32 control;
    UINT32 curBfrPtr;
    UINT32 bfrEnd;
    UINT32 tdHead;
    UINT16 frameCount;
    UINT16 psw;
    UINT16 actLen;
    BOOL underrun = FALSE;
    UINT16 i;
    

    /*
     * In some case, transmitted data is still used at either drivers or
     * applications and need to be re-swapped if they are swapped before
     * sending.
     */

    if (pIrp->bfrList[pWork->bfrNo].pid == USB_PID_SETUP ||
	pIrp->bfrList[pWork->bfrNo].pid == USB_PID_OUT)
	{
	if (pTd->sw.curBfrPtr != 0)
	    {
	    if (FROM_LITTLEL (pTd->tdg.cbp) == 0)
		{
		/*
		 * By default USB_BUFFER_SWAP is a no-op, but it can be
		 * overridden in BSP stubs as necessary.
		 */

		USB_BUFFER_SWAP ((pVOID *) pTd->sw.curBfrPtr,
			FROM_LITTLEL (pTd->tdg.be) - pTd->sw.curBfrPtr + 1);
		}
	    else
		{
		/*
		 * By default USB_BUFFER_SWAP is a no-op, but it can be
		 * overridden in BSP stubs as necessary.
		 */

		USB_BUFFER_SWAP ((pVOID *) pTd->sw.curBfrPtr,
			FROM_LITTLEL (pTd->tdg.cbp) - pTd->sw.curBfrPtr + 1);
		}
	    }
	}

    /* Release the bandwidth this TD was consuming. */

    pHost->nanoseconds -= pTd->sw.nanoseconds;


    /* Examine the TD. */

    control = FROM_LITTLEL (pTd->tdg.control);

    switch (OHCI_TGCTL_CC (control))
	{
	case OHCI_CC_NO_ERROR:	
		break;
	case OHCI_CC_CRC:
	case OHCI_CC_NO_RESPONSE:	
		pIrp->result = S_usbHcdLib_CRC_TIMEOUT;
		break;
	case OHCI_CC_BITSTUFF:	
		pIrp->result = S_usbHcdLib_BITSTUFF_FAULT;
		break;
	case OHCI_CC_STALL:     
		pIrp->result = S_usbHcdLib_STALLED;
		break;
	case OHCI_CC_DATA_TOGGLE:	
		pIrp->result = S_usbHcdLib_DATA_TOGGLE_FAULT; 
		break;
	case OHCI_CC_PID_CHECK:
	case OHCI_CC_UNEXPECTED_PID: 
		pIrp->result = S_usbHcdLib_PID_FAULT;
		break;
	case OHCI_CC_DATA_OVERRUN:
	case OHCI_CC_DATA_UNDERRUN:
	case OHCI_CC_BFR_OVERRUN:
	case OHCI_CC_BFR_UNDERRUN:	
		pIrp->result = S_usbHcdLib_DATA_BFR_FAULT;
		break;
	default:		
		pIrp->result = S_usbHcdLib_GENERAL_FAULT;
		break;
	}


    /* If there was an error, then the HC will have halted the ED.  Un-halt
     * it so future transfers can take place.
     */

    tdHead = FROM_LITTLEL (pPipe->pEd->ed.tdHead);

    if (pIrp->result != PENDING)
	{
	pPipe->pEd->ed.tdHead = TO_LITTLEL (tdHead & ~OHCI_PTR_HALTED);
	DMA_FLUSH (&pPipe->pEd->ed.tdHead, sizeof (pPipe->pEd->ed.tdHead));
	}


    /* If ok so far, calculate the actual amount of data transferred. */

    if (pIrp->result == PENDING)
	{
	pBfrList = &pIrp->bfrList [pWork->bfrNo];

	/* Note: In following assignment: pTd->tdg.be == pTd->tdi.be */

	bfrEnd = FROM_LITTLEL (pTd->tdg.be);

	if (pPipe->transferType == USB_XFRTYPE_ISOCH)
	    {
	    /* For an isoch transfer make sure each frame was executed. */

	    frameCount = OHCI_TICTL_FC (control);

	    /*
	     * Re-swap packet status words before reading if they are swapped
	     * at transmit.
	     * By default USB_BUFFER_SWAP is a no-op, but it can be
	     * overridden in BSP stubs as necessary.
	     */

	    USB_BUFFER_SWAP ((pVOID *) &pTd->tdi.psw [0],
			     frameCount * sizeof (UINT16));

	    for (actLen = i = 0; i < frameCount; i++)
		{
		psw = FROM_LITTLEW (pTd->tdi.psw [i]);

		if (OHCI_TIPSW_CC (psw) != OHCI_CC_NO_ERROR)
		    {
		    pIrp->result = S_usbHcdLib_ISOCH_FAULT;
		    break;
		    }
		}

	    actLen = bfrEnd - pTd->sw.curBfrPtr + 1;
	    }
	else
	    {
	    /* For a general transfer, calculate the actual data transferred */

	    curBfrPtr = FROM_LITTLEL (pTd->tdg.cbp);

	    if (pTd->sw.curBfrPtr == 0)
		{
		/* we requested a 0-length transfer */

		actLen = 0;
		}
	    else
		{
		/* we requested a transfer of non-zero length */

		if (curBfrPtr == 0)
		    {
		    /* transfer was successful...full length requested. */

		    actLen = bfrEnd - pTd->sw.curBfrPtr + 1;
		    }
		else
		    {
		    /* short packet was transferred.  curBfrPtr addresses
		     * the byte following the last byte transferred.
		     */

		    actLen = curBfrPtr - pTd->sw.curBfrPtr;
		    }
		}

	    /* Update the IRP's data toggle. */

	    pIrp->dataToggle = ((tdHead & OHCI_PTR_TGL_CARRY) == 0) ? 
	    USB_DATA0 : USB_DATA1;
	    } 

	
	/* Update the BFR_LIST entry and check for underrun. */

	pBfrList->actLen += actLen;

	if (pTd->sw.curBfrPtr != 0 &&
	    actLen < bfrEnd - pTd->sw.curBfrPtr + 1)
	    {
	    underrun = TRUE;

	    if ((pIrp->flags & USB_FLAG_SHORT_FAIL) != 0)
		{
		pIrp->result = S_usbHcdLib_SHORT_PACKET;
		}
	    }

	if (pBfrList->actLen == pBfrList->bfrLen || underrun)
	    {
	    pWork->bfrNo++;
	    pWork->bfrOffset = 0;
	    pWork->zeroLenMapped = FALSE;
	    }
	}


    /* Indicate that the TD is no longer in use. */

    memset (pTd, 0, sizeof (*pTd));
    pPipe->freeTdCount++;
    

    /* Check if the IRP is complete. */

    if (pIrp->result == PENDING)
	{
	if (pWork->bfrNo == pIrp->bfrCount)
	    {
	    /* Yes, all buffers for the IRP have been processed. */

	    pIrp->result = OK;
	    }
	else
	    {
	    /* No, schedule more work for the IRP. */

	    assignTds (pHost, pPipe, pIrp, pWork);
	    }
	}


    /* If this is an isochronous pipe and if we've fully mapped the current
     * IRP, then check if there are other IRPs which need to be scheduled.
     */

    if (pPipe->transferType == USB_XFRTYPE_ISOCH &&
			       ((pWork->bfrNo + 1 == pIrp->bfrCount && 
			       pWork->bfrOffset == 
			       pIrp->bfrList [pWork->bfrNo].bfrLen) ||
			       pWork->bfrNo == pIrp->bfrCount))
	{
	scheduleOtherIrps (pHost, pPipe);
	}


    /* If the IRP is complete, invalidate the cache for any input buffers. */

    if (pIrp->result != PENDING)
	{
	for (i = 0; i < pIrp->bfrCount; i++)
	    {
	    pBfrList = &pIrp->bfrList [i];
	
	    if (pBfrList->pid == USB_PID_IN && pBfrList->actLen > 0)
		{
		USER_INVALIDATE (pBfrList->pBfr, pBfrList->actLen);

		/* 
	 	 * By default USB_BUFFER_SWAP is a no-op, but can be
		 * overridden in BSP stubs as necessary.
	 	 */

		USB_BUFFER_SWAP ((pVOID *) pBfrList->pBfr, pBfrList->actLen);
		}
	    }
	}
    }


/***************************************************************************
*
* unscheduleIrp - unschedules IRP
*
* RETURNS: N/A
*/

LOCAL VOID unscheduleIrp
    (
    pHCD_HOST pHost,
    pUSB_IRP pIrp,
    pIRP_WORKSPACE pWork    
    )

    {
    pHCD_PIPE pPipe = pWork->pPipe;
    UINT16 i;
    UINT16 tdIndex;
    BOOL tdDeleted;


    /* If the IRP has no workspace, then it cannot be using TDs, so return 
     * immediately.
     */

    if (pWork == NULL)
	return;


    /* Halt processing on this ED. */

    pPipe->pEd->ed.control |= TO_LITTLEL (OHCI_EDCTL_SKIP);
    DMA_FLUSH (&pPipe->pEd->ed.control, sizeof (pPipe->pEd->ed.control));
    hcSynch (pHost);

    /* Search the pipe which owns this IRP to see if any of its TDs are
     * in use by this IRP.  If so, release them and allow another IRP (if
     * one exists) to use them.
     */

    tdIndex = pPipe->freeTdIndex;

    for (i = 0; i < pPipe->tdCount; i++)
	{
	tdDeleted = FALSE;

	if (pPipe->pTds [tdIndex].sw.pWork == pWork)
	    {
	    pPipe->freeTdCount++;
	    memset (&pPipe->pTds [tdIndex], 0, sizeof (pPipe->pTds [tdIndex]));
	    tdDeleted = TRUE;
	    }

	if (++tdIndex == pPipe->tdCount)
	    tdIndex = 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -