wince5使用access数据库_Windows CE USB Function Driver驱动简析(1)-驱动架构及UfnPdd函数(基于WinCE5.0...
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.
// Called by MDD's DllEntry.
extern"C"
BOOL
UfnPdd_DllEntry(
HANDLE hDllHandle,
DWORD dwReason,
LPVOID lpReserved
)
{
SETFNAME();
switch(dwReason) {
caseDLL_PROCESS_ATTACH:
g_pUDCBase = NULL;
break;
}
returnTRUE;
}
// 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层调用.这些函数后面一一分析.
该结构原型如下:
// Structure that the PDD must fill out in UfnPdd_Init.
typedefstruct_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释放之前分配的资源.
// 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();
staticconstUFN_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));
gotoEXIT;
}
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));
gotoEXIT;
}
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 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));
gotoEXIT;
}
elseif(dwi.dwNumIoWindows != 1) {
DEBUGMSG(ZONE_ERROR, (_T("%s %d windows configured, expected 1/r/n"),
pszFname, dwi.dwNumIoWindows));
dwRet = ERROR_INVALID_DATA;
gotoEXIT;
}
elseif(dwi.ioWindows[0].dwLen
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;
gotoEXIT;
}
elseif(dwi.ioWindows[0].dwBase == 0){
DEBUGMSG(ZONE_INIT, (_T("%s no ioBase value specified/r/n"),pszFname));
dwRet = ERROR_INVALID_DATA;
gotoEXIT;
}
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));
gotoEXIT;
}
elseif( (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;
gotoEXIT;
}
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));
gotoEXIT;
}
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));
gotoEXIT;
}
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();
returndwRet;
}
// 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对每个端点进行复位.
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
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中断.
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));
}
elseif(dwEndpoint
// 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关闭总线驱动句柄,然后禁止中断唤醒,释放逻辑中断号.
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的释放等.
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();
returnERROR_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禁止中断,释放事件句柄.
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));
gotoEXIT;
}
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));
gotoEXIT;
}
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();
gotoEXIT;
}
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();
returndwRet;
}
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.
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();
returnERROR_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端点挂起和端点中断状态.
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
}
elseif(dwEndpoint
// 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) {
caseUSB_ENDPOINT_TYPE_ISOCHRONOUS:
// Set the ISO bit
SetClearIndexedReg(pContext, dwEndpoint,IN_CSR2_REG_OFFSET,
SET_TYPE_ISO, SET);
break;
caseUSB_ENDPOINT_TYPE_BULK:
caseUSB_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();
returnERROR_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寄存器对应端点的中断.
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进行端点复位,屏蔽中断,清除端点中断状态.
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();
returnERROR_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状态.
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);
}
elseif(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();
returnERROR_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.
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 0xx 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;
}
elseif(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();
returnERROR_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 0xx 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
这个函数没有做具体工作.
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();
returndwRet;
}
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字节的包, 如果要求设置的包大小超过范围,则设置支持的最大的值.
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
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;
}
}
elseif(dwEndpoint
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
caseUSB_ENDPOINT_TYPE_ISOCHRONOUS:
RETAILMSG(1, (_T("%s Isochronous endpoints are not supported/r/n"),
pszFname));
dwRet = ERROR_INVALID_PARAMETER;
break;
caseUSB_ENDPOINT_TYPE_BULK:
caseUSB_ENDPOINT_TYPE_INTERRUPT:
// HW Can only Support 8, 16, 32, 64 byte packets
if((wPacketSize >= 8) && (wPacketSize
wPacketSize = 8;
}
elseif((wPacketSize >= 16) && (wPacketSize
// Note that 32 => Dual Packet mode - Do NOT allow
wPacketSize = 16;
}
elseif(wPacketSize >= 64 ){
wPacketSize = 64;
}
else{// wPacketSize
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();
returndwRet;
}
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
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 - 0xx, Writing 0xx/r/n"), pszFname,
bEP0IrqStatus, bEp0CsrToWrite));
WriteIndexedReg(pContext, 0, EP0_CSR_REG_OFFSET, bEp0CsrToWrite);
pContext->sendDataEnd = FALSE;
UNLOCK_ENDPOINT(peps);
}
FUNCTION_LEAVE_MSG();
returnERROR_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 - 0xx, Writing 0xx/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通知地址更新.
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();
returnERROR_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.
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();
returnERROR_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.
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) {
caseIOCTL_UFN_GET_PDD_INFO:
if( source != BUS_IOCTL || pbOut == NULL ||
cbOut !=sizeof(UFN_PDD_INFO) ) {
break;
}
// Not currently supported.
break;
caseIOCTL_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;
caseIOCTL_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();
returndwRet;
}
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为新的电源状态.
// 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;
}
elseif(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 cpsCurrent) && pContext->hBusAccess ) {
SetDevicePowerState(pContext->hBusAccess, cpsNew, NULL);
}
switch(cpsNew) {
caseD0:
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;
caseD3:
KernelIoControl(IOCTL_HAL_ENABLE_WAKE, &pContext->dwSysIntr,
sizeof(pContext->dwSysIntr), NULL, 0, NULL);
break;
caseD4:
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;
}
returnpContext->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.
wince5使用access数据库_Windows CE USB Function Driver驱动简析(1)-驱动架构及UfnPdd函数(基于WinCE5.0...相关推荐
- Windows CE SDHC驱动简析(1)-驱动架构(基于WinCE5.0 SMDK2410 BSP的SDHC驱动)
Windows CE的SD卡驱动包括总线驱动(bus driver),主控制器驱动(host controller driver)和客户端驱动(client driver). 总线驱动是客户端驱动和主 ...
- wince5使用access数据库_关于wince系统支持什么数据库的阿里云论坛用户知识和技术交流...
{"moduleinfo":{"list_count":[{"count_phone":21,"count":21}], ...
- Windows CE串口驱动简析(2)-PDD层实现:CReg2410Uart和TX部分(基于WinCE5.0 SMDK2410 BSP的Serial驱动)
二.PDD层 1.PDD架构 现在我们就来看看SMDK2410中串口驱动的PDD部分. MDD层和PDD COMMON层都是由微软提供的,一般情况下我们基本无须改动.微软为开发者提供了一个CSeria ...
- linux cdc设备驱动,Linux下USB CDC ACM 驱动简析
一.硬件平台:TI AM335X 芯片 二.软件平台:Ubuntu 10.04 三.USB CDC ACM 驱动简介 USB的CDC类是USB通信设备类 (Communication Device C ...
- WINCE6.0+S3C2443下的usb function(功能)驱动
********************************LoongEmbedded************************ 作者:LoongEmbedded(kandi) 时间:201 ...
- PHP通过PDO连接Microsoft Access数据库
1连接到access数据库 $db = new PDO("odbc:Driver={Microsoft Access Driver (*.mdb, *.accdb)}; dbq=" ...
- Windows CE USB摄像头驱动编写
作者:youngyi2006 转自:http://blog.csdn.net/youngyi2006/article/details/7731311 非常感谢下面两位高人 作者: Douglas Bo ...
- EVC4.0+AdoCe3.1访问Access数据库全攻略(附带说明及例程)
http://bbs.mscommunity.com/forums/ShowThread.aspx?PostID=26641 EVC4.0+AdoCe3.1访问Access数据库全攻略(附带说明及例程 ...
- 计算机基础access数据库操作题,2021年3月全国计算机等级考试二级Access数据库程序设计题库及答案讲解...
原标题:2021年3月全国计算机等级考试二级Access数据库程序设计题库及答案讲解 资料来源:学盛通学习网547所大学考研专业课(历年真题及模拟题可在线作答,系统自动评分,出答案及解析) 本题库是详 ...
最新文章
- 输入一个字符串,用子函数完成在字符串中找出ACSII码值最大的字符,将其放在第一个位置,并将该字符前的所有字符向后顺序移动
- bzoj 4753: [Jsoi2016]最佳团体
- Redis的复制详解
- 电脑显示器变色_电脑维修(看完后就可以开一家自己的电脑维修店!)
- python编程入门单例_python实现单例模式怎么写啊?
- 记录——《C Primer Plus (第五版)》第九章编程练习第九题
- mysql数据库笔记 约束_MySQL数据库笔记四:MySQL的约束
- 高可用之2——存储b
- weblogic安装
- 这两天,上海吹起一股“极棒”风……
- jupyter怎么换背景颜色
- 【人民币识别】基于RGB颜色空间实现人民币序列号识别含Matlab源码
- 《我的世界》Minecraft私服搭建100%成功
- Fabric v2.2 单机部署 使用tape测试
- vue中reject与provide使用
- 最新双色球彩万宝缩水使用方法大全
- 重读《触龙说赵太后》
- 亚马逊SP-API申请 PII权限申请 ERP开发 开发人员注册
- 【我是初学者】关于获取配置文件.properties的常见三种方式--只是常见的方式,欢迎牛神来加瓦
- 第一次作业(个人作业):阅读教材,提五个问题