Windows CE USB Function Driver驱动简析

Windows CE USB Function Driver驱动简析

——驱动架构及UfnPdd函数(基于WinCE5.0 SMDK2410 BSP的UFBFN驱动)

 

本文转自:http://blog.youkuaiyun.com/shevsten/archive/2010/07/15/5736889.aspx

s3c2410有2个USB Host接口,一个Device接口.首先介绍下USB的几个概念:
USB是主从结构的,PC是主端(Host),连接到PC上的设备就是从端(device或function).因此对应的驱动分别叫做USB Host Driver及USB Function Driver。我们的板子可以做host也可以做device,接U盘,鼠标到板子上,板子就是Host.板子连到PC作为Mass Storage或者用Activesync连接就是function.
USB驱动结构图示:

这里我们实现的USB Function Driver就是板子和PC连接时板子端的USB驱动.USB Function Driver包括Controller Driver和Client Driver.Controller Driver介于硬件和Client Driver直之间的控制层,而Client Driver则是具体的应用,如Mass Storage,RNDIS,Serial Class.
USB Function Driver包括MDD和PDD层,SMDK2410 BSP中的USBFN驱动实际上就是PDD部分.MDD部分在/WINCE500/PUBLIC/COMMON/OAK/DRIVERS/USBFN/CONTROLLER/MDD.在我们的PDD驱动中通过链接ufnmddbase.lib这个MDD库来生成驱动dll.
这里我们主要来看看USB Function Driver的PDD部分.实际上就一个文件,sc2410pdd.cpp.
USB Function Driver也是一个标准的流接口驱动,流接口函数实现在/WINCE500/PUBLIC/COMMON/OAK/DRIVERS/USBFN/CONTROLLER/MDD/ufnmdd.cpp中.如UFN_***的函数,会调用在PDD中实现的函数.
1.UfnPdd_DllEntry
被MDD层的DllEntry调用,仅仅设置了g_pUDCBase为NULL.
+ expand sourceview plaincopy to clipboardprint?
// Called by MDD's DllEntry.  
extern "C"   
BOOL  
UfnPdd_DllEntry(  
    HANDLE hDllHandle,  
    DWORD  dwReason,   
    LPVOID lpReserved  
    )  
{  
    SETFNAME();  
 
    switch (dwReason) {  
        case DLL_PROCESS_ATTACH:  
            g_pUDCBase = NULL;  
            break;  
    }  
 
    return TRUE;  

// Called by MDD's DllEntry.
extern "C"
BOOL
UfnPdd_DllEntry(
    HANDLE hDllHandle,
    DWORD  dwReason,
    LPVOID lpReserved
    )
{
    SETFNAME();

    switch (dwReason) {
        case DLL_PROCESS_ATTACH:
            g_pUDCBase = NULL;
            break;
    }

    return TRUE;
}
2.UfnPdd_Init
这个会被MDD层的Init函数调用,首先初始化一个UFN_PDD_INTERFACE_INFO 接口的数组,里面定义了很多函数指针,这些PDD函数都会被MDD层调用.这些函数后面一一分析.
该结构原型如下:
+ expand sourceview plaincopy to clipboardprint?
// Structure that the PDD must fill out in UfnPdd_Init.  
typedef struct _UFN_PDD_INTERFACE_INFO {  
    DWORD           dwVersion;  
 
    DWORD           dwCapabilities;  
    DWORD           dwEndpointCount;  
    PVOID           pvPddContext;  
 
    PFN_UFN_PDD_DEINIT pfnDeinit;  
    PFN_UFN_PDD_IS_CONFIGURATION_SUPPORTABLE pfnIsConfigurationSupportable;  
    PFN_UFN_PDD_IS_ENDPOINT_SUPPORTABLE pfnIsEndpointSupportable;  
    PFN_UFN_PDD_INIT_ENDPOINT pfnInitEndpoint;  
    PFN_UFN_PDD_REGISTER_DEVICE pfnRegisterDevice;  
    PFN_UFN_PDD_DEREGISTER_DEVICE pfnDeregisterDevice;  
    PFN_UFN_PDD_START pfnStart;  
    PFN_UFN_PDD_STOP pfnStop;  
    PFN_UFN_PDD_ISSUE_TRANSFER pfnIssueTransfer;  
    PFN_UFN_PDD_ABORT_TRANSFER pfnAbortTransfer;  
    PFN_UFN_DEINIT_ENDPOINT pfnDeinitEndpoint;  
    PFN_UFN_STALL_ENDPOINT pfnStallEndpoint;  
    PFN_UFN_CLEAR_ENDPOINT_STALL pfnClearEndpointStall;  
    PFN_UFN_SEND_CONTROL_STATUS_HANDSHAKE pfnSendControlStatusHandshake;  
    PFN_UFN_SET_ADDRESS pfnSetAddress;  
    PFN_UFN_IS_ENDPOINT_HALTED pfnIsEndpointHalted;  
    PFN_UFN_INITIATE_REMOTE_WAKEUP pfnInitiateRemoteWakeup;  
    PFN_UFN_POWER_DOWN pfnPowerDown;  
    PFN_UFN_POWER_UP pfnPowerUp;  
    PFN_UFN_IOCONTROL pfnIOControl;  
} UFN_PDD_INTERFACE_INFO, *PUFN_PDD_INTERFACE_INFO; 
// Structure that the PDD must fill out in UfnPdd_Init.
typedef struct _UFN_PDD_INTERFACE_INFO {
    DWORD           dwVersion;

    DWORD           dwCapabilities;
    DWORD           dwEndpointCount;
    PVOID           pvPddContext;

    PFN_UFN_PDD_DEINIT pfnDeinit;
    PFN_UFN_PDD_IS_CONFIGURATION_SUPPORTABLE pfnIsConfigurationSupportable;
    PFN_UFN_PDD_IS_ENDPOINT_SUPPORTABLE pfnIsEndpointSupportable;
    PFN_UFN_PDD_INIT_ENDPOINT pfnInitEndpoint;
    PFN_UFN_PDD_REGISTER_DEVICE pfnRegisterDevice;
    PFN_UFN_PDD_DEREGISTER_DEVICE pfnDeregisterDevice;
    PFN_UFN_PDD_START pfnStart;
    PFN_UFN_PDD_STOP pfnStop;
    PFN_UFN_PDD_ISSUE_TRANSFER pfnIssueTransfer;
    PFN_UFN_PDD_ABORT_TRANSFER pfnAbortTransfer;
    PFN_UFN_DEINIT_ENDPOINT pfnDeinitEndpoint;
    PFN_UFN_STALL_ENDPOINT pfnStallEndpoint;
    PFN_UFN_CLEAR_ENDPOINT_STALL pfnClearEndpointStall;
    PFN_UFN_SEND_CONTROL_STATUS_HANDSHAKE pfnSendControlStatusHandshake;
    PFN_UFN_SET_ADDRESS pfnSetAddress;
    PFN_UFN_IS_ENDPOINT_HALTED pfnIsEndpointHalted;
    PFN_UFN_INITIATE_REMOTE_WAKEUP pfnInitiateRemoteWakeup;
    PFN_UFN_POWER_DOWN pfnPowerDown;
    PFN_UFN_POWER_UP pfnPowerUp;
    PFN_UFN_IOCONTROL pfnIOControl;
} UFN_PDD_INTERFACE_INFO, *PUFN_PDD_INTERFACE_INFO;
接下来就是读取注册表获取相关配置信息,存到一个PCTRLR_PDD_CONTEXT结构pContext中.一开始初始化一些符号,还有MDD Context等.然后设置每个ENDPOINT对应的端点状态结构EP_STATUS的端点号,这里最多5个端点,也就是有5个EP_STATUS的结构.
接下来定义了DDKISRINFO和DDKWINDOWINFO的对象,用来读取注册表信IoBase,IoLen,Irq,并向内核申请一个SYSINTR逻辑中断号.然后读取IST优先级("Priority256"=dword:64),接着创建一个访问总线句柄pContext->hBusAccess.
最后调用MapRegisterSet将IOBASE地址(USB device controller register地址)映射到虚拟地址空间.真正的g_pUDCBase是加上了0x140(UDC寄存器基址偏移)的偏移.
然后设置attachedState为UFN_DETACH.调用ResetDevice复位UDC寄存器.将sc_PddInterfaceInfo传递给输入参数.
如果中间出现任何错误将跳转至EXIT,RegCloseKey关闭注册表,FreeCtrlrContext释放之前分配的资源.
+ expand sourceview plaincopy to clipboardprint?
// Initialize the device.  
DWORD  
WINAPI  
UfnPdd_Init(  
    LPCTSTR                     pszActiveKey,  
    PVOID                       pvMddContext,  
    PUFN_MDD_INTERFACE_INFO     pMddInterfaceInfo,  
    PUFN_PDD_INTERFACE_INFO     pPddInterfaceInfo  
    )  
{      
    SETFNAME();  
    FUNCTION_ENTER_MSG();  
 
    static const UFN_PDD_INTERFACE_INFO sc_PddInterfaceInfo = {  
        UFN_PDD_INTERFACE_VERSION,  
        UFN_PDD_CAPS_SUPPORTS_FULL_SPEED,  
        ENDPOINT_COUNT,  
        NULL, // This gets filled in later  
          
        &UfnPdd_Deinit,  
        &UfnPdd_IsConfigurationSupportable,  
        &UfnPdd_IsEndpointSupportable,  
        &UfnPdd_InitEndpoint,  
        &UfnPdd_RegisterDevice,  
        &UfnPdd_DeregisterDevice,  
        &UfnPdd_Start,  
        &UfnPdd_Stop,  
        &UfnPdd_IssueTransfer,  
        &UfnPdd_AbortTransfer,  
        &UfnPdd_DeinitEndpoint,  
        &UfnPdd_StallEndpoint,  
        &UfnPdd_ClearEndpointStall,  
        &UfnPdd_SendControlStatusHandshake,  
        &UfnPdd_SetAddress,  
        &UfnPdd_IsEndpointHalted,  
        &UfnPdd_InitiateRemoteWakeup,  
        &UfnPdd_PowerDown,  
        &UfnPdd_PowerUp,  
        &UfnPdd_IOControl,  
    };  
 
    DWORD dwType;  
    DWORD dwRet;  
 
    HKEY hkDevice = NULL;  
    PCTRLR_PDD_CONTEXT pContext = NULL;  
 
    DEBUGCHK(pszActiveKey);  
    DEBUGCHK(pMddInterfaceInfo);  
    DEBUGCHK(pPddInterfaceInfo);  
 
    hkDevice = OpenDeviceKey(pszActiveKey);  
    if (!hkDevice) {  
        dwRet = GetLastError();  
        DEBUGMSG(ZONE_ERROR, (_T("%s Could not open device key. Error: %d/r/n"),   
            pszFname, dwRet));  
        goto EXIT;          
    }  
 
    pContext = (PCTRLR_PDD_CONTEXT) LocalAlloc(LPTR, sizeof(*pContext));  
    if (pContext == NULL) {  
        dwRet = GetLastError();  
        PREFAST_DEBUGCHK(dwRet != ERROR_SUCCESS);  
        DEBUGMSG(ZONE_ERROR, (_T("%s LocalAlloc failed. Error: %d/r/n"), pszFname, dwRet));  
        goto EXIT;  
    }  
    pContext->dwSig = SC2410_SIG;  
 
    pContext->pvMddContext = pvMddContext;  
    pContext->cpsCurrent = D4;  
    pContext->dwIrq = IRQ_UNSPECIFIED;  
    pContext->pfnNotify = pMddInterfaceInfo->pfnNotify;  
    InitializeCriticalSection(&pContext->csIndexedRegisterAccess);  
 
    for (DWORD dwEp = 0; dwEp < dim(pContext->rgEpStatus); ++dwEp) {  
        pContext->rgEpStatus[dwEp].dwEndpointNumber = dwEp;  
    }  
 
    DWORD dwDataSize;  
    DWORD dwPriority;  
 
    DDKISRINFO dii;  
    DDKWINDOWINFO dwi;  
 
    // read window configuration from the registry  
    dwi.cbSize = sizeof(dwi);  
    dwRet = DDKReg_GetWindowInfo(hkDevice, &dwi);  
    if(dwRet != ERROR_SUCCESS) {  
        DEBUGMSG(ZONE_ERROR, (_T("%s DDKReg_GetWindowInfo() failed %d/r/n"),   
            pszFname, dwRet));  
        goto EXIT;  
    }   
    else if (dwi.dwNumIoWindows != 1) {  
        DEBUGMSG(ZONE_ERROR, (_T("%s %d windows configured, expected 1/r/n"),   
            pszFname, dwi.dwNumIoWindows));  
        dwRet = ERROR_INVALID_DATA;  
        goto EXIT;  
    }   
    else if (dwi.ioWindows[0].dwLen < REGISTER_SET_SIZE) {  
        DEBUGMSG(ZONE_INIT, (_T("%s ioLen of 0x%x is less than required 0x%x/r/n"),  
            pszFname, dwi.ioWindows[0].dwLen, REGISTER_SET_SIZE));  
        dwRet = ERROR_INVALID_DATA;  
        goto EXIT;          
    }  
    else if (dwi.ioWindows[0].dwBase == 0){  
        DEBUGMSG(ZONE_INIT, (_T("%s no ioBase value specified/r/n"),pszFname));  
        dwRet = ERROR_INVALID_DATA;  
        goto EXIT;  
    }  
    else {  
        pContext->dwIOBase = dwi.ioWindows[0].dwBase;  
        pContext->dwIOLen = dwi.ioWindows[0].dwLen;  
    }  
      
    // get ISR configuration information  
    dii.cbSize = sizeof(dii);  
    dwRet = DDKReg_GetIsrInfo(hkDevice, &dii);  
    if (dwRet != ERROR_SUCCESS) {  
        DEBUGMSG(ZONE_ERROR, (_T("%s DDKReg_GetIsrInfo() failed %d/r/n"),   
            pszFname, dwRet));  
        goto EXIT;  
    }  
    else if( (dii.dwSysintr == SYSINTR_NOP) && (dii.dwIrq == IRQ_UNSPECIFIED) ) {  
        DEBUGMSG(ZONE_ERROR, (_T("%s no IRQ or SYSINTR value specified/r/n"), pszFname));  
        dwRet = ERROR_INVALID_DATA;  
        goto EXIT;  
    }   
    else {  
        if (dii.dwSysintr == SYSINTR_NOP) {  
            BOOL fSuccess = KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &dii.dwIrq,   
                sizeof(DWORD), &dii.dwSysintr, sizeof(DWORD), NULL);  
            if (!fSuccess) {  
                DEBUGMSG(ZONE_ERROR, (_T("%s IOCTL_HAL_REQUEST_SYSINTR failed!/r/n"),   
                    pszFname));  
                goto EXIT;  
            }  
 
            pContext->dwIrq = dii.dwIrq;  
            pContext->dwSysIntr = dii.dwSysintr;  
        }  
        else {  
            pContext->dwSysIntr = dii.dwSysintr;  
        }  
    }  
 
    // Read the IST priority  
    dwDataSize = sizeof(dwPriority);  
    dwRet = RegQueryValueEx(hkDevice, UDC_REG_PRIORITY_VAL, NULL, &dwType,  
        (LPBYTE) &dwPriority, &dwDataSize);  
    if (dwRet != ERROR_SUCCESS) {  
        dwPriority = DEFAULT_PRIORITY;  
    }  
 
    pContext->hBusAccess = CreateBusAccessHandle(pszActiveKey);  
    if (pContext->hBusAccess == NULL) {  
        // This is not a failure.  
        DEBUGMSG(ZONE_WARNING, (_T("%s Could not create bus access handle/r/n"),  
            pszFname));  
    }  
 
    DEBUGMSG(ZONE_INIT, (_T("%s Using IO Base %x/r/n"),   
        pszFname, pContext->dwIOBase));  
    DEBUGMSG(ZONE_INIT, (_T("%s Using SysIntr %u/r/n"),   
        pszFname, pContext->dwSysIntr));  
    DEBUGMSG(ZONE_INIT, (_T("%s Using IST priority %u/r/n"),   
        pszFname, dwPriority));  
 
    pContext->dwISTPriority = dwPriority;  
 
    // map register space to virtual memory  
    dwRet = MapRegisterSet(pContext);  
    if (dwRet != ERROR_SUCCESS) {  
        DEBUGMSG(ZONE_ERROR, (_T("%s failed to map register space/r/n"),  
            pszFname));  
        goto EXIT;  
    }  
      
    pContext->attachedState = UFN_DETACH;  
 
    ResetDevice(pContext);  
    ValidateContext(pContext);  
 
    memcpy(pPddInterfaceInfo, &sc_PddInterfaceInfo, sizeof(sc_PddInterfaceInfo));  
    pPddInterfaceInfo->pvPddContext = pContext;  
 
EXIT:  
    if (hkDevice) RegCloseKey(hkDevice);  
      
    if (dwRet != ERROR_SUCCESS && pContext) {  
        FreeCtrlrContext(pContext);  
    }  
 
    FUNCTION_LEAVE_MSG();  
 
    return dwRet;  

// Initialize the device.
DWORD
WINAPI
UfnPdd_Init(
    LPCTSTR                     pszActiveKey,
    PVOID                       pvMddContext,
    PUFN_MDD_INTERFACE_INFO     pMddInterfaceInfo,
    PUFN_PDD_INTERFACE_INFO     pPddInterfaceInfo
    )
{   
    SETFNAME();
    FUNCTION_ENTER_MSG();

    static const UFN_PDD_INTERFACE_INFO sc_PddInterfaceInfo = {
        UFN_PDD_INTERFACE_VERSION,
        UFN_PDD_CAPS_SUPPORTS_FULL_SPEED,
        ENDPOINT_COUNT,
        NULL, // This gets filled in later
       
        &UfnPdd_Deinit,
        &UfnPdd_IsConfigurationSupportable,
        &UfnPdd_IsEndpointSupportable,
        &UfnPdd_InitEndpoint,
        &UfnPdd_RegisterDevice,
        &UfnPdd_DeregisterDevice,
        &UfnPdd_Start,
        &UfnPdd_Stop,
        &UfnPdd_IssueTransfer,
        &UfnPdd_AbortTransfer,
        &UfnPdd_DeinitEndpoint,
        &UfnPdd_StallEndpoint,
        &UfnPdd_ClearEndpointStall,
        &UfnPdd_SendControlStatusHandshake,
        &UfnPdd_SetAddress,
        &UfnPdd_IsEndpointHalted,
        &UfnPdd_InitiateRemoteWakeup,
        &UfnPdd_PowerDown,
        &UfnPdd_PowerUp,
        &UfnPdd_IOControl,
    };

    DWORD dwType;
    DWORD dwRet;

    HKEY hkDevice = NULL;
    PCTRLR_PDD_CONTEXT pContext = NULL;

    DEBUGCHK(pszActiveKey);
    DEBUGCHK(pMddInterfaceInfo);
    DEBUGCHK(pPddInterfaceInfo);

    hkDevice = OpenDeviceKey(pszActiveKey);
    if (!hkDevice) {
        dwRet = GetLastError();
        DEBUGMSG(ZONE_ERROR, (_T("%s Could not open device key. Error: %d/r/n"),
            pszFname, dwRet));
        goto EXIT;       
    }

    pContext = (PCTRLR_PDD_CONTEXT) LocalAlloc(LPTR, sizeof(*pContext));
    if (pContext == NULL) {
        dwRet = GetLastError();
        PREFAST_DEBUGCHK(dwRet != ERROR_SUCCESS);
        DEBUGMSG(ZONE_ERROR, (_T("%s LocalAlloc failed. Error: %d/r/n"), pszFname, dwRet));
        goto EXIT;
    }
    pContext->dwSig = SC2410_SIG;

    pContext->pvMddContext = pvMddContext;
    pContext->cpsCurrent = D4;
    pContext->dwIrq = IRQ_UNSPECIFIED;
    pContext->pfnNotify = pMddInterfaceInfo->pfnNotify;
    InitializeCriticalSection(&pContext->csIndexedRegisterAccess);

    for (DWORD dwEp = 0; dwEp < dim(pContext->rgEpStatus); ++dwEp) {
        pContext->rgEpStatus[dwEp].dwEndpointNumber = dwEp;
    }

    DWORD dwDataSize;
    DWORD dwPriority;

    DDKISRINFO dii;
    DDKWINDOWINFO dwi;

    // read window configuration from the registry
    dwi.cbSize = sizeof(dwi);
    dwRet = DDKReg_GetWindowInfo(hkDevice, &dwi);
    if(dwRet != ERROR_SUCCESS) {
        DEBUGMSG(ZONE_ERROR, (_T("%s DDKReg_GetWindowInfo() failed %d/r/n"),
            pszFname, dwRet));
        goto EXIT;
    }
    else if (dwi.dwNumIoWindows != 1) {
        DEBUGMSG(ZONE_ERROR, (_T("%s %d windows configured, expected 1/r/n"),
            pszFname, dwi.dwNumIoWindows));
        dwRet = ERROR_INVALID_DATA;
        goto EXIT;
    }
    else if (dwi.ioWindows[0].dwLen < REGISTER_SET_SIZE) {
        DEBUGMSG(ZONE_INIT, (_T("%s ioLen of 0x%x is less than required 0x%x/r/n"),
            pszFname, dwi.ioWindows[0].dwLen, REGISTER_SET_SIZE));
        dwRet = ERROR_INVALID_DATA;
        goto EXIT;       
    }
    else if (dwi.ioWindows[0].dwBase == 0){
        DEBUGMSG(ZONE_INIT, (_T("%s no ioBase value specified/r/n"),pszFname));
        dwRet = ERROR_INVALID_DATA;
        goto EXIT;
    }
    else {
        pContext->dwIOBase = dwi.ioWindows[0].dwBase;
        pContext->dwIOLen = dwi.ioWindows[0].dwLen;
    }
   
    // get ISR configuration information
    dii.cbSize = sizeof(dii);
    dwRet = DDKReg_GetIsrInfo(hkDevice, &dii);
    if (dwRet != ERROR_SUCCESS) {
        DEBUGMSG(ZONE_ERROR, (_T("%s DDKReg_GetIsrInfo() failed %d/r/n"),
            pszFname, dwRet));
        goto EXIT;
    }
    else if( (dii.dwSysintr == SYSINTR_NOP) && (dii.dwIrq == IRQ_UNSPECIFIED) ) {
        DEBUGMSG(ZONE_ERROR, (_T("%s no IRQ or SYSINTR value specified/r/n"), pszFname));
        dwRet = ERROR_INVALID_DATA;
        goto EXIT;
    }
    else {
        if (dii.dwSysintr == SYSINTR_NOP) {
            BOOL fSuccess = KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &dii.dwIrq,
                sizeof(DWORD), &dii.dwSysintr, sizeof(DWORD), NULL);
            if (!fSuccess) {
                DEBUGMSG(ZONE_ERROR, (_T("%s IOCTL_HAL_REQUEST_SYSINTR failed!/r/n"),
                    pszFname));
                goto EXIT;
            }

            pContext->dwIrq = dii.dwIrq;
            pContext->dwSysIntr = dii.dwSysintr;
        }
        else {
            pContext->dwSysIntr = dii.dwSysintr;
        }
    }

    // Read the IST priority
    dwDataSize = sizeof(dwPriority);
    dwRet = RegQueryValueEx(hkDevice, UDC_REG_PRIORITY_VAL, NULL, &dwType,
        (LPBYTE) &dwPriority, &dwDataSize);
    if (dwRet != ERROR_SUCCESS) {
        dwPriority = DEFAULT_PRIORITY;
    }

    pContext->hBusAccess = CreateBusAccessHandle(pszActiveKey);
    if (pContext->hBusAccess == NULL) {
        // This is not a failure.
        DEBUGMSG(ZONE_WARNING, (_T("%s Could not create bus access handle/r/n"),
            pszFname));
    }

    DEBUGMSG(ZONE_INIT, (_T("%s Using IO Base %x/r/n"),
        pszFname, pContext->dwIOBase));
    DEBUGMSG(ZONE_INIT, (_T("%s Using SysIntr %u/r/n"),
        pszFname, pContext->dwSysIntr));
    DEBUGMSG(ZONE_INIT, (_T("%s Using IST priority %u/r/n"),
        pszFname, dwPriority));

    pContext->dwISTPriority = dwPriority;

    // map register space to virtual memory
    dwRet = MapRegisterSet(pContext);
    if (dwRet != ERROR_SUCCESS) {
        DEBUGMSG(ZONE_ERROR, (_T("%s failed to map register space/r/n"),
            pszFname));
        goto EXIT;
    }
   
    pContext->attachedState = UFN_DETACH;

    ResetDevice(pContext);
    ValidateContext(pContext);

    memcpy(pPddInterfaceInfo, &sc_PddInterfaceInfo, sizeof(sc_PddInterfaceInfo));
    pPddInterfaceInfo->pvPddContext = pContext;

EXIT:
    if (hkDevice) RegCloseKey(hkDevice);
   
    if (dwRet != ERROR_SUCCESS && pContext) {
        FreeCtrlrContext(pContext);
    }

    FUNCTION_LEAVE_MSG();

    return dwRet;
}
ResetDevice:
再来看看ResetDevice的具体内容,对UDC内部寄存器的操作有禁止UDC中断,禁止端点中断(EP0-EP4),清楚USB中断标志,清楚端点中断标志,然后调用ResetEndpoint对每个端点进行复位.
+ expand sourceview plaincopy to clipboardprint?
ResetDevice(  
            PCTRLR_PDD_CONTEXT pContext  
            )  
{  
    SETFNAME();  
    FUNCTION_ENTER_MSG();  
 
    DEBUGCHK(IS_VALID_SC2410_CONTEXT(pContext));  
 
    // 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);  
 
    // Reset all endpoints  
    for (DWORD dwEpIdx = 0; dwEpIdx < ENDPOINT_COUNT; ++dwEpIdx) {  
        EP_STATUS *peps = GetEpStatus(pContext, dwEpIdx);  
        ResetEndpoint(pContext, peps);  
    }  
 
    FUNCTION_LEAVE_MSG();  

ResetDevice(
            PCTRLR_PDD_CONTEXT pContext
            )
{
    SETFNAME();
    FUNCTION_ENTER_MSG();

    DEBUGCHK(IS_VALID_SC2410_CONTEXT(pContext));

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

    // Reset all endpoints
    for (DWORD dwEpIdx = 0; dwEpIdx < ENDPOINT_COUNT; ++dwEpIdx) {
        EP_STATUS *peps = GetEpStatus(pContext, dwEpIdx);
        ResetEndpoint(pContext, peps);
    }

    FUNCTION_LEAVE_MSG();
}
 
ResetEndpoint:
ResetEndpoint对具体某个端点进行复位.首先对端点0清除SETUP_END和OUT_PKT_RDY状态.接下来对具体端点进行操作.如果该端点已初始化,则读取IN_CSR2_REG和OUT_CSR2_REG寄存器的值并保存.接着设置IN_CSR2_REG,端点方向为IN,禁止的DMA中断.设置IN_CSR1_REG清除data toggle bit,包的PID(标识符段)包含DATA0.然后设置OUT方向,设置OUT_CSR1_REG FLUSH FIFO,清除data toggle bit,数据包顺序设为DATA0,设置OUT_CSR2_REG,禁止DMA中断.如果初始化状态为TRUE,则恢复之前保存的寄存器内容.最后清除所有EndPoint中断.
+ expand sourceview plaincopy to clipboardprint?
static 
VOID  
ResetEndpoint(  
              PCTRLR_PDD_CONTEXT pContext,  
              EP_STATUS *peps  
              )  
{  
    SETFNAME();  
    FUNCTION_ENTER_MSG();  
 
    ValidateContext(pContext);  
    PREFAST_DEBUGCHK(peps);  
 
    // Since Reset can be called before/after an Endpoint has been configured,  
    // it is best to clear all IN and OUT bits associated with endpoint.   
    DWORD dwEndpoint = peps->dwEndpointNumber;  
    if(dwEndpoint == 0 ) {  
        // Clear all EP0 Status bits  
        WriteIndexedReg(pContext, 0, IN_CSR1_REG_OFFSET,  
            (SERVICED_OUT_PKT_RDY | SERVICED_SETUP_END));  
    }  
    else if(dwEndpoint < ENDPOINT_COUNT) {  
        // Clear the desired Endpoint - Clear both the In & Out Status bits  
        BYTE bRegIn;  
        BYTE bRegOut;  
        if(peps->fInitialized){  
            PREFAST_DEBUGCHK(peps->fInitialized); // Give prefast a clue.  
            // First Read the CSR2 Reg bit so that it can be restored  
            bRegIn = ReadIndexedReg(pContext, dwEndpoint, IN_CSR2_REG_OFFSET);  
            bRegOut = ReadIndexedReg(pContext, dwEndpoint, OUT_CSR2_REG_OFFSET);  
        }  
        // Clear the in register - Must set the Mode_in to IN  
        WriteIndexedReg(pContext, dwEndpoint, IN_CSR2_REG_OFFSET,(SET_MODE_IN | IN_DMA_INT_DISABLE));  
        WriteIndexedReg(pContext, dwEndpoint, IN_CSR1_REG_OFFSET, ( IN_CLR_DATA_TOGGLE));  
 
        // Clear the Out register  - Must set the Mode_in to OUT  
        WriteIndexedReg(pContext, dwEndpoint, IN_CSR2_REG_OFFSET, (IN_DMA_INT_DISABLE)); // mode_in bit = OUT   
        WriteIndexedReg(pContext, dwEndpoint, OUT_CSR1_REG_OFFSET, (FLUSH_OUT_FIFO | OUT_CLR_DATA_TOGGLE));  
        WriteIndexedReg(pContext, dwEndpoint,  OUT_CSR2_REG_OFFSET, OUT_DMA_INT_DISABLE);  
 
        if(peps->fInitialized) {  
            // Set the Mode_In, ISO and other Modality type bits back to the way it was - this allows   
            // ResetEndpoint to be called without having to re-init the endpoint.  
            WriteIndexedReg(pContext, dwEndpoint, IN_CSR2_REG_OFFSET, bRegIn);  
            WriteIndexedReg(pContext, dwEndpoint, OUT_CSR2_REG_OFFSET, bRegOut);  
        }  
 
        // Clear and disable interrupt  
        WriteReg(pContext, EP_INT_REG_OFFSET, EpToIrqStatBit(peps->dwEndpointNumber));  
        DisableEndpointInterrupt(pContext, peps->dwEndpointNumber);  
    }  
    else {  
        DEBUGCHK(FALSE);  
    }  
 
    FUNCTION_LEAVE_MSG();  

static
VOID
ResetEndpoint(
              PCTRLR_PDD_CONTEXT pContext,
              EP_STATUS *peps
              )
{
    SETFNAME();
    FUNCTION_ENTER_MSG();

    ValidateContext(pContext);
    PREFAST_DEBUGCHK(peps);

    // Since Reset can be called before/after an Endpoint has been configured,
    // it is best to clear all IN and OUT bits associated with endpoint.
    DWORD dwEndpoint = peps->dwEndpointNumber;
    if(dwEndpoint == 0 ) {
        // Clear all EP0 Status bits
        WriteIndexedReg(pContext, 0, IN_CSR1_REG_OFFSET,
            (SERVICED_OUT_PKT_RDY | SERVICED_SETUP_END));
    }
    else if(dwEndpoint < ENDPOINT_COUNT) {
        // Clear the desired Endpoint - Clear both the In & Out Status bits
        BYTE bRegIn;
        BYTE bRegOut;
        if(peps->fInitialized){
            PREFAST_DEBUGCHK(peps->fInitialized); // Give prefast a clue.
            // First Read the CSR2 Reg bit so that it can be restored
            bRegIn = ReadIndexedReg(pContext, dwEndpoint, IN_CSR2_REG_OFFSET);
            bRegOut = ReadIndexedReg(pContext, dwEndpoint, OUT_CSR2_REG_OFFSET);
        }
        // Clear the in register - Must set the Mode_in to IN
        WriteIndexedReg(pContext, dwEndpoint, IN_CSR2_REG_OFFSET,(SET_MODE_IN | IN_DMA_INT_DISABLE));
        WriteIndexedReg(pContext, dwEndpoint, IN_CSR1_REG_OFFSET, ( IN_CLR_DATA_TOGGLE));

        // Clear the Out register  - Must set the Mode_in to OUT
        WriteIndexedReg(pContext, dwEndpoint, IN_CSR2_REG_OFFSET, (IN_DMA_INT_DISABLE)); // mode_in bit = OUT
        WriteIndexedReg(pContext, dwEndpoint, OUT_CSR1_REG_OFFSET, (FLUSH_OUT_FIFO | OUT_CLR_DATA_TOGGLE));
        WriteIndexedReg(pContext, dwEndpoint,  OUT_CSR2_REG_OFFSET, OUT_DMA_INT_DISABLE);

        if(peps->fInitialized) {
            // Set the Mode_In, ISO and other Modality type bits back to the way it was - this allows
            // ResetEndpoint to be called without having to re-init the endpoint.
            WriteIndexedReg(pContext, dwEndpoint, IN_CSR2_REG_OFFSET, bRegIn);
            WriteIndexedReg(pContext, dwEndpoint, OUT_CSR2_REG_OFFSET, bRegOut);
        }

        // Clear and disable interrupt
        WriteReg(pContext, EP_INT_REG_OFFSET, EpToIrqStatBit(peps->dwEndpointNumber));
        DisableEndpointInterrupt(pContext, peps->dwEndpointNumber);
    }
    else {
        DEBUGCHK(FALSE);
    }

    FUNCTION_LEAVE_MSG();
}
 
FreeCtrlrContext:
FreeCtrlrContext首先释放g_pUDCBase映射的IO空间,然后调用CloseBusAccessHandle关闭总线驱动句柄,然后禁止中断唤醒,释放逻辑中断号.
+ expand sourceview plaincopy to clipboardprint?
static 
VOID  
FreeCtrlrContext(  
    PCTRLR_PDD_CONTEXT pContext  
    )  
{  
    PREFAST_DEBUGCHK(pContext);  
    DEBUGCHK(!pContext->hevInterrupt);  
    DEBUGCHK(!pContext->hIST);  
    DEBUGCHK(!pContext->fRunning);  
 
    pContext->dwSig = GARBAGE_DWORD;  
 
    UnmapRegisterSet(pContext);  
 
    if (pContext->hBusAccess) CloseBusAccessHandle(pContext->hBusAccess);  
      
    if (pContext->dwSysIntr) {  
        KernelIoControl(IOCTL_HAL_DISABLE_WAKE, &pContext->dwSysIntr,    
            sizeof(pContext->dwSysIntr), NULL, 0, NULL);  
    }  
 
    if (pContext->dwIrq != IRQ_UNSPECIFIED) {  
        KernelIoControl(IOCTL_HAL_RELEASE_SYSINTR, &pContext->dwIrq,   
            sizeof(DWORD), NULL, 0, NULL);  
    }  
      
    DeleteCriticalSection(&pContext->csIndexedRegisterAccess);  
 
    LocalFree(pContext);  

static
VOID
FreeCtrlrContext(
    PCTRLR_PDD_CONTEXT pContext
    )
{
    PREFAST_DEBUGCHK(pContext);
    DEBUGCHK(!pContext->hevInterrupt);
    DEBUGCHK(!pContext->hIST);
    DEBUGCHK(!pContext->fRunning);

    pContext->dwSig = GARBAGE_DWORD;

    UnmapRegisterSet(pContext);

    if (pContext->hBusAccess) CloseBusAccessHandle(pContext->hBusAccess);
   
    if (pContext->dwSysIntr) {
        KernelIoControl(IOCTL_HAL_DISABLE_WAKE, &pContext->dwSysIntr, 
         sizeof(pContext->dwSysIntr), NULL, 0, NULL);
    }

    if (pContext->dwIrq != IRQ_UNSPECIFIED) {
        KernelIoControl(IOCTL_HAL_RELEASE_SYSINTR, &pContext->dwIrq,
            sizeof(DWORD), NULL, 0, NULL);
    }
   
    DeleteCriticalSection(&pContext->csIndexedRegisterAccess);

    LocalFree(pContext);
}
下面就一个个来看UfnPdd_Init中声明的UFN_PDD_INTERFACE_INFO结构中的函数.
3.UfnPdd_Deinit
UfnPdd_Deinit用来进行资源的释放,检查完参数后就调用FreeCtrlrContext释放资源,如UDC寄存器地址空间的释放,SYSINTR和IRQ的释放等.
+ expand sourceview plaincopy to clipboardprint?
DWORD  
WINAPI  
UfnPdd_Deinit(  
    PVOID pvPddContext  
    )  
{  
    SETFNAME();  
    FUNCTION_ENTER_MSG();  
 
    PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;  
    ValidateContext(pContext);  
 
    FUNCTION_ENTER_MSG();  
 
    FreeCtrlrContext(pContext);  
 
    FUNCTION_LEAVE_MSG();  
 
    return ERROR_SUCCESS;  

DWORD
WINAPI
UfnPdd_Deinit(
    PVOID pvPddContext
    )
{
    SETFNAME();
    FUNCTION_ENTER_MSG();

    PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;
    ValidateContext(pContext);

    FUNCTION_ENTER_MSG();

    FreeCtrlrContext(pContext);

    FUNCTION_LEAVE_MSG();

    return ERROR_SUCCESS;
}
4.UfnPdd_Start
UfnPdd_Start用来启动USB Device设备.
一开始先创建中断事件hevInterrupt,并与SYSINTR号关联中断初始化.然后调用InterruptDone完成中断.创建对应的IST线程.如有错误,则跳转到EXIT禁止中断,释放事件句柄.
+ expand sourceview plaincopy to clipboardprint?
DWORD  
WINAPI  
UfnPdd_Start(  
    PVOID        pvPddContext  
    )  
{  
    //RETAILMSG(TRUE, (TEXT("++UfnPdd_Start for GEC2410 USBFN/r/n")));  
 
    SETFNAME();  
    FUNCTION_ENTER_MSG();  
 
    DWORD dwRet;  
    PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;  
    ValidateContext(pContext);  
 
    FUNCTION_ENTER_MSG();  
 
    DEBUGCHK(!pContext->fRunning);  
 
    BOOL fIntInitialized = FALSE;  
 
    // Create the interrupt event  
    pContext->hevInterrupt = CreateEvent(0, FALSE, FALSE, NULL);  
    if (pContext->hevInterrupt == NULL) {  
        dwRet = GetLastError();  
        RETAILMSG(1, (_T("%s Error creating  interrupt event. Error = %d/r/n"),   
            pszFname, dwRet));  
        goto EXIT;  
    }  
 
    fIntInitialized = InterruptInitialize(pContext->dwSysIntr,   
        pContext->hevInterrupt, NULL, 0);  
    if (fIntInitialized == FALSE) {  
        dwRet = ERROR_GEN_FAILURE;  
        RETAILMSG(1, (_T("%s  interrupt initialization failed/r/n"),  
            pszFname));  
        goto EXIT;  
    }  
    InterruptDone(pContext->dwSysIntr);  
 
    pContext->fExitIST = FALSE;  
    pContext->hIST = CreateThread(NULL, 0, ISTMain, pContext, 0, NULL);      
    if (pContext->hIST == NULL) {  
        RETAILMSG(1, (_T("%s IST creation failed/r/n"), pszFname));  
        dwRet = GetLastError();  
        goto EXIT;  
    }  
 
    pContext->fRunning = TRUE;  
    dwRet = ERROR_SUCCESS;  
 
EXIT:  
    if (pContext->fRunning == FALSE) {  
        DEBUGCHK(dwRet != ERROR_SUCCESS);  
        if (fIntInitialized) InterruptDisable(pContext->dwSysIntr);  
        if (pContext->hevInterrupt) CloseHandle(pContext->hevInterrupt);  
        pContext->hevInterrupt = NULL;  
    }  
 
    FUNCTION_LEAVE_MSG();  
 
    return dwRet;  

DWORD
WINAPI
UfnPdd_Start(
    PVOID        pvPddContext
    )
{
 //RETAILMSG(TRUE, (TEXT("++UfnPdd_Start for GEC2410 USBFN/r/n")));

    SETFNAME();
    FUNCTION_ENTER_MSG();

    DWORD dwRet;
    PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;
    ValidateContext(pContext);

    FUNCTION_ENTER_MSG();

    DEBUGCHK(!pContext->fRunning);

    BOOL fIntInitialized = FALSE;

    // Create the interrupt event
    pContext->hevInterrupt = CreateEvent(0, FALSE, FALSE, NULL);
    if (pContext->hevInterrupt == NULL) {
        dwRet = GetLastError();
        RETAILMSG(1, (_T("%s Error creating  interrupt event. Error = %d/r/n"),
            pszFname, dwRet));
        goto EXIT;
    }

    fIntInitialized = InterruptInitialize(pContext->dwSysIntr,
        pContext->hevInterrupt, NULL, 0);
    if (fIntInitialized == FALSE) {
        dwRet = ERROR_GEN_FAILURE;
        RETAILMSG(1, (_T("%s  interrupt initialization failed/r/n"),
            pszFname));
        goto EXIT;
    }
    InterruptDone(pContext->dwSysIntr);

    pContext->fExitIST = FALSE;
    pContext->hIST = CreateThread(NULL, 0, ISTMain, pContext, 0, NULL);   
    if (pContext->hIST == NULL) {
        RETAILMSG(1, (_T("%s IST creation failed/r/n"), pszFname));
        dwRet = GetLastError();
        goto EXIT;
    }

    pContext->fRunning = TRUE;
    dwRet = ERROR_SUCCESS;

EXIT:
    if (pContext->fRunning == FALSE) {
        DEBUGCHK(dwRet != ERROR_SUCCESS);
        if (fIntInitialized) InterruptDisable(pContext->dwSysIntr);
        if (pContext->hevInterrupt) CloseHandle(pContext->hevInterrupt);
        pContext->hevInterrupt = NULL;
    }

    FUNCTION_LEAVE_MSG();

    return dwRet;
}
5.UfnPdd_Stop
UfnPdd_Stop用来停止USB Device设备.
主要工作为关闭中断线程,设置中断线程和事件句柄为NULL,调用ResetDevice复位设备,并标记运行状态fRunning为false.
+ expand sourceview plaincopy to clipboardprint?
DWORD  
WINAPI  
UfnPdd_Stop(  
            PVOID pvPddContext  
            )  
{  
    SETFNAME();  
    FUNCTION_ENTER_MSG();  
 
    PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;  
    ValidateContext(pContext);  
 
    DEBUGCHK(pContext->fRunning);  
 
    // Stop the IST  
    pContext->fExitIST = TRUE;  
    InterruptDisable(pContext->dwSysIntr);  
    SetEvent(pContext->hevInterrupt);  
    WaitForSingleObject(pContext->hIST, INFINITE);  
    CloseHandle(pContext->hevInterrupt);  
    CloseHandle(pContext->hIST);  
    pContext->hIST = NULL;  
    pContext->hevInterrupt = NULL;  
 
    ResetDevice(pContext);  
 
    pContext->fRunning = FALSE;  
 
    RETAILMSG(1, (_T("%s Device has been stopped/r/n"),   
        pszFname));  
 
    FUNCTION_LEAVE_MSG();  
 
    return ERROR_SUCCESS;  

DWORD
WINAPI
UfnPdd_Stop(
            PVOID pvPddContext
            )
{
    SETFNAME();
    FUNCTION_ENTER_MSG();

    PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;
    ValidateContext(pContext);

    DEBUGCHK(pContext->fRunning);

    // Stop the IST
    pContext->fExitIST = TRUE;
    InterruptDisable(pContext->dwSysIntr);
    SetEvent(pContext->hevInterrupt);
    WaitForSingleObject(pContext->hIST, INFINITE);
    CloseHandle(pContext->hevInterrupt);
    CloseHandle(pContext->hIST);
    pContext->hIST = NULL;
    pContext->hevInterrupt = NULL;

    ResetDevice(pContext);

    pContext->fRunning = FALSE;

    RETAILMSG(1, (_T("%s Device has been stopped/r/n"),
        pszFname));

    FUNCTION_LEAVE_MSG();

    return ERROR_SUCCESS;
}
6.UfnPdd_InitEndpoint
UfnPdd_InitEndpoint进行初始化端点.
开始是参数检查,会调用UfnPdd_IsEndpointSupportable来查询端点是否支持(这个函数下面介绍),如果设置的参数超过硬件支持的数值,则进行修正.然后获取端点信息保存到EP_STATUS结构peps中.设置包最大字节数wMaxPacketSize(最大2047).如果是端点0,仅仅需要注册一个通知函数.同时将wMaxPacketSize赋值给EP_STATUS的成员dwPacketSizeAssigned.如果是其他端点,则首先调用ResetEndpoint复位端点,清除CSR2寄存器所有位,禁止DMA.然后设置端点方向(IN_CSR2_REG寄存器mode_in bit).
接着设置传输类型,根据输入参数pEndpointDesc来获得具体类型,如果是ISOCHRONOUS异步模式,则写IN_CSR2_REG的ISO比特,其他模式则设置该位为0,为Bulk模式.
最后将最大包字节数wMaxPacketSize写入MAX_PKT_SIZE_REG寄存器,调用UfnPdd_ClearEndpointStall和ClearEndpointInterrupt端点挂起和端点中断状态.
+ expand sourceview plaincopy to clipboardprint?
DWORD  
WINAPI  
UfnPdd_InitEndpoint(  
    PVOID                       pvPddContext,  
    DWORD                       dwEndpoint,  
    UFN_BUS_SPEED               Speed,  
    PUSB_ENDPOINT_DESCRIPTOR    pEndpointDesc,  
    PVOID                       pvReserved,  
    BYTE                        bConfigurationValue,  
    BYTE                        bInterfaceNumber,  
    BYTE                        bAlternateSetting  
    )  
{  
    SETFNAME();  
    FUNCTION_ENTER_MSG();  
 
    DEBUGCHK(EP_VALID(dwEndpoint));  
    PREFAST_DEBUGCHK(pEndpointDesc); 
 
#ifdef DEBUG  
    {  
        USB_ENDPOINT_DESCRIPTOR EndpointDesc;  
        memcpy(&EndpointDesc, pEndpointDesc, sizeof(EndpointDesc));  
        DEBUGCHK(UfnPdd_IsEndpointSupportable(pvPddContext, dwEndpoint, Speed,  
            &EndpointDesc, bConfigurationValue, bInterfaceNumber,   
            bAlternateSetting) == ERROR_SUCCESS);  
        DEBUGCHK(memcmp(&EndpointDesc, pEndpointDesc, sizeof(EndpointDesc)) == 0);  
    } 
#endif  
 
    PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;  
    ValidateContext(pContext);  
    BYTE bEndpointAddress = 0;  
 
    PEP_STATUS peps = GetEpStatus(pContext, dwEndpoint);  
    DEBUGCHK(!peps->fInitialized);  
 
    InitializeCriticalSection(&peps->cs);  
 
    WORD wMaxPacketSize =   
        pEndpointDesc->wMaxPacketSize & USB_ENDPOINT_MAX_PACKET_SIZE_MASK;  
    DEBUGCHK(wMaxPacketSize);  
      
    // If the target is endpoint 0, then only allow the function driver   
    // to register a notification function.  
    if (dwEndpoint == 0) {  
       peps->dwPacketSizeAssigned = wMaxPacketSize;  
       // Interrupts for endpoint 0 are enabled in ISTMain  
    }  
    else if (dwEndpoint < ENDPOINT_COUNT) {  
        // Clear all Status bits and leave the Endpoint interrupt disabled  
        // Clear Fifos, and all register bits  
        ResetEndpoint(pContext,peps);  
 
        // Clear all bits in CSR2 - Disable DMA for now...  
        WriteIndexedReg(pContext, dwEndpoint, IN_CSR2_REG_OFFSET, 0);  
 
        // Setup Direction (mode_in bit)   
        bEndpointAddress = pEndpointDesc->bEndpointAddress;  
        BOOL fModeOut = USB_ENDPOINT_DIRECTION_OUT(bEndpointAddress);  
        if (fModeOut) {  
            SetClearIndexedReg(pContext, dwEndpoint,IN_CSR2_REG_OFFSET,   
                SET_MODE_IN, CLEAR);                
            peps->dwDirectionAssigned = USB_OUT_TRANSFER;  
        }  
        else {  
            SetClearIndexedReg(pContext, dwEndpoint, IN_CSR2_REG_OFFSET,   
                SET_MODE_IN, SET);  
            peps->dwDirectionAssigned = USB_IN_TRANSFER;  
        }  
 
        // Set Transfer Type  
        BYTE bTransferType = pEndpointDesc->bmAttributes & USB_ENDPOINT_TYPE_MASK;  
        DEBUGCHK(bTransferType != USB_ENDPOINT_TYPE_CONTROL);  
        switch(bTransferType) {  
            case USB_ENDPOINT_TYPE_ISOCHRONOUS:  
                // Set the ISO bit  
                SetClearIndexedReg(pContext, dwEndpoint,IN_CSR2_REG_OFFSET,   
                    SET_TYPE_ISO, SET);  
                break;  
 
            case USB_ENDPOINT_TYPE_BULK:  
            case USB_ENDPOINT_TYPE_INTERRUPT:  
            default:  
                // Clear ISO bit - Set type to Bulk  
                SetClearIndexedReg(pContext, dwEndpoint,IN_CSR2_REG_OFFSET,   
                    SET_TYPE_ISO, CLEAR);  
        }  
 
        peps->dwEndpointType = bTransferType;  
        peps->dwPacketSizeAssigned = wMaxPacketSize;  
          
        // Set the Max Packet Size Register  
        BYTE maxPacketBits = (BYTE) (peps->dwPacketSizeAssigned >> 3);  
        WriteIndexedReg(pContext, dwEndpoint, MAX_PKT_SIZE_REG_OFFSET,   
            maxPacketBits);   
 
        UfnPdd_ClearEndpointStall(pvPddContext,dwEndpoint);  
 
        // Clear outstanding interrupts  
        ClearEndpointInterrupt(pContext, dwEndpoint);  
    }  
      
    peps->fInitialized = TRUE;  
    FUNCTION_LEAVE_MSG();  
 
    return ERROR_SUCCESS;  

DWORD
WINAPI
UfnPdd_InitEndpoint(
    PVOID                       pvPddContext,
    DWORD                       dwEndpoint,
    UFN_BUS_SPEED               Speed,
    PUSB_ENDPOINT_DESCRIPTOR    pEndpointDesc,
    PVOID                       pvReserved,
    BYTE                        bConfigurationValue,
    BYTE                        bInterfaceNumber,
    BYTE                        bAlternateSetting
    )
{
    SETFNAME();
    FUNCTION_ENTER_MSG();

    DEBUGCHK(EP_VALID(dwEndpoint));
    PREFAST_DEBUGCHK(pEndpointDesc);

#ifdef DEBUG
    {
        USB_ENDPOINT_DESCRIPTOR EndpointDesc;
        memcpy(&EndpointDesc, pEndpointDesc, sizeof(EndpointDesc));
        DEBUGCHK(UfnPdd_IsEndpointSupportable(pvPddContext, dwEndpoint, Speed,
            &EndpointDesc, bConfigurationValue, bInterfaceNumber,
            bAlternateSetting) == ERROR_SUCCESS);
        DEBUGCHK(memcmp(&EndpointDesc, pEndpointDesc, sizeof(EndpointDesc)) == 0);
    }
#endif

    PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;
    ValidateContext(pContext);
    BYTE bEndpointAddress = 0;

    PEP_STATUS peps = GetEpStatus(pContext, dwEndpoint);
    DEBUGCHK(!peps->fInitialized);

    InitializeCriticalSection(&peps->cs);

    WORD wMaxPacketSize =
        pEndpointDesc->wMaxPacketSize & USB_ENDPOINT_MAX_PACKET_SIZE_MASK;
    DEBUGCHK(wMaxPacketSize);
   
    // If the target is endpoint 0, then only allow the function driver
    // to register a notification function.
    if (dwEndpoint == 0) {
       peps->dwPacketSizeAssigned = wMaxPacketSize;
       // Interrupts for endpoint 0 are enabled in ISTMain
    }
    else if (dwEndpoint < ENDPOINT_COUNT) {
        // Clear all Status bits and leave the Endpoint interrupt disabled
        // Clear Fifos, and all register bits
        ResetEndpoint(pContext,peps);

        // Clear all bits in CSR2 - Disable DMA for now...
        WriteIndexedReg(pContext, dwEndpoint, IN_CSR2_REG_OFFSET, 0);

        // Setup Direction (mode_in bit)
        bEndpointAddress = pEndpointDesc->bEndpointAddress;
        BOOL fModeOut = USB_ENDPOINT_DIRECTION_OUT(bEndpointAddress);
        if (fModeOut) {
            SetClearIndexedReg(pContext, dwEndpoint,IN_CSR2_REG_OFFSET,
                SET_MODE_IN, CLEAR);             
            peps->dwDirectionAssigned = USB_OUT_TRANSFER;
        }
        else {
            SetClearIndexedReg(pContext, dwEndpoint, IN_CSR2_REG_OFFSET,
                SET_MODE_IN, SET);
            peps->dwDirectionAssigned = USB_IN_TRANSFER;
        }

        // Set Transfer Type
        BYTE bTransferType = pEndpointDesc->bmAttributes & USB_ENDPOINT_TYPE_MASK;
        DEBUGCHK(bTransferType != USB_ENDPOINT_TYPE_CONTROL);
        switch(bTransferType) {
            case USB_ENDPOINT_TYPE_ISOCHRONOUS:
                // Set the ISO bit
                SetClearIndexedReg(pContext, dwEndpoint,IN_CSR2_REG_OFFSET,
                    SET_TYPE_ISO, SET);
                break;

            case USB_ENDPOINT_TYPE_BULK:
            case USB_ENDPOINT_TYPE_INTERRUPT:
            default:
                // Clear ISO bit - Set type to Bulk
                SetClearIndexedReg(pContext, dwEndpoint,IN_CSR2_REG_OFFSET,
                    SET_TYPE_ISO, CLEAR);
        }

        peps->dwEndpointType = bTransferType;
        peps->dwPacketSizeAssigned = wMaxPacketSize;
       
        // Set the Max Packet Size Register
        BYTE maxPacketBits = (BYTE) (peps->dwPacketSizeAssigned >> 3);
        WriteIndexedReg(pContext, dwEndpoint, MAX_PKT_SIZE_REG_OFFSET,
            maxPacketBits);

        UfnPdd_ClearEndpointStall(pvPddContext,dwEndpoint);

        // Clear outstanding interrupts
        ClearEndpointInterrupt(pContext, dwEndpoint);
    }
   
    peps->fInitialized = TRUE;
    FUNCTION_LEAVE_MSG();

    return ERROR_SUCCESS;
}
UfnPdd_ClearEndpointStall函数下面介绍,先来看看ClearEndpointInterrupt
ClearEndpointInterrupt用来清除EP_INT_REG寄存器对应端点的中断.+ expand sourceview plaincopy to clipboardprint?
static 
VOID  
ClearEndpointInterrupt(  
                       PCTRLR_PDD_CONTEXT pContext,  
                       DWORD        dwEndpoint  
                       )  
{      
    SETFNAME();  
    FUNCTION_ENTER_MSG();  
      
    // Clear the Endpoint Interrupt  
    BYTE bIntBit = EpToIrqStatBit(dwEndpoint);  
    WriteReg(pContext, EP_INT_REG_OFFSET, bIntBit);  
 
    FUNCTION_LEAVE_MSG();  
} // _ClearInterrupt 
static
VOID
ClearEndpointInterrupt(
                       PCTRLR_PDD_CONTEXT pContext,
                       DWORD        dwEndpoint
                       )
{   
    SETFNAME();
    FUNCTION_ENTER_MSG();
   
    // Clear the Endpoint Interrupt
    BYTE bIntBit = EpToIrqStatBit(dwEndpoint);
    WriteReg(pContext, EP_INT_REG_OFFSET, bIntBit);

    FUNCTION_LEAVE_MSG();
} // _ClearInterrupt
7.UfnPdd_DeinitEndpoint
UfnPdd_DeinitEndpoint通过调用ResetEndpoint和ClearEndpointInterrupt进行端点复位,屏蔽中断,清除端点中断状态.
+ expand sourceview plaincopy to clipboardprint?
DWORD  
WINAPI  
UfnPdd_DeinitEndpoint(  
                      PVOID pvPddContext,  
                      DWORD dwEndpoint  
                      )  
{  
    SETFNAME();  
    FUNCTION_ENTER_MSG();  
 
    DEBUGCHK(EP_VALID(dwEndpoint));  
 
    PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;  
    ValidateContext(pContext);  
 
    PEP_STATUS peps = GetEpStatus(pContext, dwEndpoint);  
    LOCK_ENDPOINT(peps);  
 
    DEBUGCHK(peps->fInitialized);  
    DEBUGCHK(peps->pTransfer == NULL);  
 
    // Reset and disable the endpoint   
    // Mask endpoint interrupts      
    ResetEndpoint(pContext, peps);  
 
    // Clear endpoint interrupts  
    ClearEndpointInterrupt(pContext, dwEndpoint);  
 
    peps->fInitialized = FALSE;  
    UNLOCK_ENDPOINT(peps);  
 
    DeleteCriticalSection(&peps->cs);  
 
    FUNCTION_LEAVE_MSG();  
 
    return ERROR_SUCCESS;  

DWORD
WINAPI
UfnPdd_DeinitEndpoint(
                      PVOID pvPddContext,
                      DWORD dwEndpoint
                      )
{
    SETFNAME();
    FUNCTION_ENTER_MSG();

    DEBUGCHK(EP_VALID(dwEndpoint));

    PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;
    ValidateContext(pContext);

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

    DEBUGCHK(peps->fInitialized);
    DEBUGCHK(peps->pTransfer == NULL);

    // Reset and disable the endpoint
    // Mask endpoint interrupts   
    ResetEndpoint(pContext, peps);

    // Clear endpoint interrupts
    ClearEndpointInterrupt(pContext, dwEndpoint);

    peps->fInitialized = FALSE;
    UNLOCK_ENDPOINT(peps);

    DeleteCriticalSection(&peps->cs);

    FUNCTION_LEAVE_MSG();

    return ERROR_SUCCESS;
}
8.UfnPdd_ClearEndpointStall
UfnPdd_ClearEndpointStall用来清除端点的stall停止状态.
首先依然是参数检查,然后获取端点信息保存到EP_STATUS结构peps中,如果是端点0,清除EP0_CSR的send和sent stall状态.如果是其他端点,根据传输方向设置IN_CSR1_REG或OUT_CSR1_REG清除send和sent stall状态.
+ expand sourceview plaincopy to clipboardprint?
DWORD  
WINAPI  
UfnPdd_ClearEndpointStall(  
                          PVOID pvPddContext,  
                          DWORD dwEndpoint  
                          )  
{  
    DWORD dwRet = ERROR_SUCCESS;  
 
    SETFNAME();  
    FUNCTION_ENTER_MSG();  
 
    DEBUGCHK(EP_VALID(dwEndpoint));  
 
    PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;  
    ValidateContext(pContext);  
 
    PEP_STATUS peps = GetEpStatus(pContext, dwEndpoint);  
    LOCK_ENDPOINT(peps);  
 
    if (dwEndpoint == 0){  
        // Must Clear both Send and Sent Stall  
        WriteIndexedReg(pContext, 0, EP0_CSR_REG_OFFSET, 0);  
    }  
    else if (peps->dwDirectionAssigned == USB_IN_TRANSFER){  
        SetClearIndexedReg(pContext, dwEndpoint, IN_CSR1_REG_OFFSET,  
            (IN_SEND_STALL | IN_CLR_DATA_TOGGLE ), SET);  
 
        // Must Clear both Send and Sent Stall  
        SetClearIndexedReg(pContext, dwEndpoint, IN_CSR1_REG_OFFSET,  
            (IN_SEND_STALL  | IN_SENT_STALL), CLEAR);                 
    }  
    else{ // Out Endpoint  
        // Must Clear both Send and Sent Stall  
        SetClearIndexedReg(pContext, dwEndpoint, OUT_CSR1_REG_OFFSET,  
            ( OUT_SEND_STALL | OUT_CLR_DATA_TOGGLE ), SET);  
        SetClearIndexedReg(pContext ,dwEndpoint, OUT_CSR1_REG_OFFSET,  
            ( OUT_SEND_STALL  | OUT_SENT_STALL), CLEAR);  
    }  
      
    UNLOCK_ENDPOINT(peps);  
    FUNCTION_LEAVE_MSG();  
 
    return ERROR_SUCCESS;  

DWORD
WINAPI
UfnPdd_ClearEndpointStall(
                          PVOID pvPddContext,
                          DWORD dwEndpoint
                          )
{
    DWORD dwRet = ERROR_SUCCESS;

    SETFNAME();
    FUNCTION_ENTER_MSG();

    DEBUGCHK(EP_VALID(dwEndpoint));

    PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;
    ValidateContext(pContext);

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

    if (dwEndpoint == 0){
        // Must Clear both Send and Sent Stall
        WriteIndexedReg(pContext, 0, EP0_CSR_REG_OFFSET, 0);
    }
    else if (peps->dwDirectionAssigned == USB_IN_TRANSFER){
        SetClearIndexedReg(pContext, dwEndpoint, IN_CSR1_REG_OFFSET,
            (IN_SEND_STALL | IN_CLR_DATA_TOGGLE ), SET);

        // Must Clear both Send and Sent Stall
        SetClearIndexedReg(pContext, dwEndpoint, IN_CSR1_REG_OFFSET,
            (IN_SEND_STALL  | IN_SENT_STALL), CLEAR);              
    }
    else{ // Out Endpoint
        // Must Clear both Send and Sent Stall
        SetClearIndexedReg(pContext, dwEndpoint, OUT_CSR1_REG_OFFSET,
            ( OUT_SEND_STALL | OUT_CLR_DATA_TOGGLE ), SET);
        SetClearIndexedReg(pContext ,dwEndpoint, OUT_CSR1_REG_OFFSET,
            ( OUT_SEND_STALL  | OUT_SENT_STALL), CLEAR);
    }
   
    UNLOCK_ENDPOINT(peps);
    FUNCTION_LEAVE_MSG();

    return ERROR_SUCCESS;
}
9.UfnPdd_StallEndpoint
UfnPdd_StallEndpoint用来停止端点.
首先依然是参数检查,然后获取端点信息保存到EP_STATUS结构peps中,如果是端点0,清除EP0_CSR的DATA_END,SERVICED_OUT_PKT_RDY状态,设置EP0_SEND_STALL.
如果是其他端点,根据传输方向,设置IN_CSR1_REG或OUT_CSR1_REG寄存器的IN_SEND_STALL或OUT_SEND_STALL,OUT_PACKET_READY.
+ expand sourceview plaincopy to clipboardprint?
DWORD  
WINAPI  
UfnPdd_StallEndpoint(  
                     PVOID pvPddContext,  
                     DWORD dwEndpoint  
                     )  
{  
    DWORD dwRet = ERROR_SUCCESS;  
    SETFNAME();  
    FUNCTION_ENTER_MSG();  
 
    DEBUGCHK(EP_VALID(dwEndpoint));  
 
    PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;  
    ValidateContext(pContext);  
 
    PEP_STATUS peps = GetEpStatus(pContext, dwEndpoint);  
    DEBUGCHK(peps->fInitialized);  
    LOCK_ENDPOINT(peps);  
 
    if (dwEndpoint == 0) {  
        // Must Clear Out Packet Ready when sending Stall  
        BYTE bEp0StallBits = (DATA_END | SERVICED_OUT_PKT_RDY | EP0_SEND_STALL);  
        RETAILMSG(1, (_T("%s Writing 0x%02x to EP0_CSR_REG/r/n"), pszFname,  
            bEp0StallBits));  
        WriteIndexedReg(pContext, 0, EP0_CSR_REG_OFFSET, bEp0StallBits);  
        // Set Flag so that SendControlStatusHandshked does not  
        // duplicate this HW Write. Manual says all bits need  
        // to be set at the same time.  
        pContext->sendDataEnd = FALSE;  
        pContext->Ep0State = EP0_STATE_IDLE;  
    }  
    else if (peps->dwDirectionAssigned == USB_IN_TRANSFER) {  
        SetClearIndexedReg(pContext, dwEndpoint, IN_CSR1_REG_OFFSET,  
            (IN_SEND_STALL), SET);  
    }  
    else { // Out Endpoint  
        // Must Clear Out Packet Ready when sending Stall  
        SetClearIndexedReg(pContext, dwEndpoint, OUT_CSR1_REG_OFFSET,  
            (OUT_SEND_STALL), SET);  
        SetClearIndexedReg(pContext ,dwEndpoint, OUT_CSR1_REG_OFFSET,  
            (OUT_PACKET_READY), CLEAR);  
    }  
      
    UNLOCK_ENDPOINT(peps);  
    FUNCTION_LEAVE_MSG();  
 
    return ERROR_SUCCESS;  

DWORD
WINAPI
UfnPdd_StallEndpoint(
                     PVOID pvPddContext,
                     DWORD dwEndpoint
                     )
{
    DWORD dwRet = ERROR_SUCCESS;
    SETFNAME();
    FUNCTION_ENTER_MSG();

    DEBUGCHK(EP_VALID(dwEndpoint));

    PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;
    ValidateContext(pContext);

    PEP_STATUS peps = GetEpStatus(pContext, dwEndpoint);
    DEBUGCHK(peps->fInitialized);
    LOCK_ENDPOINT(peps);

    if (dwEndpoint == 0) {
        // Must Clear Out Packet Ready when sending Stall
        BYTE bEp0StallBits = (DATA_END | SERVICED_OUT_PKT_RDY | EP0_SEND_STALL);
  RETAILMSG(1, (_T("%s Writing 0x%02x to EP0_CSR_REG/r/n"), pszFname,
   bEp0StallBits));
        WriteIndexedReg(pContext, 0, EP0_CSR_REG_OFFSET, bEp0StallBits);
        // Set Flag so that SendControlStatusHandshked does not
        // duplicate this HW Write. Manual says all bits need
        // to be set at the same time.
        pContext->sendDataEnd = FALSE;
        pContext->Ep0State = EP0_STATE_IDLE;
    }
    else if (peps->dwDirectionAssigned == USB_IN_TRANSFER) {
        SetClearIndexedReg(pContext, dwEndpoint, IN_CSR1_REG_OFFSET,
            (IN_SEND_STALL), SET);
    }
    else { // Out Endpoint
        // Must Clear Out Packet Ready when sending Stall
        SetClearIndexedReg(pContext, dwEndpoint, OUT_CSR1_REG_OFFSET,
            (OUT_SEND_STALL), SET);
        SetClearIndexedReg(pContext ,dwEndpoint, OUT_CSR1_REG_OFFSET,
            (OUT_PACKET_READY), CLEAR);
    }
   
    UNLOCK_ENDPOINT(peps);
    FUNCTION_LEAVE_MSG();

    return ERROR_SUCCESS;
}
10.UfnPdd_IsConfigurationSupportable
这个函数没有做具体工作.
+ expand sourceview plaincopy to clipboardprint?
DWORD   
WINAPI   
UfnPdd_IsConfigurationSupportable(  
    PVOID                       pvPddContext,  
    UFN_BUS_SPEED               Speed,  
    PUFN_CONFIGURATION          pConfiguration  
    )  
{  
    SETFNAME();  
    FUNCTION_ENTER_MSG();  
 
    DEBUGCHK(Speed == BS_FULL_SPEED);  
 
    PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;  
    ValidateContext(pContext);  
 
    // This PDD does not have any special requirements that cannot be   
    // handled through IsEndpointSupportable.  
    DWORD dwRet = ERROR_SUCCESS;  
 
    FUNCTION_LEAVE_MSG();  
 
    return dwRet;  

DWORD
WINAPI
UfnPdd_IsConfigurationSupportable(
    PVOID                       pvPddContext,
    UFN_BUS_SPEED               Speed,
    PUFN_CONFIGURATION          pConfiguration
    )
{
    SETFNAME();
    FUNCTION_ENTER_MSG();

    DEBUGCHK(Speed == BS_FULL_SPEED);

    PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;
    ValidateContext(pContext);

    // This PDD does not have any special requirements that cannot be
    // handled through IsEndpointSupportable.
    DWORD dwRet = ERROR_SUCCESS;

    FUNCTION_LEAVE_MSG();

    return dwRet;
}
11.UfnPdd_IsEndpointSupportable
UfnPdd_IsEndpointSupportable用来查询指定端点是否支持.
首先判断是否是端点0,如果是端点0则检查其属性是否为CONTROL,并判断其做大包字节数,如果小于8,则设置成8.如果是其他端点,则需保证其属性不为CONTROL端点.然后根据不同的传输类型设置其包大小的范围.异步类型CPU UDC不支持,批量或中断传输硬件支持8,16,32,64字节的包, 如果要求设置的包大小超过范围,则设置支持的最大的值.
+ expand sourceview plaincopy to clipboardprint?
DWORD  
WINAPI  
UfnPdd_IsEndpointSupportable(  
    PVOID                       pvPddContext,  
    DWORD                       dwEndpoint,  
    UFN_BUS_SPEED               Speed,  
    PUSB_ENDPOINT_DESCRIPTOR    pEndpointDesc,  
    BYTE                        bConfigurationValue,  
    BYTE                        bInterfaceNumber,  
    BYTE                        bAlternateSetting  
    )  
{  
    SETFNAME();  
    FUNCTION_ENTER_MSG();  
 
    DEBUGCHK(EP_VALID(dwEndpoint));  
    DEBUGCHK(Speed == BS_FULL_SPEED);  
 
    DWORD dwRet = ERROR_SUCCESS;  
    PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;  
    ValidateContext(pContext);  
 
    PEP_STATUS peps = GetEpStatus(pContext, dwEndpoint);  
 
    // Special case for endpoint 0  
    if (dwEndpoint == 0) {  
        DEBUGCHK(pEndpointDesc->bmAttributes == USB_ENDPOINT_TYPE_CONTROL);  
          
        // Endpoint 0 only supports 8 or 16 byte packet size  
        if (pEndpointDesc->wMaxPacketSize < EP_0_PACKET_SIZE) {  
            RETAILMSG(1, (_T("%s Endpoint 0 only supports %u byte packets/r/n"),  
                pszFname, EP_0_PACKET_SIZE));  
            dwRet = ERROR_INVALID_PARAMETER;  
        }  
        else{    
            // Larger than EP 0 Max Packet Size - reduce to Max  
            pEndpointDesc->wMaxPacketSize = EP_0_PACKET_SIZE;  
        }  
    }  
    else if (dwEndpoint < ENDPOINT_COUNT) {  
        BYTE bTransferType = pEndpointDesc->bmAttributes & USB_ENDPOINT_TYPE_MASK;  
        DEBUGCHK(bTransferType != USB_ENDPOINT_TYPE_CONTROL);  
 
        // Validate and adjust packet size  
        WORD wPacketSize =   
            (pEndpointDesc->wMaxPacketSize & USB_ENDPOINT_MAX_PACKET_SIZE_MASK);  
 
        switch(bTransferType) {  
 
        // Isoch not currently supported by Samsung HW  
        case USB_ENDPOINT_TYPE_ISOCHRONOUS:  
            RETAILMSG(1, (_T("%s Isochronous endpoints are not supported/r/n"),  
                pszFname));  
            dwRet = ERROR_INVALID_PARAMETER;  
            break;  
 
        case USB_ENDPOINT_TYPE_BULK:  
        case USB_ENDPOINT_TYPE_INTERRUPT:  
            // HW Can only Support 8, 16, 32, 64 byte packets  
            if((wPacketSize >= 8) && (wPacketSize < 16)){  
                wPacketSize = 8;  
            }  
            else if ((wPacketSize >= 16) && (wPacketSize < 64)){  
                // Note that 32 => Dual Packet mode - Do NOT allow  
                wPacketSize = 16;  
            }  
            else if (wPacketSize >= 64 ){  
                wPacketSize = 64;                  
            }  
            else{ // wPacketSize < 8  
                dwRet = ERROR_INVALID_PARAMETER;  
            }  
            break;  
 
        default:  
            dwRet = ERROR_INVALID_PARAMETER;  
            break;  
        }    
          
        // If Requested Size is larger than what is supported ... change it.  
        // Note only try and change it if no errors so far... meaning Ep is  
        // Supportable.  
        if ( (wPacketSize != (pEndpointDesc->wMaxPacketSize & USB_ENDPOINT_MAX_PACKET_SIZE_MASK)) &&   
             (dwRet == ERROR_SUCCESS) ) {  
            pEndpointDesc->wMaxPacketSize &= ~USB_ENDPOINT_MAX_PACKET_SIZE_MASK;  
            pEndpointDesc->wMaxPacketSize |= wPacketSize;  
        }  
    }  
 
    FUNCTION_LEAVE_MSG();  
 
    return dwRet;  

DWORD
WINAPI
UfnPdd_IsEndpointSupportable(
    PVOID                       pvPddContext,
    DWORD                       dwEndpoint,
    UFN_BUS_SPEED               Speed,
    PUSB_ENDPOINT_DESCRIPTOR    pEndpointDesc,
    BYTE                        bConfigurationValue,
    BYTE                        bInterfaceNumber,
    BYTE                        bAlternateSetting
    )
{
    SETFNAME();
    FUNCTION_ENTER_MSG();

    DEBUGCHK(EP_VALID(dwEndpoint));
    DEBUGCHK(Speed == BS_FULL_SPEED);

    DWORD dwRet = ERROR_SUCCESS;
    PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;
    ValidateContext(pContext);

    PEP_STATUS peps = GetEpStatus(pContext, dwEndpoint);

    // Special case for endpoint 0
    if (dwEndpoint == 0) {
        DEBUGCHK(pEndpointDesc->bmAttributes == USB_ENDPOINT_TYPE_CONTROL);
       
        // Endpoint 0 only supports 8 or 16 byte packet size
        if (pEndpointDesc->wMaxPacketSize < EP_0_PACKET_SIZE) {
            RETAILMSG(1, (_T("%s Endpoint 0 only supports %u byte packets/r/n"),
                pszFname, EP_0_PACKET_SIZE));
            dwRet = ERROR_INVALID_PARAMETER;
        }
        else{ 
            // Larger than EP 0 Max Packet Size - reduce to Max
            pEndpointDesc->wMaxPacketSize = EP_0_PACKET_SIZE;
        }
    }
    else if (dwEndpoint < ENDPOINT_COUNT) {
        BYTE bTransferType = pEndpointDesc->bmAttributes & USB_ENDPOINT_TYPE_MASK;
        DEBUGCHK(bTransferType != USB_ENDPOINT_TYPE_CONTROL);

        // Validate and adjust packet size
        WORD wPacketSize =
            (pEndpointDesc->wMaxPacketSize & USB_ENDPOINT_MAX_PACKET_SIZE_MASK);

        switch(bTransferType) {

        // Isoch not currently supported by Samsung HW
        case USB_ENDPOINT_TYPE_ISOCHRONOUS:
            RETAILMSG(1, (_T("%s Isochronous endpoints are not supported/r/n"),
                pszFname));
            dwRet = ERROR_INVALID_PARAMETER;
            break;

        case USB_ENDPOINT_TYPE_BULK:
        case USB_ENDPOINT_TYPE_INTERRUPT:
            // HW Can only Support 8, 16, 32, 64 byte packets
            if((wPacketSize >= 8) && (wPacketSize < 16)){
                wPacketSize = 8;
            }
            else if ((wPacketSize >= 16) && (wPacketSize < 64)){
                // Note that 32 => Dual Packet mode - Do NOT allow
                wPacketSize = 16;
            }
            else if (wPacketSize >= 64 ){
                wPacketSize = 64;               
            }
            else{ // wPacketSize < 8
                dwRet = ERROR_INVALID_PARAMETER;
            }
            break;

        default:
            dwRet = ERROR_INVALID_PARAMETER;
            break;
        } 
       
        // If Requested Size is larger than what is supported ... change it.
        // Note only try and change it if no errors so far... meaning Ep is
        // Supportable.
        if ( (wPacketSize != (pEndpointDesc->wMaxPacketSize & USB_ENDPOINT_MAX_PACKET_SIZE_MASK)) &&
             (dwRet == ERROR_SUCCESS) ) {
            pEndpointDesc->wMaxPacketSize &= ~USB_ENDPOINT_MAX_PACKET_SIZE_MASK;
            pEndpointDesc->wMaxPacketSize |= wPacketSize;
        }
    }

    FUNCTION_LEAVE_MSG();

    return dwRet;
}
12.UfnPdd_SendControlStatusHandshake
UfnPdd_SendControlStatusHandshake用来发送端点0的控制状态握手信息.
参数检查后,获取端点0结构信息,然后移除Out Packet Ready标志,读取EP0_CSR寄存器,设置DATA_END,SERVICED_OUT_PKT_RDY保留EP0_STALL_BITS位,然后写入EP0_CSR寄存器,标记sendDataEnd为FALSE
+ expand sourceview plaincopy to clipboardprint?
DWORD  
WINAPI  
UfnPdd_SendControlStatusHandshake(  
    PVOID           pvPddContext,  
    DWORD           dwEndpoint  
    )  
{  
    SETFNAME();  
    FUNCTION_ENTER_MSG();  
 
    PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;  
    ValidateContext(pContext);  
 
    DEBUGCHK(dwEndpoint == 0);  
      
    // This function is only valid for Endpoint 0  
    EP_STATUS *peps = GetEpStatus(pContext, 0);  
    DEBUGCHK(peps->fInitialized);  
 
    // Remove the Out Packet Ready Condition  
    if(pContext->sendDataEnd) {  
        LOCK_ENDPOINT(peps);  
 
        RETAILMSG(1, (_T("%s Sending 0 packet /r/n"), pszFname));  
 
        BYTE bEP0IrqStatus = ReadIndexedReg(pContext, 0, EP0_CSR_REG_OFFSET);  
 
        // Write 0 to SEND_STALL and SENT_STALL to clear them, so we need to   
        // leave them unchanged by default.  
        BYTE bEp0CsrToWrite = (bEP0IrqStatus & EP0_STALL_BITS);  
 
        bEp0CsrToWrite |= (DATA_END | SERVICED_OUT_PKT_RDY);  
 
        RETAILMSG(1, (_T("%s Status - 0x%02x, Writing 0x%02x/r/n"), pszFname,  
            bEP0IrqStatus, bEp0CsrToWrite));  
 
        WriteIndexedReg(pContext, 0, EP0_CSR_REG_OFFSET, bEp0CsrToWrite);  
          
        pContext->sendDataEnd = FALSE;  
 
        UNLOCK_ENDPOINT(peps);  
    }   
      
    FUNCTION_LEAVE_MSG();  
 
    return ERROR_SUCCESS;  

DWORD
WINAPI
UfnPdd_SendControlStatusHandshake(
    PVOID           pvPddContext,
    DWORD           dwEndpoint
    )
{
    SETFNAME();
    FUNCTION_ENTER_MSG();

    PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;
    ValidateContext(pContext);

    DEBUGCHK(dwEndpoint == 0);
   
    // This function is only valid for Endpoint 0
    EP_STATUS *peps = GetEpStatus(pContext, 0);
    DEBUGCHK(peps->fInitialized);

    // Remove the Out Packet Ready Condition
    if(pContext->sendDataEnd) {
  LOCK_ENDPOINT(peps);

        RETAILMSG(1, (_T("%s Sending 0 packet /r/n"), pszFname));

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

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

        bEp0CsrToWrite |= (DATA_END | SERVICED_OUT_PKT_RDY);

  RETAILMSG(1, (_T("%s Status - 0x%02x, Writing 0x%02x/r/n"), pszFname,
   bEP0IrqStatus, bEp0CsrToWrite));

        WriteIndexedReg(pContext, 0, EP0_CSR_REG_OFFSET, bEp0CsrToWrite);
       
        pContext->sendDataEnd = FALSE;

  UNLOCK_ENDPOINT(peps);
    }
   
    FUNCTION_LEAVE_MSG();

    return ERROR_SUCCESS;
}
13.UfnPdd_SetAddress
UfnPdd_SetAddress用来设置USB设备地址.通过写ADDRESS寄存器0-6位为地址,第7为写1通知地址更新.
+ expand sourceview plaincopy to clipboardprint?
DWORD  
WINAPI  
UfnPdd_SetAddress(  
                  PVOID pvPddContext,  
                  BYTE  bAddress  
                  )  
{  
    SETFNAME();  
    FUNCTION_ENTER_MSG();  
 
    PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;  
    ValidateContext(pContext);  
 
    // Make sure that the Address Update bit is set (0x80)  
    WriteReg(pContext, SET_ADDRESS_REG_OFFSET, (0x80 | bAddress));  
 
    FUNCTION_LEAVE_MSG();  
 
    return ERROR_SUCCESS;  

DWORD
WINAPI
UfnPdd_SetAddress(
                  PVOID pvPddContext,
                  BYTE  bAddress
                  )
{
    SETFNAME();
    FUNCTION_ENTER_MSG();

    PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;
    ValidateContext(pContext);

    // Make sure that the Address Update bit is set (0x80)
    WriteReg(pContext, SET_ADDRESS_REG_OFFSET, (0x80 | bAddress));

    FUNCTION_LEAVE_MSG();

    return ERROR_SUCCESS;
}
 
14.UfnPdd_InitiateRemoteWakeup
UfnPdd_InitiateRemoteWakeup用来初始化远程唤醒.通过写PWR_REG置位MCU_RESUME.
+ expand sourceview plaincopy to clipboardprint?
DWORD  
WINAPI  
UfnPdd_InitiateRemoteWakeup(  
    PVOID pvPddContext  
    )  
{  
    SETFNAME();  
    FUNCTION_ENTER_MSG();  
 
    PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;  
    ValidateContext(pContext);  
 
    SetClearReg(pContext, PWR_REG_OFFSET, MCU_RESUME, SET);  
 
    FUNCTION_LEAVE_MSG();  
 
    return ERROR_SUCCESS;  

DWORD
WINAPI
UfnPdd_InitiateRemoteWakeup(
    PVOID pvPddContext
    )
{
    SETFNAME();
    FUNCTION_ENTER_MSG();

    PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;
    ValidateContext(pContext);

    SetClearReg(pContext, PWR_REG_OFFSET, MCU_RESUME, SET);

    FUNCTION_LEAVE_MSG();

    return ERROR_SUCCESS;
}
15.UfnPdd_RegisterDevice,UfnPdd_DeregisterDevice
这两个函数未实现任何实际工作.

16.UfnPdd_PowerDown,UfnPdd_PowerUp
这两个函数也未实现任何实际工作.

17.UfnPdd_IOControl
UfnPdd_IOControl实现了3个IOControl操作:IOCTL_UFN_GET_PDD_INFO,IOCTL_BUS_GET_POWER_STATE,IOCTL_BUS_SET_POWER_STATE.
其中IOCTL_UFN_GET_PDD_INFO未实现具体内容,仅仅检查参数后跳出.
IOCTL_BUS_GET_POWER_STATE:将pContext->cpsCurrent传递给输入参数pbIn的*pCePowerState->lpceDevicePowerState.
IOCTL_BUS_SET_POWER_STATE:调用SetPowerState将输入的lpceDevicePowerState赋值给pContext.
+ expand sourceview plaincopy to clipboardprint?
DWORD  
WINAPI  
UfnPdd_IOControl(  
                 PVOID           pvPddContext,  
                 IOCTL_SOURCE    source,  
                 DWORD           dwCode,  
                 PBYTE           pbIn,  
                 DWORD           cbIn,  
                 PBYTE           pbOut,  
                 DWORD           cbOut,  
                 PDWORD          pcbActualOut  
                 )  
{  
    SETFNAME();  
    FUNCTION_ENTER_MSG();  
 
    PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;  
    ValidateContext(pContext);  
 
    DWORD dwRet = ERROR_INVALID_PARAMETER;  
 
    switch (dwCode) {  
    case IOCTL_UFN_GET_PDD_INFO:  
        if ( source != BUS_IOCTL || pbOut == NULL ||   
             cbOut != sizeof(UFN_PDD_INFO) ) {  
            break;  
        }  
 
        // Not currently supported.  
        break;  
 
    case IOCTL_BUS_GET_POWER_STATE:  
        if (source == MDD_IOCTL) {  
            PREFAST_DEBUGCHK(pbIn);  
            DEBUGCHK(cbIn == sizeof(CE_BUS_POWER_STATE));  
 
            PCE_BUS_POWER_STATE pCePowerState = (PCE_BUS_POWER_STATE) pbIn;  
            PREFAST_DEBUGCHK(pCePowerState->lpceDevicePowerState);  
 
            RETAILMSG(1, (_T("%s IOCTL_BUS_GET_POWER_STATE/r/n"), pszFname));  
 
            *pCePowerState->lpceDevicePowerState = pContext->cpsCurrent;  
 
            dwRet = ERROR_SUCCESS;  
        }  
        break;  
 
    case IOCTL_BUS_SET_POWER_STATE:  
        if (source == MDD_IOCTL) {  
            PREFAST_DEBUGCHK(pbIn);  
            DEBUGCHK(cbIn == sizeof(CE_BUS_POWER_STATE));  
 
            PCE_BUS_POWER_STATE pCePowerState = (PCE_BUS_POWER_STATE) pbIn;  
 
            PREFAST_DEBUGCHK(pCePowerState->lpceDevicePowerState);  
            DEBUGCHK(VALID_DX(*pCePowerState->lpceDevicePowerState));  
 
            RETAILMSG(1, (_T("%s IOCTL_BUS_GET_POWER_STATE(D%u)/r/n"),   
                pszFname, *pCePowerState->lpceDevicePowerState));  
 
            SetPowerState(pContext, *pCePowerState->lpceDevicePowerState);  
 
            dwRet = ERROR_SUCCESS;  
        }  
        break;  
    }  
 
    FUNCTION_LEAVE_MSG();  
 
    return dwRet;  

DWORD
WINAPI
UfnPdd_IOControl(
                 PVOID           pvPddContext,
                 IOCTL_SOURCE    source,
                 DWORD           dwCode,
                 PBYTE           pbIn,
                 DWORD           cbIn,
                 PBYTE           pbOut,
                 DWORD           cbOut,
                 PDWORD          pcbActualOut
                 )
{
    SETFNAME();
    FUNCTION_ENTER_MSG();

    PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;
    ValidateContext(pContext);

    DWORD dwRet = ERROR_INVALID_PARAMETER;

    switch (dwCode) {
    case IOCTL_UFN_GET_PDD_INFO:
        if ( source != BUS_IOCTL || pbOut == NULL ||
             cbOut != sizeof(UFN_PDD_INFO) ) {
            break;
        }

        // Not currently supported.
        break;

    case IOCTL_BUS_GET_POWER_STATE:
        if (source == MDD_IOCTL) {
            PREFAST_DEBUGCHK(pbIn);
            DEBUGCHK(cbIn == sizeof(CE_BUS_POWER_STATE));

            PCE_BUS_POWER_STATE pCePowerState = (PCE_BUS_POWER_STATE) pbIn;
            PREFAST_DEBUGCHK(pCePowerState->lpceDevicePowerState);

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

            *pCePowerState->lpceDevicePowerState = pContext->cpsCurrent;

            dwRet = ERROR_SUCCESS;
        }
        break;

    case IOCTL_BUS_SET_POWER_STATE:
        if (source == MDD_IOCTL) {
            PREFAST_DEBUGCHK(pbIn);
            DEBUGCHK(cbIn == sizeof(CE_BUS_POWER_STATE));

            PCE_BUS_POWER_STATE pCePowerState = (PCE_BUS_POWER_STATE) pbIn;

            PREFAST_DEBUGCHK(pCePowerState->lpceDevicePowerState);
            DEBUGCHK(VALID_DX(*pCePowerState->lpceDevicePowerState));

            RETAILMSG(1, (_T("%s IOCTL_BUS_GET_POWER_STATE(D%u)/r/n"),
                pszFname, *pCePowerState->lpceDevicePowerState));

            SetPowerState(pContext, *pCePowerState->lpceDevicePowerState);

            dwRet = ERROR_SUCCESS;
        }
        break;
    }

    FUNCTION_LEAVE_MSG();

    return dwRet;
}
关于SetPowerState函数
首先根据新的电源状态进行调整,如果是D1,D2,D4将调整为D0.然后如果新的电源状态小于原来的,请求总线驱动设置新的电源状态.
然后根据新的电源状态进行不同处理:
D0:禁止唤醒,重启IST线程.
D3:允许唤醒
D4:禁止唤醒

如果新的电源状态大于原来的,请求总线驱动设置新的电源状态.
最后设置pContext->cpsCurrent为新的电源状态.
+ expand sourceview plaincopy to clipboardprint?
// This does not do much because there is not any way to control  
// power on this controller.  
static 
CEDEVICE_POWER_STATE  
SetPowerState(  
    PCTRLR_PDD_CONTEXT      pContext,  
    CEDEVICE_POWER_STATE    cpsNew  
    )  
{  
    SETFNAME();  
      
    PREFAST_DEBUGCHK(pContext);  
    DEBUGCHK(VALID_DX(cpsNew));  
    ValidateContext(pContext);  
 
    // Adjust cpsNew.  
    if (cpsNew != pContext->cpsCurrent) {  
        if (cpsNew == D1 || cpsNew == D2) {  
            // D1 and D2 are not supported.  
            cpsNew = D0;  
        }  
        else if (pContext->cpsCurrent == D4) {  
            // D4 can only go to D0.  
            cpsNew = D0;  
        }  
    }  
 
    if (cpsNew != pContext->cpsCurrent) {  
        RETAILMSG(1, (_T("%s Going from D%u to D%u/r/n"),  
            pszFname, pContext->cpsCurrent, cpsNew));  
          
        if ( (cpsNew < pContext->cpsCurrent) && pContext->hBusAccess ) {  
            SetDevicePowerState(pContext->hBusAccess, cpsNew, NULL);  
        }  
 
        switch (cpsNew) {  
        case D0:  
            KernelIoControl(IOCTL_HAL_DISABLE_WAKE, &pContext->dwSysIntr,    
                sizeof(pContext->dwSysIntr), NULL, 0, NULL);  
              
            if (pContext->fRunning) {  
                // Cause the IST to restart.  
                pContext->fRestartIST = TRUE;  
                SetInterruptEvent(pContext->dwSysIntr);  
            }             
            break;  
 
        case D3:  
            KernelIoControl(IOCTL_HAL_ENABLE_WAKE, &pContext->dwSysIntr,    
                sizeof(pContext->dwSysIntr), NULL, 0, NULL);  
            break;  
 
        case D4:  
            KernelIoControl(IOCTL_HAL_DISABLE_WAKE, &pContext->dwSysIntr,    
                sizeof(pContext->dwSysIntr), NULL, 0, NULL);  
            break;  
        }  
 
        if ( (cpsNew > pContext->cpsCurrent) && pContext->hBusAccess ) {  
            SetDevicePowerState(pContext->hBusAccess, cpsNew, NULL);  
        }  
 
        pContext->cpsCurrent = cpsNew;  
    }  
 
    return pContext->cpsCurrent;  

// This does not do much because there is not any way to control
// power on this controller.
static
CEDEVICE_POWER_STATE
SetPowerState(
    PCTRLR_PDD_CONTEXT      pContext,
    CEDEVICE_POWER_STATE    cpsNew
    )
{
    SETFNAME();
   
    PREFAST_DEBUGCHK(pContext);
    DEBUGCHK(VALID_DX(cpsNew));
    ValidateContext(pContext);

    // Adjust cpsNew.
    if (cpsNew != pContext->cpsCurrent) {
        if (cpsNew == D1 || cpsNew == D2) {
            // D1 and D2 are not supported.
            cpsNew = D0;
        }
        else if (pContext->cpsCurrent == D4) {
            // D4 can only go to D0.
            cpsNew = D0;
        }
    }

    if (cpsNew != pContext->cpsCurrent) {
        RETAILMSG(1, (_T("%s Going from D%u to D%u/r/n"),
            pszFname, pContext->cpsCurrent, cpsNew));
       
        if ( (cpsNew < pContext->cpsCurrent) && pContext->hBusAccess ) {
            SetDevicePowerState(pContext->hBusAccess, cpsNew, NULL);
        }

        switch (cpsNew) {
        case D0:
            KernelIoControl(IOCTL_HAL_DISABLE_WAKE, &pContext->dwSysIntr, 
                sizeof(pContext->dwSysIntr), NULL, 0, NULL);
           
            if (pContext->fRunning) {
                // Cause the IST to restart.
                pContext->fRestartIST = TRUE;
                SetInterruptEvent(pContext->dwSysIntr);
            }          
            break;

        case D3:
            KernelIoControl(IOCTL_HAL_ENABLE_WAKE, &pContext->dwSysIntr, 
                sizeof(pContext->dwSysIntr), NULL, 0, NULL);
            break;

        case D4:
            KernelIoControl(IOCTL_HAL_DISABLE_WAKE, &pContext->dwSysIntr, 
                sizeof(pContext->dwSysIntr), NULL, 0, NULL);
            break;
        }

        if ( (cpsNew > pContext->cpsCurrent) && pContext->hBusAccess ) {
            SetDevicePowerState(pContext->hBusAccess, cpsNew, NULL);
        }

  pContext->cpsCurrent = cpsNew;
    }

    return pContext->cpsCurrent;
}
接下来来看看驱动的IST.

 

本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/shevsten/archive/2010/07/15/5736889.aspx

上一篇我们简单分析了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事件.
+ expand sourceview plaincopy to clipboardprint?
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;  

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寄存器获取中断状态,如果还有中断则继续调用上面的流程进行处理.
完整代码如下:
+ expand sourceview plaincopy to clipboardprint?
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();  

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事件.
+ expand sourceview plaincopy to clipboardprint?
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();  

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事件.
+ expand sourceview plaincopy to clipboardprint?
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);  

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的返回值.
+ expand sourceview plaincopy to clipboardprint?
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;  

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);
+ expand sourceview plaincopy to clipboardprint?
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;  

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驱动还需要更多的阅读和实践.

 

本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/shevsten/archive/2010/08/10/5801723.aspx

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值