Windows CE USB Fu…

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.

[c-sharp:collapse] + expand source view plain copy print ?
  1. // Called by MDD's DllEntry.   
  2. extern "C"   
  3. BOOL  
  4. UfnPdd_DllEntry(  
  5.     HANDLE hDllHandle,  
  6.     DWORD  dwReason,   
  7.     LPVOID lpReserved  
  8.      
  9.  
  10.     SETFNAME();  
  11.   
  12.     switch (dwReason)  
  13.         case DLL_PROCESS_ATTACH:  
  14.             g_pUDCBase NULL;  
  15.             break;  
  16.      
  17.   
  18.     return TRUE;  
  19.  

2.UfnPdd_Init
这个会被MDD层的Init函数调用,首先初始化一个 UFN_PDD_INTERFACE_INFO 接口的数组,里面定义了很多函数指针,这些PDD函数都会被MDD层调用.这些函数后面一一分析.
该结构原型如下:
[c-sharp:collapse] + expand source view plain copy print ?
  1. // Structure that the PDD must fill out in UfnPdd_Init.   
  2. typedef struct _UFN_PDD_INTERFACE_INFO  
  3.     DWORD           dwVersion;  
  4.   
  5.     DWORD           dwCapabilities;  
  6.     DWORD           dwEndpointCount;  
  7.     PVOID           pvPddContext;  
  8.   
  9.     PFN_UFN_PDD_DEINIT pfnDeinit;  
  10.     PFN_UFN_PDD_IS_CONFIGURATION_SUPPORTABLE pfnIsConfigurationSupportable;  
  11.     PFN_UFN_PDD_IS_ENDPOINT_SUPPORTABLE pfnIsEndpointSupportable 
  12.     PFN_UFN_PDD_INIT_ENDPOINT pfnInitEndpoint;  
  13.     PFN_UFN_PDD_REGISTER_DEVICE pfnRegisterDevice;  
  14.     PFN_UFN_PDD_DEREGISTER_DEVICE pfnDeregisterDevice;  
  15.     PFN_UFN_PDD_START pfnStart;  
  16.     PFN_UFN_PDD_STOP pfnStop;  
  17.     PFN_UFN_PDD_ISSUE_TRANSFER pfnIssueTransfer;  
  18.     PFN_UFN_PDD_ABORT_TRANSFER pfnAbortTransfer;  
  19.     PFN_UFN_DEINIT_ENDPOINT pfnDeinitEndpoint;  
  20.     PFN_UFN_STALL_ENDPOINT pfnStallEndpoint;  
  21.     PFN_UFN_CLEAR_ENDPOINT_STALL pfnClearEndpointStall;  
  22.     PFN_UFN_SEND_CONTROL_STATUS_HANDSHAKE pfnSendControlStatusHandshake;  
  23.     PFN_UFN_SET_ADDRESS pfnSetAddress;  
  24.     PFN_UFN_IS_ENDPOINT_HALTED pfnIsEndpointHalted;  
  25.     PFN_UFN_INITIATE_REMOTE_WAKEUP pfnInitiateRemoteWakeup;  
  26.     PFN_UFN_POWER_DOWN pfnPowerDown;  
  27.     PFN_UFN_POWER_UP pfnPowerUp;  
  28.     PFN_UFN_IOCONTROL pfnIOControl;  
  29. 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释放之前分配的资源.
[c-sharp:collapse] + expand source view plain copy print ?
  1. // Initialize the device.   
  2. DWORD  
  3. WINAPI  
  4. UfnPdd_Init(  
  5.     LPCTSTR                     pszActiveKey,  
  6.     PVOID                       pvMddContext,  
  7.     PUFN_MDD_INTERFACE_INFO     pMddInterfaceInfo,  
  8.     PUFN_PDD_INTERFACE_INFO     pPddInterfaceInfo  
  9.      
  10.      
  11.     SETFNAME();  
  12.     FUNCTION_ENTER_MSG();  
  13.   
  14.     static const UFN_PDD_INTERFACE_INFO sc_PddInterfaceInfo  
  15.         UFN_PDD_INTERFACE_VERSION,  
  16.         UFN_PDD_CAPS_SUPPORTS_FULL_SPEED,  
  17.         ENDPOINT_COUNT,  
  18.         NULL, // This gets filled in later   
  19.           
  20.         &UfnPdd_Deinit,  
  21.         &UfnPdd_IsConfigurationSupportable,  
  22.         &UfnPdd_IsEndpointSupportable,  
  23.         &UfnPdd_InitEndpoint,  
  24.         &UfnPdd_RegisterDevice,  
  25.         &UfnPdd_DeregisterDevice,  
  26.         &UfnPdd_Start,  
  27.         &UfnPdd_Stop,  
  28.         &UfnPdd_IssueTransfer,  
  29.         &UfnPdd_AbortTransfer,  
  30.         &UfnPdd_DeinitEndpoint,  
  31.         &UfnPdd_StallEndpoint,  
  32.         &UfnPdd_ClearEndpointStall,  
  33.         &UfnPdd_SendControlStatusHandshake,  
  34.         &UfnPdd_SetAddress,  
  35.         &UfnPdd_IsEndpointHalted,  
  36.         &UfnPdd_InitiateRemoteWakeup,  
  37.         &UfnPdd_PowerDown,  
  38.         &UfnPdd_PowerUp,  
  39.         &UfnPdd_IOControl,  
  40.     };  
  41.   
  42.     DWORD dwType;  
  43.     DWORD dwRet;  
  44.   
  45.     HKEY hkDevice NULL;  
  46.     PCTRLR_PDD_CONTEXT pContext NULL;  
  47.   
  48.     DEBUGCHK(pszActiveKey);  
  49.     DEBUGCHK(pMddInterfaceInfo);  
  50.     DEBUGCHK(pPddInterfaceInfo);  
  51.   
  52.     hkDevice OpenDeviceKey(pszActiveKey);  
  53.     if (!hkDevice)  
  54.         dwRet GetLastError();  
  55.         DEBUGMSG(ZONE_ERROR, (_T("%s Could not open device key. Error: %d/r/n"),   
  56.             pszFname, dwRet));  
  57.         goto EXIT;          
  58.      
  59.   
  60.     pContext (PCTRLR_PDD_CONTEXT) LocalAlloc(LPTR, sizeof(*pContext));  
  61.     if (pContext == NULL)  
  62.         dwRet GetLastError();  
  63.         PREFAST_DEBUGCHK(dwRet != ERROR_SUCCESS);  
  64.         DEBUGMSG(ZONE_ERROR, (_T("%s LocalAlloc failed. Error: %d/r/n"), pszFname, dwRet));  
  65.         goto EXIT;  
  66.      
  67.     pContext->dwSig SC2410_SIG;  
  68.   
  69.     pContext->pvMddContext pvMddContext;  
  70.     pContext->cpsCurrent D4;  
  71.     pContext->dwIrq IRQ_UNSPECIFIED;  
  72.     pContext->pfnNotify pMddInterfaceInfo->pfnNotify;  
  73.     InitializeCriticalSection(&pContext->csIndexedRegisterAccess);  
  74.   
  75.     for (DWORD dwEp 0; dwEp dim(pContext->rgEpStatus); ++dwEp)  
  76.         pContext->rgEpStatus[dwEp].dwEndpointNumber dwEp;  
  77.      
  78.   
  79.     DWORD dwDataSize;  
  80.     DWORD dwPriority;  
  81.   
  82.     DDKISRINFO dii;  
  83.     DDKWINDOWINFO dwi;  
  84.   
  85.     // read window configuration from the registry   
  86.     dwi.cbSize sizeof(dwi);  
  87.     dwRet DDKReg_GetWindowInfo(hkDevice, &dwi);  
  88.     if(dwRet != ERROR_SUCCESS)  
  89.         DEBUGMSG(ZONE_ERROR, (_T("%s DDKReg_GetWindowInfo() failed %d/r/n"),   
  90.             pszFname, dwRet));  
  91.         goto EXIT;  
  92.       
  93.     else if (dwi.dwNumIoWindows != 1)  
  94.         DEBUGMSG(ZONE_ERROR, (_T("%s %d windows configured, expected 1/r/n"),   
  95.             pszFname, dwi.dwNumIoWindows));  
  96.         dwRet ERROR_INVALID_DATA;  
  97.         goto EXIT;  
  98.       
  99.     else if (dwi.ioWindows[0].dwLen REGISTER_SET_SIZE)  
  100.         DEBUGMSG(ZONE_INIT, (_T("%s ioLen of 0x%x is less than required 0x%x/r/n"),  
  101.             pszFname, dwi.ioWindows[0].dwLen, REGISTER_SET_SIZE));  
  102.         dwRet ERROR_INVALID_DATA;  
  103.         goto EXIT;          
  104.      
  105.     else if (dwi.ioWindows[0].dwBase == 0){  
  106.         DEBUGMSG(ZONE_INIT, (_T("%s no ioBase value specified/r/n"),pszFname));  
  107.         dwRet ERROR_INVALID_DATA;  
  108.         goto EXIT;  
  109.      
  110.     else  
  111.         pContext->dwIOBase dwi.ioWindows[0].dwBase;  
  112.         pContext->dwIOLen dwi.ioWindows[0].dwLen;  
  113.      
  114.       
  115.     // get ISR configuration information   
  116.     dii.cbSize sizeof(dii);  
  117.     dwRet DDKReg_GetIsrInfo(hkDevice, &dii);  
  118.     if (dwRet != ERROR_SUCCESS)  
  119.         DEBUGMSG(ZONE_ERROR, (_T("%s DDKReg_GetIsrInfo() failed %d/r/n"),   
  120.             pszFname, dwRet));  
  121.         goto EXIT;  
  122.      
  123.     else if( (dii.dwSysintr == SYSINTR_NOP) && (dii.dwIrq == IRQ_UNSPECIFIED)  
  124.         DEBUGMSG(ZONE_ERROR, (_T("%s no IRQ or SYSINTR value specified/r/n"), pszFname));  
  125.         dwRet ERROR_INVALID_DATA;  
  126.         goto EXIT;  
  127.       
  128.     else  
  129.         if (dii.dwSysintr == SYSINTR_NOP)  
  130.             BOOL fSuccess KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &dii.dwIrq,   
  131.                 sizeof(DWORD), &dii.dwSysintr, sizeof(DWORD), NULL);  
  132.             if (!fSuccess)  
  133.                 DEBUGMSG(ZONE_ERROR, (_T("%s IOCTL_HAL_REQUEST_SYSINTR failed!/r/n"),   
  134.                     pszFname));  
  135.                 goto EXIT;  
  136.              
  137.   
  138.             pContext->dwIrq dii.dwIrq;  
  139.             pContext->dwSysIntr dii.dwSysintr;  
  140.          
  141.         else  
  142.             pContext->dwSysIntr dii.dwSysintr;  
  143.          
  144.      
  145.   
  146.     // Read the IST priority   
  147.     dwDataSize sizeof(dwPriority);  
  148.     dwRet RegQueryValueEx(hkDevice, UDC_REG_PRIORITY_VAL, NULL, &dwType,  
  149.         (LPBYTE) &dwPriority, &dwDataSize);  
  150.     if (dwRet != ERROR_SUCCESS)  
  151.         dwPriority DEFAULT_PRIORITY;  
  152.      
  153.   
  154.     pContext->hBusAccess CreateBusAccessHandle(pszActiveKey);  
  155.     if (pContext->hBusAccess == NULL)  
  156.         // This is not failure.   
  157.         DEBUGMSG(ZONE_WARNING, (_T("%s Could not create bus access handle/r/n"),  
  158.             pszFname));  
  159.      
  160.   
  161.     DEBUGMSG(ZONE_INIT, (_T("%s Using IO Base %x/r/n"),   
  162.         pszFname, pContext->dwIOBase));  
  163.     DEBUGMSG(ZONE_INIT, (_T("%s Using SysIntr %u/r/n"),   
  164.         pszFname, pContext->dwSysIntr));  
  165.     DEBUGMSG(ZONE_INIT, (_T("%s Using IST priority %u/r/n"),   
  166.         pszFname, dwPriority));  
  167.   
  168.     pContext->dwISTPriority dwPriority;  
  169.   
  170.     // map register space to virtual memory   
  171.     dwRet MapRegisterSet(pContext);  
  172.     if (dwRet != ERROR_SUCCESS)  
  173.         DEBUGMSG(ZONE_ERROR, (_T("%s failed to map register space/r/n"),  
  174.             pszFname));  
  175.         goto EXIT;  
  176.      
  177.       
  178.     pContext->attachedState UFN_DETACH;  
  179.   
  180.     ResetDevice(pContext);  
  181.     ValidateContext(pContext);  
  182.   
  183.     memcpy(pPddInterfaceInfo, &sc_PddInterfaceInfo, sizeof(sc_PddInterfaceInfo));  
  184.     pPddInterfaceInfo->pvPddContext pContext;  
  185.   
  186. EXIT:  
  187.     if (hkDevice) RegCloseKey(hkDevice);  
  188.       
  189.     if (dwRet != ERROR_SUCCESS && pContext)  
  190.         FreeCtrlrContext(pContext);  
  191.      
  192.   
  193.     FUNCTION_LEAVE_MSG();  
  194.   
  195.     return dwRet;  
  196.  

ResetDevice:
再来看看ResetDevice的具体内容,对UDC内部寄存器的操作有禁止UDC中断,禁止端点中断(EP0-EP4),清楚USB中断标志,清楚端点中断标志,然后调用ResetEndpoint对每个端点进行复位.
[c-sharp:collapse] + expand source view plain copy print ?
  1. ResetDevice(  
  2.             PCTRLR_PDD_CONTEXT pContext  
  3.              
  4.  
  5.     SETFNAME();  
  6.     FUNCTION_ENTER_MSG();  
  7.   
  8.     DEBUGCHK(IS_VALID_SC2410_CONTEXT(pContext));  
  9.   
  10.     // Disable Device  interrupts write Zeros to Disable   
  11.     WriteReg(pContext, USB_INT_EN_REG_OFFSET, );  
  12.   
  13.     // Disable endpoint interrupts write Zeros to Disable   
  14.     WriteReg(pContext, EP_INT_EN_REG_OFFSET, 0);  
  15.   
  16.     // Clear any outstanding device endpoint interrupts   
  17.     // USB Device Interrupt Status Write '1' to Clear    
  18.     WriteReg(pContext, USB_INT_REG_OFFSET,   
  19.         (USB_RESET_INTR USB_RESUME_INTR USB_SUSPEND_INTR));  
  20.     // End point Interrupt Status Write '1' to Clear   
  21.     WriteReg(pContext, EP_INT_REG_OFFSET, CLEAR_ALL_EP_INTRS);  
  22.   
  23.     // Reset all endpoints   
  24.     for (DWORD dwEpIdx 0; dwEpIdx ENDPOINT_COUNT; ++dwEpIdx)  
  25.         EP_STATUS *peps GetEpStatus(pContext, dwEpIdx);  
  26.         ResetEndpoint(pContext, peps);  
  27.      
  28.   
  29.     FUNCTION_LEAVE_MSG();  
  30.  

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中断.
[c-sharp:collapse] + expand source view plain copy print ?
  1. static  
  2. VOID  
  3. ResetEndpoint(  
  4.               PCTRLR_PDD_CONTEXT pContext,  
  5.               EP_STATUS *peps  
  6.                
  7.  
  8.     SETFNAME();  
  9.     FUNCTION_ENTER_MSG();  
  10.   
  11.     ValidateContext(pContext);  
  12.     PREFAST_DEBUGCHK(peps);  
  13.   
  14.     // Since Reset can be called before/after an Endpoint has been configured,   
  15.     // it is best to clear all IN and OUT bits associated with endpoint.    
  16.     DWORD dwEndpoint peps->dwEndpointNumber;  
  17.     if(dwEndpoint ==  
  18.         // Clear all EP0 Status bits   
  19.         WriteIndexedReg(pContext, 0, IN_CSR1_REG_OFFSET,  
  20.             (SERVICED_OUT_PKT_RDY SERVICED_SETUP_END));  
  21.      
  22.     else if(dwEndpoint ENDPOINT_COUNT)  
  23.         // Clear the desired Endpoint Clear both the In Out Status bits   
  24.         BYTE bRegIn;  
  25.         BYTE bRegOut;  
  26.         if(peps->fInitialized){  
  27.             PREFAST_DEBUGCHK(peps->fInitialized); // Give prefast clue.   
  28.             // First Read the CSR2 Reg bit so that it can be restored   
  29.             bRegIn ReadIndexedReg(pContext, dwEndpoint, IN_CSR2_REG_OFFSET);  
  30.             bRegOut ReadIndexedReg(pContext, dwEndpoint, OUT_CSR2_REG_OFFSET);  
  31.          
  32.         // Clear the in register Must set the Mode_in to IN   
  33.         WriteIndexedReg(pContext, dwEndpoint, IN_CSR2_REG_OFFSET,(SET_MODE_IN IN_DMA_INT_DISABLE));  
  34.         WriteIndexedReg(pContext, dwEndpoint, IN_CSR1_REG_OFFSET, IN_CLR_DATA_TOGGLE));  
  35.   
  36.         // Clear the Out register  Must set the Mode_in to OUT   
  37.         WriteIndexedReg(pContext, dwEndpoint, IN_CSR2_REG_OFFSET, (IN_DMA_INT_DISABLE)); // mode_in bit OUT    
  38.         WriteIndexedReg(pContext, dwEndpoint, OUT_CSR1_REG_OFFSET, (FLUSH_OUT_FIFO OUT_CLR_DATA_TOGGLE));  
  39.         WriteIndexedReg(pContext, dwEndpoint,  OUT_CSR2_REG_OFFSET, OUT_DMA_INT_DISABLE);  
  40.   
  41.         if(peps->fInitialized)  
  42.             // Set the Mode_In, ISO and other Modality type bits back to the way it was this allows    
  43.             // ResetEndpoint to be called without having to re-init the endpoint.   
  44.             WriteIndexedReg(pContext, dwEndpoint, IN_CSR2_REG_OFFSET, bRegIn);  
  45.             WriteIndexedReg(pContext, dwEndpoint, OUT_CSR2_REG_OFFSET, bRegOut);  
  46.          
  47.   
  48.         // Clear and disable interrupt   
  49.         WriteReg(pContext, EP_INT_REG_OFFSET, EpToIrqStatBit(peps->dwEndpointNumber));  
  50.         DisableEndpointInterrupt(pContext, peps->dwEndpointNumber);  
  51.      
  52.     else  
  53.         DEBUGCHK(FALSE);  
  54.      
  55.   
  56.     FUNCTION_LEAVE_MSG();  
  57.  

FreeCtrlrContext:
FreeCtrlrContext首先释放g_pUDCBase映射的IO空间,然后调用CloseBusAccessHandle关闭总线驱动句柄,然后禁止中断唤醒,释放逻辑中断号.
[c-sharp:collapse] + expand source view plain copy print ?
  1. static  
  2. VOID  
  3. FreeCtrlrContext(  
  4.     PCTRLR_PDD_CONTEXT pContext  
  5.      
  6.  
  7.     PREFAST_DEBUGCHK(pContext);  
  8.     DEBUGCHK(!pContext->hevInterrupt);  
  9.     DEBUGCHK(!pContext->hIST);  
  10.     DEBUGCHK(!pContext->fRunning);  
  11.   
  12.     pContext->dwSig GARBAGE_DWORD;  
  13.   
  14.     UnmapRegisterSet(pContext);  
  15.   
  16.     if (pContext->hBusAccess) CloseBusAccessHandle(pContext->hBusAccess);  
  17.       
  18.     if (pContext->dwSysIntr)  
  19.         KernelIoControl(IOCTL_HAL_DISABLE_WAKE, &pContext->dwSysIntr,    
  20.             sizeof(pContext->dwSysIntr), NULL, 0, NULL);  
  21.      
  22.   
  23.     if (pContext->dwIrq != IRQ_UNSPECIFIED)  
  24.         KernelIoControl(IOCTL_HAL_RELEASE_SYSINTR, &pContext->dwIrq,   
  25.             sizeof(DWORD), NULL, 0, NULL);  
  26.      
  27.       
  28.     DeleteCriticalSection(&pContext->csIndexedRegisterAccess);  
  29.   
  30.     LocalFree(pContext);  
  31.  

下面就一个个来看UfnPdd_Init中声明的UFN_PDD_INTERFACE_INFO结构中的函数.
3.UfnPdd_Deinit
UfnPdd_Deinit用来进行资源的释放,检查完参数后就调用FreeCtrlrContext释放资源,如UDC寄存器地址空间的释放,SYSINTR和IRQ的释放等.
[c-sharp:collapse] + expand source view plain copy print ?
  1. DWORD  
  2. WINAPI  
  3. UfnPdd_Deinit(  
  4.     PVOID pvPddContext  
  5.      
  6.  
  7.     SETFNAME();  
  8.     FUNCTION_ENTER_MSG();  
  9.   
  10.     PCTRLR_PDD_CONTEXT pContext (PCTRLR_PDD_CONTEXT) pvPddContext;  
  11.     ValidateContext(pContext);  
  12.   
  13.     FUNCTION_ENTER_MSG();  
  14.   
  15.     FreeCtrlrContext(pContext);  
  16.   
  17.     FUNCTION_LEAVE_MSG();  
  18.   
  19.     return ERROR_SUCCESS;  
  20.  

4.UfnPdd_Start
UfnPdd_Start用来启动USB Device设备.
一开始先创建中断事件hevInterrupt,并与SYSINTR号关联中断初始化.然后调用InterruptDone完成中断.创建对应的IST线程.如有错误,则跳转到EXIT禁止中断,释放事件句柄.
[c-sharp:collapse] + expand source view plain copy print ?
  1. DWORD  
  2. WINAPI  
  3. UfnPdd_Start(  
  4.     PVOID        pvPddContext  
  5.      
  6.  
  7.     //RETAILMSG(TRUE, (TEXT("++UfnPdd_Start for GEC2410 USBFN/r/n")));   
  8.   
  9.     SETFNAME();  
  10.     FUNCTION_ENTER_MSG();  
  11.   
  12.     DWORD dwRet;  
  13.     PCTRLR_PDD_CONTEXT pContext (PCTRLR_PDD_CONTEXT) pvPddContext;  
  14.     ValidateContext(pContext);  
  15.   
  16.     FUNCTION_ENTER_MSG();  
  17.   
  18.     DEBUGCHK(!pContext->fRunning);  
  19.   
  20.     BOOL fIntInitialized FALSE;  
  21.   
  22.     // Create the interrupt event   
  23.     pContext->hevInterrupt CreateEvent(0, FALSE, FALSE, NULL);  
  24.     if (pContext->hevInterrupt == NULL)  
  25.         dwRet GetLastError();  
  26.         RETAILMSG(1, (_T("%s Error creating  interrupt event. Error %d/r/n"),   
  27.             pszFname, dwRet));  
  28.         goto EXIT;  
  29.      
  30.   
  31.     fIntInitialized InterruptInitialize(pContext->dwSysIntr,   
  32.         pContext->hevInterrupt, NULL, 0);  
  33.     if (fIntInitialized == FALSE)  
  34.         dwRet ERROR_GEN_FAILURE;  
  35.         RETAILMSG(1, (_T("%s  interrupt initialization failed/r/n"),  
  36.             pszFname));  
  37.         goto EXIT;  
  38.      
  39.     InterruptDone(pContext->dwSysIntr);  
  40.   
  41.     pContext->fExitIST FALSE;  
  42.     pContext->hIST CreateThread(NULL, 0, ISTMain, pContext, 0, NULL);      
  43.     if (pContext->hIST == NULL)  
  44.         RETAILMSG(1, (_T("%s IST creation failed/r/n"), pszFname));  
  45.         dwRet GetLastError();  
  46.         goto EXIT;  
  47.      
  48.   
  49.     pContext->fRunning TRUE;  
  50.     dwRet ERROR_SUCCESS;  
  51.   
  52. EXIT:  
  53.     if (pContext->fRunning == FALSE)  
  54.         DEBUGCHK(dwRet != ERROR_SUCCESS);  
  55.         if (fIntInitialized) InterruptDisable(pContext->dwSysIntr);  
  56.         if (pContext->hevInterrupt) CloseHandle(pContext->hevInterrupt);  
  57.         pContext->hevInterrupt NULL;  
  58.      
  59.   
  60.     FUNCTION_LEAVE_MSG();  
  61.   
  62.     return dwRet;  
  63.  

5.UfnPdd_Stop
UfnPdd_Stop用来停止USB Device设备.
主要工作为关闭中断线程,设置中断线程和事件句柄为NULL,调用ResetDevice复位设备,并标记运行状态fRunning为false.
[c-sharp:collapse] + expand source view plain copy print ?
  1. DWORD  
  2. WINAPI  
  3. UfnPdd_Stop(  
  4.             PVOID pvPddContext  
  5.              
  6.  
  7.     SETFNAME();  
  8.     FUNCTION_ENTER_MSG();  
  9.   
  10.     PCTRLR_PDD_CONTEXT pContext (PCTRLR_PDD_CONTEXT) pvPddContext;  
  11.     ValidateContext(pContext);  
  12.   
  13.     DEBUGCHK(pContext->fRunning);  
  14.   
  15.     // Stop the IST   
  16.     pContext->fExitIST TRUE;  
  17.     InterruptDisable(pContext->dwSysIntr);  
  18.     SetEvent(pContext->hevInterrupt);  
  19.     WaitForSingleObject(pContext->hIST, INFINITE);  
  20.     CloseHandle(pContext->hevInterrupt);  
  21.     CloseHandle(pContext->hIST);  
  22.     pContext->hIST NULL;  
  23.     pContext->hevInterrupt NULL;  
  24.   
  25.     ResetDevice(pContext);  
  26.   
  27.     pContext->fRunning FALSE;  
  28.   
  29.     RETAILMSG(1, (_T("%s Device has been stopped/r/n"),   
  30.         pszFname));  
  31.   
  32.     FUNCTION_LEAVE_MSG();  
  33.   
  34.     return ERROR_SUCCESS;  
  35.  

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端点挂起和端点中断状态.
[c-sharp:collapse] + expand source view plain copy print ?
  1. DWORD  
  2. WINAPI  
  3. UfnPdd_InitEndpoint(  
  4.     PVOID                       pvPddContext,  
  5.     DWORD                       dwEndpoint,  
  6.     UFN_BUS_SPEED               Speed,  
  7.     PUSB_ENDPOINT_DESCRIPTOR    pEndpointDesc,  
  8.     PVOID                       pvReserved,  
  9.     BYTE                        bConfigurationValue,  
  10.     BYTE                        bInterfaceNumber,  
  11.     BYTE                        bAlternateSetting  
  12.      
  13.  
  14.     SETFNAME();  
  15.     FUNCTION_ENTER_MSG();  
  16.   
  17.     DEBUGCHK(EP_VALID(dwEndpoint));  
  18.     PREFAST_DEBUGCHK(pEndpointDesc);  
  19.  
  20. #ifdef DEBUG   
  21.      
  22.         USB_ENDPOINT_DESCRIPTOR EndpointDesc;  
  23.         memcpy(&EndpointDesc, pEndpointDesc, sizeof(EndpointDesc));  
  24.         DEBUGCHK(UfnPdd_IsEndpointSupportable(pvPddContext, dwEndpoint, Speed,  
  25.             &EndpointDesc, bConfigurationValue, bInterfaceNumber,   
  26.             bAlternateSetting) == ERROR_SUCCESS);  
  27.         DEBUGCHK(memcmp(&EndpointDesc, pEndpointDesc, sizeof(EndpointDesc)) == 0);  
  28.     }  
  29. #endif   
  30.   
  31.     PCTRLR_PDD_CONTEXT pContext (PCTRLR_PDD_CONTEXT) pvPddContext;  
  32.     ValidateContext(pContext);  
  33.     BYTE bEndpointAddress 0;  
  34.   
  35.     PEP_STATUS peps GetEpStatus(pContext, dwEndpoint);  
  36.     DEBUGCHK(!peps->fInitialized);  
  37.   
  38.     InitializeCriticalSection(&peps->cs);  
  39.   
  40.     WORD wMaxPacketSize   
  41.         pEndpointDesc->wMaxPacketSize USB_ENDPOINT_MAX_PACKET_SIZE_MASK;  
  42.     DEBUGCHK(wMaxPacketSize);  
  43.       
  44.     // If the target is endpoint 0, then only allow the function driver    
  45.     // to register notification function.   
  46.     if (dwEndpoint == 0)  
  47.        peps->dwPacketSizeAssigned wMaxPacketSize;  
  48.        // Interrupts for endpoint are enabled in ISTMain   
  49.      
  50.     else if (dwEndpoint ENDPOINT_COUNT)  
  51.         // Clear all Status bits and leave the Endpoint interrupt disabled   
  52.         // Clear Fifos, and all register bits   
  53.         ResetEndpoint(pContext,peps);  
  54.   
  55.         // Clear all bits in CSR2 Disable DMA for now...   
  56.         WriteIndexedReg(pContext, dwEndpoint, IN_CSR2_REG_OFFSET, 0);  
  57.   
  58.         // Setup Direction (mode_in bit)    
  59.         bEndpointAddress pEndpointDesc->bEndpointAddress;  
  60.         BOOL fModeOut USB_ENDPOINT_DIRECTION_OUT(bEndpointAddress);  
  61.         if (fModeOut)  
  62.             SetClearIndexedReg(pContext, dwEndpoint,IN_CSR2_REG_OFFSET,   
  63.                 SET_MODE_IN, CLEAR);                
  64.             peps->dwDirectionAssigned USB_OUT_TRANSFER;  
  65.          
  66.         else  
  67.             SetClearIndexedReg(pContext, dwEndpoint, IN_CSR2_REG_OFFSET,   
  68.                 SET_MODE_IN, SET);  
  69.             peps->dwDirectionAssigned USB_IN_TRANSFER;  
  70.          
  71.   
  72.         // Set Transfer Type   
  73.         BYTE bTransferType pEndpointDesc->bmAttributes USB_ENDPOINT_TYPE_MASK;  
  74.         DEBUGCHK(bTransferType != USB_ENDPOINT_TYPE_CONTROL);  
  75.         switch(bTransferType)  
  76.             case USB_ENDPOINT_TYPE_ISOCHRONOUS:  
  77.                 // Set the ISO bit   
  78.                 SetClearIndexedReg(pContext, dwEndpoint,IN_CSR2_REG_OFFSET,   
  79.                     SET_TYPE_ISO, SET);  
  80.                 break;  
  81.   
  82.             case USB_ENDPOINT_TYPE_BULK:  
  83.             case USB_ENDPOINT_TYPE_INTERRUPT:  
  84.             default:  
  85.                 // Clear ISO bit Set type to Bulk   
  86.                 SetClearIndexedReg(pContext, dwEndpoint,IN_CSR2_REG_OFFSET,   
  87.                     SET_TYPE_ISO, CLEAR);  
  88.          
  89.   
  90.         peps->dwEndpointType bTransferType;  
  91.         peps->dwPacketSizeAssigned wMaxPacketSize;  
  92.           
  93.         // Set the Max Packet Size Register   
  94.         BYTE maxPacketBits (BYTE) (peps->dwPacketSizeAssigned >> 3);  
  95.         WriteIndexedReg(pContext, dwEndpoint, MAX_PKT_SIZE_REG_OFFSET,   
  96.             maxPacketBits);   
  97.   
  98.         UfnPdd_ClearEndpointStall(pvPddContext,dwEndpoint);  
  99.   
  100.         // Clear outstanding interrupts   
  101.         ClearEndpointInterrupt(pContext, dwEndpoint);  
  102.      
  103.       
  104.     peps->fInitialized TRUE;  
  105.     FUNCTION_LEAVE_MSG();  
  106.   
  107.     return ERROR_SUCCESS;  
  108.  

UfnPdd_ClearEndpointStall函数下面介绍,先来看看ClearEndpointInterrupt
ClearEndpointInterrupt用来清除EP_INT_REG寄存器对应端点的中断.
[c-sharp:collapse] + expand source view plain copy print ?
  1. static  
  2. VOID  
  3. ClearEndpointInterrupt(  
  4.                        PCTRLR_PDD_CONTEXT pContext,  
  5.                        DWORD        dwEndpoint  
  6.                         
  7.      
  8.     SETFNAME();  
  9.     FUNCTION_ENTER_MSG();  
  10.       
  11.     // Clear the Endpoint Interrupt   
  12.     BYTE bIntBit EpToIrqStatBit(dwEndpoint);  
  13.     WriteReg(pContext, EP_INT_REG_OFFSET, bIntBit);  
  14.   
  15.     FUNCTION_LEAVE_MSG();  
  16. // _ClearInterrupt  

7.UfnPdd_DeinitEndpoint
UfnPdd_DeinitEndpoint通过调用ResetEndpoint和ClearEndpointInterrupt进行端点复位,屏蔽中断,清除端点中断状态.
[c-sharp:collapse] + expand source view plain copy print ?
  1. DWORD  
  2. WINAPI  
  3. UfnPdd_DeinitEndpoint(  
  4.                       PVOID pvPddContext,  
  5.                       DWORD dwEndpoint  
  6.                        
  7.  
  8.     SETFNAME();  
  9.     FUNCTION_ENTER_MSG();  
  10.   
  11.     DEBUGCHK(EP_VALID(dwEndpoint));  
  12.   
  13.     PCTRLR_PDD_CONTEXT pContext (PCTRLR_PDD_CONTEXT) pvPddContext;  
  14.     ValidateContext(pContext);  
  15.   
  16.     PEP_STATUS peps GetEpStatus(pContext, dwEndpoint);  
  17.     LOCK_ENDPOINT(peps);  
  18.   
  19.     DEBUGCHK(peps->fInitialized);  
  20.     DEBUGCHK(peps->pTransfer == NULL);  
  21.   
  22.     // Reset and disable the endpoint    
  23.     // Mask endpoint interrupts       
  24.     ResetEndpoint(pContext, peps);  
  25.   
  26.     // Clear endpoint interrupts   
  27.     ClearEndpointInterrupt(pContext, dwEndpoint);  
  28.   
  29.     peps->fInitialized FALSE;  
  30.     UNLOCK_ENDPOINT(peps);  
  31.   
  32.     DeleteCriticalSection(&peps->cs);  
  33.   
  34.     FUNCTION_LEAVE_MSG();  
  35.   
  36.     return ERROR_SUCCESS;  
  37.  

8.UfnPdd_ClearEndpointStall
UfnPdd_ClearEndpointStall用来清除端点的stall停止状态.
首先依然是参数检查,然后获取端点信息保存到EP_STATUS结构peps中,如果是端点0,清除EP0_CSR的send和sent stall状态.如果是其他端点,根据传输方向设置IN_CSR1_REG或OUT_CSR1_REG清除send和sent stall状态.
[c-sharp:collapse] + expand source view plain copy print ?
  1. DWORD  
  2. WINAPI  
  3. UfnPdd_ClearEndpointStall(  
  4.                           PVOID pvPddContext,  
  5.                           DWORD dwEndpoint  
  6.                            
  7.  
  8.     DWORD dwRet ERROR_SUCCESS;  
  9.   
  10.     SETFNAME();  
  11.     FUNCTION_ENTER_MSG();  
  12.   
  13.     DEBUGCHK(EP_VALID(dwEndpoint));  
  14.   
  15.     PCTRLR_PDD_CONTEXT pContext (PCTRLR_PDD_CONTEXT) pvPddContext;  
  16.     ValidateContext(pContext);  
  17.   
  18.     PEP_STATUS peps GetEpStatus(pContext, dwEndpoint);  
  19.     LOCK_ENDPOINT(peps);  
  20.   
  21.     if (dwEndpoint == 0){  
  22.         // Must Clear both Send and Sent Stall   
  23.         WriteIndexedReg(pContext, 0, EP0_CSR_REG_OFFSET, 0);  
  24.      
  25.     else if (peps->dwDirectionAssigned == USB_IN_TRANSFER){  
  26.         SetClearIndexedReg(pContext, dwEndpoint, IN_CSR1_REG_OFFSET,  
  27.             (IN_SEND_STALL IN_CLR_DATA_TOGGLE ), SET);  
  28.   
  29.         // Must Clear both Send and Sent Stall   
  30.         SetClearIndexedReg(pContext, dwEndpoint, IN_CSR1_REG_OFFSET,  
  31.             (IN_SEND_STALL  IN_SENT_STALL), CLEAR);                 
  32.      
  33.     else{ // Out Endpoint   
  34.         // Must Clear both Send and Sent Stall   
  35.         SetClearIndexedReg(pContext, dwEndpoint, OUT_CSR1_REG_OFFSET,  
  36.             OUT_SEND_STALL OUT_CLR_DATA_TOGGLE ), SET);  
  37.         SetClearIndexedReg(pContext ,dwEndpoint, OUT_CSR1_REG_OFFSET,  
  38.             OUT_SEND_STALL  OUT_SENT_STALL), CLEAR);  
  39.      
  40.       
  41.     UNLOCK_ENDPOINT(peps);  
  42.     FUNCTION_LEAVE_MSG();  
  43.   
  44.     return ERROR_SUCCESS;  
  45.  

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.
[c-sharp:collapse] + expand source view plain copy print ?
  1. DWORD  
  2. WINAPI  
  3. UfnPdd_StallEndpoint(  
  4.                      PVOID pvPddContext,  
  5.                      DWORD dwEndpoint  
  6.                       
  7.  
  8.     DWORD dwRet ERROR_SUCCESS;  
  9.     SETFNAME();  
  10.     FUNCTION_ENTER_MSG();  
  11.   
  12.     DEBUGCHK(EP_VALID(dwEndpoint));  
  13.   
  14.     PCTRLR_PDD_CONTEXT pContext (PCTRLR_PDD_CONTEXT) pvPddContext;  
  15.     ValidateContext(pContext);  
  16.   
  17.     PEP_STATUS peps GetEpStatus(pContext, dwEndpoint);  
  18.     DEBUGCHK(peps->fInitialized);  
  19.     LOCK_ENDPOINT(peps);  
  20.   
  21.     if (dwEndpoint == 0)  
  22.         // Must Clear Out Packet Ready when sending Stall   
  23.         BYTE bEp0StallBits (DATA_END SERVICED_OUT_PKT_RDY EP0_SEND_STALL);  
  24.         RETAILMSG(1, (_T("%s Writing 0xx to EP0_CSR_REG/r/n"), pszFname,  
  25.             bEp0StallBits));  
  26.         WriteIndexedReg(pContext, 0, EP0_CSR_REG_OFFSET, bEp0StallBits);  
  27.         // Set Flag so that SendControlStatusHandshked does not   
  28.         // duplicate this HW Write. Manual says all bits need   
  29.         // to be set at the same time.   
  30.         pContext->sendDataEnd FALSE;  
  31.         pContext->Ep0State EP0_STATE_IDLE;  
  32.      
  33.     else if (peps->dwDirectionAssigned == USB_IN_TRANSFER)  
  34.         SetClearIndexedReg(pContext, dwEndpoint, IN_CSR1_REG_OFFSET,  
  35.             (IN_SEND_STALL), SET);  
  36.      
  37.     else // Out Endpoint   
  38.         // Must Clear Out Packet Ready when sending Stall   
  39.         SetClearIndexedReg(pContext, dwEndpoint, OUT_CSR1_REG_OFFSET,  
  40.             (OUT_SEND_STALL), SET);  
  41.         SetClearIndexedReg(pContext ,dwEndpoint, OUT_CSR1_REG_OFFSET,  
  42.             (OUT_PACKET_READY), CLEAR);  
  43.      
  44.       
  45.     UNLOCK_ENDPOINT(peps);  
  46.     FUNCTION_LEAVE_MSG();  
  47.   
  48.     return ERROR_SUCCESS;  
  49.  

10.UfnPdd_IsConfigurationSupportab le
这个函数没有做具体工作.
[c-sharp:collapse] + expand source view plain copy print ?
  1. DWORD   
  2. WINAPI   
  3. UfnPdd_IsConfigurationSupportable(  
  4.     PVOID                       pvPddContext,  
  5.     UFN_BUS_SPEED               Speed,  
  6.     PUFN_CONFIGURATION          pConfiguration  
  7.      
  8.  
  9.     SETFNAME();  
  10.     FUNCTION_ENTER_MSG();  
  11.   
  12.     DEBUGCHK(Speed == BS_FULL_SPEED);  
  13.   
  14.     PCTRLR_PDD_CONTEXT pContext (PCTRLR_PDD_CONTEXT) pvPddContext;  
  15.     ValidateContext(pContext);  
  16.   
  17.     // This PDD does not have any special requirements that cannot be    
  18.     // handled through IsEndpointSupportable.   
  19.     DWORD dwRet ERROR_SUCCESS;  
  20.   
  21.     FUNCTION_LEAVE_MSG();  
  22.   
  23.     return dwRet;  
  24.  

11.UfnPdd_IsEndpointSupportable
UfnPdd_IsEndpointSupportable用来查询指定端点是否支持.
首先判断是否是端点0,如果是端点0则检查其属性是否为CONTROL,并判断其做大包字节数,如果小于8,则设置成8.如果是其他端点,则需保证其属性不为CONTROL端点.然后根据不同的传输类型设置其包大小的范围.异步类型CPU UDC不支持,批量或中断传输硬件支持8,16,32,64字节的包, 如果要求设置的包大小超过范围,则设置支持的最大的值.
[c-sharp:collapse] + expand source view plain copy print ?
  1. DWORD  
  2. WINAPI  
  3. UfnPdd_IsEndpointSupportable(  
  4.     PVOID                       pvPddContext,  
  5.     DWORD                       dwEndpoint,  
  6.     UFN_BUS_SPEED               Speed,  
  7.     PUSB_ENDPOINT_DESCRIPTOR    pEndpointDesc,  
  8.     BYTE                        bConfigurationValue,  
  9.     BYTE                        bInterfaceNumber,  
  10.     BYTE                        bAlternateSetting  
  11.      
  12.  
  13.     SETFNAME();  
  14.     FUNCTION_ENTER_MSG();  
  15.   
  16.     DEBUGCHK(EP_VALID(dwEndpoint));  
  17.     DEBUGCHK(Speed == BS_FULL_SPEED);  
  18.   
  19.     DWORD dwRet ERROR_SUCCESS;  
  20.     PCTRLR_PDD_CONTEXT pContext (PCTRLR_PDD_CONTEXT) pvPddContext;  
  21.     ValidateContext(pContext);  
  22.   
  23.     PEP_STATUS peps GetEpStatus(pContext, dwEndpoint);  
  24.   
  25.     // Special case for endpoint 0   
  26.     if (dwEndpoint == 0)  
  27.         DEBUGCHK(pEndpointDesc->bmAttributes == USB_ENDPOINT_TYPE_CONTROL);  
  28.           
  29.         // Endpoint only supports or 16 byte packet size   
  30.         if (pEndpointDesc->wMaxPacketSize EP_0_PACKET_SIZE)  
  31.             RETAILMSG(1, (_T("%s Endpoint only supports %u byte packets/r/n"),  
  32.                 pszFname, EP_0_PACKET_SIZE));  
  33.             dwRet ERROR_INVALID_PARAMETER;  
  34.          
  35.         else{    
  36.             // Larger than EP Max Packet Size reduce to Max   
  37.             pEndpointDesc->wMaxPacketSize EP_0_PACKET_SIZE;  
  38.          
  39.      
  40.     else if (dwEndpoint ENDPOINT_COUNT)  
  41.         BYTE bTransferType pEndpointDesc->bmAttributes USB_ENDPOINT_TYPE_MASK;  
  42.         DEBUGCHK(bTransferType != USB_ENDPOINT_TYPE_CONTROL);  
  43.   
  44.         // Validate and adjust packet size   
  45.         WORD wPacketSize   
  46.             (pEndpointDesc->wMaxPacketSize USB_ENDPOINT_MAX_PACKET_SIZE_MASK);  
  47.   
  48.         switch(bTransferType)  
  49.   
  50.         // Isoch not currently supported by Samsung HW   
  51.         case USB_ENDPOINT_TYPE_ISOCHRONOUS:  
  52.             RETAILMSG(1, (_T("%s Isochronous endpoints are not supported/r/n"),  
  53.                 pszFname));  
  54.             dwRet ERROR_INVALID_PARAMETER;  
  55.             break;  
  56.   
  57.         case USB_ENDPOINT_TYPE_BULK:  
  58.         case USB_ENDPOINT_TYPE_INTERRUPT:  
  59.             // HW Can only Support 8, 16, 32, 64 byte packets   
  60.             if((wPacketSize >= 8) && (wPacketSize 16)){  
  61.                 wPacketSize 8;  
  62.              
  63.             else if ((wPacketSize >= 16) && (wPacketSize 64)){  
  64.                 // Note that 32 => Dual Packet mode Do NOT allow   
  65.                 wPacketSize 16;  
  66.              
  67.             else if (wPacketSize >= 64 ){  
  68.                 wPacketSize 64;                  
  69.              
  70.             else{ // wPacketSize 8   
  71.                 dwRet ERROR_INVALID_PARAMETER;  
  72.              
  73.             break;  
  74.   
  75.         default:  
  76.             dwRet ERROR_INVALID_PARAMETER;  
  77.             break;  
  78.            
  79.           
  80.         // If Requested Size is larger than what is supported ... change it.   
  81.         // Note only try and change it if no errors so far... meaning Ep is   
  82.         // Supportable.   
  83.         if (wPacketSize != (pEndpointDesc->wMaxPacketSize USB_ENDPOINT_MAX_PACKET_SIZE_MASK)) &&   
  84.              (dwRet == ERROR_SUCCESS)  
  85.             pEndpointDesc->wMaxPacketSize &= ~USB_ENDPOINT_MAX_PACKET_SIZE_MASK;  
  86.             pEndpointDesc->wMaxPacketSize |= wPacketSize;  
  87.          
  88.      
  89.   
  90.     FUNCTION_LEAVE_MSG();  
  91.   
  92.     return dwRet;  
  93.  

12.UfnPdd_SendControlStatusHandsha ke
UfnPdd_SendControlStatusHandsha ke用来发送端点0的控制状态握手信息.
参数检查后,获取端点0结构信息,然后移除Out Packet Ready标志,读取EP0_CSR寄存器,设置DATA_END,SERVICED_OUT_PKT_RDY保留EP0_STALL_BITS位,然后写入EP0_CSR寄存器,标记sendDataEnd为FALSE
[c-sharp:collapse] + expand source view plain copy print ?
  1. DWORD  
  2. WINAPI  
  3. UfnPdd_SendControlStatusHandshake(  
  4.     PVOID           pvPddContext,  
  5.     DWORD           dwEndpoint  
  6.      
  7.  
  8.     SETFNAME();  
  9.     FUNCTION_ENTER_MSG();  
  10.   
  11.     PCTRLR_PDD_CONTEXT pContext (PCTRLR_PDD_CONTEXT) pvPddContext;  
  12.     ValidateContext(pContext);  
  13.   
  14.     DEBUGCHK(dwEndpoint == 0);  
  15.       
  16.     // This function is only valid for Endpoint 0   
  17.     EP_STATUS *peps GetEpStatus(pContext, 0);  
  18.     DEBUGCHK(peps->fInitialized);  
  19.   
  20.     // Remove the Out Packet Ready Condition   
  21.     if(pContext->sendDataEnd)  
  22.         LOCK_ENDPOINT(peps);  
  23.   
  24.         RETAILMSG(1, (_T("%s Sending packet /r/n"), pszFname));  
  25.   
  26.         BYTE bEP0IrqStatus ReadIndexedReg(pContext, 0, EP0_CSR_REG_OFFSET);  
  27.   
  28.         // Write to SEND_STALL and SENT_STALL to clear them, so we need to    
  29.         // leave them unchanged by default.   
  30.         BYTE bEp0CsrToWrite (bEP0IrqStatus EP0_STALL_BITS);  
  31.   
  32.         bEp0CsrToWrite |= (DATA_END SERVICED_OUT_PKT_RDY);  
  33.   
  34.         RETAILMSG(1, (_T("%s Status 0xx, Writing 0xx/r/n"), pszFname,  
  35.             bEP0IrqStatus, bEp0CsrToWrite));  
  36.   
  37.         WriteIndexedReg(pContext, 0, EP0_CSR_REG_OFFSET, bEp0CsrToWrite);  
  38.           
  39.         pContext->sendDataEnd FALSE;  
  40.   
  41.         UNLOCK_ENDPOINT(peps);  
  42.       
  43.       
  44.     FUNCTION_LEAVE_MSG();  
  45.   
  46.     return ERROR_SUCCESS;  
  47.  

13.UfnPdd_SetAddress
UfnPdd_SetAddress用来设置USB设备地址.通过写ADDRESS寄存器0-6位为地址,第7为写1通知地址更新.
[c-sharp:collapse] + expand source view plain copy print ?
  1. DWORD  
  2. WINAPI  
  3. UfnPdd_SetAddress(  
  4.                   PVOID pvPddContext,  
  5.                   BYTE  bAddress  
  6.                    
  7.  
  8.     SETFNAME();  
  9.     FUNCTION_ENTER_MSG();  
  10.   
  11.     PCTRLR_PDD_CONTEXT pContext (PCTRLR_PDD_CONTEXT) pvPddContext;  
  12.     ValidateContext(pContext);  
  13.   
  14.     // Make sure that the Address Update bit is set (0x80)   
  15.     WriteReg(pContext, SET_ADDRESS_REG_OFFSET, (0x80 bAddress));  
  16.   
  17.     FUNCTION_LEAVE_MSG();  
  18.   
  19.     return ERROR_SUCCESS;  
  20.  

14.UfnPdd_InitiateRemoteWakeup
UfnPdd_InitiateRemoteWakeup用来初始化远程唤醒.通过写PWR_REG置位MCU_RESUME.
[c-sharp:collapse] + expand source view plain copy print ?
  1. DWORD  
  2. WINAPI  
  3. UfnPdd_InitiateRemoteWakeup(  
  4.     PVOID pvPddContext  
  5.      
  6.  
  7.     SETFNAME();  
  8.     FUNCTION_ENTER_MSG();  
  9.   
  10.     PCTRLR_PDD_CONTEXT pContext (PCTRLR_PDD_CONTEXT) pvPddContext;  
  11.     ValidateContext(pContext);  
  12.   
  13.     SetClearReg(pContext, PWR_REG_OFFSET, MCU_RESUME, SET);  
  14.   
  15.     FUNCTION_LEAVE_MSG();  
  16.   
  17.     return ERROR_SUCCESS;  
  18.  

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.
[c-sharp:collapse] + expand source view plain copy print ?
  1. DWORD  
  2. WINAPI  
  3. UfnPdd_IOControl(  
  4.                  PVOID           pvPddContext,  
  5.                  IOCTL_SOURCE    source,  
  6.                  DWORD           dwCode,  
  7.                  PBYTE           pbIn,  
  8.                  DWORD           cbIn,  
  9.                  PBYTE           pbOut,  
  10.                  DWORD           cbOut,  
  11.                  PDWORD          pcbActualOut  
  12.                   
  13.  
  14.     SETFNAME();  
  15.     FUNCTION_ENTER_MSG();  
  16.   
  17.     PCTRLR_PDD_CONTEXT pContext (PCTRLR_PDD_CONTEXT) pvPddContext;  
  18.     ValidateContext(pContext);  
  19.   
  20.     DWORD dwRet ERROR_INVALID_PARAMETER;  
  21.   
  22.     switch (dwCode)  
  23.     case IOCTL_UFN_GET_PDD_INFO:  
  24.         if source != BUS_IOCTL || pbOut == NULL ||   
  25.              cbOut != sizeof(UFN_PDD_INFO)  
  26.             break;  
  27.          
  28.   
  29.         // Not currently supported.   
  30.         break;  
  31.   
  32.     case IOCTL_BUS_GET_POWER_STATE:  
  33.         if (source == MDD_IOCTL)  
  34.             PREFAST_DEBUGCHK(pbIn);  
  35.             DEBUGCHK(cbIn == sizeof(CE_BUS_POWER_STATE));  
  36.   
  37.             PCE_BUS_POWER_STATE pCePowerState (PCE_BUS_POWER_STATE) pbIn;  
  38.             PREFAST_DEBUGCHK(pCePowerState->lpceDevicePowerState);  
  39.   
  40.             RETAILMSG(1, (_T("%s IOCTL_BUS_GET_POWER_STATE/r/n"), pszFname));  
  41.   
  42.             *pCePowerState->lpceDevicePowerState pContext->cpsCurrent;  
  43.   
  44.             dwRet ERROR_SUCCESS;  
  45.          
  46.         break;  
  47.   
  48.     case IOCTL_BUS_SET_POWER_STATE:  
  49.         if (source == MDD_IOCTL)  
  50.             PREFAST_DEBUGCHK(pbIn);  
  51.             DEBUGCHK(cbIn == sizeof(CE_BUS_POWER_STATE));  
  52.   
  53.             PCE_BUS_POWER_STATE pCePowerState (PCE_BUS_POWER_STATE) pbIn;  
  54.   
  55.             PREFAST_DEBUGCHK(pCePowerState->lpceDevicePowerState);  
  56.             DEBUGCHK(VALID_DX(*pCePowerState->lpceDevicePowerState));  
  57.   
  58.             RETAILMSG(1, (_T("%s IOCTL_BUS_GET_POWER_STATE(D%u)/r/n"),   
  59.                 pszFname, *pCePowerState->lpceDevicePowerState));  
  60.   
  61.             SetPowerState(pContext, *pCePowerState->lpceDevicePowerState);  
  62.   
  63.             dwRet ERROR_SUCCESS;  
  64.          
  65.         break;  
  66.      
  67.   
  68.     FUNCTION_LEAVE_MSG();  
  69.   
  70.     return dwRet;  
  71.  

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

如果新的电源状态大于原来的,请求总线驱动设置新的电源状态.
最后设置pContext->cpsCurrent为新的电源状态.

[c-sharp:collapse] + expand source view plain copy print ?
  1. // This does not do much because there is not any way to control   
  2. // power on this controller.   
  3. static  
  4. CEDEVICE_POWER_STATE  
  5. SetPowerState(  
  6.     PCTRLR_PDD_CONTEXT      pContext,  
  7.     CEDEVICE_POWER_STATE    cpsNew  
  8.      
  9.  
  10.     SETFNAME();  
  11.       
  12.     PREFAST_DEBUGCHK(pContext);  
  13.     DEBUGCHK(VALID_DX(cpsNew));  
  14.     ValidateContext(pContext);  
  15.   
  16.     // Adjust cpsNew.   
  17.     if (cpsNew != pContext->cpsCurrent)  
  18.         if (cpsNew == D1 || cpsNew == D2)  
  19.             // D1 and D2 are not supported.   
  20.             cpsNew D0;  
  21.          
  22.         else if (pContext->cpsCurrent == D4)  
  23.             // D4 can only go to D0.   
  24.             cpsNew D0;  
  25.          
  26.      
  27.   
  28.     if (cpsNew != pContext->cpsCurrent)  
  29.         RETAILMSG(1, (_T("%s Going from D%u to D%u/r/n"),  
  30.             pszFname, pContext->cpsCurrent, cpsNew));  
  31.           
  32.         if (cpsNew pContext->cpsCurrent) && pContext->hBusAccess  
  33.             SetDevicePowerState(pContext->hBusAccess, cpsNew, NULL);  
  34.          
  35.   
  36.         switch (cpsNew)  
  37.         case D0:  
  38.             KernelIoControl(IOCTL_HAL_DISABLE_WAKE, &pContext->dwSysIntr,    
  39.                 sizeof(pContext->dwSysIntr), NULL, 0, NULL);  
  40.               
  41.             if (pContext->fRunning)  
  42.                 // Cause the IST to restart.   
  43.                 pContext->fRestartIST TRUE;  
  44.                 SetInterruptEvent(pContext->dwSysIntr);  
  45.                         
  46.             break;  
  47.   
  48.         case D3:  
  49.             KernelIoControl(IOCTL_HAL_ENABLE_WAKE, &pContext->dwSysIntr,    
  50.                 sizeof(pContext->dwSysIntr), NULL, 0, NULL);  
  51.             break;  
  52.   
  53.         case D4:  
  54.             KernelIoControl(IOCTL_HAL_DISABLE_WAKE, &pContext->dwSysIntr,    
  55.                 sizeof(pContext->dwSysIntr), NULL, 0, NULL);  
  56.             break;  
  57.          
  58.   
  59.         if (cpsNew pContext->cpsCurrent) && pContext->hBusAccess  
  60.             SetDevicePowerState(pContext->hBusAccess, cpsNew, NULL);  
  61.          
  62.   
  63.         pContext->cpsCurrent cpsNew;  
  64.      
  65.   
  66.     return pContext->cpsCurrent;  
  67.  

接下来来看看驱动的IST.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值