您的位置:首页 > 其它

Windows CE USB Function Driver驱动简析(2)-IST函数(基于WinCE5.0 SMDK2410 BSP的UFBFN驱动)

2010-08-10 15:49 267 查看
上一篇我们简单分析了UFN驱动中的Ufn_pdd函数,现在我们来看看IST主线程ISTMain函数及相关处理函数.
1.ISTMain
ISTMain在UfnPdd_Start被创建:
pContext->hIST = CreateThread(NULL, 0, ISTMain, pContext, 0, NULL);
ISTMain在参数检查后,设置优先级后,然后进入while循环,循环条件为fExitIST为FALSE,即不退出IST.
循环内禁止所有端点中断,然后使能USB reset中断,使能端点0中断.然后等待中断事件hevInterrupt发生.发生后调用HandleUSBEvent进行中断处理.当退出线程fExitIST或重启线程fRestartIST为TRUE时,在禁止中断和清除中断状态后退出线程.并通知MDD层DETACH事件.
static
DWORD
WINAPI
ISTMain(
LPVOID lpParameter
)
{
SETFNAME();
FUNCTION_ENTER_MSG();

PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) lpParameter;
ValidateContext(pContext);

CeSetThreadPriority(pContext->hIST, pContext->dwISTPriority);

while (!pContext->fExitIST) {
pContext->fRestartIST = FALSE;

// Enable Suspend Mode in the Power Register
//        SetClearReg(pContext, PWR_REG_OFFSET, SUSPEND_MODE_ENABLE_CTRL, SET);

// Disable All Endpoint interrupts
WriteReg(pContext, EP_INT_EN_REG_OFFSET, 0); // Disable All

// Enable Device interrupts
WriteReg(pContext, USB_INT_EN_REG_OFFSET, (USB_RESET_INTR));// | USB_SUSPEND_INTR));

// Enable Endpoint interrupt 0
EnableEndpointInterrupt(pContext, 0);

while (TRUE) {
DWORD dwWait = WaitForSingleObject(pContext->hevInterrupt, INFINITE);
if (pContext->fExitIST || pContext->fRestartIST) {
break;
}

if (dwWait == WAIT_OBJECT_0) {
HandleUSBEvent(pContext);
InterruptDone(pContext->dwSysIntr);
}
else {
RETAILMSG(1, (_T("%s WaitForMultipleObjects failed. Exiting IST./r/n"),
pszFname));
break;
}
}

// Disable Device  interrupts - write Zeros to Disable
WriteReg(pContext, USB_INT_EN_REG_OFFSET, 0 );

// Disable endpoint interrupts - write Zeros to Disable
WriteReg(pContext, EP_INT_EN_REG_OFFSET, 0);

// Clear any outstanding device & endpoint interrupts
// USB Device Interrupt Status - Write a '1' to Clear
WriteReg(pContext, USB_INT_REG_OFFSET,
(USB_RESET_INTR | USB_RESUME_INTR | USB_SUSPEND_INTR));
// End point Interrupt Status - Write a '1' to Clear
WriteReg(pContext, EP_INT_REG_OFFSET, CLEAR_ALL_EP_INTRS);

// Send detach
pContext->pfnNotify(pContext->pvMddContext,
UFN_MSG_BUS_EVENTS, UFN_DETACH);

pContext->fSpeedReported = FALSE;
pContext->attachedState = UFN_DETACH;
}

FUNCTION_LEAVE_MSG();

return 0;
}

2.HandleUSBEvent
当UDC中断发生时就会调用HandleUSBEvent来处理.
首先读取INT_REG和USB_INT_REG寄存器分别获取EP中断状态和USB中断状态(RESET or RESUME or SUSPEND)
BYTE bEpIrqStat = ReadReg(pContext, EP_INT_REG_OFFSET);
BYTE bUSBBusIrqStat = ReadReg(pContext, USB_INT_REG_OFFSET);

然后根据具体的中断状态调用相应的处理函数,如USBbus中断调用HandleUSBBusIrq
if (bUSBBusIrqStat) {
RETAILMSG(1, (_T("%s USB_INT_REG = 0x%02x/r/n"),
pszFname, bUSBBusIrqStat));
HandleUSBBusIrq(pContext, bUSBBusIrqStat);
}
EP中断根据是EP0中断还是EP1-4中断分别调用HandleEndpoint0Event和HandleEndpointEvent.
if (bEpIrqStat & EP0_INT_INTR) {
HandleEndpoint0Event(pContext);
}
for (DWORD dwEndpoint = 1; dwEndpoint < ENDPOINT_COUNT; ++dwEndpoint) {
BYTE bEpBit = EpToIrqStatBit(dwEndpoint);
if (bEpIrqStat & bEpBit) {
HandleEndpointEvent(pContext, dwEndpoint, bEpIrqStat);
}
}
然后继续读取INT_REG和USB_INT_REG寄存器获取中断状态,如果还有中断则继续调用上面的流程进行处理.
完整代码如下:
static
VOID
HandleUSBEvent(
PCTRLR_PDD_CONTEXT pContext
)
{
SETFNAME();
FUNCTION_ENTER_MSG();
ValidateContext(pContext);

BYTE bEpIrqStat = ReadReg(pContext, EP_INT_REG_OFFSET);
BYTE bUSBBusIrqStat = ReadReg(pContext, USB_INT_REG_OFFSET);

while (bEpIrqStat || bUSBBusIrqStat) {
if (bUSBBusIrqStat) {
RETAILMSG(1, (_T("%s USB_INT_REG = 0x%02x/r/n"),
pszFname, bUSBBusIrqStat));
HandleUSBBusIrq(pContext, bUSBBusIrqStat);
}

if (bEpIrqStat) {
RETAILMSG(1, (_T("%s EP_INT_REG = 0x%02x/r/n"),
pszFname, bEpIrqStat));

if (bEpIrqStat & EP0_INT_INTR) {
HandleEndpoint0Event(pContext);
}

// Process All Other (besides EP0) Endpoints
for (DWORD dwEndpoint = 1; dwEndpoint < ENDPOINT_COUNT; ++dwEndpoint) {
// Check the Interrupt Mask
// Check the Interrupt Status
BYTE bEpBit =  EpToIrqStatBit(dwEndpoint);
if (bEpIrqStat & bEpBit) {
HandleEndpointEvent(pContext, dwEndpoint, bEpIrqStat);
}
}
}

bEpIrqStat = ReadReg(pContext, EP_INT_REG_OFFSET);
bUSBBusIrqStat = ReadReg(pContext, USB_INT_REG_OFFSET);
}

FUNCTION_LEAVE_MSG();
}

3.HandleUSBBusIrq
HandleUSBBusIrq用来处理USBbus中段(RESET or RESUME or SUSPEND).实际上只处理了RESET中断.
如果是RESET中断,清除中断标志,设置fSpeedReported为false;
如果是UFN_DETACH状态,则通知MDD层UFN_ATTACH事件.
接着设置EP0状态为EP0_STATE_IDLE,并通知MDD层UFN_RESET事件.
static
VOID
HandleUSBBusIrq(
PCTRLR_PDD_CONTEXT  pContext,
BYTE                bUSBBusIrqStat
)
{
SETFNAME();
FUNCTION_ENTER_MSG();

if (bUSBBusIrqStat & USB_RESET_INTR) {
WriteReg(pContext, USB_INT_REG_OFFSET, USB_RESET_INTR);

RETAILMSG(1, (_T("%s Reset/r/n"), pszFname));

pContext->fSpeedReported = FALSE;

if (pContext->attachedState == UFN_DETACH){
pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_ATTACH);
pContext->attachedState = UFN_ATTACH;
}

pContext->Ep0State = EP0_STATE_IDLE;
pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_RESET);

}

FUNCTION_LEAVE_MSG();
}

4.HandleEndpoint0Event
当EP0中断发生时,被会调用HandleEndpoint0Event.
首先进行参数检查,获取EP0状态结构PEP_STATUS保存到peps.然后清除EP0中断状态.然后设置INDEX_REG为EP0读取EP0_CSR.
当中断状态为SETUP_END配置结束时,写EP0_CSR寄存器清除SETUP_END,将要写的值先保存在bEp0CsrToWrite中,最后一起写入.同时设置EP0状态为IDLE.
接着获取EP0状态结构的PSTransfer,如果存在,调用CompleteTransfer通知MDD UFN_MSG_TRANSFER_COMPLETE事件.
if (bEP0IrqStatus & SETUP_END) {
bEp0CsrToWrite |= SERVICED_SETUP_END;

pContext->Ep0State = EP0_STATE_IDLE;
PSTransfer pTransfer = peps->pTransfer;

// Make MDD think everything is ok.
if(pTransfer) {
pContext->sendDataEnd = FALSE;
CompleteTransfer(pContext, peps, UFN_NO_ERROR);
}
}
如果是SENT_STALL状态,即协议冲突发生时,设置Ep0State为EP0_STATE_IDLE,交由下面的代码继续处理.
if (bEP0IrqStatus & EP0_SENT_STALL) {
pContext->Ep0State = EP0_STATE_IDLE;
}
接着读取OUT_FIFO_CNT1寄存器,该寄存器保存了写出数据的字节数低位.
DWORD cbFifo = ReadIndexedReg(pContext, 0, OUT_FIFO_CNT1_REG_OFFSET);
当Ep0State状态为EP0_STATE_IDLE时,判断bEP0IrqStatus是否是EP0_OUT_PACKET_RDY(写数据包准备好),如果未通知MDD速度则发出FULL SPEED的通知.
然后准备发送配置包,读取要发送包的字节数,获得USB Device Request指针:
const DWORD cbOutFifo = ReadIndexedReg(pContext, 0,
OUT_FIFO_CNT1_REG_OFFSET);
PBYTE pbUdr = (PBYTE) &pContext->udr;
读取FIFO数据(EP0_FIFO_REG)到pbUdr
volatile ULONG *pulFifoReg = _GetDataRegister(0);
DWORD cbBytesRemaining = cbOutFifo;
while (cbBytesRemaining--) {
*pbUdr++ = (BYTE) *pulFifoReg;
}
如果数据大小不匹配,设置bEp0CsrToWrite,清除相应状态标志.
if (cbOutFifo != sizeof(pContext->udr)) {
// Ideally this should not hapen. This is a recovery mechanism if
// we get out of sync somehow.
bEp0CsrToWrite |= (EP0_SEND_STALL | SERVICED_OUT_PKT_RDY |
DATA_END);
}
否则对读到的数据进行解析,如果数据长度大于0,获得传输方向:
if (pContext->udr.bmRequestType & USB_ENDPOINT_DIRECTION_MASK) {
// Start the SW OUT State Machine
pContext->Ep0State = EP0_STATE_IN_DATA_PHASE;
}
else {
// Start the SW OUT State Machine
pContext->Ep0State = EP0_STATE_OUT_DATA_PHASE;
}
如果数据长度为0,设置sendDataEnd为TRUE表示数据传输完成.
接下来根据上面获得是发出数据还是接收数据状态,调用不同的处理流程.
如果是接收数据(EP0_STATE_OUT_DATA_PHASE),并且OUT_PACKET_READY数据准备好,调用HandleRx:
bEp0CsrToWrite |= HandleRx(pContext, peps, &fCompleted, &dwStatus);
否则设置状态为EP0_STATE_IDLE.
如果是发送数据(EP0_STATE_IN_DATA_PHASE),当OUT_PACKET_READY和cbFifo为0(控制传输结束)或者IN_PACKET_READY,调用HandleTx:
if (bHandleTx) {
bEp0CsrToWrite |= HandleTx(pContext, peps, 0);
}
最后然后清除中断状态,调用CompleteTransfer置pTransfer为NULL,并如果通知MDD UFN_MSG_TRANSFER_COMPLETE事件.
如果向UDR发送数据(fSendUdr为TRUE)通知MDD UFN_MSG_SETUP_PACKET事件.
static
VOID
HandleEndpoint0Event(
PCTRLR_PDD_CONTEXT  pContext
)
{
SETFNAME();
FUNCTION_ENTER_MSG();

ValidateContext(pContext);
DEBUGCHK(pContext->fRunning);

PEP_STATUS peps = GetEpStatus(pContext, 0);
LOCK_ENDPOINT(peps);

ClearEndpointInterrupt(pContext, 0);
BYTE bEP0IrqStatus = ReadIndexedReg(pContext, 0, EP0_CSR_REG_OFFSET);

RETAILMSG(1, (_T("%s EP0_CSR_REG = 0x%02x. Data phase = %u/r/n"),
pszFname, bEP0IrqStatus, pContext->Ep0State));

// Write 0 to SEND_STALL and SENT_STALL to clear them, so we need to
// leave them unchanged by default.
BYTE bEp0CsrToWrite = 0;

if (bEP0IrqStatus & SETUP_END) {
bEp0CsrToWrite |= SERVICED_SETUP_END;

pContext->Ep0State = EP0_STATE_IDLE;
PSTransfer pTransfer = peps->pTransfer;

// Make MDD think everything is ok.
if(pTransfer) {
pContext->sendDataEnd = FALSE;
CompleteTransfer(pContext, peps, UFN_NO_ERROR);
}

RETAILMSG(1, (_T("%s Setup End, %x/r/n"),
pszFname, bEP0IrqStatus));
}

// Set By USB if protocol violation detected
if (bEP0IrqStatus & EP0_SENT_STALL) {
// Must Clear both Send and Sent Stall
pContext->Ep0State = EP0_STATE_IDLE;
}

BOOL fSendUdr = FALSE;

DWORD cbFifo = ReadIndexedReg(pContext, 0, OUT_FIFO_CNT1_REG_OFFSET);
BOOL fCompleted = FALSE;
DWORD dwStatus;

if (pContext->Ep0State == EP0_STATE_IDLE) {
if (bEP0IrqStatus & EP0_OUT_PACKET_RDY) {
if (pContext->fSpeedReported == FALSE) {
// After Every Reset Notify MDD of Speed setting.
// This device can only support FULL Speed.
pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_SPEED,
BS_FULL_SPEED);
pContext->fSpeedReported = TRUE;
}

// New setup packet
const DWORD cbOutFifo = ReadIndexedReg(pContext, 0,
OUT_FIFO_CNT1_REG_OFFSET);

PBYTE pbUdr = (PBYTE) &pContext->udr;
volatile ULONG *pulFifoReg = _GetDataRegister(0);

DWORD cbBytesRemaining = cbOutFifo;
while (cbBytesRemaining--) {
*pbUdr++ = (BYTE) *pulFifoReg;
}

if (cbOutFifo != sizeof(pContext->udr)) {
RETAILMSG(1, (_T("%s Setup packet was only %x bytes!/r/n"),
pszFname, cbOutFifo));

// Ideally this should not hapen. This is a recovery mechanism if
// we get out of sync somehow.
bEp0CsrToWrite |= (EP0_SEND_STALL | SERVICED_OUT_PKT_RDY |
DATA_END);
}
else {
// Parse the Setup Command this is necessary to Configure the
// SW State Machine and to set bits to enable the HW to
// ACK/NAK correctly.

// Determine if this is a NO Data Packet
if (pContext->udr.wLength > 0) {
// Determine transfer Direction
if (pContext->udr.bmRequestType & USB_ENDPOINT_DIRECTION_MASK) {
// Start the SW OUT State Machine
pContext->Ep0State = EP0_STATE_IN_DATA_PHASE;
}
else {
// Start the SW OUT State Machine
pContext->Ep0State = EP0_STATE_OUT_DATA_PHASE;
}

pContext->sendDataEnd = FALSE;
}
else { // udr.wLength == 0
// ClientDriver will issue a SendControlStatusHandshake to
// complete the transaction.
pContext->sendDataEnd = TRUE;

// Nothing left to do... stay in IDLE.
DEBUGCHK(pContext->Ep0State == EP0_STATE_IDLE);
}

fSendUdr = TRUE;
}
}
}
else if (pContext->Ep0State == EP0_STATE_OUT_DATA_PHASE) {
if (bEP0IrqStatus & OUT_PACKET_READY) {
bEp0CsrToWrite |= SERVICED_OUT_PKT_RDY;

// Check For out packet read && receive fifo not empty -> out token event
if (cbFifo) {
RETAILMSG(1, (_T("%s out token packet on endpoint 0 /r/n"),
pszFname));
bEp0CsrToWrite |= HandleRx(pContext, peps, &fCompleted, &dwStatus);
}
// status stage of control transfer; zero-length packet received
else {
RETAILMSG(1, (_T("%s status stage of control transfer on endpoint 0/r/n"),
pszFname));
pContext->Ep0State = EP0_STATE_IDLE;
}
}
}
else {
RETAILMSG(1, (_T("%s Data Phase In Token/r/n"), pszFname));

DEBUGCHK(pContext->Ep0State == EP0_STATE_IN_DATA_PHASE);

BOOL bHandleTx = FALSE;

// IN Data Phase and IPR is cleared
// Check For status stage - End control transfer; zero-length packet received
if ( (bEP0IrqStatus &  OUT_PACKET_READY) && (cbFifo == 0) ) {
bHandleTx = TRUE;

RETAILMSG(1, (_T("%s In - end xfer/r/n"),
pszFname));
}
else if ((bEP0IrqStatus & IN_PACKET_READY) == 0) {
bHandleTx = TRUE;
}

if (bHandleTx) {
bEp0CsrToWrite |= HandleTx(pContext, peps, 0);
}
}

// Clear any interrupts
RETAILMSG(1, (_T("%s Writing 0x%02x to EP0_CSR/r/n"), pszFname, bEp0CsrToWrite));
WriteIndexedReg(pContext, 0, EP0_CSR_REG_OFFSET, bEp0CsrToWrite);

if (fCompleted) {
CompleteTransfer(pContext, peps, dwStatus);
}

if (fSendUdr) {
pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_SETUP_PACKET, (DWORD) &pContext->udr);
}

FUNCTION_LEAVE_MSG();
UNLOCK_ENDPOINT(peps);
}

5.HandleRx
HandleRx用来读取端点数据.
首先获取端点号dwEndpoint,传输结构pTransfer,如果为TRUE,则验证传输方向,然后获得端点FIFO数据地址:
volatile ULONG *pulFifoReg = _GetDataRegister(dwEndpoint);
然后获取buffer地址pbBuffer,剩余buffer大小,读取数据的大小cbFifo,实际读取数据大小cbRead,接着将pulFifoReg地址的FIFO数据读取到pbBuffer中.
PBYTE pbBuffer = (PBYTE)pTransfer->pvBuffer + pTransfer->cbTransferred;

DWORD cbBuffer = pTransfer->cbBuffer - pTransfer->cbTransferred;
DWORD cbFifo = ReadIndexedReg(pContext, dwEndpoint, OUT_FIFO_CNT1_REG_OFFSET);
DEBUGCHK(cbFifo <= peps->dwPacketSizeAssigned);

// Read from the FIFO
const DWORD cbRead = min(cbFifo, cbBuffer);
DWORD cbToRead = cbRead;
while (cbToRead--) {
*pbBuffer++ = (BYTE) *pulFifoReg;
}
同时设置已传输数据大小:
pTransfer->cbTransferred += cbRead;
如果是short packet或者buffer已满,则结束传输清除Out Packet Ready,如果是端点0设置DATA_END的返回值.
static
BYTE
HandleRx(
PCTRLR_PDD_CONTEXT       pContext,
PEP_STATUS peps,
PBOOL pfCompleted,
PDWORD pdwStatus
)
{
BOOL fCompleted = FALSE;
DWORD dwStatus = ERROR_GEN_FAILURE;
DWORD dwEndpoint = peps->dwEndpointNumber;
BYTE bRet = 0;

SETFNAME();
FUNCTION_ENTER_MSG();

PSTransfer pTransfer = peps->pTransfer;

pTransfer = peps->pTransfer;
if (pTransfer) {
DEBUGCHK(pTransfer->dwFlags == USB_OUT_TRANSFER);
DEBUGCHK(pTransfer->dwUsbError == UFN_NOT_COMPLETE_ERROR);

ValidateTransferDirection(pContext, peps, pTransfer);

DEBUGCHK(peps->fInitialized);

DWORD dwCurrentPermissions = GetCurrentPermissions();
SetProcPermissions(pTransfer->dwCallerPermissions);

__try {
volatile ULONG *pulFifoReg = _GetDataRegister(dwEndpoint);
DEBUGCHK(pulFifoReg != NULL);

PBYTE  pbBuffer =  (PBYTE)pTransfer->pvBuffer + pTransfer->cbTransferred;

DWORD cbBuffer = pTransfer->cbBuffer - pTransfer->cbTransferred;
DWORD cbFifo = ReadIndexedReg(pContext, dwEndpoint, OUT_FIFO_CNT1_REG_OFFSET);
DEBUGCHK(cbFifo <= peps->dwPacketSizeAssigned);

// Read from the FIFO
const DWORD cbRead = min(cbFifo, cbBuffer);
DWORD cbToRead = cbRead;
while (cbToRead--) {
*pbBuffer++ = (BYTE) *pulFifoReg;
}

DEBUGCHK(cbRead <= pTransfer->cbBuffer - pTransfer->cbTransferred);
pTransfer->cbTransferred += cbRead;

if ( (cbRead < peps->dwPacketSizeAssigned) ||
(pTransfer->cbTransferred == pTransfer->cbBuffer) ) {
// Short packet or filled buffer. Complete transfer.
fCompleted = TRUE;
dwStatus = UFN_NO_ERROR;
}

if (dwEndpoint == 0) {
bRet |= SERVICED_OUT_PKT_RDY;

if (fCompleted) {
bRet |= DATA_END;
pContext->Ep0State = EP0_STATE_IDLE;
}
}
else {
// Clear Out Packet Ready - Allow next packet to come in.
DEBUGCHK( (bRet & OUT_PACKET_READY) == 0);
}
}
__except(EXCEPTION_EXECUTE_HANDLER) {
RETAILMSG(1, (_T("%s Exception!/r/n"), pszFname));
fCompleted = TRUE;
dwStatus = UFN_CLIENT_BUFFER_ERROR;
}

SetProcPermissions(dwCurrentPermissions);

RETAILMSG(1, (_T("%s Rx Ep%x BufferSize=%u,Xfrd=%u /r/n"),
pszFname, dwEndpoint, pTransfer->cbBuffer, pTransfer->cbTransferred));

if (fCompleted) {
RETAILMSG(1, (_T("%s RxDone Ep%x BufferSize=%u, Xfrd=%u/r/n"),
pszFname, dwEndpoint,pTransfer->cbBuffer, pTransfer->cbTransferred));
}
}

*pfCompleted = fCompleted;
*pdwStatus = dwStatus;
FUNCTION_LEAVE_MSG();

return bRet;
}

6.HandleTx
HandleTx用来写数据到端点.
首先获取端点号dwEndpoint,传输结构pTransfer,如果为TRUE,则验证传输方向.
然后获取buffer地址pbBuffer,剩余buffer大小,数据FIFO地址pulFifoReg,写数据大小cbToWrite,读取IN_CSR1_REG寄存器
PBYTE pbBuffer = (PBYTE) pTransfer->pvBuffer + pTransfer->cbTransferred;
DWORD cbBuffer = pTransfer->cbBuffer - pTransfer->cbTransferred;

volatile ULONG *pulFifoReg = _GetDataRegister(dwEndpoint);

DWORD cbWritten = 0;

// Min of input byte count and supported size
DWORD cbToWrite = min(cbBuffer, peps->dwPacketSizeAssigned);
BYTE bRegStatus = ReadIndexedReg(pContext, dwEndpoint, IN_CSR1_REG_OFFSET);
如果是端点0.将pbBuffer的数据写入FIFO寄存器:
if (dwEndpoint == 0) {
for (cbWritten = 0; cbWritten < cbToWrite; cbWritten++) {
*pulFifoReg = *pbBuffer++;
}
如果Buffer已满或者数据长度为0,则标志数据传输完成.设置EP状态为IDLE以及DATA_END的返回值.
如果数据大于0,或者buffer已满,设置EP0_IN_PACKET_RDY
如果数据长度为0,设置EP0_IN_PACKET_RDY,并置pTransfer->pvPddData为0.

如果是其他端点,使能端点中断:
EnableEndpointInterrupt(pContext, dwEndpoint);
写数据到FIFO:
for (cbWritten = 0; cbWritten < cbToWrite; cbWritten++) {
*pulFifoReg = (ULONG) *pbBuffer++;
}
如果Buffer已满或者数据长度为0,则标志传输完成.否则设置IN_PACKET_READY,并更新已发送数据大小.
数据传输完成后(fCompleted为TRUE),禁止端点中断,通知MDD传输完成:
DisableEndpointInterrupt(pContext, peps->dwEndpointNumber);
CompleteTransfer(pContext, peps, dwStatus);
static
BYTE
HandleTx(
PCTRLR_PDD_CONTEXT       pContext,
PEP_STATUS peps,
BOOL fEnableInterrupts
)
{
SETFNAME();
DEBUGCHK(pContext);
PREFAST_DEBUGCHK(peps);

// This routine can be entered from both ISTMain and MDD/Client threads so
// need critical section.

FUNCTION_ENTER_MSG();

BYTE bRet = 0;

BOOL fCompleted = FALSE;
PSTransfer pTransfer = peps->pTransfer;
DWORD dwStatus = ERROR_GEN_FAILURE;
DEBUGCHK(peps->fInitialized);
DWORD dwEndpoint = peps->dwEndpointNumber;

pTransfer = peps->pTransfer;
if (pTransfer) {
ValidateTransferDirection(pContext, peps, pTransfer);

DEBUGCHK(pTransfer->dwFlags == USB_IN_TRANSFER);
DEBUGCHK(pTransfer->dwUsbError == UFN_NOT_COMPLETE_ERROR);

DWORD dwCurrentPermissions = GetCurrentPermissions();
SetProcPermissions(pTransfer->dwCallerPermissions);

// Transfer is ready
__try {
PBYTE pbBuffer = (PBYTE) pTransfer->pvBuffer + pTransfer->cbTransferred;
DWORD cbBuffer = pTransfer->cbBuffer - pTransfer->cbTransferred;

volatile ULONG *pulFifoReg = _GetDataRegister(dwEndpoint);

DWORD cbWritten = 0;

// Min of input byte count and supported size
DWORD cbToWrite = min(cbBuffer, peps->dwPacketSizeAssigned);
BYTE bRegStatus = ReadIndexedReg(pContext, dwEndpoint,
IN_CSR1_REG_OFFSET);

RETAILMSG(1, (_T("%s Tx on EP %u, Bytes = %u/r/n"),
pszFname, dwEndpoint, cbToWrite));

if (dwEndpoint == 0) {
for (cbWritten = 0; cbWritten < cbToWrite; cbWritten++) {
*pulFifoReg = *pbBuffer++;
}

/* We can complete on a packet which is full. We need to wait till
* next time and generate a zero length packet, so only complete
* if we're at the end and it is not the max packet size.
*/
pTransfer->cbTransferred += cbWritten;
if (pTransfer->cbTransferred == pTransfer->cbBuffer && pTransfer->pvPddData == 0) {
dwStatus = UFN_NO_ERROR;
fCompleted = TRUE;
pContext->Ep0State = EP0_STATE_IDLE;
bRet |= DATA_END;
}

/* Update the register - Set the IPR bit
and possibly data end*/
if( (cbWritten > 0) || (pTransfer->cbBuffer == 0) ) {
bRet |= EP0_IN_PACKET_RDY;
}
// Also set IPR if a 0 byte packet needs to go out.
else if(pTransfer->pvPddData) {
bRet |= EP0_IN_PACKET_RDY;
pTransfer->pvPddData = 0;
}
}
else {
// Enable Interrupts before writing to the FIFO. This insures
// That any interrupts generated because of the write will be
// "latched"
if (fEnableInterrupts) {
DEBUGCHK(dwEndpoint != 0);
EnableEndpointInterrupt(pContext, dwEndpoint);
}

// Write to the FIFO directly to send the bytes.
for (cbWritten = 0; cbWritten < cbToWrite; cbWritten++) {
*pulFifoReg = (ULONG) *pbBuffer++;
}

// By Placing the check for packet complete here, before
// cbTransferred is updated, there is a 1 interrupt cycle delay
// That is complete is not declared until the data has actually
// been ACKd (TPC set) by the host
if ( (pTransfer->cbTransferred == pTransfer->cbBuffer) ||
(cbWritten == 0) ){
fCompleted = TRUE;
dwStatus = UFN_NO_ERROR;
}
else {
/* Set In Packet Ready , this will Tells the HW the FIFO is
ready to be transitted to be sent
*/
bRet |= IN_PACKET_READY;
}

// Update the Transfered Count
pTransfer->cbTransferred += cbWritten;
}
}
__except(EXCEPTION_EXECUTE_HANDLER) {
RETAILMSG(1, (_T("%s Exception!/r/n"), pszFname));
fCompleted = TRUE;
dwStatus = UFN_CLIENT_BUFFER_ERROR;
}

SetProcPermissions(dwCurrentPermissions);
}
else {
// It is possible for an interrupt to come in while still in this
// function for first pass of transfer. If this happens it is possible
// to complete the transfer and have that interrupt be unnecessary
// so... just ignore it.
goto EXIT;
}

if (fCompleted) {
// Disable transfer interrupts until another transfer is issued.
if (peps->dwEndpointNumber != 0) {
DisableEndpointInterrupt(pContext, peps->dwEndpointNumber);
}

RETAILMSG(1, (_T("%s Tx Done  Ep%x  Status %u/r/n"), pszFname,
dwEndpoint, dwStatus));
CompleteTransfer(pContext, peps, dwStatus);
}
else {
RETAILMSG(1, (_T("%s Tx EP%x BufferSize=%u, Xfrd=%u/r/n"),
pszFname, dwEndpoint, pTransfer->cbBuffer, pTransfer->cbTransferred));
}

EXIT:
FUNCTION_LEAVE_MSG();

return bRet;
}

SMDK2410的USB Device Driver的PDD层驱动就简单解析到这里,如果错误,欢迎指正.,更多代码请参考sc2410pdd.cpp.要深入了解USB驱动还需要更多的阅读和实践.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐