📄 usbhcduhcilib.c
字号:
/* * HCD_HOST * * HCD_HOST maintains all information about a connection to a specific * universal host controller (UHC). */typedef struct hcd_host { HCD_CLIENT_HANDLE handle; /* handle associated with host */ BOOL shutdown; /* TRUE during shutdown */ PCI_CFG_HEADER pciCfgHdr; /* PCI config header for UHC */ UINT16 uhcAttributes; /* vendor/model specific attributes */ UINT32 ioBase; /* Base I/O address */ USB_HCD_MNGMT_CALLBACK mngmtCallback; /* callback routine for mngmt evt */ pVOID mngmtCallbackParam; /* caller-defined parameter */ MUTEX_HANDLE hostMutex; /* guards host structure */ THREAD_HANDLE intThread; /* Thread used to handle interrupts */ SEM_HANDLE intPending; /* semaphore indicates int pending */ BOOL intThreadExitRequest; /* TRUE when intThread should terminate */ SEM_HANDLE intThreadExit; /* signalled when int thread exits */ UINT32 intCount; /* number of interrupts processed */ BOOL intInstalled; /* TRUE when h/w int handler installed */ UINT16 intBits; /* interrupt bits */ UINT16 rootAddress; /* current address of root hub */ UINT8 configValue; /* current configuration value */ BOOL powered [UHCI_PORTS]; /* TRUE if port is powered */ BOOL cSuspend [UHCI_PORTS]; /* TRUE if suspend status change */ BOOL cReset [UHCI_PORTS]; /* TRUE if reset status change */ /* descriptor fields order-dependent */ USB_DEVICE_DESCR devDescr; /* standard device descriptor */ USB_CONFIG_DESCR configDescr; /* standard config descriptor */ USB_INTERFACE_DESCR ifDescr; /* standard interface descriptor */ USB_ENDPOINT_DESCR endpntDescr; /* standard endpoint descriptor */ USB_HUB_DESCR hubDescr; /* root hub descriptor */ LIST_HEAD pipes; /* active pipes */ UINT16 rootIrpCount; /* count of entries on pRootIrps */ LIST_HEAD rootIrps; /* IRPs pending on root hub */ LIST_HEAD busIrps; /* IRPs pending on devices not */ /* including root hub */ char *dmaPool; /* memory alloc'd by cacheDmaMalloc() */ PART_ID memPartId; /* memory partition ID */ pUHCI_FRAME_LIST pFrameList; /* UHC frame list */ pQH_WRAPPER pIntAnchorQhs; /* UHC QH "anchor" list */ pQH_WRAPPER pCtlAnchorQh; /* Anchor for ctl transfer QHs */ pQH_WRAPPER pLastCtlQh; /* pointer to last ctl QH in use */ pQH_WRAPPER pBulkAnchorQh; /* Anchor for bulk transfer QHs */ UINT32 pciPtrToBulkAnchorQh; /* pre-calculated PCIPTR */ pQH_WRAPPER pLastBulkQh; /* pointer to last bulk QH in use */ UINT32 hostErrCount; /* incremented if host ctlr reports err */ UINT32 nanoseconds; /* current worst case of bus time */ /* required for scheduled TDs */ UINT16 sofInterval; /* current SOF interval */ BOOL suspended; /* TRUE when global suspend is TRUE */ SEM_ID hcSyncSem; /* syncronization semaphore */ } HCD_HOST, *pHCD_HOST;/* locals *//* UHC vendor/device table. * * The following table defines the features/operating modes we use for * UHCI controllers with which we've tested. * * Intel PIIX4: Hard system crashes have been observed when enabling * bandwidth reclamation on the PIIX4. There are unconfirmed reports * that the PIIX3 can consume all available PCI bandwidth when all QHs * on the bandwidth reclamation loop are complete, thus hanging the * system. We surmise that this may also be the cause of the problems * observed on the PIIX4. * * ViaTech: The ViaTech parts appear to work fine with bandwidth * reclamation enabled. */#define UHC_ATTR_INTEL_PIIX (UHC_ATTR_HC_SYNCH)#define UHC_ATTR_VIATECH (UHC_ATTR_HC_SYNCH | UHC_ATTR_BW_RECLAMATION)LOCAL UHC_TABLE uhcTable [] = { {PCI_VID_INTEL, PCI_DID_INTEL_PIIX3, UHC_ATTR_INTEL_PIIX}, {PCI_VID_INTEL, PCI_DID_INTEL_PIIX4, UHC_ATTR_INTEL_PIIX}, {PCI_VID_VIATECH, PCI_DID_VIATECH_82C586, UHC_ATTR_VIATECH}, {0, 0, 0}};/* Language descriptor */LOCAL USB_LANGUAGE_DESCR langDescr = {sizeof (USB_LANGUAGE_DESCR), USB_DESCR_STRING, {TO_LITTLEW (UNICODE_ENGLISH)}};/***************************************************************************** getUhcAttributes - get attributes based on type of UHCI controller** Based on information in the PCI configuration header passed by the* caller, searches for a matching entry in the uhcTable[]. If one is* found, returns the corresponding attribute value. If no entry is* found, returns the default value.** RETURNS: UINT16 vector containing UHC attributes*/LOCAL UINT16 getUhcAttributes ( pPCI_CFG_HEADER pCfgHdr ) { pUHC_TABLE pTable; for (pTable = &uhcTable [0]; pTable->pciVendorId != 0; pTable++) if (pTable->pciVendorId == pCfgHdr->vendorId && pTable->pciDeviceId == pCfgHdr->deviceId) { return pTable->uhcAttributes; } return UHC_ATTR_DEFAULT; }/***************************************************************************** waitOnBits - wait for a word register bit to reach the desired state** RETURNS: TRUE if successful, else FALSE if desired bit state not detected*/LOCAL BOOL waitOnBits ( pHCD_HOST pHost, UINT16 p, UINT16 bitMask, UINT16 bitState ) { UINT32 start = OSS_TIME (); BOOL desiredState; while (!(desiredState = ((UHC_WORD_IN (p) & bitMask) == bitState)) && OSS_TIME () - start < BIT_TIMEOUT) ; return desiredState; }/***************************************************************************** getFrameNo - returns current hardware frame number** RETURNS: value of current frame number*/LOCAL UINT16 getFrameNo ( pHCD_HOST pHost ) { return FINDEX (UHC_WORD_IN (UHCI_FRNUM)); }/***************************************************************************** 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; }/***************************************************************************** planAheadTime - returns "plan-ahead time"** The "plan ahead interval" is the maximum time that code should "plan* ahead when setting up work for the UHC. It is expected that interrupt* latency will never exceed one half of this time.** RETURNS: plan ahead time in msec*/LOCAL UINT16 planAheadTime ( pHCD_HOST pHost ) { return PLAN_AHEAD_TIME; }/***************************************************************************** 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 <= 255 */ ) { UINT16 i; /* Select an interval which is the largest power of two less than or * equal to the requested interval. */ for (i = 2; i < 256; i <<= 1) { if (i > interval) break; } return i >> 1; }/***************************************************************************** calcQhTd - calculates number of QHs and TDs to be allocated for IRP** Calculates the number of TDs/QHs which need to be allocated for <pIrp>* in order to complete the IRP or manage it through at least the "plan* ahead interval." Returns number of TDs in <pTdCount> and QHs in* <pQhCount>.** RETURNS: N/A*/LOCAL VOID calcQhTd ( pHCD_HOST pHost, pHCD_PIPE pPipe, pUSB_IRP pIrp, pUINT16 pQhCount, pUINT16 pTdCount ) { UINT16 qhCount = 0; UINT16 tdCount = 0; UINT16 trialTdCount; UINT32 bytesPerFrame; /* The calculation of TDs/QHs varies based on the type of transfer */ switch (pPipe->transferType) { case USB_XFRTYPE_ISOCH: /* IRPs for isochronous transfers have one or more bfrList[] * entries which requires a variable number of TDs. There * will be a single TD per frame, and the number of TDs * is bounded by the "plan ahead time". * * NOTE: for isoch transfers, maxPacketSize is the number * of bytes to be transmitted each frame. */ qhCount = 0; bytesPerFrame = pPipe->bandwidth / 1000L; trialTdCount = (pIrp->transferLen + bytesPerFrame - 1) / bytesPerFrame; tdCount = min (trialTdCount, planAheadTime (pHost)); break; case USB_XFRTYPE_INTERRUPT: /* IRPs for interrupt transfers have one or more bfrList[] * entries. Each IRP requires a single QHs which may be linked * into multiple frame lists (to allow it to be scheduled * periodically) plus a variable number of TDs. */ qhCount = 1; trialTdCount = (pIrp->transferLen + pPipe->maxPacketSize - 1) / pPipe->maxPacketSize; tdCount = min (trialTdCount, MAX_IRP_TDS); break; case USB_XFRTYPE_CONTROL: /* IRPs for control transfers have two or more bfrList[] * entries. We need one QH for the transfer plus one TD * for the Setup packet (first bfrList[] entry) plus * a variable number of TDs for the additional bfr list entries * plus a final TD for the status packet. There is an overriding * limit on the number of TDs per control IRP set at MAX_IRP_TDS. * * NOTE: For low-speed control transfers, we impose a limit of * one oustanding TD at a time. */ qhCount = 1; if (pPipe->speed == USB_SPEED_LOW) { tdCount = 1; } else { tdCount = 2; /* for Setup and status packets */ if (pIrp->bfrCount > 1) { trialTdCount = (pIrp->transferLen - pIrp->bfrList [0].bfrLen + pPipe->maxPacketSize - 1) / pPipe->maxPacketSize; tdCount += min (trialTdCount, MAX_IRP_TDS - tdCount); } } break; case USB_XFRTYPE_BULK: /* IRPs for bulk transfers have one or more bfrList[] entries. * Each IRP requires a single QH plus a variable number of TDs. */ qhCount = 1; trialTdCount = (pIrp->transferLen + pPipe->maxPacketSize - 1) / pPipe->maxPacketSize; tdCount = min (trialTdCount, MAX_IRP_TDS); break; } /* return results */ if (pQhCount != NULL) *pQhCount = qhCount; if (pTdCount != NULL) *pTdCount = tdCount; }/***************************************************************************** freeIrpWorkspace - releases IRP_WORKSPACE and related QHs and TDs** Releases all QHs and TDs associated with an IRP_WORKSPACE and frees* the IRP_WORKSPACE structure itself.** RETURNS: N/A*/LOCAL VOID freeIrpWorkspace ( pHCD_HOST pHost, pUSB_IRP pIrp ) { pIRP_WORKSPACE pWork = (pIRP_WORKSPACE) pIrp->hcdPtr; if (pWork != NULL) { if (pWork->pQh != NULL) DMA_FREE (pWork->pQh); if (pWork->pTdPool != NULL) DMA_FREE (pWork->pTdPool); OSS_FREE (pWork); pIrp->hcdPtr = NULL; } }/***************************************************************************** allocIrpWorkspace - allocates QH and TD structures for IRP** Calculates the required number of QH and TD structures for an IRP* and allocates aligned memory. Also creates an IRP_WORKSPACE structure* to manage the QHs and TDs allocated for the IRP and links it into the* IRP.** RETURNS: TRUE if successful, else FALSE*/LOCAL BOOL allocIrpWorkspace ( pHCD_HOST pHost, pHCD_PIPE pPipe, pUSB_IRP pIrp ) { pIRP_WORKSPACE pWork; UINT16 tdLen; UINT16 i; /* Allocate IRP_WORKSPACE */ if ((pWork = OSS_CALLOC (sizeof (*pWork))) == NULL) return FALSE; pIrp->hcdPtr = pWork; pWork->pPipe = pPipe; pWork->pIrp = pIrp; /* Calculate number of QHs and TDs */ calcQhTd (pHost, pPipe, pIrp, &pWork->qhCount, &pWork->tdCount); /* Allocate QHs and TDs */ if (pWork->qhCount > 0) { if ((pWork->pQh = DMA_MALLOC (sizeof (QH_WRAPPER), UHCI_QH_ALIGNMENT)) == NULL) { freeIrpWorkspace (pHost, pIrp); return FALSE; } memset (pWork->pQh, 0, sizeof (QH_WRAPPER)); pWork->pQh->sw.pWork = pWork; pWork->pQh->qh.tdLink = UHC_END_OF_LIST; } if (pWork->tdCount > 0) { tdLen = pWork->tdCount * sizeof (TD_WRAPPER);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -