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

📄 usbhcduhcilib.c

📁 T2.0 USB driver.rar T2.0 USB driver.rar
💻 C
📖 第 1 页 / 共 5 页
字号:
    {    pTD_WRAPPER pTd;    pUSB_BFR_LIST pBfrList;    UINT32 nanosecondsAtStart;    UINT32 ctlSts;    UINT32 token;    UINT16 actLen;    BOOL underrun = FALSE;    int s = PENDING;    UINT16 i;        /* If there is no workspace, this IRP has not been scheduled yet. */    if (pWork == NULL)	return PENDING;    /* Record the bus time already used by this transfer. */    nanosecondsAtStart = pWork->nanoseconds;    /* Examine the "in use" TDs.  If any are complete, return them to the     * free pool for this IRP.	If any completed with errors, indicate that     * the IRP has failed.     *     * NOTE: Complete TDs will always be in front.  If we encouter a TD     * which is not complete, then we need not check any further TDs in the     * list.  If we detect an underrun on an IN transfer, then we continue     * to process the TD list anyway, moving TDs from the in-use list to the     * free list.     */    while (s == PENDING && pWork->pTdInUse != NULL)	{	/* Examine the TDs status */	pTd = pWork->pTdInUse;	DMA_INVALIDATE (pTd, sizeof (*pTd));	ctlSts = FROM_LITTLEL (pTd->td.ctlSts);	if ((ctlSts & UHCI_TDCS_STS_ACTIVE) != 0 && !underrun)	    {	    /* TD is still active.	Stop checking this list. */	    break;	    }	else	    {	    /* Release the bandwidth this TD was consuming. */	    pWork->nanoseconds -= pTd->sw.nanoseconds;	    if (!underrun)		{		/* This TD is no longer active.  Did it 		 * complete successfully? 		 */		if ((ctlSts & UHCI_TDCS_STS_STALLED) != 0)		    s = S_usbHcdLib_STALLED;		else if ((ctlSts & UHCI_TDCS_STS_DBUFERR) != 0)		    s = S_usbHcdLib_DATA_BFR_FAULT;		else if ((ctlSts & UHCI_TDCS_STS_BABBLE) != 0)		    s = S_usbHcdLib_BABBLE;		else if ((ctlSts & UHCI_TDCS_STS_TIME_CRC) != 0)		    s = S_usbHcdLib_CRC_TIMEOUT;		else if ((ctlSts & UHCI_TDCS_STS_BITSTUFF) != 0)		    s = S_usbHcdLib_BITSTUFF_FAULT;		}	    if (!underrun && s == PENDING)		{		/* There doesn't appear to be an error.  Update the actlen		 * field in the IRP.		 */		pBfrList = &pIrp->bfrList [pWork->bfrNo];		/* If this in an IN and the actLen was shorter than the 		 * expected size, then the transfer is complete.  If the 		 * IRP flag USB_FLAG_SHORT_FAIL is set, then fail the 		 * transfer.		 */		actLen = UHCI_TDCS_ACTLEN (ctlSts);		pBfrList->actLen += actLen;		token = FROM_LITTLEL (pTd->td.token);		if (UHCI_TDTOK_PID (token) == USB_PID_IN && 		    actLen < UHCI_TDTOK_MAXLEN (token))		    underrun = TRUE;		if (pBfrList->actLen == pBfrList->bfrLen || underrun)		    {		    pWork->bfrNo++;		    pWork->bfrOffset = 0;		    pWork->zeroLenMapped = FALSE;		    }		if (underrun && (pIrp->flags & USB_FLAG_SHORT_FAIL) != 0)		    s = S_usbHcdLib_SHORT_PACKET;		if (underrun && pWork->pQh != NULL)		    {		    /* When an underrun is detected, there is still a QH 		     * pointing to the TD which caused the underrun.  In 		     * this case, we need to get the TD out of the work 		     * list before we can re-use it.		     */		    pWork->pQh->qh.tdLink = UHC_END_OF_LIST;		    DMA_FLUSH (&pWork->pQh->qh.tdLink, 		    sizeof (pWork->pQh->qh.tdLink));		    }		}	    /* If this is an isochronous transfer, delink it from the	     * UHC work list.	     */	    if (pWork->pPipe->transferType == USB_XFRTYPE_ISOCH)		unlinkIsochTd (pHost, pTd->sw.pWork, pTd->sw.frameNo);	    /* Delink this TD from the in-use pool.  If this happens to	     * be the last TD in use, then update pLastTdInUse.	     */	    if ((pWork->pTdInUse = pTd->sw.pNext) == NULL)		pWork->pLastTdInUse = NULL;	    /* Link TD to free pool. */	    pTd->sw.pNext = pWork->pTdFree;	    pWork->pTdFree = pTd;	    }	}    /* Update the bus tally of bandwidth in use. */    if (s == PENDING)	{	/* Transfer is ok.	Release bandwidth from TDs we processed */	pHost->nanoseconds -= nanosecondsAtStart - pWork->nanoseconds;	}    else	{	/* Transfer has failed.  Release all associated bandwidth. */	pHost->nanoseconds -= nanosecondsAtStart;	}    /* If the IRP has not failed, and if there is work remaining to be done,     * and if there are entries on the free TD pool, then prepare additional     * TDs.  If the IRP has not failed and there is no work remaining to be     * done then mark the IRP as successful.     */    if (s == PENDING)	{	if (pWork->bfrNo == pIrp->bfrCount)	    {	    s = OK;	    }	else 	    {	    /* For interrupt, control, and bulk transfers the QH is already 	     * in the UHC work list.  So, re-assigning TDs will continue the 	     * transfer.  However, for isochronous transfers, fresh TDs need	     * to be injected into the work list.	     */	    assignTds (pHost, pIrp, pWork);	    if (pWork->pPipe->transferType == USB_XFRTYPE_ISOCH)		scheduleIsochFrames (pHost, pIrp, pWork);	    }	}    /* Check if IRP has finished */    if (s != PENDING)	{	/* The IRP has finished, invalidate the cache for any input buffers */	for (i = 0; i < pIrp->bfrCount; i++)	    {	    pBfrList = &pIrp->bfrList [i];		    if (pBfrList->pid == USB_PID_IN && pBfrList->actLen > 0)		USER_INVALIDATE (pBfrList->pBfr, pBfrList->actLen);	    }	}    return s;    }/***************************************************************************** hcSynch - give the host controller a chance to synchronize** It appears that certain UHCI host controllers (e.g., Via Tech)* pre-fetch QHs.  This creates a problem for us when we want to* unlink the QH, as the host controller still has a record of it.* To make sure the host controller doesn't declare a consistency* error when it examines the QH/TDs associated with the QH, we* wait until the current frame ends before freeing the QH/TD* memory.  On the next frame, the host controller will re-fetch* all QHs, and it won't see the ones we've removed.** RETURNS: N/A*/LOCAL VOID hcSynch    (    pHCD_HOST pHost    )    {    UINT16 currentFrameNo = getFrameNo (pHost);    while (getFrameNo (pHost) == currentFrameNo)	semTake(pHost->hcSyncSem, 1);    }/***************************************************************************** cancelIrp - cancel's an outstanding IRP** If the IRP's result code is not PENDING, then we cannot cancel* the IRP as it has either already completed or it is not yet enqueued.** RETURNS: OK if IRP canceled*      S_usbHcdLib_CANNOT_CANCEL if IRP already completed*/LOCAL int cancelIrp    (    pHCD_HOST pHost,    pUSB_IRP pIrp,    int result		    /* error to assign to IRP */    )    {    pIRP_WORKSPACE pWork;    int s = OK;    if (pIrp->result != PENDING)	s = S_usbHcdLib_CANNOT_CANCEL;    else	{	/* The IRP is pending.  Unlink it. */	usbListUnlink (&pIrp->hcdLink);	/* If this IRP is a "bus" IRP - as opposed to a root IRP - then	 * remove it from the UHC's work list.	 */	if ((pWork = (pIRP_WORKSPACE) pIrp->hcdPtr) != NULL &&	    pWork->pPipe->busAddress != pHost->rootAddress)	    {	    /* Remove QHs/TDs from the work list and release workspace. */	    unscheduleIrp (pHost, pIrp, pWork);	    HC_SYNCH (pHost);	    freeIrpWorkspace (pHost, pIrp);	    }	setIrpResult (pIrp, result);    	}    return s;    }/***************************************************************************** processUhcInterrupt - process a hardware interrupt from the UHC** Determine the cause of a hardware interrupt and service it.  If the* interrupt results in the completion of one or more IRPs, handle the* completion processing for those IRPs.** RETURNS: N/A*/LOCAL VOID processUhcInterrupt    (    pHCD_HOST pHost    )    {    pUSB_IRP pIrp;    pUSB_IRP pNextIrp;    pIRP_WORKSPACE pWork;    LIST_HEAD completeIrps = {0};    int irpsCompleted = 0;    int result;    /* evaluate the interrupt condition */    if ((pHost->intBits & (UHCI_STS_PROCERR | UHCI_STS_HOSTERR)) != 0)	{	/* No response, just clear error condition */	pHost->intBits &= ~(UHCI_STS_PROCERR | UHCI_STS_HOSTERR);	pHost->hostErrCount++;	}    if ((pHost->intBits & UHCI_STS_RESUME) != 0)	{	/* Remote device is driving resume signalling.  If the HCD client	 * installed a management callback, invoke it.	 */	pHost->intBits &= ~UHCI_STS_RESUME;	if (pHost->mngmtCallback != NULL)	    (*pHost->mngmtCallback) (pHost->mngmtCallbackParam, pHost->handle,	    0 /* bus number */, HCD_MNGMT_RESUME);	}    if ((pHost->intBits & (UHCI_STS_USBERR | UHCI_STS_USBINT)) != 0)	{	/* Completion of one or more USB transactions detected. */	pHost->intBits &= ~(UHCI_STS_USBERR | UHCI_STS_USBINT);	/* Search for one or more IRPs which have been completed	 * (or partially completed).	 */	pIrp = usbListFirst (&pHost->busIrps);	while (pIrp != NULL)	    {	    pNextIrp = usbListNext (&pIrp->hcdLink);	    	    /* As we walk the list of IRPs, try to reschedule QHs and TDs	     * which are complete.	     */	    pWork = (pIRP_WORKSPACE) pIrp->hcdPtr;	    if ((result = rescheduleTds (pHost, pIrp, pWork)) != PENDING)		{		/* The indicated IRP is complete. */		irpsCompleted++;		/* De-link the QH for this transfer.		 *		 * NOTE: We defer freeing the workspace associated with each		 * IRP until we're ready to do the callbacks.  This gives us		 * a chance to synchronize with the host controller, below.		 */		unscheduleIrp (pHost, pIrp, pWork);		/* Unlink the IRP from the list of active IRPs */		usbListUnlink (&pIrp->hcdLink);		pIrp->result = result;		usbListLink (&completeIrps, pIrp, &pIrp->hcdLink, LINK_TAIL);		}	    pIrp = pNextIrp;	    }	/* Invoke IRP callbacks for all completed IRPs. */	if (irpsCompleted > 0)	    HC_SYNCH (pHost);	while ((pIrp = usbListFirst (&completeIrps)) != NULL)	    {	    usbListUnlink (&pIrp->hcdLink);	    freeIrpWorkspace (pHost, pIrp);	    setIrpResult (pIrp, pIrp->result);	    }	}    }/***************************************************************************** checkIrpTimeout - Checks for IRPs which may have timed-out** RETURNS: N/A*/LOCAL VOID checkIrpTimeout    (    pHCD_HOST pHost	/* host to check */    )    {    pUSB_IRP pIrp;    pUSB_IRP pNextIrp;    pIRP_WORKSPACE pWork;    UINT32 now;    /* Search for one or more IRPs which have been completed     * (or partially completed).     */    now = OSS_TIME ();    pIrp = usbListFirst (&pHost->busIrps);    while (pIrp != NULL)	{	pNextIrp = usbListNext (&pIrp->hcdLink);	    	pWork = (pIRP_WORKSPACE) pIrp->hcdPtr;	if (pIrp->timeout != USB_TIMEOUT_NONE && pWork->irpRunning &&	    now - pWork->startTime > pIrp->timeout)	    {	    /* This IRP has exceeded its run time. */	    cancelIrp (pHost, pIrp, S_usbHcdLib_TIMEOUT);	    }	pIrp = pNextIrp;	}    }/***************************************************************************** isHubStatus - checks status on root hub** RETURNS: hub and port status bitmap as defined by USB*/LOCAL UINT8 isHubStatus    (    pHCD_HOST pHost    )    {    UINT8 hubStatus = 0;    UINT16 port;    UINT16 portReg;    UINT16 portStatus;    for (port = 0; port < UHCI_PORTS; port++)	{	portReg = UHCI_PORTSC1 + port * 2;	portStatus = UHC_WORD_IN (portReg);	if ((portStatus & UHCI_PORT_CNCTCHG) != 0 ||	    (portStatus & UHCI_PORT_ENBCHG) != 0 ||	    pHost->cSuspend [port] || 	    pHost->cReset [port])	    {	    hubStatus |= USB_HUB_ENDPOINT_STS_PORT0 << port;	    }	}    return hubStatus;    }/***************************************************************************** intThread - Thread invoked when hardware interrupts are detected** By convention, the <param> t

⌨️ 快捷键说明

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