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

📄 usbhcdohcilib.c

📁 基于VXWORK环境的ARM9 S2410的USB驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
	{	/* Append this ED to the end of the control 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));	}    }/***************************************************************************** unscheduleBulkPipe - removes bulk transfer from the schedule** RETURNS: N/A*/LOCAL VOID unscheduleBulkPipe    (    pHCD_HOST pHost,    pHCD_PIPE pPipe    )    {    pED_WRAPPER pCurEd;    pED_WRAPPER pNextEd;    /* We need to halt processing of bulk transfers before de-linking. */    HC_CLR_BITS (OHCI_HC_CONTROL, OHCI_CTL_BLE);    hcSynch (pHost);    /* Find the pipe's ED and de-link it. */    if ((pCurEd = FROM_PCIPTR (HC_DWORD_IN (OHCI_HC_BULK_HEAD_ED)))				== pPipe->pEd)	{	/* ED is the head of the list. */	HC_DWORD_OUT (OHCI_HC_BULK_HEAD_ED, 		      FROM_LITTLEL (pPipe->pEd->ed.nextEd));	}    else	{	/* Walk the list looking for the ED.	 *	 * NOTE: We know the ED must be on the list, so there's no need	 * to check for the end of list as we proceed. 	 */	while ((pNextEd = ED_FROM_PCIPTR (pCurEd->ed.nextEd)) != pPipe->pEd)					  pCurEd = pNextEd;		pCurEd->ed.nextEd = pPipe->pEd->ed.nextEd;	}    /*       * shutOffListProcessing() halts isoch, interrupt and bulk transfers      * when a device is disconnected, we make sure they are re-enabled.     */                      HC_SET_BITS(OHCI_HC_CONTROL,OHCI_CTL_PLE);    HC_SET_BITS(OHCI_HC_CONTROL,OHCI_CTL_IE);    HC_SET_BITS(OHCI_HC_CONTROL,OHCI_CTL_BLE);    }    /***************************************************************************** scheduleBulkPipe - inserts bulk pipe into the schedule** Inserts the bulk transfer into the portion of the frame list appropriate * for bulk transfers.** RETURNS: N/A*/LOCAL VOID scheduleBulkPipe    (    pHCD_HOST pHost,    pHCD_PIPE pPipe    )    {    pED_WRAPPER pLastEd = FROM_PCIPTR (HC_DWORD_IN (OHCI_HC_BULK_HEAD_ED));    pED_WRAPPER pNextEd;    /* Flush the ED out of the cache before giving it to the HC. */    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 = 0;    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)	    {	    /* 	     * By default USB_BUFFER_SWAP is a no-op, but it can be	     * overridden in BSP stubs as necessary.	     */	    USB_BUFFER_SWAP ((pVOID *) pBfrList->pBfr, pBfrList->bfrLen);	    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;		}	    /*	     * Packet status words need to be swapped before sending on	     * some particular controllers.	     * By default USB_BUFFER_SWAP is a no-op, but it can be	     * overridden in BSP stubs as necessary.	     */	    USB_BUFFER_SWAP ((pVOID *) &pTd->tdi.psw [0],			     frameCount * sizeof (UINT16));	    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)+sizeof(OHCI_TD_GEN));	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:

⌨️ 快捷键说明

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