Windows CE USB Fu…

上一篇我们简单分析了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事件.

[c-sharp:collapse] + expand source view plain copy print ?
  1. static  
  2. DWORD  
  3. WINAPI  
  4. ISTMain(  
  5.         LPVOID lpParameter  
  6.          
  7.  
  8.     SETFNAME();  
  9.     FUNCTION_ENTER_MSG();  
  10.   
  11.     PCTRLR_PDD_CONTEXT pContext (PCTRLR_PDD_CONTEXT) lpParameter;  
  12.     ValidateContext(pContext);  
  13.   
  14.     CeSetThreadPriority(pContext->hIST, pContext->dwISTPriority);  
  15.   
  16.     while (!pContext->fExitIST)  
  17.         pContext->fRestartIST FALSE;  
  18.   
  19.         // Enable Suspend Mode in the Power Register   
  20. //        SetClearReg(pContext, PWR_REG_OFFSET, SUSPEND_MODE_ENABLE_CTRL, SET);   
  21.   
  22.         // Disable All Endpoint interrupts   
  23.         WriteReg(pContext, EP_INT_EN_REG_OFFSET, 0); // Disable All   
  24.   
  25.         // Enable Device interrupts   
  26.         WriteReg(pContext, USB_INT_EN_REG_OFFSET, (USB_RESET_INTR));// USB_SUSPEND_INTR));   
  27.   
  28.         // Enable Endpoint interrupt 0   
  29.         EnableEndpointInterrupt(pContext, 0);  
  30.   
  31.         while (TRUE)  
  32.             DWORD dwWait WaitForSingleObject(pContext->hevInterrupt, INFINITE);  
  33.             if (pContext->fExitIST || pContext->fRestartIST)  
  34.                 break;  
  35.              
  36.   
  37.             if (dwWait == WAIT_OBJECT_0)  
  38.                 HandleUSBEvent(pContext);  
  39.                 InterruptDone(pContext->dwSysIntr);  
  40.              
  41.             else  
  42.                 RETAILMSG(1, (_T("%s WaitForMultipleObjects failed. Exiting IST./r/n"),   
  43.                     pszFname));  
  44.                 break;  
  45.              
  46.          
  47.   
  48.         // Disable Device  interrupts write Zeros to Disable   
  49.         WriteReg(pContext, USB_INT_EN_REG_OFFSET, );  
  50.   
  51.         // Disable endpoint interrupts write Zeros to Disable   
  52.         WriteReg(pContext, EP_INT_EN_REG_OFFSET, 0);  
  53.           
  54.         // Clear any outstanding device endpoint interrupts   
  55.         // USB Device Interrupt Status Write '1' to Clear    
  56.         WriteReg(pContext, USB_INT_REG_OFFSET,   
  57.             (USB_RESET_INTR USB_RESUME_INTR USB_SUSPEND_INTR));  
  58.         // End point Interrupt Status Write '1' to Clear   
  59.         WriteReg(pContext, EP_INT_REG_OFFSET, CLEAR_ALL_EP_INTRS);  
  60.   
  61.         // Send detach   
  62.         pContext->pfnNotify(pContext->pvMddContext,   
  63.             UFN_MSG_BUS_EVENTS, UFN_DETACH);  
  64.   
  65.         pContext->fSpeedReported FALSE;  
  66.         pContext->attachedState UFN_DETACH;  
  67.      
  68.   
  69.     FUNCTION_LEAVE_MSG();  
  70.   
  71.     return 0;  
  72.  

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 = 0xx/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寄存器获取中断状态,如果还有中断则继续调用上面的流程进行处理.
完整代码如下:

[c-sharp:collapse] + expand source view plain copy print ?
  1. static  
  2. VOID  
  3. HandleUSBEvent(  
  4.                PCTRLR_PDD_CONTEXT pContext  
  5.                 
  6.  
  7.     SETFNAME();  
  8.     FUNCTION_ENTER_MSG();  
  9.     ValidateContext(pContext);  
  10.   
  11.     BYTE bEpIrqStat ReadReg(pContext, EP_INT_REG_OFFSET);  
  12.     BYTE bUSBBusIrqStat ReadReg(pContext, USB_INT_REG_OFFSET);  
  13.   
  14.     while (bEpIrqStat || bUSBBusIrqStat)  
  15.         if (bUSBBusIrqStat)  
  16.             RETAILMSG(1, (_T("%s USB_INT_REG 0xx/r/n"),   
  17.                 pszFname, bUSBBusIrqStat));  
  18.             HandleUSBBusIrq(pContext, bUSBBusIrqStat);  
  19.          
  20.   
  21.         if (bEpIrqStat)  
  22.             RETAILMSG(1, (_T("%s EP_INT_REG 0xx/r/n"),   
  23.                 pszFname, bEpIrqStat));  
  24.   
  25.             if (bEpIrqStat EP0_INT_INTR)  
  26.                 HandleEndpoint0Event(pContext);  
  27.              
  28.               
  29.             // Process All Other (besides EP0) Endpoints   
  30.             for (DWORD dwEndpoint 1; dwEndpoint ENDPOINT_COUNT; ++dwEndpoint)  
  31.                 // Check the Interrupt Mask    
  32.                 // Check the Interrupt Status    
  33.                 BYTE bEpBit  EpToIrqStatBit(dwEndpoint);  
  34.                 if (bEpIrqStat bEpBit)  
  35.                     HandleEndpointEvent(pContext, dwEndpoint, bEpIrqStat);  
  36.                  
  37.              
  38.          
  39.   
  40.         bEpIrqStat ReadReg(pContext, EP_INT_REG_OFFSET);  
  41.         bUSBBusIrqStat ReadReg(pContext, USB_INT_REG_OFFSET);  
  42.      
  43.       
  44.     FUNCTION_LEAVE_MSG();  
  45.  

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事件.
[c-sharp:collapse] + expand source view plain copy print ?
  1. static  
  2. VOID  
  3. HandleUSBBusIrq(  
  4.                     PCTRLR_PDD_CONTEXT  pContext,  
  5.                     BYTE                bUSBBusIrqStat  
  6.                      
  7.  
  8.     SETFNAME();  
  9.     FUNCTION_ENTER_MSG();  
  10.       
  11.         if (bUSBBusIrqStat USB_RESET_INTR)  
  12.             WriteReg(pContext, USB_INT_REG_OFFSET, USB_RESET_INTR);  
  13.               
  14.             RETAILMSG(1, (_T("%s Reset/r/n"), pszFname));  
  15.               
  16.             pContext->fSpeedReported FALSE;  
  17.   
  18.   
  19.             if (pContext->attachedState == UFN_DETACH){  
  20.                 pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_ATTACH);  
  21.                 pContext->attachedState UFN_ATTACH;  
  22.              
  23.               
  24.             pContext->Ep0State EP0_STATE_IDLE;  
  25.             pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_RESET);  
  26.   
  27.   
  28.          
  29.   
  30.     FUNCTION_LEAVE_MSG();  
  31.  

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事件.

  1. static  
  2. VOID  
  3. HandleEndpoint0Event(  
  4.                     PCTRLR_PDD_CONTEXT  pContext  
  5.                      
  6.  
  7.     SETFNAME();  
  8.     FUNCTION_ENTER_MSG();  
  9.   
  10.     ValidateContext(pContext);  
  11.     DEBUGCHK(pContext->fRunning);  
  12.   
  13.     PEP_STATUS peps GetEpStatus(pContext, 0);  
  14.     LOCK_ENDPOINT(peps);  
  15.   
  16.     ClearEndpointInterrupt(pContext, 0);  
  17.     BYTE bEP0IrqStatus ReadIndexedReg(pContext, 0, EP0_CSR_REG_OFFSET);  
  18.   
  19.     RETAILMSG(1, (_T("%s EP0_CSR_REG 0xx. Data phase %u/r/n"),   
  20.         pszFname, bEP0IrqStatus, pContext->Ep0State));  
  21.   
  22.     // Write to SEND_STALL and SENT_STALL to clear them, so we need to    
  23.     // leave them unchanged by default.   
  24.     BYTE bEp0CsrToWrite 0;  
  25.   
  26.     if (bEP0IrqStatus SETUP_END)  
  27.         bEp0CsrToWrite |= SERVICED_SETUP_END;  
  28.   
  29.         pContext->Ep0State EP0_STATE_IDLE;  
  30.         PSTransfer pTransfer peps->pTransfer;  
  31.   
  32.         // Make MDD think everything is ok.   
  33.         if(pTransfer)  
  34.             pContext->sendDataEnd FALSE;  
  35.             CompleteTransfer(pContext, peps, UFN_NO_ERROR);  
  36.          
  37.   
  38.         RETAILMSG(1, (_T("%s Setup End, %x/r/n"),   
  39.             pszFname, bEP0IrqStatus));  
  40.      
  41.   
  42.     // Set By USB if protocol violation detected   
  43.     if (bEP0IrqStatus EP0_SENT_STALL)  
  44.         // Must Clear both Send and Sent Stall   
  45.         pContext->Ep0State EP0_STATE_IDLE;  
  46.      
  47.   
  48.     BOOL fSendUdr FALSE;  
  49.       
  50.     DWORD cbFifo ReadIndexedReg(pContext, 0, OUT_FIFO_CNT1_REG_OFFSET);  
  51.     BOOL fCompleted FALSE;  
  52.     DWORD dwStatus;  
  53.   
  54.     if (pContext->Ep0State == EP0_STATE_IDLE)  
  55.         if (bEP0IrqStatus EP0_OUT_PACKET_RDY)  
  56.             if (pContext->fSpeedReported == FALSE)  
  57.                 // After Every Reset Notify MDD of Speed setting.   
  58.                 // This device can only support FULL Speed.   
  59.                 pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_SPEED,  
  60.                     BS_FULL_SPEED);  
  61.                 pContext->fSpeedReported TRUE;  
  62.              
  63.               
  64.             // New setup packet   
  65.             const DWORD cbOutFifo ReadIndexedReg(pContext, 0,   
  66.                 OUT_FIFO_CNT1_REG_OFFSET);  
  67.   
  68.             PBYTE pbUdr (PBYTE) &pContext->udr;  
  69.             volatile ULONG *pulFifoReg _GetDataRegister(0);  
  70.               
  71.             DWORD cbBytesRemaining cbOutFifo;  
  72.             while (cbBytesRemaining--)  
  73.                 *pbUdr++ (BYTE) *pulFifoReg;  
  74.              
  75.   
  76.             if (cbOutFifo != sizeof(pContext->udr))  
  77.                 RETAILMSG(1, (_T("%s Setup packet was only %x bytes!/r/n"),  
  78.                     pszFname, cbOutFifo));  
  79.                   
  80.                 // Ideally this should not hapen. This is recovery mechanism if    
  81.                 // we get out of sync somehow.     
  82.                 bEp0CsrToWrite |= (EP0_SEND_STALL SERVICED_OUT_PKT_RDY   
  83.                     DATA_END);  
  84.              
  85.             else  
  86.                 // Parse the Setup Command this is necessary to Configure the    
  87.                 // SW State Machine and to set bits to enable the HW to    
  88.                 // ACK/NAK correctly.   
  89.                   
  90.                 // Determine if this is NO Data Packet   
  91.                 if (pContext->udr.wLength 0)  
  92.                     // Determine transfer Direction   
  93.                     if (pContext->udr.bmRequestType USB_ENDPOINT_DIRECTION_MASK)  
  94.                         // Start the SW OUT State Machine   
  95.                         pContext->Ep0State EP0_STATE_IN_DATA_PHASE;                        
  96.                      
  97.                     else  
  98.                         // Start the SW OUT State Machine   
  99.                         pContext->Ep0State EP0_STATE_OUT_DATA_PHASE;   
  100.                      
  101.   
  102.                     pContext->sendDataEnd FALSE;  
  103.                  
  104.                 else // udr.wLength == 0   
  105.                     // ClientDriver will issue SendControlStatusHandshake to    
  106.                     // complete the transaction.   
  107.                     pContext->sendDataEnd TRUE;  
  108.   
  109.                     // Nothing left to do... stay in IDLE.   
  110.                     DEBUGCHK(pContext->Ep0State == EP0_STATE_IDLE);  
  111.                  
  112.   
  113.                 fSendUdr TRUE;  
  114.              
  115.          
  116.      
  117.     else if (pContext->Ep0State == EP0_STATE_OUT_DATA_PHASE)  
  118.         if (bEP0IrqStatus OUT_PACKET_READY)  
  119.             bEp0CsrToWrite |= SERVICED_OUT_PKT_RDY;  
  120.               
  121.             // Check For out packet read && receive fifo not empty -> out token event   
  122.             if (cbFifo)  
  123.                 RETAILMSG(1, (_T("%s out token packet on endpoint /r/n"),  
  124.                     pszFname));                  
  125.                 bEp0CsrToWrite |= HandleRx(pContext, peps, &fCompleted, &dwStatus);  
  126.              
  127.             // status stage of control transfer; zero-length packet received   
  128.             else                       
  129.                 RETAILMSG(1, (_T("%s status stage of control transfer on endpoint 0/r/n"),  
  130.                     pszFname));  
  131.                 pContext->Ep0State EP0_STATE_IDLE;  
  132.              
  133.          
  134.      
  135.     else  
  136.         RETAILMSG(1, (_T("%s Data Phase In Token/r/n"), pszFname));  
  137.           
  138.         DEBUGCHK(pContext->Ep0State == EP0_STATE_IN_DATA_PHASE);  
  139.   
  140.         BOOL bHandleTx FALSE;  
  141.   
  142.         // IN Data Phase and IPR is cleared    
  143.         // Check For status stage End control transfer; zero-length packet received   
  144.         if (bEP0IrqStatus  OUT_PACKET_READY) && (cbFifo == 0)  
  145.             bHandleTx TRUE;  
  146.   
  147.             RETAILMSG(1, (_T("%s In end xfer/r/n"),  
  148.                 pszFname));  
  149.          
  150.         else if ((bEP0IrqStatus IN_PACKET_READY) == 0)  
  151.             bHandleTx TRUE;  
  152.          
  153.   
  154.         if (bHandleTx)  
  155.             bEp0CsrToWrite |= HandleTx(pContext, peps, 0);  
  156.          
  157.      
  158.   
  159.     // Clear any interrupts   
  160.     RETAILMSG(1, (_T("%s Writing 0xx to EP0_CSR/r/n"), pszFname, bEp0CsrToWrite));  
  161.     WriteIndexedReg(pContext, 0, EP0_CSR_REG_OFFSET, bEp0CsrToWrite);  
  162.   
  163.     if (fCompleted)  
  164.         CompleteTransfer(pContext, peps, dwStatus);  
  165.      
  166.   
  167.     if (fSendUdr)  
  168.         pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_SETUP_PACKET, (DWORD) &pContext->udr);  
  169.      
  170.   
  171.     FUNCTION_LEAVE_MSG();  
  172.     UNLOCK_ENDPOINT(peps);  
  173.  

5.HandleRx
HandleRx用来读取端点数据.
首先获取端点号dwEndpoint,传输结构pTransfer,如果为TRUE,则验证传输方向,然后获得端点FIFO数据地址:
vo latile 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的返回值.

[c-sharp:collapse] + expand source view plain copy print ?
  1. static  
  2. BYTE  
  3. HandleRx(  
  4.          PCTRLR_PDD_CONTEXT       pContext,  
  5.          PEP_STATUS peps,  
  6.          PBOOL pfCompleted,  
  7.          PDWORD pdwStatus  
  8.           
  9.  
  10.     BOOL fCompleted FALSE;  
  11.     DWORD dwStatus ERROR_GEN_FAILURE;  
  12.     DWORD dwEndpoint peps->dwEndpointNumber;  
  13.     BYTE bRet 0;  
  14.   
  15.     SETFNAME();  
  16.     FUNCTION_ENTER_MSG();  
  17.   
  18.     PSTransfer pTransfer peps->pTransfer;  
  19.   
  20.     pTransfer peps->pTransfer;  
  21.     if (pTransfer)  
  22.         DEBUGCHK(pTransfer->dwFlags == USB_OUT_TRANSFER);  
  23.         DEBUGCHK(pTransfer->dwUsbError == UFN_NOT_COMPLETE_ERROR);  
  24.   
  25.         ValidateTransferDirection(pContext, peps, pTransfer);  
  26.   
  27.         DEBUGCHK(peps->fInitialized);  
  28.   
  29.         DWORD dwCurrentPermissions GetCurrentPermissions();  
  30.         SetProcPermissions(pTransfer->dwCallerPermissions);  
  31.   
  32.         __try  
  33.             volatile ULONG *pulFifoReg _GetDataRegister(dwEndpoint);  
  34.             DEBUGCHK(pulFifoReg != NULL);  
  35.               
  36.             PBYTE  pbBuffer  (PBYTE)pTransfer->pvBuffer pTransfer->cbTransferred;  
  37.   
  38.             DWORD cbBuffer pTransfer->cbBuffer pTransfer->cbTransferred;  
  39.             DWORD cbFifo ReadIndexedReg(pContext, dwEndpoint, OUT_FIFO_CNT1_REG_OFFSET);  
  40.             DEBUGCHK(cbFifo <= peps->dwPacketSizeAssigned);  
  41.   
  42.             // Read from the FIFO   
  43.             const DWORD cbRead min(cbFifo, cbBuffer);  
  44.             DWORD cbToRead cbRead;  
  45.             while (cbToRead--)  
  46.                 *pbBuffer++ (BYTE) *pulFifoReg;  
  47.              
  48.   
  49.             DEBUGCHK(cbRead <= pTransfer->cbBuffer pTransfer->cbTransferred);  
  50.             pTransfer->cbTransferred += cbRead;  
  51.   
  52.             if (cbRead peps->dwPacketSizeAssigned) ||  
  53.                  (pTransfer->cbTransferred == pTransfer->cbBuffer)  
  54.                 // Short packet or filled buffer. Complete transfer.   
  55.                 fCompleted TRUE;  
  56.                 dwStatus UFN_NO_ERROR;  
  57.              
  58.   
  59.             if (dwEndpoint == 0)  
  60.                 bRet |= SERVICED_OUT_PKT_RDY;  
  61.   
  62.                 if (fCompleted)  
  63.                     bRet |= DATA_END;  
  64.                     pContext->Ep0State EP0_STATE_IDLE;  
  65.                  
  66.              
  67.             else  
  68.                 // Clear Out Packet Ready Allow next packet to come in.   
  69.                 DEBUGCHK( (bRet OUT_PACKET_READY) == 0);  
  70.              
  71.          
  72.         __except(EXCEPTION_EXECUTE_HANDLER)  
  73.             RETAILMSG(1, (_T("%s Exception!/r/n"), pszFname));  
  74.             fCompleted TRUE;  
  75.             dwStatus UFN_CLIENT_BUFFER_ERROR;  
  76.          
  77.   
  78.         SetProcPermissions(dwCurrentPermissions);  
  79.       
  80.         RETAILMSG(1, (_T("%s Rx Ep%x BufferSize=%u,Xfrd=%u /r/n"),   
  81.             pszFname, dwEndpoint, pTransfer->cbBuffer, pTransfer->cbTransferred));  
  82.   
  83.         if (fCompleted)  
  84.             RETAILMSG(1, (_T("%s RxDone Ep%x BufferSize=%u, Xfrd=%u/r/n"),   
  85.                 pszFname, dwEndpoint,pTransfer->cbBuffer, pTransfer->cbTransferred));  
  86.          
  87.      
  88.   
  89.     *pfCompleted fCompleted;  
  90.     *pdwStatus dwStatus;  
  91.     FUNCTION_LEAVE_MSG();  
  92.   
  93.     return bRet;  
  94.  

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);

[c-sharp:collapse] + expand source view plain copy print ?
  1. static   
  2. BYTE  
  3. HandleTx(  
  4.          PCTRLR_PDD_CONTEXT       pContext,  
  5.          PEP_STATUS peps,  
  6.          BOOL fEnableInterrupts  
  7.           
  8.  
  9.     SETFNAME();  
  10.     DEBUGCHK(pContext);  
  11.     PREFAST_DEBUGCHK(peps);  
  12.   
  13.     // This routine can be entered from both ISTMain and MDD/Client threads so   
  14.     // need critical section.   
  15.   
  16.     FUNCTION_ENTER_MSG();  
  17.   
  18.     BYTE bRet 0;  
  19.   
  20.     BOOL fCompleted FALSE;  
  21.     PSTransfer pTransfer peps->pTransfer;  
  22.     DWORD dwStatus ERROR_GEN_FAILURE;  
  23.     DEBUGCHK(peps->fInitialized);  
  24.     DWORD dwEndpoint peps->dwEndpointNumber;  
  25.   
  26.     pTransfer peps->pTransfer;  
  27.     if (pTransfer)  
  28.         ValidateTransferDirection(pContext, peps, pTransfer);  
  29.   
  30.         DEBUGCHK(pTransfer->dwFlags == USB_IN_TRANSFER);  
  31.         DEBUGCHK(pTransfer->dwUsbError == UFN_NOT_COMPLETE_ERROR);  
  32.   
  33.         DWORD dwCurrentPermissions GetCurrentPermissions();  
  34.         SetProcPermissions(pTransfer->dwCallerPermissions);  
  35.   
  36.         // Transfer is ready   
  37.         __try  
  38.             PBYTE pbBuffer (PBYTE) pTransfer->pvBuffer pTransfer->cbTransferred;  
  39.             DWORD cbBuffer pTransfer->cbBuffer pTransfer->cbTransferred;  
  40.   
  41.             volatile ULONG *pulFifoReg _GetDataRegister(dwEndpoint);  
  42.   
  43.             DWORD cbWritten 0;  
  44.   
  45.             // Min of input byte count and supported size   
  46.             DWORD cbToWrite min(cbBuffer, peps->dwPacketSizeAssigned);  
  47.             BYTE bRegStatus ReadIndexedReg(pContext, dwEndpoint,   
  48.                 IN_CSR1_REG_OFFSET);  
  49.   
  50.             RETAILMSG(1, (_T("%s Tx on EP %u, Bytes %u/r/n"),   
  51.                 pszFname, dwEndpoint, cbToWrite));  
  52.   
  53.             if (dwEndpoint == 0)  
  54.                 for (cbWritten 0; cbWritten cbToWrite; cbWritten++)  
  55.                     *pulFifoReg *pbBuffer++;  
  56.                  
  57.   
  58.                   
  59.                 pTransfer->cbTransferred += cbWritten;  
  60.                 if (pTransfer->cbTransferred == pTransfer->cbBuffer && pTransfer->pvPddData == 0)  
  61.                     dwStatus UFN_NO_ERROR;  
  62.                     fCompleted TRUE;  
  63.                     pContext->Ep0State EP0_STATE_IDLE;  
  64.                     bRet |= DATA_END;  
  65.                  
  66.                   
  67.                   
  68.                 if( (cbWritten 0) || (pTransfer->cbBuffer == 0)  
  69.                     bRet |= EP0_IN_PACKET_RDY;  
  70.                  
  71.                 // Also set IPR if byte packet needs to go out.   
  72.                 else if(pTransfer->pvPddData)  
  73.                     bRet |= EP0_IN_PACKET_RDY;  
  74.                     pTransfer->pvPddData 0;  
  75.                  
  76.              
  77.             else  
  78.                 // Enable Interrupts before writing to the FIFO. This insures   
  79.                 // That any interrupts generated because of the write will be   
  80.                 // "latched"   
  81.                 if (fEnableInterrupts)  
  82.                     DEBUGCHK(dwEndpoint != 0);  
  83.                     EnableEndpointInterrupt(pContext, dwEndpoint);  
  84.                  
  85.   
  86.                 // Write to the FIFO directly to send the bytes.   
  87.                 for (cbWritten 0; cbWritten cbToWrite; cbWritten++)  
  88.                     *pulFifoReg (ULONG) *pbBuffer++;  
  89.                  
  90.   
  91.                 // By Placing the check for packet complete here, before   
  92.                 // cbTransferred is updated, there is interrupt cycle delay   
  93.                 // That is complete is not declared until the data has actually   
  94.                 // been ACKd (TPC set) by the host   
  95.                 if (pTransfer->cbTransferred == pTransfer->cbBuffer) ||   
  96.                      (cbWritten == 0) ){  
  97.                     fCompleted TRUE;  
  98.                     dwStatus UFN_NO_ERROR;  
  99.                  
  100.                 else  
  101.                       
  102.                     bRet |= IN_PACKET_READY;  
  103.                  
  104.                   
  105.                 // Update the Transfered Count   
  106.                 pTransfer->cbTransferred += cbWritten;  
  107.              
  108.          
  109.         __except(EXCEPTION_EXECUTE_HANDLER)  
  110.             RETAILMSG(1, (_T("%s Exception!/r/n"), pszFname));  
  111.             fCompleted TRUE;  
  112.             dwStatus UFN_CLIENT_BUFFER_ERROR;  
  113.          
  114.   
  115.         SetProcPermissions(dwCurrentPermissions);  
  116.         
  117.     else  
  118.         // It is possible for an interrupt to come in while still in this    
  119.         // function for first pass of transfer. If this happens it is possible   
  120.         // to complete the transfer and have that interrupt be unnecessary   
  121.         // so... just ignore it.   
  122.         goto EXIT;  
  123.      
  124.   
  125.     if (fCompleted)  
  126.         // Disable transfer interrupts until another transfer is issued.   
  127.         if (peps->dwEndpointNumber != 0)  
  128.             DisableEndpointInterrupt(pContext, peps->dwEndpointNumber);  
  129.          
  130.   
  131.         RETAILMSG(1, (_T("%s Tx Done  Ep%x  Status %u/r/n"), pszFname,   
  132.             dwEndpoint, dwStatus));  
  133.         CompleteTransfer(pContext, peps, dwStatus);  
  134.      
  135.     else  
  136.         RETAILMSG(1, (_T("%s Tx EP%x BufferSize=%u, Xfrd=%u/r/n"),   
  137.             pszFname, dwEndpoint, pTransfer->cbBuffer, pTransfer->cbTransferred));  
  138.      
  139.   
  140. EXIT:  
  141.     FUNCTION_LEAVE_MSG();  
  142.   
  143.     return bRet;  
  144.  

SMDK2410的USB Device Driver的PDD层驱动就简单解析到这里,如果错误,欢迎指正.,更多代码请参考sc2410pdd.cpp.要深入了解USB驱动还需要更多的阅读和实践.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值