usbhcduhcilib.c
来自「cpc-1631的BSP包for VxWorks操作系统」· C语言 代码 · 共 2,337 行 · 第 1/5 页
C
2,337 行
}
/* Update the bandwidth-in-use for this controller.
*
* NOTE: The pWork->nanoseconds field is 0 for all transfer types
* except low speed control transfers, so the following calculation
* often has no effect.
*/
pHost->nanoseconds += pWork->nanoseconds - nanosecondsAtStart;
}
/***************************************************************************
*
* unlinkIsochTd - unlink an isochronous TD
*
* Searches the indicated <frame> for a TD which corresponds to the
* IRP_WORKSPACE <pWork> (and hence which correspond to a given TD).
* If found, the TD is unlinked.
*
* RETURNS: N/A
*/
LOCAL VOID unlinkIsochTd
(
pHCD_HOST pHost,
pIRP_WORKSPACE pWork,
UINT32 frame
)
{
pUINT32 pPciPtrToTd;
pTD_WRAPPER pTd;
/* Search frame for a TD belonging to this IRP and remove it from the
* work list. We've exhausted the list of isochronous TDs when we
* reach the "interrupt anchor" QH.
*/
pPciPtrToTd = &pHost->pFrameList->linkPtr [frame];
pTd = TD_FROM_PCIPTR (*pPciPtrToTd);
while (pTd != (pTD_WRAPPER) &pHost->pIntAnchorQhs [frame])
{
if (pTd->sw.pWork == pWork)
{
/* We found a TD for this IRP. Unlink it. */
*pPciPtrToTd = pTd->td.linkPtr;
DMA_FLUSH (pPciPtrToTd, sizeof (*pPciPtrToTd));
--pWork->isochCount;
break;
}
pPciPtrToTd = (pUINT32) &pTd->td.linkPtr;
pTd = TD_FROM_PCIPTR (pTd->td.linkPtr);
}
}
/***************************************************************************
*
* unscheduleIsochTransfer - removes isochronous transfer from work list
*
* RETURNS: N/A
*/
LOCAL VOID unscheduleIsochTransfer
(
pHCD_HOST pHost,
pUSB_IRP pIrp,
pIRP_WORKSPACE pWork
)
{
UINT16 frame;
/* Remove all pending isoch TDs for this IRP from the work list */
for (frame = 0;
frame < UHCI_FRAME_LIST_ENTRIES && pWork->isochCount > 0;
frame++)
{
unlinkIsochTd (pHost, pWork, frame);
}
}
/***************************************************************************
*
* scheduleIsochFrames - insert isoch frames into work list
*
* Schedules isochronous transfers into frames.
*
* RETURNS: N/A
*/
LOCAL VOID scheduleIsochFrames
(
pHCD_HOST pHost,
pUSB_IRP pIrp,
pIRP_WORKSPACE pWork
)
{
pTD_WRAPPER pTd;
UINT16 frame;
/* Schedule all initialized TDs onto the work list */
while ((pTd = pWork->pNextIsochTd) != NULL &&
pWork->isochCount < UHCI_FRAME_LIST_ENTRIES)
{
/* Link the TD into the work list. */
pTd->sw.frameNo = frame = pWork->isochNext;
pTd->td.linkPtr = pHost->pFrameList->linkPtr [frame];
DMA_FLUSH (&pTd->td.linkPtr, sizeof (pTd->td.linkPtr));
pHost->pFrameList->linkPtr [pWork->isochNext] = TO_PCIPTR (pTd);
DMA_FLUSH (&pHost->pFrameList->linkPtr [frame],
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
)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?