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

📄 usbhcdohcilib.c

📁 VxWorks BSP for S3C2510A
💻 C
📖 第 1 页 / 共 5 页
字号:

    {
    pED_WRAPPER pCurEd;
    pED_WRAPPER pNextEd;


    /* We need to halt processing of control transfers before de-linking. */

    HC_CLR_BITS (OHCI_HC_CONTROL, OHCI_CTL_CLE);
    hcSynch (pHost);


    /* Find the pipe's ED and de-link it. */

    if ((pCurEd = FROM_PCIPTR (HC_DWORD_IN (OHCI_HC_CONTROL_HEAD_ED)))
			      == pPipe->pEd)
	{
	/* ED is the head of the list */

	HC_DWORD_OUT (OHCI_HC_CONTROL_HEAD_ED, 
		      FROM_LITTLEL (pPipe->pEd->ed.nextEd));
	}
    else
	{
	/* Walk the list looking for the ED.
	 *
	 * NOTE: We know the ED must be on the list, so there's no need
	 * to check for the end of list as we proceed. 
	 */

	while ((pNextEd = ED_FROM_PCIPTR (pCurEd->ed.nextEd)) != pPipe->pEd)
					  pCurEd = pNextEd;

	pCurEd->ed.nextEd = pPipe->pEd->ed.nextEd;
	}

    /*  
     * shutOffListProcessing() halts isoch, interrupt and bulk transfers 
     * when a device is disconnected, we make sure they are re-enabled.
     */                 
 
    HC_SET_BITS(OHCI_HC_CONTROL,OHCI_CTL_PLE);
    HC_SET_BITS(OHCI_HC_CONTROL,OHCI_CTL_IE);
    HC_SET_BITS(OHCI_HC_CONTROL,OHCI_CTL_BLE);

    /* Re-enable the control list. */

    HC_SET_BITS (OHCI_HC_CONTROL, OHCI_CTL_CLE);

    }
    

/***************************************************************************
*
* scheduleControlPipe - inserts control pipe into the schedule
*
* Inserts the control transfer into the portion of the frame list 
* appropriate for control transfers.
*
* RETURNS: N/A
*/

LOCAL VOID scheduleControlPipe
    (
    pHCD_HOST pHost,
    pHCD_PIPE pPipe
    )

    {
    pED_WRAPPER pLastEd = FROM_PCIPTR (HC_DWORD_IN (OHCI_HC_CONTROL_HEAD_ED));
    pED_WRAPPER pNextEd;


    /* Flush the ED out of the cache before giving it to the HC. */

    DMA_FLUSH (pPipe->pEd, sizeof (*pPipe->pEd));


    if (pLastEd == NULL)
	{
	/* This will be the first ED on the control list. */

	HC_DWORD_OUT (OHCI_HC_CONTROL_HEAD_ED, TO_PCIPTR (pPipe->pEd));
	}
    else
	{
	/* Append this ED to the end of the control list. */

	while ((pNextEd = ED_FROM_PCIPTR (pLastEd->ed.nextEd)) != NULL)
	    pLastEd = pNextEd;

	pLastEd->ed.nextEd = TO_LITTLEL (TO_PCIPTR (pPipe->pEd));
	DMA_FLUSH (&pLastEd->ed.nextEd, sizeof (pLastEd->ed.nextEd));
	}
    }


/***************************************************************************
*
* unscheduleBulkPipe - removes bulk transfer from the schedule
*
* RETURNS: N/A
*/

LOCAL VOID unscheduleBulkPipe
    (
    pHCD_HOST pHost,
    pHCD_PIPE pPipe
    )

    {
    pED_WRAPPER pCurEd;
    pED_WRAPPER pNextEd;


    /* We need to halt processing of bulk transfers before de-linking. */

    HC_CLR_BITS (OHCI_HC_CONTROL, OHCI_CTL_BLE);
    hcSynch (pHost);


    /* Find the pipe's ED and de-link it. */

    if ((pCurEd = FROM_PCIPTR (HC_DWORD_IN (OHCI_HC_BULK_HEAD_ED)))
				== pPipe->pEd)
	{
	/* ED is the head of the list. */

	HC_DWORD_OUT (OHCI_HC_BULK_HEAD_ED, 
		      FROM_LITTLEL (pPipe->pEd->ed.nextEd));
	}
    else
	{
	/* Walk the list looking for the ED.
	 *
	 * NOTE: We know the ED must be on the list, so there's no need
	 * to check for the end of list as we proceed. 
	 */

	while ((pNextEd = ED_FROM_PCIPTR (pCurEd->ed.nextEd)) != pPipe->pEd)
					  pCurEd = pNextEd;

		pCurEd->ed.nextEd = pPipe->pEd->ed.nextEd;
	}

    /*  
     * shutOffListProcessing() halts isoch, interrupt and bulk transfers 
     * when a device is disconnected, we make sure they are re-enabled.
     */                 
 
    HC_SET_BITS(OHCI_HC_CONTROL,OHCI_CTL_PLE);
    HC_SET_BITS(OHCI_HC_CONTROL,OHCI_CTL_IE);
    HC_SET_BITS(OHCI_HC_CONTROL,OHCI_CTL_BLE);

    }
    

/***************************************************************************
*
* scheduleBulkPipe - inserts bulk pipe into the schedule
*
* Inserts the bulk transfer into the portion of the frame list appropriate 
* for bulk transfers.
*
* RETURNS: N/A
*/

LOCAL VOID scheduleBulkPipe
    (
    pHCD_HOST pHost,
    pHCD_PIPE pPipe
    )

    {
    pED_WRAPPER pLastEd = FROM_PCIPTR (HC_DWORD_IN (OHCI_HC_BULK_HEAD_ED));
    pED_WRAPPER pNextEd;


    /* Flush the ED out of the cache before giving it to the HC. */

    DMA_FLUSH (pPipe->pEd, sizeof (*pPipe->pEd));


    if (pLastEd == NULL)
	{
	/* This will be the first ED on the bulk list. */

	HC_DWORD_OUT (OHCI_HC_BULK_HEAD_ED, TO_PCIPTR (pPipe->pEd));
	}
    else
	{
	/* Append this ED to the end of the bulk list. */

	while ((pNextEd = ED_FROM_PCIPTR (pLastEd->ed.nextEd)) != NULL) 
	    pLastEd = pNextEd;

	pLastEd->ed.nextEd = TO_LITTLEL (TO_PCIPTR (pPipe->pEd));
	DMA_FLUSH (&pLastEd->ed.nextEd, sizeof (pLastEd->ed.nextEd));
	}
    }


/***************************************************************************
*
* unschedulePipe - Removes pipe from schedule
*
* RETURNS: N/A
*/

LOCAL VOID unschedulePipe
    (
    pHCD_HOST pHost,
    pHCD_PIPE pPipe
    )

    {
    /* un-Scheduling proceeds differently for each transaction type. */

    switch (pPipe->transferType)
	{
	case USB_XFRTYPE_ISOCH:
	    unscheduleIsochPipe (pHost, pPipe);
	    break;

	case USB_XFRTYPE_INTERRUPT: 
	    unscheduleInterruptPipe (pHost, pPipe);
	    break;

	case USB_XFRTYPE_CONTROL:
	    unscheduleControlPipe (pHost, pPipe);
	    break;

	case USB_XFRTYPE_BULK:
	    unscheduleBulkPipe (pHost, pPipe);
	    break;
	}
    }


/***************************************************************************
*
* schedulePipe - Adds a pipe to the schedule
*
* RETURNS: N/A
*/

LOCAL VOID schedulePipe
    (
    pHCD_HOST pHost,
    pHCD_PIPE pPipe
    )

    {
    /* Scheduling proceeds differently for each transaction type. */

    switch (pPipe->transferType)
	{
	case USB_XFRTYPE_ISOCH:
	    scheduleIsochPipe (pHost, pPipe);
	    break;

	case USB_XFRTYPE_INTERRUPT: 
	    scheduleInterruptPipe (pHost, pPipe);
	    break;

	case USB_XFRTYPE_CONTROL:
	    scheduleControlPipe (pHost, pPipe);
	    break;

	case USB_XFRTYPE_BULK:
	    scheduleBulkPipe (pHost, pPipe);
	    break;
	}
    }


/***************************************************************************
*
* assignTds - assign TDs for each IRP bfrList[] entry
*
* Assigns and initializes TDs to map the next bfrList[] entry in the IRP.  
* Stops when all all bfrList[] entries have been mapped, when all TDs for 
* the IRP have been exhausted, or when buffer bandwidth calculations indicate 
* we shouldn't map any more TDs at this time.  
*
* This function also updates the pHost->nanoseconds field with the bandwidth
* required by this transfer if appropriate.
*
* NOTE: We choose to map only one bfrList[] entry at a time to simplify the
* the handling of input underrun.  When an underrun occurs, the 
* releaseTd() function releases all TDs scheduled up through that point.
* We then schedule TDs for the following bfrList[] entries if any.
*
* RETURNS: N/A
*/

LOCAL VOID assignTds
    (
    pHCD_HOST pHost,
    pHCD_PIPE pPipe,
    pUSB_IRP pIrp,
    pIRP_WORKSPACE pWork
    )

    {
    pUSB_BFR_LIST pBfrList;
    pTD_WRAPPER pTd;
    UINT32 bytesThroughFrameCount;
    UINT16 bytesThisFrame;
    UINT16 isochLen;
    UINT32 isochOffset;
    UINT16 maxLen;
    UINT32 nanoseconds;
    UINT32 control = 0;
    UINT32 curBfrPtr;
    UINT32 bfrEnd;
    UINT16 frameCount;
    UINT16 psw;
    UINT32 pciPtrToNextFree;
    UINT16 i;


    /* Assign TDs to map the current bfrList[] entry.  Stop when the buffer is 
     * fully mapped, when we run out of TDs, or when bus bandwidth calculations 
     * indicate we should not allocate more TDs at this time.
     */

    if (pWork->bfrNo == pIrp->bfrCount)
	return;

    pBfrList = &pIrp->bfrList [pWork->bfrNo];

    while ((pWork->bfrOffset < pBfrList->bfrLen ||
	    (pBfrList->bfrLen == 0 && 
	    !pWork->zeroLenMapped)) && 
	    pPipe->freeTdCount > 0)
    	{

        /* Calculate the length of this TD and determine if there are any
         * bandwidth limitations which would prevent scheduling it at this time.
         *
         * NOTE: Since the USBD has already checked bandwidth availability for
         * isochronous and interrupt transfers, we need only check bandwidth
         * availability for low speed control transfers.
         */

        if (isBandwidthTracked (pPipe))
	    {
    	    nanoseconds = usbTransferTime (pPipe->transferType, 
					   dirFromPid (pBfrList->pid), 
					   pPipe->speed, 
				   min (pBfrList->bfrLen - pWork->bfrOffset, 
 					pPipe->maxPacketSize), 
					   HC_HOST_DELAY, 
					   HC_HUB_LS_SETUP);

  	    if (pHost->nanoseconds + nanoseconds > USB_LIMIT_ALL)
		{
	    	/* There isn't enough bandwidth at this time.  Stop scheduling 
	     	 * for this transfer.
             	 */
	
	    	break;
	    	}
	    }
        else
	    {
	    nanoseconds = 0;
	    }


       /* If this is the first time we've mapped a part of this bfrList[] entry,
         * then flush the cache.  Note that we do this for input buffers as well
         * since we don't know where the user's buffer is allocated and some CPU
         * cache architectures may get confused near cache-line boundaries.
     	*/

        if (pWork->bfrOffset == 0 && pBfrList->bfrLen > 0)
	    {
	    /* 
	     * By default USB_BUFFER_SWAP is a no-op, but it can be
	     * overridden in BSP stubs as necessary.
	     */

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


        /* Grab the first free TD for our use...Then advance the "free TD 
         * index" so that it points to the next free TD.  (Since freeTdCount
         * is initialized to be one less than tdCount, we are guaranteed that
         * there are always at least two free TDs when we reach this point in
         * the code.
         */

        pTd = &pPipe->pTds [pPipe->freeTdIndex];
        pTd->sw.inUse = 1;
        pPipe->freeTdCount--;

        do
    	    {
	    if (++pPipe->freeTdIndex == pPipe->tdCount)
		pPipe->freeTdIndex = 0;
	    }
        while (pPipe->pTds [pPipe->freeTdIndex].sw.inUse != 0);


        /* OHCI TD's can span up to two, 4k pages.	Based on this limit,
         * calculate the maximum amount of data we'll try to transfer with
         * this TD.
         */

        curBfrPtr = TO_PCIPTR ((pVOID) &pBfrList->pBfr [pWork->bfrOffset]);

        maxLen = OHCI_PAGE_SIZE - (curBfrPtr & ~OHCI_PAGE_MASK) + \
					 OHCI_PAGE_SIZE;

        maxLen = min (maxLen, pBfrList->bfrLen - pWork->bfrOffset);


        /* Initialize TD. 
         *
         * NOTE: By convention, TD is always cleared to 0's at initialization
         * or after being discarded by the previous transfer.
         */

        switch (pBfrList->pid)
    	    {
    	    case USB_PID_SETUP: 
		control = OHCI_TGCTL_PID_SETUP; 
		break;

	    case USB_PID_OUT:   
		control = OHCI_TGCTL_PID_OUT;   
		break;

	    case USB_PID_IN:    
		control = OHCI_TGCTL_PID_IN;    
		break;
	    }

        if (pPipe->transferType == USB_XFRTYPE_ISOCH)
	    {
	    /* Isochronous TD */

	    /* Map up to a complete TD (eight frames). */

	    frameCount = 0;
	    isochOffset = 0;

	    for (i = 0; i < OHCI_ISO_PSW_CNT && maxLen > 0; i++)
		{
		/* Calculate the packet length for the next frame. */

		bytesThroughFrameCount = (pWork->frameCount + 1) * 
					  pPipe->bandwidth / 1000L;

		bytesThisFrame = bytesThroughFrameCount - pWork->bytesSoFar;

		/* NOTE: If maxLen is less than the desired number of bytes
		 * for this frame *AND* we are not yet at the end of this
		 * BFR_LIST entry, then don't schedule any more frames for
		 * this TD...For this situation to arise we must be near a
		 * page boundary crossing...The next TD will begin one page
		 * later and will allow us to schedule the full frame as
		 * desired.
		 */

		if (maxLen < bytesThisFrame &&
		    pWork->bfrOffset + maxLen != pBfrList->bfrLen)
		    break;

		isochLen = min (bytesThisFrame, maxLen);

		isochLen = min (isochLen, pPipe->maxPacketSize);

		if (pIrp->dataBlockSize != 0 && isochLen > pIrp->dataBlockSize)
		    {
		    isochLen = (isochLen / pIrp->dataBlockSize) * 
		    pIrp->dataBlockSize;
		    }

		pWork->bytesSoFar += isochLen;

		maxLen -= isochLen;

		pWork->frameCount++;
		frameCount++;


		/* Initialize the TD PSW for this frame. */

		psw = OHCI_TIPSW_CC_FMT (OHCI_CC_NOT_ACCESSED);
		psw |= (curBfrPtr + isochOffset) & OHCI_ISO_OFFSET_MASK;
		    
		if ((curBfrPtr & OHCI_PAGE_MASK) != 
		    ((curBfrPtr + isochOffset) & OHCI_PAGE_MASK))
		    {
		    psw |= OHCI_ISO_OFFSET_BE;
		    }

⌨️ 快捷键说明

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