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

📄 usbhcdsl811hslib.c

📁 有关vxworks 的host 的源程序
💻 C
📖 第 1 页 / 共 5 页
字号:
	pPipe->speed == USB_SPEED_LOW)
	return TRUE;

    return FALSE;
    }


/***************************************************************************
*
* dirFromPid - returns USB_DIR_xxxx based on USB_PID_xxxx
*
* RETURNS: USB_DIR_xxxx
*/

LOCAL UINT16 dirFromPid
    (
    UINT16 pid
    )

    {
    switch (pid)
    {
    case USB_PID_SETUP:
    case USB_PID_OUT:	
	return USB_DIR_OUT;

    case USB_PID_IN:	
	return USB_DIR_IN;

    default:	    
	return USB_DIR_IN;
    }
    }


/***************************************************************************
*
* 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.
*
* This mapping has the effect of moving TDs from the free list to the "in
* use" list in the IRP_WORKSPACE.  TDs in the "in use" list are always
* linked in the order in which they should be executed.
*
* 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 
* rescheduleTds() 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,
    pUSB_IRP pIrp,
    pIRP_WORKSPACE pWork
    )

    {
    pHCD_PIPE pPipe = pWork->pPipe;
    pTD_WRAPPER pTd;
    pUSB_BFR_LIST pBfrList;
    UINT32 bytesThroughFrameCount;
    UINT16 maxLen;
    UINT32 nanoseconds;
    UINT32 nanosecondsAtStart;
    UINT32 ctlSts;
    UINT32 token;


    /* Record the bus time already used by this transfer. */

    nanosecondsAtStart = pWork->nanoseconds;


    /* 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.
     */

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

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

	/* Calculate the length of this TD. */

	if (pPipe->transferType == USB_XFRTYPE_ISOCH)
	    {
	    pWork->frameCount++;

	    bytesThroughFrameCount = pWork->frameCount 
				     * pPipe->bandwidth 
				     / 1000L;

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

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

	    if (pIrp->dataBlockSize != 0 && maxLen > pIrp->dataBlockSize)
		    maxLen = (maxLen / pIrp->dataBlockSize) 
			     * pIrp->dataBlockSize;

	    pWork->bytesSoFar += maxLen;
	    }
	else
	    {
	    /* Transfer length calculation for non-isoch pipes. */

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


	/* Determine if there are any bandwidth limitations which would prevent 
	 * scheduling this TD 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, maxLen, 
	    UHC_HOST_DELAY, UHC_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)
	    {
	    USER_FLUSH (pBfrList->pBfr, pBfrList->bfrLen);
	    }


	/* Unlink the TD from the free list. */

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


	/* Initialize TD buffer pointer. */

	pTd->td.bfrPtr = TO_PCIPTR (&pBfrList->pBfr [pWork->bfrOffset]);
	pWork->bfrOffset += maxLen;

	if (maxLen == 0)
	    pWork->zeroLenMapped = TRUE;


	/* Initialize TD control/status word */ 

	ctlSts = UHCI_TDCS_SHORT | UHCI_TDCS_ERRCTR_3ERR;
	ctlSts |= (pPipe->speed == USB_SPEED_LOW) ? UHCI_TDCS_LOWSPEED : 0;
	ctlSts |= (pPipe->transferType == USB_XFRTYPE_ISOCH) ? 
		   UHCI_TDCS_ISOCH : 0;
	ctlSts |= UHCI_TDCS_STS_ACTIVE;


	/* enable IOC (interrupt on complete) if this is the last TD.  If
	 * this is an isochronous transfer, also enable IOC on a regular
	 * interval defined by ISOCH_INT_INTERVAL. 
	 */

	if (pWork->bfrOffset == pBfrList->bfrLen || pWork->pTdFree == NULL)
	    ctlSts |= UHCI_TDCS_COMPLETE;

	if (pPipe->transferType == USB_XFRTYPE_ISOCH)
	    {
	    pWork->isochTdsCreated++;

	    if (pWork->isochTdsCreated % ISOCH_INT_INTERVAL == 0)
		    ctlSts |= UHCI_TDCS_COMPLETE;
	    }

	pTd->td.ctlSts = TO_LITTLEL (ctlSts);


	/* Initialize TD token word */

	token = UHCI_TDTOK_MAXLEN_FMT (maxLen);

	if (pPipe->transferType != USB_XFRTYPE_ISOCH)
	    {
	    /* Normally, the data toggle begins with DATA0 and alternates
	     * between DATA0 and DATA1.  However, the last transfer for
	     * a control transfer - the status packet - is always a DATA1. 
	     */

	    if (pPipe->transferType == USB_XFRTYPE_CONTROL &&
		pWork->bfrNo == pIrp->bfrCount - 1)
		{
		token |= UHCI_TDTOK_DATA_TOGGLE;
		}
	    else
		{
		if (pIrp->dataToggle == USB_DATA0)
		    {
		    pIrp->dataToggle = USB_DATA1;
		    }
		else 
		    {
		    token |= UHCI_TDTOK_DATA_TOGGLE;
		    pIrp->dataToggle = USB_DATA0;
		    }
		}
	    }
	    
	token |= UHCI_TDTOK_ENDPT_FMT (pPipe->endpoint);
	token |= UHCI_TDTOK_DEVADRS_FMT (pPipe->busAddress);
	token |= UHCI_TDTOK_PID_FMT (pBfrList->pid);

	pTd->td.token = TO_LITTLEL (token);


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

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


	/* put the TD at the end of the "in use" list.
	 *
	 * NOTE: If this QH is already active, then as soon as we
	 * set the linkPtr of the last TD in use we must expect
	 * that the UHC may begin executing this TD (does not apply
	 * to isochronous TDs for which there is no QH).
	 */

	pTd->td.linkPtr = UHC_END_OF_LIST;
	pTd->sw.pNext = NULL;

	if (pWork->pTdInUse == NULL)
	    {
	    pWork->pTdInUse = pTd;
	    }

	if (pPipe->transferType == USB_XFRTYPE_ISOCH &&
	    pWork->pNextIsochTd == NULL)
	    {
	    pWork->pNextIsochTd = pTd;
	    }

	DMA_FLUSH (&pTd->td, sizeof (pTd->td));

	if (pWork->pLastTdInUse != NULL)
	    {
	    pWork->pLastTdInUse->sw.pNext = pTd;

	    /* For non-isochronous transfers, append this TD to the list
	     * of TDs assigned to the IRP.	(Isochronous TDs are inserted
	     * into the schedule by calling scheduleIsochFrames().
	     */

	    if (pPipe->transferType != USB_XFRTYPE_ISOCH)
		{
		/* NOTE: Setting the "Vf" bit improves performance by 
		 * allowing the host controller to exchange data 
		 * continuously with the device until the device NAKs.
		 */
#ifdef INCLUDE_USB_PCI
		pWork->pLastTdInUse->td.linkPtr = TO_PCIPTR (pTd) 
						  | TO_LITTLEL (UHCI_LINK_VF);
#else
		pWork->pLastTdInUse->td.linkPtr = TO_PCIPTR (pTd) | UHCI_LINK_VF;
#endif

		DMA_FLUSH (&pWork->pLastTdInUse->td.linkPtr, 
			   sizeof (pWork->pLastTdInUse->td.linkPtr));
		}
	    }

	pWork->pLastTdInUse = pTd;
	}


    /* If there is a QH, we should initialize it to point to the beginning of 
     * the TD list.
     */

    if (pWork->pQh != NULL && pWork->pQh->qh.tdLink == UHC_END_OF_LIST)
	{
	/* Initialize QH "vertical" pointer */

	pWork->pQh->qh.tdLink = TO_PCIPTR (pWork->pTdInUse);
	DMA_FLUSH (&pWork->pQh->qh.tdLink, sizeof (pWork->pQh->qh.tdLink));
	}

    /* 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

⌨️ 快捷键说明

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