📄 usbhcdohcilib.c
字号:
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; /* * In some case, transmitted data is still used at either drivers or * applications and need to be re-swapped if they are swapped before * sending. */ if (pIrp->bfrList[pWork->bfrNo].pid == USB_PID_SETUP || pIrp->bfrList[pWork->bfrNo].pid == USB_PID_OUT) { if (pTd->sw.curBfrPtr != 0) { if (FROM_LITTLEL (pTd->tdg.cbp) == 0) { /* * By default USB_BUFFER_SWAP is a no-op, but it can be * overridden in BSP stubs as necessary. */ USB_BUFFER_SWAP ((pVOID *) pTd->sw.curBfrPtr, FROM_LITTLEL (pTd->tdg.be) - pTd->sw.curBfrPtr + 1); } else { /* * By default USB_BUFFER_SWAP is a no-op, but it can be * overridden in BSP stubs as necessary. */ USB_BUFFER_SWAP ((pVOID *) pTd->sw.curBfrPtr, FROM_LITTLEL (pTd->tdg.cbp) - pTd->sw.curBfrPtr + 1); } } } /* 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. */ if (pIrp->result == PENDING) { pBfrList = &pIrp->bfrList [pWork->bfrNo]; /* Note: In following assignment: pTd->tdg.be == pTd->tdi.be */ bfrEnd = FROM_LITTLEL (pTd->tdg.be); if (pPipe->transferType == USB_XFRTYPE_ISOCH) { /* For an isoch transfer make sure each frame was executed. */ frameCount = OHCI_TICTL_FC (control); /* * Re-swap packet status words before reading if they are swapped * at transmit. * 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)); for (actLen = i = 0; i < frameCount; i++) { psw = FROM_LITTLEW (pTd->tdi.psw [i]); if (OHCI_TIPSW_CC (psw) != OHCI_CC_NO_ERROR) { pIrp->result = S_usbHcdLib_ISOCH_FAULT; break; } } actLen = bfrEnd - pTd->sw.curBfrPtr + 1; } else { /* For a general transfer, calculate the actual data transferred */ curBfrPtr = FROM_LITTLEL (pTd->tdg.cbp); if (pTd->sw.curBfrPtr == 0) { /* we requested a 0-length transfer */ actLen = 0; } else { /* we requested a transfer of non-zero length */ if (curBfrPtr == 0) { /* transfer was successful...full length requested. */ actLen = bfrEnd - pTd->sw.curBfrPtr + 1; } else { /* short packet was transferred. curBfrPtr addresses * the byte following the last byte transferred. */ actLen = curBfrPtr - pTd->sw.curBfrPtr; } } /* Update the IRP's data toggle. */ pIrp->dataToggle = ((tdHead & OHCI_PTR_TGL_CARRY) == 0) ? USB_DATA0 : USB_DATA1; } /* Update the BFR_LIST entry and check for underrun. */ pBfrList->actLen += actLen; if (pTd->sw.curBfrPtr != 0 && actLen < bfrEnd - pTd->sw.curBfrPtr + 1) { underrun = TRUE; if ((pIrp->flags & USB_FLAG_SHORT_FAIL) != 0) { pIrp->result = S_usbHcdLib_SHORT_PACKET; } } if (pBfrList->actLen == pBfrList->bfrLen || underrun) { pWork->bfrNo++; pWork->bfrOffset = 0; pWork->zeroLenMapped = FALSE; } } /* Indicate that the TD is no longer in use. */ memset (pTd, 0, sizeof (*pTd)); pPipe->freeTdCount++; /* Check if the IRP is complete. */ if (pIrp->result == PENDING) { if (pWork->bfrNo == pIrp->bfrCount) { /* Yes, all buffers for the IRP have been processed. */ pIrp->result = OK; } else { /* No, schedule more work for the IRP. */ assignTds (pHost, pPipe, pIrp, pWork); } } /* If this is an isochronous pipe and if we've fully mapped the current * IRP, then check if there are other IRPs which need to be scheduled. */ if (pPipe->transferType == USB_XFRTYPE_ISOCH && ((pWork->bfrNo + 1 == pIrp->bfrCount && pWork->bfrOffset == pIrp->bfrList [pWork->bfrNo].bfrLen) || pWork->bfrNo == pIrp->bfrCount)) { scheduleOtherIrps (pHost, pPipe); } /* If the IRP is complete, invalidate the cache for any input buffers. */ if (pIrp->result != PENDING) { 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); /* * By default USB_BUFFER_SWAP is a no-op, but can be * overridden in BSP stubs as necessary. */ USB_BUFFER_SWAP ((pVOID *) pBfrList->pBfr, pBfrList->actLen); } } } }/***************************************************************************** unscheduleIrp - unschedules IRP** RETURNS: N/A*/LOCAL VOID unscheduleIrp ( pHCD_HOST pHost, pUSB_IRP pIrp, pIRP_WORKSPACE pWork ) { pHCD_PIPE pPipe = pWork->pPipe; UINT16 i; UINT16 tdIndex; BOOL tdDeleted; /* If the IRP has no workspace, then it cannot be using TDs, so return * immediately. */ if (pWork == NULL) return; /* Halt processing on this ED. */ pPipe->pEd->ed.control |= TO_LITTLEL (OHCI_EDCTL_SKIP); DMA_FLUSH (&pPipe->pEd->ed.control, sizeof (pPipe->pEd->ed.control)); hcSynch (pHost); /* Search the pipe which owns this IRP to see if any of its TDs are * in use by this IRP. If so, release them and allow another IRP (if * one exists) to use them. */ tdIndex = pPipe->freeTdIndex; for (i = 0; i < pPipe->tdCount; i++) { tdDeleted = FALSE; if (pPipe->pTds [tdIndex].sw.pWork == pWork) { pPipe->freeTdCount++; memset (&pPipe->pTds [tdIndex], 0, sizeof (pPipe->pTds [tdIndex])); tdDeleted = TRUE; } if (++tdIndex == pPipe->tdCount) tdIndex = 0; /* 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -