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

📄 usbhcdohcilib.c

📁 VxWorks BSP for S3C2510A
💻 C
📖 第 1 页 / 共 5 页
字号:

	/* If we deleted this TD, then advance head of TD list. */

	if (tdDeleted)
	    {
	    pPipe->pEd->ed.tdHead = 
	    TO_LITTLEL (TO_PCIPTR (&pPipe->pTds [tdIndex]));
	    DMA_FLUSH (&pPipe->pEd->ed.tdHead, sizeof (pPipe->pEd->ed.tdHead));
	    }
	}

    
    /* Allow the ED to resume. */

    pPipe->pEd->ed.control &= ~(TO_LITTLEL (OHCI_EDCTL_SKIP));
    DMA_FLUSH (&pPipe->pEd->ed.control, sizeof (pPipe->pEd->ed.control));
    }


/***************************************************************************
*
* serviceBusIrps - Services completed USB transactions
*
* RETURNS: N/A
*/

LOCAL VOID serviceBusIrps
    (
    pHCD_HOST pHost
    )

    {
    UINT32 pciPtrToTd;
    pTD_WRAPPER pFirstTd;
    pTD_WRAPPER pTd;
    pUSB_IRP pIrp;
    pIRP_WORKSPACE pWork;
    LIST_HEAD completeIrps = {0};


    /* Walk the list of complete TDs and update the status of their
     * respective IRPs.
     *
     * NOTE: TDs are in reverse order on the list...That is, the TDs
     * which executed first are behind TDs which executed later.  We
     * need to process them in the order in which they executed.
     */

    DMA_INVALIDATE (&pHost->pHcca->doneHead, sizeof (pHost->pHcca->doneHead));

    pFirstTd = NULL;

    pciPtrToTd = pHost->pHcca->doneHead & TO_LITTLEL (OHCI_PTR_MEM_MASK);

    while ((pTd = TD_FROM_PCIPTR (pciPtrToTd)) != NULL)
	{
	DMA_INVALIDATE (pTd, sizeof (*pTd));

	pTd->sw.doneLink = pFirstTd;
	pFirstTd = pTd;

	pciPtrToTd = pTd->tdg.nextTd & TO_LITTLEL (OHCI_PTR_MEM_MASK);
	}


    /* pFirstTd now points to a list of TDs in the order in which they
     * were completed.
     */

    while (pFirstTd != NULL)
	{
	pTd = pFirstTd;
	pFirstTd = pTd->sw.doneLink;

	pIrp = pTd->sw.pWork->pIrp;

	releaseTd (pHost, pTd->sw.pWork->pPipe, pIrp, pTd->sw.pWork, pTd);

	if (pIrp->result != PENDING)
	    {
	    /* IRP is finished...move it to the list of completed IRPs. */

	    usbListUnlink (&pIrp->hcdLink);
	    usbListLink (&completeIrps, pIrp, &pIrp->hcdLink, LINK_TAIL);
	    }
	}


    /* Invoke IRP callbacks for all completed IRPs. */

    while ((pIrp = usbListFirst (&completeIrps)) != NULL)
	{
	usbListUnlink (&pIrp->hcdLink);


	/* See if other IRPs can take advantage of freed TDs. */

	pWork = (pIRP_WORKSPACE) pIrp->hcdPtr;

	if (pIrp->result != OK)
	    unscheduleIrp (pHost, pIrp, pWork);

	scheduleOtherIrps (pHost, pWork->pPipe);


	/* Release IRP workspace and invoke callback. */

	freeIrpWorkspace (pHost, pIrp);
	setIrpResult (pIrp, pIrp->result);
	}
    }


/***************************************************************************
*
* scheduleIrp - schedules IRP for execution
*
* RETURNS: N/A
*/

LOCAL VOID scheduleIrp
    (
    pHCD_HOST pHost,
    pHCD_PIPE pPipe,
    pUSB_IRP pIrp
    )

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


    /* Mark the time the IRP started */

    pWork->irpRunning = TRUE;	    /* running... */
    pWork->startTime = OSS_TIME (); /* and its start time */


    /* Assign starting frame number for isoch transfers */

    if (pPipe->transferType == USB_XFRTYPE_ISOCH)
	{
	if ((pIrp->flags & USB_FLAG_ISO_ASAP) != 0)
	    pWork->isochNext = FINDEX (getFrameNo (pHost) + HC_FRAME_SKIP);
	else
	    pWork->isochNext = FINDEX (pIrp->startFrame);
	}


    /* Assign TDs to direct data transfer. */

    assignTds (pHost, pPipe, pIrp, pWork);
    }



/***************************************************************************
*
* 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;
    pHCD_PIPE pPipe;
    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 HC'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. */

	    pPipe = pWork->pPipe;

	    unscheduleIrp (pHost, pIrp, pWork);
	    freeIrpWorkspace (pHost, pIrp);


	    /* This may create an opportunity to schedule other IRPs. */

	    scheduleOtherIrps (pHost, pPipe);
	    }

	setIrpResult (pIrp, result);    
	}

    return s;
    }



/***************************************************************************
*
* shutOffListProcessing - shut of host controller interrupts for list proc.
*
* Permits the host controller from processing the periodic, interrupt and bulk
* TD lists.
*
* RETURNS: N/A.
*/

LOCAL void shutOffListProcessing
    (
    pHCD_HOST pHost
    )

    {
    UINT32 controlRegChange;

    hcSynch (pHost);

    /* 
     * Read the register and mask off the bits that denote list processing 
     * is enabled 
     */

    /*  Periodic List = Isoc transfers */

    controlRegChange = HC_DWORD_IN (OHCI_HC_CONTROL) & (OHCI_CTL_PLE);
    pHost->pHcControlReg = controlRegChange;
    HC_CLR_BITS (OHCI_HC_CONTROL, pHost->pHcControlReg);

    /*  Interrupt List = Interrupt transfers */

    controlRegChange = HC_DWORD_IN (OHCI_HC_CONTROL) &(OHCI_CTL_IE);
    pHost->pHcControlReg = controlRegChange;
    HC_CLR_BITS (OHCI_HC_CONTROL, pHost->pHcControlReg);

    /*  Bulk List = Bulk transfers */

    controlRegChange = HC_DWORD_IN (OHCI_HC_CONTROL) & OHCI_CTL_BLE;
    pHost->pHcControlReg = controlRegChange; 
    HC_CLR_BITS (OHCI_HC_CONTROL, pHost->pHcControlReg);

    }


/***************************************************************************
*
* 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;
    UINT32 portRegOffset;
    UINT32 portChange;
    UINT32 hcRhPortStatusReg;

    for (port = 0; port < pHost->numPorts; port++)
	{
	portRegOffset = OHCI_HC_RH_PORT_STATUS + port * sizeof (UINT32);

	/* Read & clear pending change status */

	hcRhPortStatusReg = HC_DWORD_IN (portRegOffset);

	portChange = hcRhPortStatusReg & 
		     (OHCI_RHPS_CSC | 
		     OHCI_RHPS_PESC | 
		     OHCI_RHPS_PSSC | 
		     OHCI_RHPS_OCIC | 
		     OHCI_RHPS_PRSC);

	if (portChange != 0)
	    HC_DWORD_OUT (portRegOffset, portChange);

        hcSynch (pHost);

	/* Combine the change bits reported by the HC with those we
	 * already know about.  Then report if a change is pending.
	 */

	pHost->pRhPortChange [port] |= portChange;

	if ((pHost->pRhPortChange [port] & 
	    (OHCI_RHPS_CSC | 
	    OHCI_RHPS_PESC | 
	    OHCI_RHPS_PSSC | 
	    OHCI_RHPS_OCIC | 
	    OHCI_RHPS_PRSC)) != 0)
	    {
	    hubStatus |= USB_HUB_ENDPOINT_STS_PORT0 << port;
	    }

	/*  there was a change - a device has been plugged, or unplugged */

	if ( (hcRhPortStatusReg & OHCI_RHPS_CSC) !=0)

	    /*  A device has been unplugged */

	    if ( (hcRhPortStatusReg & OHCI_RHPS_CCS) == 0 )
		{
		/* Stop the host controller from processing TD's */

	        shutOffListProcessing (pHost);
		}

	}

    return hubStatus;
    }


/***************************************************************************
*
* serviceRootIrps - Services root hub transactions
*
* RETURNS: N/A
*/

LOCAL VOID serviceRootIrps
    (
    pHCD_HOST pHost
    )

    {
    UINT8 hubStatus;
    UINT16 irpCount;
    pUSB_IRP pIrp;


    if ((hubStatus = isHubStatus (pHost)) != 0)
	{
	for (irpCount = pHost->rootIrpCount; irpCount > 0; irpCount--)
	    {
	    pIrp = usbListFirst (&pHost->rootIrps);

	    --pHost->rootIrpCount;
	    usbListUnlink (&pIrp->hcdLink);

	    *(pIrp->bfrList [0].pBfr) = hubStatus;
	    pIrp->bfrList [0].actLen = 1;

	    setIrpResult (pIrp, OK);
	    }
	}
    }


/***************************************************************************
*
* processInterrupt - process a hardware interrupt from the HC
*
* 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 processInterrupt
    (
    pHCD_HOST pHost
    )

    {

    UINT32 intBits = HC_DWORD_IN (OHCI_HC_INT_STATUS) & INT_ENABLE_MASK;

    /* evaluate the interrupt condition */

    if ((intBits & OHCI_INT_SO) != 0)
	{
	/* Scheduling overrun detected.  Record it. */

	pHost->errScheduleOverrun++;
	HC_DWORD_OUT (OHCI_HC_INT_STATUS, OHCI_INT_SO); /* acknowledge */
	}

    if ((intBits & OHCI_INT_UE) != 0)
	{
	/* Unrecoverable error detected.  Record it. */

	pHost->errUnrecoverable++;
	HC_DWORD_OUT (OHCI_HC_INT_STATUS, OHCI_INT_UE); /* acknowledge */
	}

    if ((intBits & OHCI_INT_RD) != 0)
	{
	/* Resume detected. */

	if (pHost->mngmtCallback != NULL)
	    (*pHost->mngmtCallback) (pHost->mngmtCallbackParam, 
				     pHost->handle,
				     0 /* bus number */, 
				     HCD_MNGMT_RESUME);

	HC_DWORD_OUT (OHCI_HC_INT_STATUS, OHCI_INT_RD); /* acknowledge */
	}

    if ((intBits & OHCI_INT_RHSC) != 0)
	{
	/* Root host change detected. */

	serviceRootIrps (pHost);
	HC_DWORD_OUT (OHCI_HC_INT_STATUS, OHCI_INT_RHSC); /* acknowledge */
	}

    if ((intBits & OHCI_INT_WDH) != 0)
	{
	/* The HC has updated the done queue.  This implies completion 
	 * of one or more USB transactions detected. 
	 */

	serviceBusIrps (pHost);
	pHost->pHcca->doneHead = 0;
	HC_DWORD_OUT (OHCI_HC_INT_STATUS, OHCI_INT_WDH); /* acknowledge */
	}


    /* Re-enable HC interrupts */

    HC_DWORD_OUT (OHCI_HC_INT_ENABLE, INT_ENABLE_MASK);
    }


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


/***************************************************************************
*
* intThread - Thread invoked when hardware interrupts are detected
*
* By convention, the <param> to this thread is a pointer to an HCD_HOST.
* This thread waits on the intPending semaphore in the HCD_HOST which is
* signalled by the actual interrupt handler.  This thread will continue
* to process interrupts until intThreadExitRequest is set 

⌨️ 快捷键说明

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