系统下面许多设备,比如键盘,串口,触摸屏,硬盘......这些设备什么时候被系统使用的?这些设备怎样被系统使用的?加载过程是怎么样的?设备如何加入系统协同工作的?为什么系统能检测到并使用即插即用的设备(如usb鼠标)?系统是怎么控制设备的电源的?
CE管理设备的程序叫做DEVICE.EXE,这是一个独立的用户级进程,它主要负责跟踪,维护系统的设备信息并对设备资源进行调配.设备管理器包括即插即用设备管理,电源管理,io资源管理等等.
结构示意图:
目录树:c:/WINCE500/PRIVATE/WINCEOS/COREOS/DEVICE/
[DEVCORE]设备管理器的核心代码部分.
Devapi.c
Devcore.c
Devfile.c
Devfsd.c
Devload.c
Devpnp.c
Celogdev.h
[DEVMAIN]程序入口点.
devmain.c
[INC]头文件
Devmgrif.h
Devmgrp.h
Devzones.h
Iormif.h
Pmif.h
[IORM]io资源管理
Iorm.c
[NOPMIF]电源管理模块接口(这里是不要电源管理模块的'空'接口)
Nopmif.c
[PMIF]电源管理模块接口
Pmif.c
源码分析按照先后执行顺序来分析源代码.)
在[DEVMAIN]中有一个devmain.c的代码,这是device.exe的入口点.如同标准c的main()函数所在,因为是windows所以入口点是WinMain()这样的函数.在WinMain()内没有其他内容,只调用了StartDeviceManager()这个函数.
int WINAPIWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR lpCmdLine, int nCmdShow)
{
int status;
status = StartDeviceManager(hInst, hPrevInst, lpCmdLine, nCmdShow);
return status;
}
前面WinMain()调用的StartDeviceManager()函数位于devcore.c. 这个函数初始化设备管理器,电源管理器,IO资源管理,然后启动设备管理器,开始负责设备驱动的加载和卸载工作.
int WINAPI
StartDeviceManager(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR lpCmdLine, int nCmShow)
{
HINSTANCE hCeddkDll;
HANDLE hEvent;
if (IsAPIReady(SH_DEVMGR_APIS)) {
return 0;
}
DEBUGREGISTER(NULL);
DEBUGMSG(ZONE_BOOTSEQ, (TEXT("DEVICE: Starting boot phase 1/n")));
// PHASE 1
g_BootPhase = 1; //用一个全局变量来表示现在处于启动的哪个阶段.一共有3个阶段.
// 0表示还没有开始启动;1表示在搜索注册表的值;2表示在加载设备;
// 3表示已经开始正常运行了.
InitOOMSettings(); // 初始化OOM.
InitializeListHead(&g_DevChain);// 初始化常规状态设备列表
InitializeListHead(&g_ActivatingDevs); // 初始化激活的已经注册的设备列表
InitializeListHead(&g_DyingDevs); // 初始化消亡状态的设备列表
InitializeListHead(&g_CandidateDevs); // 初始化正在加载的设备驱动列表.
g_hCleanEvt = CreateEvent(NULL, FALSE, FALSE, NULL);
g_hDevApiHandle = CreateAPISet("WFLD", NUM_FDEV_APIS, FDevApiMethods, FDevApiSigs);// 向系统注册api
g_hDevFileApiHandle = CreateAPISet("W32D", NUM_FAPIS, DevFileApiMethods, DevFileApiSigs); // 向系统注册api
RegisterAPISet(g_hDevFileApiHandle, HT_FILE | REGISTER_APISET_TYPE);
InitializePnPNotifications(); // 这个程序将调用StartDeviceNotifyThread()
// 这将启动一个线程.它的具体实现在devpnp.c文件中.
InitializeCriticalSection(&g_devcs); // 初始化临界区.
ResourceInitModule(); // 初始化一个全局变量gdwMaxDenseResources
// 根据注册表来初始化设备管理资源
ResourceInitFromRegistry(TEXT("Drivers//Resources"));
SetPowerOffHandler((FARPROC) DevMgrPowerOffHandler);
RegisterAPISet(g_hDevApiHandle, SH_DEVMGR_APIS);
InitDeviceFilesystems();
// Indicate that the device manager is up and running
hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, _T("SYSTEM/DevMgrApiSetReady"));
DEBUGCHK(hEvent != NULL);
if (hEvent != NULL) {
SetEvent(hEvent);//设置一个全局事件.通知别的程序设备管理器api已经准备好了.
// 在其他的应用里面,使用设备管理器api前,如果希望确认设备管理器
// 的api已经注册好,它会等待这样一个事件.
CloseHandle(hEvent);
}
// Calibrate stall counter that is used for StallExecution
// 以下代码调用ceddk.dll里面的fnCalibrateStall()函数.
hCeddkDll = LoadLibrary (TEXT("ceddk.dll"));
if (NULL != hCeddkDll) {
pCalibrateStallFn fnCalibrateStall = (pCalibrateStallFn)/
GetProcAddress(hCeddkDll, TEXT("CalibrateStallCounter"));
if (!fnCalibrateStall) {
DEBUGMSG(ZONE_BOOTSEQ,(L"GetProcAddress failed on ceddk.dll/r/n"));
FreeLibrary(hCeddkDll);
}
else {
fnCalibrateStall();
}
}
// Call the power manager initialization entry point
PM_Init(); // 初始化电源管理模块.电源管理模块是一个pm.dll.它也被device.exe调用.这里// 暂时不打算涉及电源管理部分.简单来说:在PM_Init()函数里面会启动3个线程,
// PnpThreadProc,ResumeThreadProc, ActivityTimersThreadProc
// 它们各自负责监控即插即用,Resume,和激活定时器
PM_SetSystemPowerState(NULL, POWER_STATE_ON, POWER_FORCE);//设置系统电源开.
// See if we are going to have two boot phases
// 根据注册表内容,决定采用怎样的加载过程.
// 如果存在SYSTEM/BootPhase1.分2个步骤来加载:
// 先DevloadInit()加载一次,然后等待通知后,继续调用InitDevice()加载.
// 如果没有SYSTEM/BootPhase1,则调用DevloadInit()一次完成.
// 也许是满足一些需要2次加载设备的情况,所以留下这个功能.
hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, _T("SYSTEM/BootPhase1"));
if (hEvent != NULL) {
// Load phase 1 drivers from the boot registry
DevloadInit(); // 加载设备.DevloadInit()函数位于devload.c,它首先删除注册表里面
// Device/Active,然后调用InitDevices()函数加载设备驱动.
// Signal boot phase 1 complete
SetEvent(hEvent); // 发出通知,阶段1已经完成.
CloseHandle(hEvent);
// Wait for phase 2 of the boot to begin
// 等待通知后进入阶段2
hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, TEXT("SYSTEM/BootPhase2"));
DEBUGCHK(hEvent);
if (hEvent) {
DEBUGMSG(ZONE_BOOTSEQ, (TEXT("DEVICE: Started, waiting for boot phase 2/r/n")));
WaitForSingleObject(hEvent, INFINITE);
CloseHandle(hEvent);
}
// Load any new drivers from the persistent registry.Since the
// registry may have changed, update the power state for any devices
// that need it.
DEBUGMSG(ZONE_BOOTSEQ, (TEXT("DEVICE: Second-phase driver load/r/n")));
g_BootPhase = 2;
PM_SetSystemPowerState(NULL, POWER_STATE_ON, POWER_FORCE);
InitDevices(NULL); // DevInit()加载会先清空注册表Acitve下的内容,
// 第二次加载不能把前面一次的清空,所以这里不能用DevInit().
DEBUGMSG(ZONE_BOOTSEQ, (TEXT("DEVICE: Startup sequence complete/r/n")));
SignalStartedUsingReg(); // SignalStarted call with the right args
} else {
DEBUGMSG(ZONE_BOOTSEQ, (TEXT("DEVICE: No boot registry - skipping to boot phase 2/n")));
g_BootPhase = 2;
DevloadInit();
SignalStarted(_wtol(lpCmdLine));
}
// Boot phase 3 isn't any different from phase 2; just marks that we got here.
DEBUGMSG(ZONE_BOOTSEQ,
(TEXT("DEVICE: Finished loading primary drivers - entering boot phase 3/n")));
g_BootPhase = 3; // 进入阶段3,同时也标志设备管理器开始运行了.
CELOG_DeviceFinished (); // 记录日志.
while (1) {
WaitForSingleObject(g_hCleanEvt, INFINITE);
// check for auto-deregister devs first as they may end up queuing
// themselves on the dying devs list
ProcessAutoDeregisterDevs();
ProcessDyingDevs();
ProcessDyingOpens();
}
return 1;// should not ever be reached
}
加载设备的函数,DevloadInit()事实上也是调用InitDevices来实现,只不过事先清空了Acitve下的注册表内容
void DevloadInit(void)
{
DEBUGMSG(ZONE_INIT, (TEXT("DEVICE!DevloadInit/r/n")));
#define PHASE_1_BUSNAME TEXT("BuiltInPhase1")
//
// Delete the HLM/Drivers/Active key since there are no active devices at
// init time.
// 清空注册表Active下的内容.
RegDeleteKey(HKEY_LOCAL_MACHINE, s_ActiveKey);
#ifdef DEBUG
v_NextDeviceNum = 0xFFFFFFF0;// expect wraparound
#else// DEBUG
v_NextDeviceNum = 1;
#endif// DEBUG
g_bSystemInitd = FALSE;
InitDevices(PHASE_1_BUSNAME);
}
InitDevices(LPCTSTR lpBusName )
{
HKEY RootKey;
DWORD status;
DWORD ValType;
DWORD ValLen;
TCHAR RootKeyPath[REG_PATH_LEN];
TCHAR BusName[DEVKEY_LEN];
REGINI reg[1];
DWORDdwRegCount=0;
//
// Open HLM/Drivers key
//打开注册表HLM/Drivers.
status = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
DEVLOAD_DRIVERS_KEY, //DEVLOAD_DRIVERS_KEY= "Drivers"
0,
0,
&RootKey);
if (status != ERROR_SUCCESS) {
DEBUGMSG(ZONE_ROOT|ZONE_ERROR,
(TEXT("DEVICE!InitDevices RegOpenKeyEx(%s) returned %d./r/n"),
DEVLOAD_DRIVERS_KEY, status));
return;
}
//
// Look for root key value; if not found use current Root Key as default,
// otherwise open new root key
// 查询注册表中 RootKey的值,一般这个值是Devices/BuildIn.将查询的值保存到RootKeyPath.
// 如果没有指定,则使用Devices来替代.
ValLen = sizeof(RootKeyPath);
status = RegQueryValueEx(
RootKey,
DEVLOAD_ROOTKEY_VALNAME, //DEVLOAD_ROOTKEY_VALNAME =RootKey
NULL,
&ValType,
(PUCHAR)RootKeyPath,
&ValLen);
RootKeyPath[ARRAYSIZE(RootKeyPath) - 1] = 0;
if (status != ERROR_SUCCESS) {
// Root key value not found, thus root key is Drivers
_tcscpy(RootKeyPath, DEVLOAD_DRIVERS_KEY); // 没有找到,使用Devices来替代.
}
// Close previous root key
RegCloseKey(RootKey);
DEBUGMSG(1,
(L"DEVICE!InitDevices: Root Key is %s./r/n",
RootKeyPath));
// 为ActiveDeviceEx准备参数reg. 如果输入参数lpBusName指定了,则从参数lpBusName获得,
// 否则从注册表中读取.
if (lpBusName!=NULL) {
reg[0].lpszVal = DEVLOAD_BUSNAME_VALNAME;
reg[0].dwType= DEVLOAD_BUSNAME_VALTYPE;
reg[0].pData= (PBYTE) lpBusName ;
reg[0].dwLen= (_tcslen( lpBusName ) + 1) * sizeof(TCHAR);
dwRegCount = 1;
}
else {
status = RegOpenKeyEx( HKEY_LOCAL_MACHINE, RootKeyPath,0,0, &RootKey);
if (status == ERROR_SUCCESS ) {
ValLen = sizeof( BusName);
status = RegQueryValueEx(
RootKey,
DEVLOAD_BUSNAME_VALNAME,
NULL,
&ValType,
(PUCHAR)BusName,
&ValLen);
if (status == ERROR_SUCCESS && ValType==DEVLOAD_BUSNAME_VALTYPE) {
// We found Bus Name. This is new bus driver model. So we use new format.
BusName[DEVKEY_LEN-1] = 0;
reg[0].lpszVal = DEVLOAD_BUSNAME_VALNAME;
reg[0].dwType= DEVLOAD_BUSNAME_VALTYPE;
reg[0].pData= (PBYTE)BusName;
reg[0].dwLen=ValLen;
dwRegCount = 1;
}
// Close previous root key
RegCloseKey(RootKey);
}
}
// Someday we'll want to track the handle returned by ActivateDevice so that
// we can potentially deactivate it later. But since this code refers only to
// builtin (ie, static) devices, we can just throw away the key.
if (dwRegCount)
ActivateDeviceEx(RootKeyPath,reg,dwRegCount,NULL);
else
ActivateDevice(RootKeyPath, 0);
}// InitDevices
至此,已经明确了系统是通过InitDevice()来加载驱动,更具体的InitDevice()会调用ActivateDeviceEx()来加载驱动,但是,这里只加载了一个驱动啊,难道系统就只加载一次?
这个唯一被加载的驱动是BusEnum.dll(在CE4.2是RegEnum.dll)这个驱动位于public下,它枚举了BuiltIn下所有的设备,逐个加载,并在Active下记录成功加载的设备.
分享到:
相关推荐
windows ce 开发相关论文\嵌入式Windows CE 5.0驱动程序开发及测试.pdf
2004 年开始专业从事 Windows CE 技术开发从 Windows CE 4.2 ,Windows CE 5.0 到,Windows Embedded CE 6.0。2006 年,获推荐参加 Microsoft 全球 Windows CE6.0 讲师培训,经微软考核认证,获得TTT资深讲师资格。
WINCE5.0 VS2005 应用例子供WINCE开发参考。
Windows CE 5.0 ROM 应用程序集合,最强大的 EXE ROM 程序,其中包含 wceload.exe cab 安装程序,给没有cab安装程序的导航仪wince5系统使用,使用时需要关联cab文件,这个用注册表就可以了。 cab1.reg cab2.reg 注册...
vc++.net 2005,mfc; windows mobile 5.0 ppc 串行口操作; 包括串口类,和一个完整的测试... 我一直用mfc编程,看来该学学c#了,ce5.0下mfc很费劲呀,资料也少。老了,跟不上开发环境时代的变化了。
CE5.0/CE6.0输入法
CE5.0 工具合集 excel pdf
Windows CE 5.0下的文本编辑器,支持简单的打开保存
Windows CE 5.0模拟文件,.bin格式,使用方法主程序中有,一看就懂~ 主程序地址:http://download.csdn.net/source/1000677
Windows CE 5.0 模拟器 Microsoft Windows CE 5.0 Emulator,挺好用!
WinCE5.0下VT6656的驱动程序,CE5.0Drv_VT6656.msi.
Windows CE 5.0 小工具
window ce 5.0 .net framwork 2.0 安装包
嵌入式操作系统原理 -Windows CE 5.0-微软嵌入式教学.rar 嵌入式操作系统原理 -Windows CE 5.0-微软嵌入式教学.rar
VS2008开发CE5.0环境拾建.rar
在windows系统的win CE5.0模拟器
Sysmbol公司MC3000系列开发实例
WindowsCE5.0模拟器,WindowsCE5.0模拟器
CE5.0模拟器E、WM下的导航软件更新的真是一个快,让我们这些用车载电脑的人口水狂流... PC版的导航软件实在是太老了... 早就想过在模拟器上运行CE、WM导航软件,一直未动手 直到前段时间想把模拟器直接集成到SRTocos...
《Windows CE设备驱动程序开发指南》,描述了CE驱动程序的开发