usbhcduhcilib.c

来自「cpc-1631的BSP包for VxWorks操作系统」· C语言 代码 · 共 2,337 行 · 第 1/5 页

C
2,337
字号
	}

    /* Update the bandwidth-in-use for this controller.  
     *
     * NOTE: The pWork->nanoseconds field is 0 for all transfer types
     * except low speed control transfers, so the following calculation
     * often has no effect.
     */

    pHost->nanoseconds += pWork->nanoseconds - nanosecondsAtStart;
    }


/***************************************************************************
*
* unlinkIsochTd - unlink an isochronous TD
*
* Searches the indicated <frame> for a TD which corresponds to the
* IRP_WORKSPACE <pWork> (and hence which correspond to a given TD).
* If found, the TD is unlinked.
*
* RETURNS: N/A
*/

LOCAL VOID unlinkIsochTd
    (
    pHCD_HOST pHost,
    pIRP_WORKSPACE pWork,
    UINT32 frame
    )

    {
    pUINT32 pPciPtrToTd;
    pTD_WRAPPER pTd;


    /* Search frame for a TD belonging to this IRP and remove it from the 
     * work list.  We've exhausted the list of isochronous TDs when we 
     * reach the "interrupt anchor" QH.
     */

    pPciPtrToTd = &pHost->pFrameList->linkPtr [frame];
    pTd = TD_FROM_PCIPTR (*pPciPtrToTd);

    while (pTd != (pTD_WRAPPER) &pHost->pIntAnchorQhs [frame])
	{
	if (pTd->sw.pWork == pWork)
	    {
	    /* We found a TD for this IRP.	Unlink it. */

	    *pPciPtrToTd = pTd->td.linkPtr;
	    DMA_FLUSH (pPciPtrToTd, sizeof (*pPciPtrToTd));

	    --pWork->isochCount;

	    break;
	    }

	pPciPtrToTd = (pUINT32) &pTd->td.linkPtr;
	pTd = TD_FROM_PCIPTR (pTd->td.linkPtr);
	}
    }


/***************************************************************************
*
* unscheduleIsochTransfer - removes isochronous transfer from work list
*
* RETURNS: N/A
*/

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

    {
    UINT16 frame;


    /* Remove all pending isoch TDs for this IRP from the work list */

    for (frame = 0; 
         frame < UHCI_FRAME_LIST_ENTRIES && pWork->isochCount > 0; 
	 frame++)
	{
	unlinkIsochTd (pHost, pWork, frame);
	}
    }
    

/***************************************************************************
*
* scheduleIsochFrames - insert isoch frames into work list
*
* Schedules isochronous transfers into frames.
*
* RETURNS: N/A
*/

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

    {
    pTD_WRAPPER pTd;
    UINT16 frame;

    /* Schedule all initialized TDs onto the work list */

    while ((pTd = pWork->pNextIsochTd) != NULL && 
	    pWork->isochCount < UHCI_FRAME_LIST_ENTRIES)
	{
	/* Link the TD into the work list. */

	pTd->sw.frameNo = frame = pWork->isochNext;

	pTd->td.linkPtr = pHost->pFrameList->linkPtr [frame];
	DMA_FLUSH (&pTd->td.linkPtr, sizeof (pTd->td.linkPtr));

	pHost->pFrameList->linkPtr [pWork->isochNext] = TO_PCIPTR (pTd);
	DMA_FLUSH (&pHost->pFrameList->linkPtr [frame], 
		   sizeof (pHost->pFrameList->linkPtr [frame]));


	/* Advance to the next isoch TD for this IRP. */

	pWork->pNextIsochTd = pTd->sw.pNext;

	if (++pWork->isochNext == UHCI_FRAME_LIST_ENTRIES)
	    pWork->isochNext = 0;

	pWork->isochCount++;
	}
    }


/***************************************************************************
*
* scheduleIsochTransfer - inserts isoch IRP in frame list
*
* Schedules an isochronous transfer for the first time.
*
* RETURNS: N/A
*/

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

    {
    /* Isochronous transfers are scheduled immediately if the
     * USB_IRP.flag USB_FLAG_ISO_ASAP is set else beginning in the
     * frame specified by USB_IRP.startFrame.  The number of frames
     * to be scheduled is equal to the number of TDs in the 
     * IRP_WORKSPACE.
     */

    if ((pIrp->flags & USB_FLAG_ISO_ASAP) != 0)
	    pWork->isochNext = FINDEX (getFrameNo (pHost) + UHC_FRAME_SKIP);
    else
	    pWork->isochNext = FINDEX (pIrp->startFrame);

    pWork->isochCount = 0;

    scheduleIsochFrames (pHost, pIrp, pWork);
    }


/***************************************************************************
*
* unscheduleInterruptTransfer - removes interrupt transfer from work list
*
* RETURNS: N/A
*/

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

    {
    pQH_WRAPPER pCurrentQh;
    pQH_WRAPPER pNextQh;
    UINT16 i;

    /* We need to search the list of interrupt QHs to find any references
     * to the indicated QH and purge each one.
     */

    for (i = 0; i < UHCI_FRAME_LIST_ENTRIES; i += pWork->interval)
	{
	pCurrentQh = &pHost->pIntAnchorQhs [i];

	while ((pNextQh = QH_FROM_PCIPTR (pCurrentQh->qh.qhLink))
		!= pHost->pCtlAnchorQh &&
		pNextQh->sw.pWork->interval >= pWork->interval &&
		pNextQh != pWork->pQh)
	    {
	    pCurrentQh = pNextQh;
	    }

	if (pNextQh == pWork->pQh)
	    {
	    /* We found a reference to this QH. Modify the QH list to
	     * skip over it.  NOTE: pNextQh == pWork->pQh. */

	    pCurrentQh->qh.qhLink = pNextQh->qh.qhLink;
	    DMA_FLUSH (&pCurrentQh->qh.qhLink, sizeof (pCurrentQh->qh.qhLink));
	    }
	}
    }
    

/***************************************************************************
*
* scheduleInterruptTransfer - inserts interrupt IRP in frame list
*
* Schedules an interrupt transfer repeatedly in the frame list as
* indicated by the service interval.
*
* RETURNS: N/A
*/

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

    {
    pQH_WRAPPER pExistingQh;
    pQH_WRAPPER pNextQh;
    UINT16 i;


    /* Calculate the service interval we'll actually use. */

    pWork->interval = calcIntInterval (pWork->pPipe->interval);


    /* Schedule interrupt transfer periodically throughout frame list */

    for (i = 0; i < UHCI_FRAME_LIST_ENTRIES; i += pWork->interval)
	{
	/* Find the appropriate point in the list of interrupt QHs for this
	 * frame into which to schedule this QH.  This QH needs to be
	 * scheduled ahead of all interrupt QHs which are serviced more
	 * frequently (ie., least frequently serviced QHs come first).
	 */

	pExistingQh = &pHost->pIntAnchorQhs [i];

	while ((pNextQh = QH_FROM_PCIPTR (pExistingQh->qh.qhLink)) 
		!= pHost->pCtlAnchorQh &&
		pNextQh->sw.pWork->interval >= pWork->interval &&
		pNextQh != pWork->pQh)
	    {
	    pExistingQh = pNextQh;
	    }

	if (pNextQh != pWork->pQh)
	    {
	    if (i == 0)
		{
		pWork->pQh->qh.qhLink = pExistingQh->qh.qhLink;
		DMA_FLUSH (&pWork->pQh->qh, sizeof (pWork->pQh->qh));
		}

	    pExistingQh->qh.qhLink = QH_TO_PCIPTR (pWork->pQh);
	    DMA_FLUSH (&pExistingQh->qh.qhLink, sizeof (pExistingQh->qh.qhLink));
	    }
	}
    }


/***************************************************************************
*
* unscheduleControlTransfer - removes control transfer from work list
*
* RETURNS: N/A
*/

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

    {
    pQH_WRAPPER pCurrentQh;
    pQH_WRAPPER pNextQh;

    /* Find the control transfer in the work list and unlink it. */

    pCurrentQh = pHost->pCtlAnchorQh;

    while ((pNextQh = QH_FROM_PCIPTR (pCurrentQh->qh.qhLink)) != pWork->pQh)
	{
	pCurrentQh = pNextQh;
	}

    if (pNextQh == pWork->pQh)
	{
	/* Bipass pWork->pQh. */

	pCurrentQh->qh.qhLink = pWork->pQh->qh.qhLink;
	DMA_FLUSH (&pCurrentQh->qh.qhLink, sizeof (pCurrentQh->qh.qhLink));

	if (pHost->pLastCtlQh == pWork->pQh)
	    pHost->pLastCtlQh = pCurrentQh;
	}
    }
    

/***************************************************************************
*
* scheduleControlTransfer - inserts control IRP in frame list
*
* Inserts the control transfer into the portion of the frame list 
* appropriate for control transfers.
*
* RETURNS: N/A
*/

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

    {
    pQH_WRAPPER pExistingQh;
    pQH_WRAPPER pNextQh;


    /* Low speed control transfers must always be scheduled before full
     * speed control transfers in order to ensure that they execute
     * completely within a specified frame.
     */

    if (pWork->pPipe->speed == USB_SPEED_LOW)
	{
	/* Insert this low speed transfer after currently scheduled low
	 * speed transfers and ahead of any high speed transfers.
	 */

	pExistingQh = pHost->pCtlAnchorQh;

	while ((pNextQh = QH_FROM_PCIPTR (pExistingQh->qh.qhLink)) 
		!= pHost->pBulkAnchorQh && 
		pNextQh->sw.pWork->pPipe->speed == USB_SPEED_LOW)
	    {
	    pExistingQh = pNextQh;
	    }
	}
    else
	{
	/* This is a full speed transfer.  Add the QH to the end of the list 
	 * of control QHs. 
	 */

	pExistingQh = pHost->pLastCtlQh;
	}


    /* Set this QH's forward link to pExistingQh's forward link */

    if ((pWork->pQh->qh.qhLink = pExistingQh->qh.qhLink) == 
	pHost->pciPtrToBulkAnchorQh)
	{
	pHost->pLastCtlQh = pWork->pQh;
	}

    DMA_FLUSH (&pWork->pQh->qh, sizeof (pWork->pQh->qh));

    /* Set the forward link of the previous QH to this QH. */

    pExistingQh->qh.qhLink = QH_TO_PCIPTR (pWork->pQh);
    DMA_FLUSH (&pExistingQh->qh.qhLink, sizeof (pExistingQh->qh.qhLink));
    }


/***************************************************************************
*
* unscheduleBulkTransfer - removes bulk transfer from work list
*
* RETURNS: N/A
*/

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

    {
    pQH_WRAPPER pCurrentQh;
    pQH_WRAPPER pNextQh;

    /* Find the bulk transfer in the work list and unlink it. */

    pCurrentQh = pHost->pBulkAnchorQh;

    while ((pNextQh = QH_FROM_PCIPTR (pCurrentQh->qh.qhLink)) != pWork->pQh)
	{
	pCurrentQh = pNextQh;
	}

    if (pNextQh == pWork->pQh)
	{
	/* Bipass pWork->pQh. */

	if (ENABLE_BANDWIDTH_RECLAMATION (pHost))
	    {
	    if (pCurrentQh == pHost->pBulkAnchorQh &&
		pNextQh->qh.qhLink == pHost->pciPtrToBulkAnchorQh)
		{
		pCurrentQh->qh.qhLink = UHC_END_OF_LIST;
		}
	    else
		{
		pCurrentQh->qh.qhLink = pNextQh->qh.qhLink;
		}
	    }
	else
	    {
	    pCurrentQh->qh.qhLink = pNextQh->qh.qhLink;
	    }

	DMA_FLUSH (&pCurrentQh->qh.qhLink, sizeof (pCurrentQh->qh.qhLink));

	if (pHost->pLastBulkQh == pNextQh)
	    pHost->pLastBulkQh = pCurrentQh;
	}
    }
    

/***************************************************************************
*
* scheduleBulkTransfer - inserts bulk IRP in frame list
*
* Inserts the bulk transfer into the portion of the frame list appropriate 
* for bulk transfers.
*
* RETURNS: N/A
*/

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

⌨️ 快捷键说明

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