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

📄 usbhcdsl811hslib.c

📁 SL811HS VxWorks Host Driver v1.0
💻 C
📖 第 1 页 / 共 5 页
字号:
*
* 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
    )

    {
    /* Set the forward link of this QH to the forward link of the
     * QH which is currently last on the bulk list.
     */

    if (ENABLE_BANDWIDTH_RECLAMATION (pHost))
	{
	if (pHost->pLastBulkQh->qh.qhLink == UHC_END_OF_LIST)
	    pWork->pQh->qh.qhLink = pHost->pciPtrToBulkAnchorQh;
	else
	    pWork->pQh->qh.qhLink = pHost->pLastBulkQh->qh.qhLink;
	}
    else
	{
	pWork->pQh->qh.qhLink = pHost->pLastBulkQh->qh.qhLink;
	}

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


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

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

    pHost->pLastBulkQh = pWork->pQh;
    }


/***************************************************************************
*
* unscheduleIrp - Removes QH/TDs for IRP from work UHC work lists
*
* RETURNS: N/A
*/

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

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

    switch (pWork->pPipe->transferType)
	{
	case USB_XFRTYPE_ISOCH:
	    unscheduleIsochTransfer (pHost, pIrp, pWork);
	    break;

	case USB_XFRTYPE_INTERRUPT: 
	    unscheduleInterruptTransfer (pHost, pIrp, pWork);
	    break;

	case USB_XFRTYPE_CONTROL:
	    unscheduleControlTransfer (pHost, pIrp, pWork);
	    break;

	case USB_XFRTYPE_BULK:
	    unscheduleBulkTransfer (pHost, pIrp, pWork);
	    break;
	}
    }


/***************************************************************************
*
* scheduleIrp - try to schedule an IRP in the frame list
*
* RETURNS: N/A
*/

LOCAL VOID scheduleIrp
    (
    pHCD_HOST pHost,
    pUSB_IRP pIrp
    )

    {
    pIRP_WORKSPACE pWork = (pIRP_WORKSPACE) pIrp->hcdPtr;
    pHCD_PIPE pPipe = pWork->pPipe;


    /* prepare TDs */

    assignTds (pHost, pIrp, pWork);


    /* Mark the time the IRP was first scheduled. */

    if (!pWork->irpRunning)
	{
	pWork->irpRunning = TRUE;
	pWork->startTime = OSS_TIME ();
	}


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

    switch (pPipe->transferType)
	{
	case USB_XFRTYPE_ISOCH:
	    scheduleIsochTransfer (pHost, pIrp, pWork);
	    break;

	case USB_XFRTYPE_INTERRUPT: 
	    scheduleInterruptTransfer (pHost, pIrp, pWork);
	    break;

	case USB_XFRTYPE_CONTROL:
	    scheduleControlTransfer (pHost, pIrp, pWork);
	    break;

	case USB_XFRTYPE_BULK:
	    scheduleBulkTransfer (pHost, pIrp, pWork);
	    break;
	}
    }


/***************************************************************************
*
* rescheduleTds - Examine the given IRP and see if it needs servicing
*
* <pIrp> is an IRP which may/may not have been assigned QHs and TDs and
* currently be schedule for execution.	Examine the <pIrp> and its
* associated USB_WORKSPACE in <pWork> (which might be NULL).  If no work
* has been scheduled or if no TDs have been completed by the UHC, then
* we do nothing.  If there are TDs which have been completed, then we
* release them to the "free" pool.  If work remains to be done, then we
* reschedule the TDs.  If no work remains to be done or if there is an
* error, then we report that the IRP is complete.
*
* RETURNS: OK = IRP completed ok
*      PENDING = IRP still being executed
*      S_usbHcdLib_xxx = IRP fai

⌨️ 快捷键说明

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