usbhcduhcilib.c
来自「cpc-1631的BSP包for VxWorks操作系统」· C语言 代码 · 共 2,337 行 · 第 1/5 页
C
2,337 行
UINT16 qhCount; /* count of QHs allocated for IRP */
pQH_WRAPPER pQh; /* pointer to QH for this transfer */
UINT16 tdCount; /* count of TDs allocated for IRP */
pTD_WRAPPER pTdPool; /* pointer to block of TDs allocated */
pTD_WRAPPER pTdFree; /* unused TDs */
pTD_WRAPPER pTdInUse; /* first TD in use */
pTD_WRAPPER pLastTdInUse; /* pointer to last TD */
UINT32 nanoseconds; /* bus time required for TDs in use */
UINT16 bfrNo; /* highest IRP bfrList[] serviced */
UINT32 bfrOffset; /* offset into bfrList[].pBfr */
BOOL zeroLenMapped; /* TRUE when zero len bfrList [] serviced */
UINT16 interval; /* how often interrupt xfr scheduled */
UINT32 isochTdsCreated; /* count of isoch TDs created, in total */
UINT32 frameCount; /* count of frames used for isoch pipe */
UINT32 bytesSoFar; /* bytes transferred so far for isoch pipe */
UINT16 isochNext; /* next isoch frame number to schedule */
UINT16 isochCount; /* count of isoch frames scheduled */
pTD_WRAPPER pNextIsochTd; /* next isoch TD to schedule */
BOOL irpRunning; /* TRUE once IRP scheduled onto bus */
UINT32 startTime; /* time when IRP was scheduled onto bus */
} IRP_WORKSPACE, *pIRP_WORKSPACE;
/*
* 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)}};
/***************************************************************************
*
* uhciByteRead - Read a 8 bit value from the UHCI controller.
*
* RETURNS: A big-endian adjusted UINT8
*/
UINT32 uhciByteRead
(
UINT32 offset
)
{
CACHE_PIPE_FLUSH ();
return USB_PCI_BYTE_IN (offset);
}
char uhciread(char offet)
{
sysInByte(0xfe00a000+offet);
}
/*
void usb_set_bit(char p,char val)
{
sysOutWord((0xfe00a000+p),sysInWord(0xfe00a000+p)|val);
}
void usb_clr_bit(char p,char val)
{
sysOutWord((0xfe00a000+p),sysInWord(0xfe00a000+p)&(~val));
}
void usb_set_bit1(char p,char val)
{
UHC_WORD_OUT (p, UHC_WORD_IN (p) | (val));
}*/
/***************************************************************************
*
* uhciWordRead - Read a 16 bit value from the UHCI controller.
*
* RETURNS: A big-endian adjusted UINT16
*/
UINT32 uhciWordRead
(
UINT32 offset
)
{
CACHE_PIPE_FLUSH ();
return USB_PCI_WORD_IN (offset);
}
/***************************************************************************
*
* 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;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?