📄 usbhcdsl811hslib.c
字号:
* Each UHCI_QH must be aligned to a 16 byte boundary.
*/
typedef union qh_wrapper
{
VOLATILE UHCI_QH qh; /* standard UHCI QH, 8 bytes */
struct
{
VOLATILE UINT32 reserved [2]; /* 2 DWORDs used by QH */
UINT32 reserved1; /* 1 DWORD pad */
struct irp_workspace *pWork;/* workspace which owns QH */
} sw;
} QH_WRAPPER, *pQH_WRAPPER;
#define QH_WRAPPER_LEN 16
#define QH_WRAPPER_ACTLEN sizeof (QH_WRAPPER)
#define INT_ANCHOR_LIST_SIZE (QH_WRAPPER_ACTLEN * UHCI_FRAME_LIST_ENTRIES)
/*
* HCD_PIPE
*
* HCD_PIPE maintains all information about an active pipe.
*/
typedef struct hcd_pipe
{
HCD_PIPE_HANDLE pipeHandle; /* handle assigned to pipe */
LINK link; /* linked list of pipes */
UINT16 busAddress; /* bus address of USB device */
UINT16 endpoint; /* device endpoint */
UINT16 transferType; /* transfer type */
UINT16 direction; /* transfer/pipe direction */
UINT16 speed; /* transfer speed */
UINT16 maxPacketSize; /* packet size */
UINT32 bandwidth; /* bandwidth required by pipe */
UINT16 interval; /* service interval */
UINT32 time; /* bandwidth (time) allocated to pipe */
} HCD_PIPE, *pHCD_PIPE;
/*
* IRP_WORKSPACE
*
* Associates QHs and TDs with the IRPs they are currently servicing.
*
* Note: The pTdInUse and pTdFree lists use the TD_WRAPPER.sw.pNext field to
* maintain lists of TDs. When TDs are scheduled, their UHCI_TD.linkPtr
* fields are also used to link the TDs in the correct order. The reader
* must be aware that the UHCI_TD.linkPtr fields are formatted for direct
* access by the UHCI PCI controller, and may not be dereferenced directly
* by software. Instead, the TD_FROM_PCIPTR() macro may be used to
* dereference the UHCI_TD.linkPtr field if necessary. There is no such
* restriction for the TD_WRAPPER.sw.pNext field.
*
* Note also that the linkPtr field uses the UHC convention that the end
* of a TD list is marked by a pointer with only the UHC_LINK_TERMINATE bit
* set (unlike the more conventional use of NULL to mark end of list).
*/
typedef struct irp_workspace
{
pHCD_PIPE pPipe; /* pointer to pipe for this IRP */
pUSB_IRP pIrp; /* pointer to parent IRP */
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 */
SL811_IO_CFG sl811CfgHdr; /* SL811 IO config */
UINT16 uhcAttributes; /* vendor/model specific attributes */
UINT32 ioBase; /* Base I/O address */
UINT32 ioBaseData; /* Base I/O data address */
USB_HCD_MNGMT_CALLBACK mngmtCallback; /* callback routine for mngmt evt */
pVOID mngmtCallbackParam; /* caller-defined parameter */
MUTEX_HANDLE hostMutex; /* guards host structure */
int 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 */
UINT8 intBits; /* interrupt bits */
int xmitPending;
BOOL sofPending;
UINT16 rootAddress; /* current address of root hub */
UINT8 configValue; /* current configuration value */
BOOL powered [SL811_PORTS]; /* TRUE if port is powered */
BOOL cSuspend [SL811_PORTS]; /* TRUE if suspend status change */
BOOL cReset [SL811_PORTS]; /* TRUE if reset status change */
/* added DGJ */
BOOL connected[SL811_PORTS];/* TRUE if port is connected to device*/
BOOL suspended[SL811_PORTS];/* TRUE if port is suspended */
BOOL enabled[SL811_PORTS]; /* TRUE if port is enabled */
BOOL lowSpeed[SL811_PORTS]; /* TRUE if port is lowSpeed */
BOOL cConnect[SL811_PORTS]; /* TRUE if connection status change */
BOOL cEnable[SL811_PORTS]; /* TRUE if enabled 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 */
/* added DGJ */
VOLATILE UHCI_QH *pCurrentQH; /* current QH in progress */
VOLATILE UHCI_TD *pCurrentTD; /* current TD in progress */
char eof;
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 gSuspended; /* TRUE when global suspend is TRUE */
SEM_ID hcSyncSem; /* syncronization semaphore */
UINT16 frameNo; /* frame number. */
void *nextTDQH; /* next TD or QH to send */
} 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)
/* Language descriptor */
LOCAL USB_LANGUAGE_DESCR langDescr =
{sizeof (USB_LANGUAGE_DESCR), USB_DESCR_STRING,
{TO_LITTLEW (UNICODE_ENGLISH)}};
static pHCD_HOST pDbgHost=NULL;
/***************************************************************************
*
* sl811Reset - reset the SL811HS controller chip and attached USB devices
*
*
* RETURNS: N/A
*/
void sl811Reset(pHCD_HOST pHost)
{
UINT8 status;
DBG_PRINTF(("R"));
DBG_LOG("Reset\n",1,2,3,4,5,6);
/* disable all interrupts */
SL811_REG_WRITE(SL811HS_IER, 0);
SL811_REG_WRITE(SL811HS_CTRL_REG_1, 0);
OSS_THREAD_SLEEP(500);
/* clear interrupt status reg */
SL811_REG_WRITE(SL811HS_INT_STAT_REG, 0xFF);
/* check connection status */
status = SL811_REG_READ(SL811HS_INT_STAT_REG);
/* Check if device is removed */
if (status & 0x40)
{
pHost->connected[0] = FALSE;
DBG_LOG("sl881Reset : No device or no power\n",1,2,3,4,5,6);
}
else
{
pHost->connected[0] = TRUE;
if (!(status & 0x80 ))
{
/* slow speed device connected directly to root-hub */
SL811_REG_WRITE(SL811HS_SOFCNTH_CTRL_2, 0xEE);
SL811_REG_WRITE(SL811HS_SOFCNTL_REV, 0xE0);
SL811_REG_WRITE(SL811HS_CTRL_REG_1, 0x29);
OSS_THREAD_SLEEP(10);
SL811_REG_WRITE(SL811HS_CTRL_REG_1, 0x21);
pHost->lowSpeed[0] = TRUE;
DBG_LOG("sl881Reset : Low speed device connected\n",1,2,3,4,5,6);
}
else
{
/* full speed device connect directly to root hub */
SL811_REG_WRITE(SL811HS_SOFCNTH_CTRL_2, 0xAE);
SL811_REG_WRITE(SL811HS_SOFCNTL_REV, 0xE0);
SL811_REG_WRITE(SL811HS_CTRL_REG_1, 0xd);
OSS_THREAD_SLEEP(10);
SL811_REG_WRITE(SL811HS_CTRL_REG_1, 0x5);
pHost->lowSpeed[0] = FALSE;
DBG_LOG("sl881Reset : Full speed device connected\n",1,2,3,4,5,6);
}
/* start the SOF or EOP */
SL811_REG_WRITE(SL811HS_PID_DEVEND_A, 0x50) ;
SL811_REG_WRITE(SL811HS_DEVADDR_TCNT_A, 0) ;
SL811_REG_WRITE(SL811HS_CTRL_REG_A, 1) ;
}
pHost->frameNo = 0;
OSS_THREAD_SLEEP(25);
/* clear interrupt status reg */
SL811_REG_WRITE(SL811HS_INT_STAT_REG, 0xFF);
/* Enable interrupts */
SL811_REG_WRITE(SL811HS_IER, pHost->intBits);
pHost->xmitPending = 0;
pHost->sofPending = FALSE;
}
#ifndef INCLUDE_USB_PCI
/***************************************************************************
*
* sl811DcrInit -
*
* RETURNS: N/A
*/
LOCAL void sl811DcrInit()
{
int regValue = 0;
printf ("Enter sl811DcrInit\n");
/* IRQ0 from SL811HS daugther card is edge sensitive */
regValue = sysDcrUictrGet() | 0x00000040;
sysDcrUictrSet(regValue); /* set int trigger levels */
/* Configure the DCR CR0 register */
/* Disable GPIO 17 to enable IRQ0 as an interrupt */
regValue = sysDcrCr0Get() & ~CR0_GPIO_17_EN;
sysDcrCr0Set(regValue);
/* printf ("dcrInit: DCR CR0 reg value = 0x%x\n", sysDcrCr0Get()); */
/* Configure the DCR CR1 register to set the enable pin */
regValue = sysDcrCr1Get() | CR1_PCI_PW_EN;
sysDcrCr1Set(regValue);
/* printf ("dcrInit: DCR CR1 reg value = 0x%x\n", sysDcrCr1Get()); */
/* Configure the EBC Configuration Register EBC0_CFG */
sysDcrEbcSet (EBC_CFG, 0xb84c0000);
/* Configure the Peripheral Bank 2 Configuration Reg */
sysDcrEbcSet (EBC_B2CR, 0x700f8000);
/* Configure the Peripheral Bank 2 Access Reg */
sysDcrEbcSet (EBC_B2AP, 0x090ffe00);
}
#endif
/***************************************************************************
*
* sl811Init - initialize the SL811HS controller chip
*
*
* Adapted from SL811HS Application Notes, page 12
*
* RETURNS: N/A
*/
LOCAL void sl811Init(pHCD_HOST pHost)
{
UINT8 status;
/* disable all interrupts */
SL811_REG_WRITE(SL811HS_IER, 0);
SL811_REG_WRITE(SL811HS_CTRL_REG_1, 0);
OSS_THREAD_SLEEP(500);
/* clear interrupt status reg */
SL811_REG_WRITE(SL811HS_INT_STAT_REG, 0xFF);
/* check connection status */
status = SL811_REG_READ(SL811HS_INT_STAT_REG);
if (status & 0x40)
{
pHost->connected[0] = FALSE;
DBG_LOG("sl881Init : No device or no power\n",1,2,3,4,5,6);
}
else
{
pHost->connected[0] = TRUE;
if (!(status & 0x80 ))
{
/* slow speed device connected directly to root-hub */
pHost->lowSpeed[0] = TRUE;
DBG_LOG("sl881Init : Low speed device connected\n",1,2,3,4,5,6);
}
else
{
/* full speed device connect directly to root hub */
pHost->lowSpeed[0] = FALSE;
DBG_LOG("sl881Reset : Full speed device connected\n",1,2,3,4,5,6);
}
}
}
/***************************************************************************
*
* fetchTD - follow a QH to get a TD
*
*
*
* RETURNS: pointer to next TD in QH, NULL if no more TDs remaning in QH
*/
LOCAL void *fetchTD(pHCD_HOST pHost, BOOL vertical)
{
void *pTD = NULL;
BOOL gotTD = FALSE;
/* Special processing if this QH should process TD depth first */
if (!vertical) goto step10;
while (!gotTD)
{
/* is element pointer an inactive entry ? */
if (UHC_FROM_LITTLEL(pHost->pCurrentQH->tdLink) & UHCI_LINK_TERMINATE)
{
/* element pointer inactive. Follow horizontal link */
step10:
if (UHC_FROM_LITTLEL(pHost->pCurrentQH->qhLink) & UHCI_LINK_TERMINATE)
{
return(pTD);
}
pHost->pCurrentQH = (UHCI_QH *) (UHC_FROM_LITTLEL(pHost->pCurrentQH->qhLink) &
UHCI_LINK_PTR_MASK);
if ((UHC_FROM_LITTLEL(pHost->pCurrentQH->tdLink) & UHCI_LINK_TERMINATE)
&& (UHC_FROM_LITTLEL(pHost->pCurrentQH->qhLink) & UHCI_LINK_TERMINATE))
{
/* header pointer inactive. Leave function and then idle */
gotTD = TRUE;
}
continue;
}
/* element pointer not inactive. Is element pointer pointing to a QH ?*/
else if (UHC_FROM_LITTLEL(pHost->pCurrentQH->tdLink) & UHCI_LINK_QH)
{
/* element pointer points to a QH. Get next QH from vertical link */
/* and continue processing */
pHost->pCurrentQH = (UHCI_QH *) (UHC_FROM_LITTLEL(pHost->pCurrentQH->tdLink) &
UHCI_LINK_PTR_MASK);
continue;
}
/* element pointer points to a TD. return it */
else
{
gotTD = TRUE;
pTD = (void *) (UHC_FROM_LITTLEL(pHost->pCurrentQH->tdLink) & UHCI_LINK_PTR_MASK);
}
}
return(pTD);
}
/***************************************************************************
*
* execute TD - execute a TD
*
*
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -