KernelIoControl无论是在驱动开发,还是应用程序中,我们都会用到各种各样的IOControl指令,去完成相关的操作.
eg.
KernelIoControl(IOCTL_HAL_REBOOT, NULL, 0, NULL, 0, NULL);
这行代码完成了系统WarmBoot的功能,我们无法看到KernelIoControl的具体实现,从Windows Mobile 6 Document中,看得出来该函数会最终调用OEMIoControl,我们可以从这个函数入手。
The kernel calls the OEMIoControl function when adevice driver or application calls the kernel function KernelIoControl and passesan I/O control code.
PrototypeOf KernelIoControl
BOOL KernelIoControl( DWORD dwIoControlCode, LPVOID lpInBuf, DWORD nInBufSize, LPVOID lpOutBuf, DWORD nOutBufSize, LPDWORD lpBytesReturned ); |
RequirementsOf KernelIoControl
Header | pkfuncs.h |
Library | coredll.lib |
Windows Mobile | Windows Mobile Version 5.0 and later |
上述涉及到的两个文件的存放路径如下:
WM613\PUBLIC\COMMON\OAK\INC\pkfuncs.h
WM613\PUBLIC\COMMON\OAK\LIB\ARMV4I\RETAIL\coredll.lib
OEMIoControl该函数用来Driver Layer和Kernel进行通讯的,当应用层调用KernelIoControl时,该函数会最终被调用,或者Driver Layer可以直接调用它。
\WM613\PLATFORM\COMMON\SRC\COMMON\IOCTL\ioctl.c
该函数的功能主要就是在g_oalIoCtlTable查找目标函数,并执行。
// Search the IOCTL table for the requestedcode.
for (i = 0; g_oalIoCtlTable[i].pfnHandler!= NULL; i++) {
if (g_oalIoCtlTable[i].code == code)break;
}
// Execute the handler
rc = g_oalIoCtlTable[i].pfnHandler(
code, pInBuffer, inSize, pOutBuffer, outSize, pOutSize
);
查找的依据是g_oalIoCtlTable[i].code,eg.IOCTL_HAL_REBOOT(在phfuncs.h中定义)。
g_oalIoCtlTable在ioctl.c中定义。
SMDK6410\Src\Kernel\Oal\ioctl.c
const OAL_IOCTL_HANDLERg_oalIoCtlTable[] = {
#include "ioctl_tab.h"
};
在浏览ioctl_tab.h的内容之前,我们先看一下OAL_IOCTL_HANDLER结构体的定义。
typedef struct {
UINT32 code;
UINT32 flags;
BOOL (*pfnHandler)(UINT32,VOID*, UINT32, VOID*, UINT32, UINT32*);
} OAL_IOCTL_HANDLER,*POAL_IOCTL_HANDLER
就是通过code来查找目标函数的,SMDK6410\Src\Inc\ioctl_tab.h中的内容如下:
{ IOCTL_HAL_INITREGISTRY, 0, OALIoCtlHalInitRegistry },
{ IOCTL_HAL_INIT_RTC, 0, OALIoCtlHalInitRTC },
{ IOCTL_HAL_REBOOT, 0, OALIoCtlHalReboot },
{ IOCTL_HAL_PRE_POWEROFF, 0, OALIoCtlHalPrePowerOff }
OALIoCtlHalReboot的实体在SMDK6410\Src\Kernel\Oal\ioctl.c中定义。
static BOOL OALIoCtlHalReboot(
UINT32code, VOID *pInpBuffer, UINT32 inpSize,
VOID*pOutBuffer, UINT32 outSize, UINT32 *pOutSize)
{
OALMSG(OAL_IOCTL&&OAL_FUNC,(TEXT("[OAL] ++OALIoCtlHalReboot()\r\n")));
OEMSWReset();
OALMSG(OAL_IOCTL&&OAL_FUNC,(TEXT("[OAL] --OALIoCtlHalReboot()\r\n")));
Return TRUE;
}
UserDefined如何定义自己的IOControl呢?从上面的分析来看,主要分三个步骤:
FirstStep:定义控制码,<phfuncs.h, ioctl_cfg.h,oal_ioctl.h或者其他的,只要能被Application, DriverAnd Kernel看到即可>,我选择了ioctl_cfg.h
#defineIOCTL_HAL_PRE_POWEROFF CTL_CODE(FILE_DEVICE_HAL, 2123, METHOD_BUFFERED, FILE_ANY_ACCESS)
注意红色标注的部分,Note that functioncodes 0-2047 are reserved for Microsoft Corporation, and 2048-4095 are reservedfor customers.
SencondStep:配置g_oalIoCtlTable。在ioctl_tab.h中添加。
{ IOCTL_HAL_PRE_POWEROFF, 0, OALIoCtlHalPrePowerOff }
LastStep:实现OALIoCtlHalPrePowerOff,在SMDK6410\Src\Kernel\Oal\ioctl.c中定义即可,当然也可以自由选择,调用的时候能找到就行。
static BOOLOALIoCtlHalPrePowerOff(
UINT32 code, VOID*pInpBuffer, UINT32 inpSize,
VOID *pOutBuffer, UINT32outSize, UINT32 *pOutSize)
{
BOOL bFlag= FALSE;
if(inpSize == 0 ||!pInpBuffer)
{
return FALSE;
}
bFlag = *(BOOL*)pInpBuffer;
OEMPrePowerOff(bFlag);
return TRUE;
}
这样你就可以在Application Layer或者Driver Layer调用该函数了。
KernelIoControl(IOCTL_HAL_PRE_POWEROFF,&bPowerOff, sizeof(BOOL), NULL, 0, NULL)