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...相关推荐

  1. Windows CE SDHC驱动简析(1)-驱动架构(基于WinCE5.0 SMDK2410 BSP的SDHC驱动)

    Windows CE的SD卡驱动包括总线驱动(bus driver),主控制器驱动(host controller driver)和客户端驱动(client driver). 总线驱动是客户端驱动和主 ...

  2. wince5使用access数据库_关于wince系统支持什么数据库的阿里云论坛用户知识和技术交流...

    {"moduleinfo":{"list_count":[{"count_phone":21,"count":21}], ...

  3. Windows CE串口驱动简析(2)-PDD层实现:CReg2410Uart和TX部分(基于WinCE5.0 SMDK2410 BSP的Serial驱动)

    二.PDD层 1.PDD架构 现在我们就来看看SMDK2410中串口驱动的PDD部分. MDD层和PDD COMMON层都是由微软提供的,一般情况下我们基本无须改动.微软为开发者提供了一个CSeria ...

  4. linux cdc设备驱动,Linux下USB CDC ACM 驱动简析

    一.硬件平台:TI AM335X 芯片 二.软件平台:Ubuntu 10.04 三.USB CDC ACM 驱动简介 USB的CDC类是USB通信设备类 (Communication Device C ...

  5. WINCE6.0+S3C2443下的usb function(功能)驱动

    ********************************LoongEmbedded************************ 作者:LoongEmbedded(kandi) 时间:201 ...

  6. PHP通过PDO连接Microsoft Access数据库

    1连接到access数据库 $db = new PDO("odbc:Driver={Microsoft Access Driver (*.mdb, *.accdb)}; dbq=" ...

  7. Windows CE USB摄像头驱动编写

    作者:youngyi2006 转自:http://blog.csdn.net/youngyi2006/article/details/7731311 非常感谢下面两位高人 作者: Douglas Bo ...

  8. EVC4.0+AdoCe3.1访问Access数据库全攻略(附带说明及例程)

    http://bbs.mscommunity.com/forums/ShowThread.aspx?PostID=26641 EVC4.0+AdoCe3.1访问Access数据库全攻略(附带说明及例程 ...

  9. 计算机基础access数据库操作题,2021年3月全国计算机等级考试二级Access数据库程序设计题库及答案讲解...

    原标题:2021年3月全国计算机等级考试二级Access数据库程序设计题库及答案讲解 资料来源:学盛通学习网547所大学考研专业课(历年真题及模拟题可在线作答,系统自动评分,出答案及解析) 本题库是详 ...

最新文章

  1. 输入一个字符串,用子函数完成在字符串中找出ACSII码值最大的字符,将其放在第一个位置,并将该字符前的所有字符向后顺序移动
  2. bzoj 4753: [Jsoi2016]最佳团体
  3. Redis的复制详解
  4. 电脑显示器变色_电脑维修(看完后就可以开一家自己的电脑维修店!)
  5. python编程入门单例_python实现单例模式怎么写啊?
  6. 记录——《C Primer Plus (第五版)》第九章编程练习第九题
  7. mysql数据库笔记 约束_MySQL数据库笔记四:MySQL的约束
  8. 高可用之2——存储b
  9. weblogic安装
  10. 这两天,上海吹起一股“极棒”风……
  11. jupyter怎么换背景颜色
  12. 【人民币识别】基于RGB颜色空间实现人民币序列号识别含Matlab源码
  13. 《我的世界》Minecraft私服搭建100%成功
  14. Fabric v2.2 单机部署 使用tape测试
  15. vue中reject与provide使用
  16. 最新双色球彩万宝缩水使用方法大全
  17. 重读《触龙说赵太后》
  18. 亚马逊SP-API申请 PII权限申请 ERP开发 开发人员注册
  19. 【我是初学者】关于获取配置文件.properties的常见三种方式--只是常见的方式,欢迎牛神来加瓦
  20. 第一次作业(个人作业):阅读教材,提五个问题

热门文章

  1. 状态机设计模式:电动车报警器项目实战
  2. c语言入门之项目2.4——利用while求最大公约数
  3. 怎么把video文件改成mp4_腾讯视频文件怎么转换格式_如何把腾讯视频转换成mp4格式-win7之家...
  4. AdaBoost-股票涨跌预测模型搭建
  5. 【C盘炸了】利用分区助手扩充C盘
  6. 长安系统升级无法连接服务器,为什么到现在还说无法连接啊
  7. 监控/定位/诊断必杀技——JAVA应用生产问题
  8. 我的读书笔记 -《人类动物园》
  9. Python开发爬虫完整代码解析
  10. 手机系统电池是否进入省电模式