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

📄 usbhcdohcilib.c

📁 T2.0 USB driver.rar T2.0 USB driver.rar
💻 C
📖 第 1 页 / 共 5 页
字号:
    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 = NULL;    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)	{	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;		    }		pTd->tdi.psw [i] = TO_LITTLEW (psw);		isochOffset += isochLen;		}	    bfrEnd = curBfrPtr + isochOffset - 1;	    pWork->bfrOffset += isochOffset;	    /* Initialize remaining fields in isochronous TD. */	    control |= OHCI_TICTL_FC_FMT (frameCount);	    control |= OHCI_TICTL_SF_FMT (pWork->isochNext);	    pWork->isochNext = FINDEX (pWork->isochNext + frameCount);	    pTd->tdi.control = TO_LITTLEL (control);	    pTd->tdi.bp0 = TO_LITTLEL (curBfrPtr & OHCI_PAGE_MASK);	    pTd->tdi.be = TO_LITTLEL (bfrEnd);	    }	else	    {	    /* General TD */	    control |= OHCI_TGCTL_BFR_RND | OHCI_TGCTL_TOGGLE_USETD;	    /* If this transfer does not complete the BFR_LIST entry, then	     * truncate it to an even number of frames. 	     */	    if (maxLen > pPipe->maxPacketSize &&		pWork->bfrOffset + maxLen != pBfrList->bfrLen)		{		maxLen = (maxLen / pPipe->maxPacketSize) * pPipe->maxPacketSize;		}	    if (maxLen == 0)		{		pWork->zeroLenMapped = TRUE;		curBfrPtr = bfrEnd = 0;		}	    else		{		bfrEnd = curBfrPtr + maxLen - 1;		}	    pWork->bfrOffset += maxLen;	    /* The last BFR_LIST entry for a control transfer (the status	     * packet) is alwasy DATA1. 	     */	    if (pPipe->transferType == USB_XFRTYPE_CONTROL &&		pWork->bfrNo == pIrp->bfrCount - 1)		{		control |= OHCI_TGCTL_TOGGLE_DATA1;		}	    else		{		control |= (pIrp->dataToggle == USB_DATA0) ? 						OHCI_TGCTL_TOGGLE_DATA0 :						OHCI_TGCTL_TOGGLE_DATA1;		}	    pTd->tdg.control = TO_LITTLEL (control);	    pTd->tdg.cbp = TO_LITTLEL (curBfrPtr);	    pTd->tdg.be = TO_LITTLEL (bfrEnd);	    }	pTd->sw.curBfrPtr = curBfrPtr;	/* Link the TD back to the workspace for the IRP. */	pTd->sw.pWork = pWork;	/* Store the time required to execute this TD */	pHost->nanoseconds += nanoseconds;	pTd->sw.nanoseconds = nanoseconds;	/* Append TD to the end of the ED's TD queue. 	 *	 * NOTE: pTd->tdg.nextTd == pTd->tdi.nextTd. */	pciPtrToNextFree = TO_LITTLEL (TO_PCIPTR (&pPipe->pTds [pPipe->freeTdIndex]));	pTd->tdg.nextTd = pciPtrToNextFree;	DMA_FLUSH (pTd, sizeof (OHCI_TD_ISO));	pPipe->pEd->ed.tdTail = pciPtrToNextFree;	DMA_FLUSH (&pPipe->pEd->ed.tdTail, sizeof (pPipe->pEd->ed.tdTail));	/* If necessary, notify the HC that new a new transfer is ready. */	switch (pPipe->transferType)	    {	    case USB_XFRTYPE_CONTROL:		HC_SET_BITS (OHCI_HC_COMMAND_STATUS, OHCI_CS_CLF);		 break;	    case USB_XFRTYPE_BULK:		HC_SET_BITS (OHCI_HC_COMMAND_STATUS, OHCI_CS_BLF);		break;	    }	}    }/***************************************************************************** scheduleOtherIrps - schedules other IRPs if TDs are available on a pipe** RETURNS: N/A*/LOCAL VOID scheduleOtherIrps    (    pHCD_HOST pHost,    pHCD_PIPE pPipe    )    {    pUSB_IRP pIrp;    pUSB_IRP pNextIrp;    pIRP_WORKSPACE pWork;    pIrp = usbListFirst (&pHost->busIrps);    while (pIrp != NULL && pPipe->freeTdCount > 0)	{	pNextIrp = usbListNext (&pIrp->hcdLink);	pWork = (pIRP_WORKSPACE) pIrp->hcdPtr;	if (pWork->pPipe == pPipe)	    assignTds (pHost, pPipe, pIrp, pWork);	pIrp = pNextIrp;	}    }/***************************************************************************** releaseTd - Update an IRP based on a completed IRP.** Sets <result> field in <pIrp> to OK or S_usbHcdLib_xxx if IRP completed.** NOTE: Automatically reschedules TDs.** RETURNS: N/A*/LOCAL VOID releaseTd    (    pHCD_HOST pHost,    pHCD_PIPE pPipe,    pUSB_IRP pIrp,    pIRP_WORKSPACE pWork,    pTD_WRAPPER pTd    )    {    pUSB_BFR_LIST pBfrList;    UINT32 control;    UINT32 curBfrPtr;    UINT32 bfrEnd;    UINT32 tdHead;    UINT16 frameCount;    UINT16 psw;    UINT16 actLen;    BOOL underrun = FALSE;    UINT16 i;        /* Release the bandwidth this TD was consuming. */    pHost->nanoseconds -= pTd->sw.nanoseconds;    /* Examine the TD. */    control = FROM_LITTLEL (pTd->tdg.control);    switch (OHCI_TGCTL_CC (control))	{	case OHCI_CC_NO_ERROR:			break;	case OHCI_CC_CRC:	case OHCI_CC_NO_RESPONSE:			pIrp->result = S_usbHcdLib_CRC_TIMEOUT; 		break;	case OHCI_CC_BITSTUFF:			pIrp->result = S_usbHcdLib_BITSTUFF_FAULT;  		break;	case OHCI_CC_STALL:     		pIrp->result = S_usbHcdLib_STALLED;     		break;	case OHCI_CC_DATA_TOGGLE:			pIrp->result = S_usbHcdLib_DATA_TOGGLE_FAULT; 		break;	case OHCI_CC_PID_CHECK:	case OHCI_CC_UNEXPECTED_PID: 		pIrp->result = S_usbHcdLib_PID_FAULT;			break;	case OHCI_CC_DATA_OVERRUN:	case OHCI_CC_DATA_UNDERRUN:	case OHCI_CC_BFR_OVERRUN:	case OHCI_CC_BFR_UNDERRUN:			pIrp->result = S_usbHcdLib_DATA_BFR_FAULT;  		break;	default:				pIrp->result = S_usbHcdLib_GENERAL_FAULT;   		break;	}    /* If there was an error, then the HC will have halted the ED.  Un-halt     * it so future transfers can take place.     */    tdHead = FROM_LITTLEL (pPipe->pEd->ed.tdHead);    if (pIrp->result != PENDING)	{	pPipe->pEd->ed.tdHead = TO_LITTLEL (tdHead & ~OHCI_PTR_HALTED);	DMA_FLUSH (&pPipe->pEd->ed.tdHead, sizeof (pPipe->pEd->ed.tdHead));	}    /* If ok so far, calculate the actual amount of data transferred. */

⌨️ 快捷键说明

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