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) { -
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. - 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 pfnIsConfigurationSuppor table; -
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 pfnSendControlStatusHand shake; -
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(); -
-
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_IsConfigurationSupportab le, -
&UfnPdd_IsEndpointSupportable, -
&UfnPdd_InitEndpoint, -
&UfnPdd_RegisterDevice, -
&UfnPdd_DeregisterDevice, -
&UfnPdd_Start, -
&UfnPdd_Stop, -
&UfnPdd_IssueTransfer, -
&UfnPdd_AbortTransfer, -
&UfnPdd_DeinitEndpoint, -
&UfnPdd_StallEndpoint, -
&UfnPdd_ClearEndpointStall, -
&UfnPdd_SendControlStatusHandsha ke, -
&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; -
InitializeCriticalSectio n(&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 < 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)); -
} -
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); - }
下面就一个个来看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(); -
-
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)); -
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(); -
-
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); -
-
InitializeCriticalSectio n(&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
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(); -
-
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); -
} -
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 SendControlStatusHandshk ed 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_IsConfigurationSupportab
这个函数没有做具体工作.
- DWORD
- WINAPI
- UfnPdd_IsConfigurationSupportab
le( -
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 < 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_SendControlStatusHandsha
UfnPdd_SendControlStatusHandsha
参数检查后,获取端点0结构信息,然后移除Out Packet Ready标志,读取EP0_CSR寄存器,设置DATA_END,SERVICED_OUT_PKT_RDY保留EP0_STALL_BITS位,然后写入EP0_CSR寄存器,标记sendDataEnd为FALSE
- DWORD
- WINAPI
- UfnPdd_SendControlStatusHandsha
ke( -
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(); -
-
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(); -
-
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) { -
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; -
} -
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.