上一篇我们简单分析了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) {
}
EP中断根据是EP0中断还是EP1-4中断分别调用HandleEndpoint0Event和HandleEndpointEvent.
if (bEpIrqStat & EP0_INT_INTR) {
for (DWORD dwEndpoint = 1; dwEndpoint < ENDPOINT_COUNT; ++dwEndpoint) {
}
然后继续读取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 = 0xx/r/n"), -
pszFname, bUSBBusIrqStat)); -
HandleUSBBusIrq(pContext, bUSBBusIrqStat); -
} -
-
if (bEpIrqStat) { -
RETAILMSG(1, (_T("%s EP_INT_REG = 0xx/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) {
如果是SENT_STALL状态,即协议冲突发生时,设置Ep0State为EP0_STATE_IDLE,交由下面的代码继续处理.
if (bEP0IrqStatus & EP0_SENT_STALL) {
}
接着读取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,
PBYTE pbUdr = (PBYTE) &pContext->udr;
读取FIFO数据(EP0_FIFO_REG)到pbUdr
volatile ULONG *pulFifoReg = _GetDataRegister(0);
DWORD cbBytesRemaining = cbOutFifo;
while (cbBytesRemaining--) {
}
如果数据大小不匹配,设置bEp0CsrToWrite,清除相应状态标志.
if (cbOutFifo != sizeof(pContext->udr)) {
}
否则对读到的数据进行解析,如果数据长度大于0,获得传输方向:
if (pContext->udr.bmRequestType & USB_ENDPOINT_DIRECTION_MASK) {
}
else {
}
如果数据长度为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) {
}
最后然后清除中断状态,调用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 = 0xx. 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 SendControlStatusHandsha ke 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 0xx 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数据地址:
vo latile ULONG *pulFifoReg = _GetDataRegister(dwEndpoint);
然后获取buffer地址pbBuffer,剩余buffer大小,读取数据的大小cbFifo,实际读取数据大小cbRead,接着将pulFifoReg地址的FIFO数据读取到pbBuffer中.
同时设置已传输数据大小:
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); -
-
ValidateTransferDirectio n(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) {
如果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++) {
如果Buffer已满或者数据长度为0,则标志传输完成.否则设置IN_PACKET_READY,并更新已发送数据大小.
数据传输完成后(fCompleted为TRUE),禁止端点中断,通知MDD传输完成:
DisableEndpointInterrupt
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) { -
ValidateTransferDirectio n(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++; -
} -
-
-
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; -
} -
-
-
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 { -
-
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驱动还需要更多的阅读和实践.