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

📄 usbhcduhcilib.c

📁 T2.0 USB driver.rar T2.0 USB driver.rar
💻 C
📖 第 1 页 / 共 5 页
字号:
	if ((pWork->pTdPool = DMA_MALLOC (tdLen, UHCI_TD_ALIGNMENT)) == NULL)	    {	    freeIrpWorkspace (pHost, pIrp);	    return FALSE;	    }	memset (pWork->pTdPool, 0, tdLen);	}    /* Create a chain of TDs in the "free" list */    pWork->pTdInUse = pWork->pTdFree = NULL;    for (i = 0; i < pWork->tdCount; i++)	{	pWork->pTdPool [i].sw.pWork = pWork;	pWork->pTdPool [i].sw.pNext = pWork->pTdFree;	pWork->pTdFree = &pWork->pTdPool [i];	}    /* Initialize the pointer to the last TD in use */    pWork->pLastTdInUse = NULL;    return TRUE;    }/***************************************************************************** isBandwidthTracked - determines if bandwidth is tracked for this transfer** Since the USBD has already reserved adequate bandwidth for isochronous* and interrupt transfers, we only track low speed control transfers.** RETURNS: TRUE if bandwidth tracked, else FALSE.*/LOCAL BOOL isBandwidthTracked    (    pHCD_PIPE pPipe    )    {    if (pPipe->transferType == USB_XFRTYPE_CONTROL && 	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.		 */		pWork->pLastTdInUse->td.linkPtr = TO_PCIPTR (pTd) 						  | TO_LITTLEL (UHCI_LINK_VF);		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], 

⌨️ 快捷键说明

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