📄 usbhcdohcilib.c
字号:
LOCAL UINT16 getFrameNo ( pHCD_HOST pHost ) { return OHCI_FMN_FN (HC_DWORD_IN (OHCI_HC_FM_NUMBER)); }/***************************************************************************** setFrameInterval - sets OHCI frame interval ** RETURNS: N/A*/LOCAL VOID setFrameInterval ( pHCD_HOST pHost, UINT16 sofInterval ) { UINT32 fmi; fmi = HC_DWORD_IN (OHCI_HC_FM_INTERVAL) & ~OHCI_FMI_FIT; fmi ^= OHCI_FMI_FIT; fmi |= OHCI_FMI_FI_FMT (sofInterval); fmi |= OHCI_FMI_FSMPS_FMT (((sofInterval - MAX_FRAME_OVERHEAD) * 6) / 7); HC_DWORD_OUT (OHCI_HC_FM_INTERVAL, fmi); pHost->sofInterval = sofInterval; }/***************************************************************************** hcSynch - give the host controller a chance to synchronize** RETURNS: N/A*/LOCAL VOID hcSynch ( pHCD_HOST pHost ) { UINT16 currentFrameNo = getFrameNo (pHost); while (getFrameNo (pHost) == currentFrameNo); semTake (pHost->hcSyncSem, 1); semTake (pHost->hcSyncSem, 1); }/***************************************************************************** setIrpResult - sets result in IRP and executes IRP callback** RETURNS: value from Irp result field*/LOCAL int setIrpResult ( pUSB_IRP pIrp, int result ) { if (result != PENDING) { pIrp->result = result; if (pIrp->usbdCallback != NULL) (*pIrp->usbdCallback) (pIrp); else if (pIrp->userCallback != NULL) (*pIrp->userCallback) (pIrp); } return result; }/***************************************************************************** calcIntInterval - calculates the scheduling interval for interrupt transfer** RETURNS: Actual interval to be used for interrupt transfer*/LOCAL UINT16 calcIntInterval ( UINT16 interval /* 1 <= requested interval <= OHCI_INT_ED_COUNT */ ) { UINT16 i; /* Select an interval which is the largest power of two less than or * equal to the requested interval. */ for (i = 2; i < OHCI_INT_ED_COUNT + 1; i <<= 1) { if (i > interval) break; } return i >> 1; }/***************************************************************************** freeIrpWorkspace - releases IRP_WORKSPACE** Releases the IRP_WORKSPACE associated with an IRP (if there is one).** RETURNS: N/A*/LOCAL VOID freeIrpWorkspace ( pHCD_HOST pHost, pUSB_IRP pIrp ) { pIRP_WORKSPACE pWork = (pIRP_WORKSPACE) pIrp->hcdPtr; if (pWork != NULL) { OSS_FREE (pWork); pIrp->hcdPtr = NULL; } }/***************************************************************************** allocIrpWorkspace - creates workspace for IRP** Creates an IRP_WORKSPACE structure to manage the IRP data transfer.** RETURNS: TRUE if successful, else FALSE*/LOCAL BOOL allocIrpWorkspace ( pHCD_HOST pHost, pHCD_PIPE pPipe, pUSB_IRP pIrp ) { pIRP_WORKSPACE pWork; /* Allocate IRP_WORKSPACE */ if ((pWork = OSS_CALLOC (sizeof (*pWork))) == NULL) return FALSE; pIrp->hcdPtr = pWork; pWork->pPipe = pPipe; pWork->pIrp = pIrp; return TRUE; }/***************************************************************************** isBandwidthTracked - determines if bandwidth is tracked for this transfer** Since the USBD has already reserved adequate bandwidth for isochronous* and interrupt transfers, we only track low speed control transfers.** RETURNS: TRUE if bandwidth tracked, else FALSE.*/LOCAL BOOL isBandwidthTracked ( pHCD_PIPE pPipe ) { if (pPipe->transferType == USB_XFRTYPE_CONTROL && pPipe->speed == USB_SPEED_LOW) return TRUE; return FALSE; }/***************************************************************************** dirFromPid - returns USB_DIR_xxxx based on USB_PID_xxxx** RETURNS: USB_DIR_xxxx*/LOCAL UINT16 dirFromPid ( UINT16 pid ) { switch (pid) { case USB_PID_SETUP: case USB_PID_OUT: return USB_DIR_OUT; case USB_PID_IN: return USB_DIR_IN; default: return USB_DIR_IN; } }/***************************************************************************** unscheduleIsochPipe - removes an isoch pipe from the schedule** RETURNS: N/A*/LOCAL VOID unscheduleIsochPipe ( pHCD_HOST pHost, pHCD_PIPE pPipe ) { pUINT32 pPciPtrToEd; pED_WRAPPER pCurEd; /* Note: Instead of halting periodic transfers before delinking, we * immediately delink them and afterward wait for the next frame to start... * This ensures that caller won't de-allocate the structures while the * HC may still be referencing them. */ /* Walk the isoch. list until we find the ED to be removed. */ pPciPtrToEd = (pUINT32) &pHost->pIsochAnchorEd->ed.nextEd; while ((pCurEd = ED_FROM_PCIPTR (*pPciPtrToEd)) != pPipe->pEd) { pPciPtrToEd = (pUINT32) &pCurEd->ed.nextEd; } *pPciPtrToEd = pPipe->pEd->ed.nextEd; DMA_FLUSH (pPciPtrToEd, sizeof (*pPciPtrToEd)); /* * 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); /* Wait for the HC to make sure the structure is really released. */ hcSynch (pHost); } /***************************************************************************** scheduleIsochPipe - inserts isoch pipe into the schedule** Schedules an isochronous transfer for the first time.** RETURNS: N/A*/LOCAL VOID scheduleIsochPipe ( pHCD_HOST pHost, pHCD_PIPE pPipe ) { pED_WRAPPER pLastEd; pED_WRAPPER pNextEd; /* Flush the ED out of the cache before giving it to the HC. */ DMA_FLUSH (pPipe->pEd, sizeof (*pPipe->pEd)); /* Append this ED to the end of the isoch. list. */ pLastEd = pHost->pIsochAnchorEd; 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)); }/***************************************************************************** unscheduleInterruptPipe - removes interrupt pipe from the schedule** RETURNS: N/A*/LOCAL VOID unscheduleInterruptPipe ( pHCD_HOST pHost, pHCD_PIPE pPipe ) { pUINT32 pPciPtrToEd; pED_WRAPPER pCurEd; UINT16 i; /* Note: Instead of halting periodic transfers before delinking, we * immediately delink them and afterward wait for the next frame to start... * This ensures that caller won't de-allocate the structures while the * HC may still be referencing them. */ /* Remove the pipe from the interrupt lists. */ for (i = 0; i < OHCI_INT_ED_COUNT; i += pPipe->actInterval) { /* Walk this list until we find the ED to be removed. */ pPciPtrToEd = &pHost->pHcca->intEdTable [i]; while ((pCurEd = ED_FROM_PCIPTR (*pPciPtrToEd)) != pHost->pIsochAnchorEd && pCurEd->sw.pPipe->actInterval >= pPipe->actInterval && pCurEd != pPipe->pEd) { pPciPtrToEd = (pUINT32) &pCurEd->ed.nextEd; } if (pCurEd == pPipe->pEd) { *pPciPtrToEd = pPipe->pEd->ed.nextEd; DMA_FLUSH (pPciPtrToEd, sizeof (*pPciPtrToEd)); } } /* * 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); /* Wait for the HC to make sure the structure is really released. */ hcSynch (pHost); } /***************************************************************************** scheduleInterruptPipe - inserts interrupt pipe into the schedule** Schedules an interrupt transfer repeatedly in the frame list as* indicated by the service interval.** RETURNS: N/A*/LOCAL VOID scheduleInterruptPipe ( pHCD_HOST pHost, pHCD_PIPE pPipe ) { pUINT32 pPciPtrToEd; pED_WRAPPER pCurEd; UINT16 i; /* Schedule the pipe onto the interrupt lists. */ for (i = 0; i < OHCI_INT_ED_COUNT; i += pPipe->actInterval) { /* Walk this list until we hit the isoch. anchor or until we * find an pipe with a smaller interval (higher frequency). */ pPciPtrToEd = &pHost->pHcca->intEdTable [i]; while ((pCurEd = ED_FROM_PCIPTR (*pPciPtrToEd)) != pHost->pIsochAnchorEd && pCurEd->sw.pPipe->actInterval >= pPipe->actInterval && pCurEd != pPipe->pEd) { pPciPtrToEd = (pUINT32) &pCurEd->ed.nextEd; } if (pCurEd != pPipe->pEd) { if (i == 0) { pPipe->pEd->ed.nextEd = *pPciPtrToEd; DMA_FLUSH (pPipe->pEd, sizeof (*pPipe->pEd)); } *pPciPtrToEd = TO_LITTLEL (TO_PCIPTR (pPipe->pEd)); DMA_FLUSH (pPciPtrToEd, sizeof (*pPciPtrToEd)); } } }/***************************************************************************** unscheduleControlPipe - removes control pipe from the schedule** RETURNS: N/A*/LOCAL VOID unscheduleControlPipe ( pHCD_HOST pHost, pHCD_PIPE pPipe ) { pED_WRAPPER pCurEd; pED_WRAPPER pNextEd; /* We need to halt processing of control transfers before de-linking. */ HC_CLR_BITS (OHCI_HC_CONTROL, OHCI_CTL_CLE); hcSynch (pHost); /* Find the pipe's ED and de-link it. */ if ((pCurEd = FROM_PCIPTR (HC_DWORD_IN (OHCI_HC_CONTROL_HEAD_ED))) == pPipe->pEd) { /* ED is the head of the list */ HC_DWORD_OUT (OHCI_HC_CONTROL_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); /* Re-enable the control list. */ HC_SET_BITS (OHCI_HC_CONTROL, OHCI_CTL_CLE); } /***************************************************************************** scheduleControlPipe - inserts control pipe into the schedule** Inserts the control transfer into the portion of the frame list * appropriate for control transfers.** RETURNS: N/A*/LOCAL VOID scheduleControlPipe ( pHCD_HOST pHost, pHCD_PIPE pPipe ) { pED_WRAPPER pLastEd = FROM_PCIPTR (HC_DWORD_IN (OHCI_HC_CONTROL_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 control list. */ HC_DWORD_OUT (OHCI_HC_CONTROL_HEAD_ED, TO_PCIPTR (pPipe->pEd)); } else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -