📄 usbhcdsl811hslib.c
字号:
* RETURNS:
*/
LOCAL void executeTD(pHCD_HOST pHost)
{
UINT32 ctlSts, token;
UINT8 *buffer;
SL11XACTION xact;
BOOL lowSpeedDevice, isoXfer;
UINT8 tmp = 0;
/* get control/status */
ctlSts = FROM_LITTLEL(pHost->pCurrentTD->ctlSts);
/* get token */
token = FROM_LITTLEL(pHost->pCurrentTD->token);
/* get buffer */
buffer = (UINT8 *) (UHC_FROM_LITTLEL(pHost->pCurrentTD->bfrPtr));
/* get speed */
lowSpeedDevice = ctlSts & UHCI_TDCS_LOWSPEED;
/* iso xfer ? */
isoXfer = ctlSts & UHCI_TDCS_ISOCH;
/* get data len */
xact.dlen = UHCI_TDTOK_MAXLEN(token);
/* get endpoint */
xact.ep = UHCI_TDTOK_ENDPT(token);
/* get device address */
xact.addr = UHCI_TDTOK_DEVADRS(token);
/* get packet id */
xact.pid = UHCI_TDTOK_PID(token);
/* set pid and ep register */
SL811_REG_WRITE(SL811HS_PID_DEVEND_A, ((xact.pid & 0xf) << 4) | xact.ep);
/* set usb address register */
SL811_REG_WRITE(SL811HS_DEVADDR_TCNT_A, xact.addr);
/* set length register */
SL811_REG_WRITE(SL811HS_BASE_LEN_A, xact.dlen);
/* set base address register */
SL811_REG_WRITE(SL811HS_BASE_ADDR_A, 0x10);
/* move output data to buffer */
if ((xact.pid == USB_PID_SETUP) || (xact.pid == USB_PID_OUT))
{
int i,j;
#ifdef SL811HS_LOG
int l=xact.dlen;
UINT8 *b=buffer;
#endif
/* SL811_BUF_WRITE(0x10,buffer,xact.dlen); */
for (i=0,j=0x10; i<xact.dlen; j++,i++) {SL811_REG_WRITE(j,buffer[i]);}
#ifdef SL811HS_LOG
{
char dbgStr[1500]=" OUT ";
for ( i=0;i<l;i++ )
{
sprintf(dbgStr+8+(i*3),"%02x ",b[i]);
} /* end of for () */
sprintf(dbgStr+8+(i*3),"\n");
DBG_LOG(dbgStr,1,2,3,4,5,6);
}
#endif
}
/* figure out CTRL REG A */
if (lowSpeedDevice && (!(pHost->lowSpeed[0])))
tmp |= SL811HS_HCTLMASK_PREAMBLE;
if (token & (UINT32)(UHCI_TDTOK_DATA_TOGGLE)) tmp |= SL811HS_HCTLMASK_SEQ;
if (isoXfer) tmp |= SL811HS_HCTLMASK_ISOCH;
if ((xact.pid == USB_PID_SETUP) || (xact.pid == USB_PID_OUT))
tmp |= SL811HS_HCTLMASK_WRITE;
else tmp |= SL811HS_HCTLMASK_SEQ;
/* start the xfer */
tmp |= SL811HS_HCTLMASK_ARM | SL811HS_HCTLMASK_ENBLEP;
SL811_REG_WRITE(SL811HS_CTRL_REG_A, tmp);
}
/***************************************************************************
*
* getFrameNo - returns current hardware frame number
*
* RETURNS: value of current frame number
*/
LOCAL UINT16 getFrameNo
(
pHCD_HOST pHost
)
{
return FINDEX(pHost->frameNo);
}
/***************************************************************************
*
* 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);
if ((pWork->pTdPool = DMA_MALLOC (tdLen, UHCI_TD_ALIGNMENT)) == NULL)
{
freeIrpWorkspace (pHost, pIrp);
return FALSE;
}
memset (pWork->pTdPool, 0, tdLen);
}
/* Create a chain of TDs in the "free" list */
pWork->pTdInUse = pWork->pTdFree = NULL;
for (i = 0; i < pWork->tdCount; i++)
{
pWork->pTdPool [i].sw.pWork = pWork;
pWork->pTdPool [i].sw.pNext = pWork->pTdFree;
pWork->pTdFree = &pWork->pTdPool [i];
}
/* Initialize the pointer to the last TD in use */
pWork->pLastTdInUse = NULL;
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 &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -