📄 usbhcdohcilib.c
字号:
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); 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); } } }/***************************************************************************** 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); 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 control 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 */ controlRegChange = HC_DWORD_IN (OHCI_HC_CONTROL) & (OHCI_CTL_CLE | 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -