📄 usbhcduhcilib.c
字号:
sizeof (pHost->pFrameList->linkPtr [frame])); /* Advance to the next isoch TD for this IRP. */ pWork->pNextIsochTd = pTd->sw.pNext; if (++pWork->isochNext == UHCI_FRAME_LIST_ENTRIES) pWork->isochNext = 0; pWork->isochCount++; } }/***************************************************************************** scheduleIsochTransfer - inserts isoch IRP in frame list** Schedules an isochronous transfer for the first time.** RETURNS: N/A*/LOCAL VOID scheduleIsochTransfer ( pHCD_HOST pHost, pUSB_IRP pIrp, pIRP_WORKSPACE pWork ) { /* Isochronous transfers are scheduled immediately if the * USB_IRP.flag USB_FLAG_ISO_ASAP is set else beginning in the * frame specified by USB_IRP.startFrame. The number of frames * to be scheduled is equal to the number of TDs in the * IRP_WORKSPACE. */ if ((pIrp->flags & USB_FLAG_ISO_ASAP) != 0) pWork->isochNext = FINDEX (getFrameNo (pHost) + UHC_FRAME_SKIP); else pWork->isochNext = FINDEX (pIrp->startFrame); pWork->isochCount = 0; scheduleIsochFrames (pHost, pIrp, pWork); }/***************************************************************************** unscheduleInterruptTransfer - removes interrupt transfer from work list** RETURNS: N/A*/LOCAL VOID unscheduleInterruptTransfer ( pHCD_HOST pHost, pUSB_IRP pIrp, pIRP_WORKSPACE pWork ) { pQH_WRAPPER pCurrentQh; pQH_WRAPPER pNextQh; UINT16 i; /* We need to search the list of interrupt QHs to find any references * to the indicated QH and purge each one. */ for (i = 0; i < UHCI_FRAME_LIST_ENTRIES; i += pWork->interval) { pCurrentQh = &pHost->pIntAnchorQhs [i]; while ((pNextQh = QH_FROM_PCIPTR (pCurrentQh->qh.qhLink)) != pHost->pCtlAnchorQh && pNextQh->sw.pWork->interval >= pWork->interval && pNextQh != pWork->pQh) { pCurrentQh = pNextQh; } if (pNextQh == pWork->pQh) { /* We found a reference to this QH. Modify the QH list to * skip over it. NOTE: pNextQh == pWork->pQh. */ pCurrentQh->qh.qhLink = pNextQh->qh.qhLink; DMA_FLUSH (&pCurrentQh->qh.qhLink, sizeof (pCurrentQh->qh.qhLink)); } } } /***************************************************************************** scheduleInterruptTransfer - inserts interrupt IRP in frame list** Schedules an interrupt transfer repeatedly in the frame list as* indicated by the service interval.** RETURNS: N/A*/LOCAL VOID scheduleInterruptTransfer ( pHCD_HOST pHost, pUSB_IRP pIrp, pIRP_WORKSPACE pWork ) { pQH_WRAPPER pExistingQh; pQH_WRAPPER pNextQh; UINT16 i; /* Calculate the service interval we'll actually use. */ pWork->interval = calcIntInterval (pWork->pPipe->interval); /* Schedule interrupt transfer periodically throughout frame list */ for (i = 0; i < UHCI_FRAME_LIST_ENTRIES; i += pWork->interval) { /* Find the appropriate point in the list of interrupt QHs for this * frame into which to schedule this QH. This QH needs to be * scheduled ahead of all interrupt QHs which are serviced more * frequently (ie., least frequently serviced QHs come first). */ pExistingQh = &pHost->pIntAnchorQhs [i]; while ((pNextQh = QH_FROM_PCIPTR (pExistingQh->qh.qhLink)) != pHost->pCtlAnchorQh && pNextQh->sw.pWork->interval >= pWork->interval && pNextQh != pWork->pQh) { pExistingQh = pNextQh; } if (pNextQh != pWork->pQh) { if (i == 0) { pWork->pQh->qh.qhLink = pExistingQh->qh.qhLink; DMA_FLUSH (&pWork->pQh->qh, sizeof (pWork->pQh->qh)); } pExistingQh->qh.qhLink = QH_TO_PCIPTR (pWork->pQh); DMA_FLUSH (&pExistingQh->qh.qhLink, sizeof (pExistingQh->qh.qhLink)); } } }/***************************************************************************** unscheduleControlTransfer - removes control transfer from work list** RETURNS: N/A*/LOCAL VOID unscheduleControlTransfer ( pHCD_HOST pHost, pUSB_IRP pIrp, pIRP_WORKSPACE pWork ) { pQH_WRAPPER pCurrentQh; pQH_WRAPPER pNextQh; /* Find the control transfer in the work list and unlink it. */ pCurrentQh = pHost->pCtlAnchorQh; while ((pNextQh = QH_FROM_PCIPTR (pCurrentQh->qh.qhLink)) != pWork->pQh) { pCurrentQh = pNextQh; } if (pNextQh == pWork->pQh) { /* Bipass pWork->pQh. */ pCurrentQh->qh.qhLink = pWork->pQh->qh.qhLink; DMA_FLUSH (&pCurrentQh->qh.qhLink, sizeof (pCurrentQh->qh.qhLink)); if (pHost->pLastCtlQh == pWork->pQh) pHost->pLastCtlQh = pCurrentQh; } } /***************************************************************************** scheduleControlTransfer - inserts control IRP in frame list** Inserts the control transfer into the portion of the frame list * appropriate for control transfers.** RETURNS: N/A*/LOCAL VOID scheduleControlTransfer ( pHCD_HOST pHost, pUSB_IRP pIrp, pIRP_WORKSPACE pWork ) { pQH_WRAPPER pExistingQh; pQH_WRAPPER pNextQh; /* Low speed control transfers must always be scheduled before full * speed control transfers in order to ensure that they execute * completely within a specified frame. */ if (pWork->pPipe->speed == USB_SPEED_LOW) { /* Insert this low speed transfer after currently scheduled low * speed transfers and ahead of any high speed transfers. */ pExistingQh = pHost->pCtlAnchorQh; while ((pNextQh = QH_FROM_PCIPTR (pExistingQh->qh.qhLink)) != pHost->pBulkAnchorQh && pNextQh->sw.pWork->pPipe->speed == USB_SPEED_LOW) { pExistingQh = pNextQh; } } else { /* This is a full speed transfer. Add the QH to the end of the list * of control QHs. */ pExistingQh = pHost->pLastCtlQh; } /* Set this QH's forward link to pExistingQh's forward link */ if ((pWork->pQh->qh.qhLink = pExistingQh->qh.qhLink) == pHost->pciPtrToBulkAnchorQh) { pHost->pLastCtlQh = pWork->pQh; } DMA_FLUSH (&pWork->pQh->qh, sizeof (pWork->pQh->qh)); /* Set the forward link of the previous QH to this QH. */ pExistingQh->qh.qhLink = QH_TO_PCIPTR (pWork->pQh); DMA_FLUSH (&pExistingQh->qh.qhLink, sizeof (pExistingQh->qh.qhLink)); }/***************************************************************************** unscheduleBulkTransfer - removes bulk transfer from work list** RETURNS: N/A*/LOCAL VOID unscheduleBulkTransfer ( pHCD_HOST pHost, pUSB_IRP pIrp, pIRP_WORKSPACE pWork ) { pQH_WRAPPER pCurrentQh; pQH_WRAPPER pNextQh; /* Find the bulk transfer in the work list and unlink it. */ pCurrentQh = pHost->pBulkAnchorQh; while ((pNextQh = QH_FROM_PCIPTR (pCurrentQh->qh.qhLink)) != pWork->pQh) { pCurrentQh = pNextQh; } if (pNextQh == pWork->pQh) { /* Bipass pWork->pQh. */ if (ENABLE_BANDWIDTH_RECLAMATION (pHost)) { if (pCurrentQh == pHost->pBulkAnchorQh && pNextQh->qh.qhLink == pHost->pciPtrToBulkAnchorQh) { pCurrentQh->qh.qhLink = UHC_END_OF_LIST; } else { pCurrentQh->qh.qhLink = pNextQh->qh.qhLink; } } else { pCurrentQh->qh.qhLink = pNextQh->qh.qhLink; } DMA_FLUSH (&pCurrentQh->qh.qhLink, sizeof (pCurrentQh->qh.qhLink)); if (pHost->pLastBulkQh == pNextQh) pHost->pLastBulkQh = pCurrentQh; } } /***************************************************************************** scheduleBulkTransfer - inserts bulk IRP in frame list** Inserts the bulk transfer into the portion of the frame list appropriate * for bulk transfers.** RETURNS: N/A*/LOCAL VOID scheduleBulkTransfer ( pHCD_HOST pHost, pUSB_IRP pIrp, pIRP_WORKSPACE pWork ) { /* Set the forward link of this QH to the forward link of the * QH which is currently last on the bulk list. */ if (ENABLE_BANDWIDTH_RECLAMATION (pHost)) { if (pHost->pLastBulkQh->qh.qhLink == UHC_END_OF_LIST) pWork->pQh->qh.qhLink = pHost->pciPtrToBulkAnchorQh; else pWork->pQh->qh.qhLink = pHost->pLastBulkQh->qh.qhLink; } else { pWork->pQh->qh.qhLink = pHost->pLastBulkQh->qh.qhLink; } DMA_FLUSH (&pWork->pQh->qh, sizeof (pWork->pQh->qh)); /* Set the forward link of the previous QH to this QH. */ pHost->pLastBulkQh->qh.qhLink = QH_TO_PCIPTR (pWork->pQh); DMA_FLUSH (&pHost->pLastBulkQh->qh.qhLink, sizeof (pHost->pLastBulkQh->qh.qhLink)); pHost->pLastBulkQh = pWork->pQh; }/***************************************************************************** unscheduleIrp - Removes QH/TDs for IRP from work UHC work lists** RETURNS: N/A*/LOCAL VOID unscheduleIrp ( pHCD_HOST pHost, pUSB_IRP pIrp, pIRP_WORKSPACE pWork ) { /* un-Scheduling proceeds differently for each transaction type. */ switch (pWork->pPipe->transferType) { case USB_XFRTYPE_ISOCH: unscheduleIsochTransfer (pHost, pIrp, pWork); break; case USB_XFRTYPE_INTERRUPT: unscheduleInterruptTransfer (pHost, pIrp, pWork); break; case USB_XFRTYPE_CONTROL: unscheduleControlTransfer (pHost, pIrp, pWork); break; case USB_XFRTYPE_BULK: unscheduleBulkTransfer (pHost, pIrp, pWork); break; } }/***************************************************************************** scheduleIrp - try to schedule an IRP in the frame list** RETURNS: N/A*/LOCAL VOID scheduleIrp ( pHCD_HOST pHost, pUSB_IRP pIrp ) { pIRP_WORKSPACE pWork = (pIRP_WORKSPACE) pIrp->hcdPtr; pHCD_PIPE pPipe = pWork->pPipe; /* prepare TDs */ assignTds (pHost, pIrp, pWork); /* Mark the time the IRP was first scheduled. */ if (!pWork->irpRunning) { pWork->irpRunning = TRUE; pWork->startTime = OSS_TIME (); } /* Scheduling proceeds differently for each transaction type. */ switch (pPipe->transferType) { case USB_XFRTYPE_ISOCH: scheduleIsochTransfer (pHost, pIrp, pWork); break; case USB_XFRTYPE_INTERRUPT: scheduleInterruptTransfer (pHost, pIrp, pWork); break; case USB_XFRTYPE_CONTROL: scheduleControlTransfer (pHost, pIrp, pWork); break; case USB_XFRTYPE_BULK: scheduleBulkTransfer (pHost, pIrp, pWork); break; } }/***************************************************************************** rescheduleTds - Examine the given IRP and see if it needs servicing** <pIrp> is an IRP which may/may not have been assigned QHs and TDs and* currently be schedule for execution. Examine the <pIrp> and its* associated USB_WORKSPACE in <pWork> (which might be NULL). If no work* has been scheduled or if no TDs have been completed by the UHC, then* we do nothing. If there are TDs which have been completed, then we* release them to the "free" pool. If work remains to be done, then we* reschedule the TDs. If no work remains to be done or if there is an* error, then we report that the IRP is complete.** RETURNS: OK = IRP completed ok* PENDING = IRP still being executed* S_usbHcdLib_xxx = IRP failed with error*/LOCAL int rescheduleTds ( pHCD_HOST pHost, pUSB_IRP pIrp, pIRP_WORKSPACE pWork )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -