原来认真写**是多么辛苦的事啊!佩服老hot那么高产...<br />大家有空请指正.<br />----------<br /><br />系统下面许多设备,比如键盘,串口,触摸屏,硬盘......这些设备什么时候被系统使用的?这些设备怎样被系统使用的?加载过程是怎么样的?设备如何加入系统协同工作的?为什么系统能检测到并使用即插即用的设备(如usb鼠标)?系统是怎么控制设备的电源的?<br /><br />CE管理设备的程序叫做DEVICE.EXE,这是一个独立的用户级进程,它主要负责跟踪,维护系统的设备信息并对设备资源进行调配.设备管理器包括即插即用设备管理,电源管理,io资源管理等等.<br /><br />结构示意图:<br /><br /><br />目录树:c:\WINCE500\PRIVATE\WINCEOS\COREOS\DEVICE\<br /><br />[DEVCORE] 设备管理器的核心代码部分.<br />Devapi.c<br />Devcore.c<br />Devfile.c<br />Devfsd.c<br />Devload.c<br />De***p.c<br />Celogdev.h<br />[DEVMAIN] 程序入口点.<br />devmain.c<br />[INC] 头文件<br />Devmgrif.h<br />Devmgrp.h<br />Devzones.h<br />Iormif.h<br />Pmif.h<br />[IORM] io资源管理<br />Iorm.c<br />[NOPMIF] 电源管理模块接口(这里是不要电源管理模块的'空'接口)<br />Nopmif.c<br />[PMIF] 电源管理模块接口<br />Pmif.c<br /><br /><br />源码分析:(按照先后执行顺序来分析源代码.)<br /><br />在[DEVMAIN]中有一个devmain.c的代码,这是device.exe的入口点.如同标准c的main()函数所在,因为是windows所以入口点是WinMain()这样的函数.在WinMain()内没有其他内容,只调用了StartDeviceManager()这个函数.<br />int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR lpCmdLine, int nCmdShow)<br /> {<br /> int status;<br /> status = StartDeviceManager(hInst, hPrevInst, lpCmdLine, nCmdShow);<br /> return status;<br />}<br /><br /><br /><br />前面WinMain()调用的StartDeviceManager()函数位于devcore.c. 这个函数初始化设备管理器,电源管理器,IO资源管理,然后启动设备管理器,开始负责设备驱动的加载和卸载工作.<br /><br />int WINAPI <br />StartDeviceManager(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR lpCmdLine, int nCmShow)<br />{<br /><br /> HINSTANCE hCeddkDll;<br /> HANDLE hEvent;<br /><br /> if (IsAPIReady(SH_DEVMGR_APIS)) {<br /> return 0;<br /> }<br /> <br /> DEBUGREGISTER(NULL);<br /> DEBUGMSG(ZONE_BOOTSEQ, (TEXT("DEVICE: Starting boot phase 1\n")));<br /><br /> // PHASE 1<br /> g_BootPhase = 1; //用一个全局变量来表示现在处于启动的哪个阶段.一共有3个阶段.<br /> // 0表示还没有开始启动;1表示在搜索注册表的值;2表示在加载设备;<br /> // 3表示已经开始正常运行了.<br /> InitOOMSettings(); // 初始化OOM.<br /> InitializeListHead(&g_DevChain); // 初始化常规状态设备列表<br /> InitializeListHead(&g_ActivatingDevs); // 初始化激活的已经注册的设备列表<br /> InitializeListHead(&g_DyingDevs); // 初始化消亡状态的设备列表<br /> InitializeListHead(&g_CandidateDevs); // 初始化正在加载的设备驱动列表.<br /> g_hCleanEvt = CreateEvent(NULL, FALSE, FALSE, NULL);<br /> g_hDevApiHandle = CreateAPISet("WFLD", NUM_FDEV_APIS, FDevApiMethods, FDevApiSigs); // 向系统注册api<br /> g_hDevFileApiHandle = CreateAPISet("W32D", NUM_FAPIS, DevFileApiMethods, DevFileApiSigs); // 向系统注册api<br /> RegisterAPISet(g_hDevFileApiHandle, HT_FILE | REGISTER_APISET_TYPE);<br /> InitializePnPNotifications(); // 这个程序将调用StartDeviceNotifyThread()<br />// 这将启动一个线程.它的具体实现在de***p.c文件中.<br /> InitializeCriticalSection(&g_devcs); // 初始化临界区.<br /> ResourceInitModule(); // 初始化一个全局变量gdwMaxDenseResources<br />// 根据注册表来初始化设备管理资源 <br /> ResourceInitFromRegistry(TEXT("Drivers\\Resources"));<br /><br />SetPowerOffHandler((FARPROC) DevMgrPowerOffHandler);<br /> RegisterAPISet(g_hDevApiHandle, SH_DEVMGR_APIS);<br /> InitDeviceFilesystems();<br /><br /> // Indicate that the device manager is up and running<br /> hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, _T("SYSTEM/DevMgrApiSetReady"));<br /> DEBUGCHK(hEvent != NULL);<br /> if (hEvent != NULL) {<br /> SetEvent(hEvent); // 设置一个全局事件.通知别的程序设备管理器api已经准备好了.<br /> // 在其他的应用里面,使用设备管理器api前,如果希望确认设备管理器<br /> // 的api已经注册好,它会等待这样一个事件.<br /> CloseHandle(hEvent);<br /> }<br /><br /> // Calibrate stall counter that is used for StallExecution<br />// 以下代码调用ceddk.dll里面的fnCalibrateStall()函数.<br /> hCeddkDll = LoadLibrary (TEXT("ceddk.dll"));<br /> if (NULL != hCeddkDll) {<br /> pCalibrateStallFn fnCalibrateStall = (pCalibrateStallFn)\<br /> GetProcAddress(hCeddkDll, TEXT("CalibrateStallCounter"));<br /> if (!fnCalibrateStall) {<br /> DEBUGMSG(ZONE_BOOTSEQ, (L"GetProcAddress failed on ceddk.dll\r\n"));<br /> FreeLibrary(hCeddkDll); <br /> }<br /> else {<br /> fnCalibrateStall();<br /> }<br /> }<br /><br /> // Call the power manager initialization entry point<br /> PM_Init(); // 初始化电源管理模块.电源管理模块是一个pm.dll.它也被device.exe调用.这里 // 暂时不打算涉及电源管理部分.简单来说:在PM_Init()函数里面会启动3个线程,<br />// PnpThreadProc,ResumeThreadProc, ActivityTimersThreadProc<br />// 它们各自负责监控即插即用,Resume,和激活定时器<br /> PM_SetSystemPowerState(NULL, POWER_STATE_ON, POWER_FORCE);//设置系统电源开.<br /><br /> // See if we are going to have two boot phases<br /> // 根据注册表内容,决定采用怎样的加载过程.<br />// 如果存在SYSTEM/BootPhase1.分2个步骤来加载:<br />// 先DevloadInit()加载一次,然后等待通知后,继续调用InitDevice()加载.<br />// 如果没有SYSTEM/BootPhase1,则调用DevloadInit()一次完成.<br />// 也许是满足一些需要2次加载设备的情况,所以留下这个功能.<br /> hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, _T("SYSTEM/BootPhase1"));<br /> if (hEvent != NULL) {<br /> // Load phase 1 drivers from the boot registry<br /> DevloadInit(); // 加载设备.DevloadInit()函数位于devload.c,它首先删除注册表里面<br /> // Device\Active,然后调用InitDevices()函数加载设备驱动.<br /><br /> // Signal boot phase 1 complete<br /> SetEvent(hEvent); // 发出通知,阶段1已经完成.<br /> CloseHandle(hEvent);<br /><br /> // Wait for phase 2 of the boot to begin<br />// 等待通知后进入阶段2<br /> hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, TEXT("SYSTEM/BootPhase2"));<br /> DEBUGCHK(hEvent);<br /> if (hEvent) {<br /> DEBUGMSG(ZONE_BOOTSEQ, (TEXT("DEVICE: Started, waiting for boot phase 2\r\n")));<br /> WaitForSingleObject(hEvent, INFINITE);<br /> CloseHandle(hEvent);<br /> }<br /><br /> // Load any new drivers from the persistent registry. Since the <br /> // registry may have changed, update the power state for any devices<br /> // that need it.<br /> DEBUGMSG(ZONE_BOOTSEQ, (TEXT("DEVICE: Second-phase driver load\r\n")));<br /> g_BootPhase = 2;<br /> PM_SetSystemPowerState(NULL, POWER_STATE_ON, POWER_FORCE);<br /> InitDevices(NULL); // DevInit()加载会先清空注册表Acitve下的内容,<br /> // 第二次加载不能把前面一次的清空,所以这里不能用DevInit().<br /> <br /> DEBUGMSG(ZONE_BOOTSEQ, (TEXT("DEVICE: Startup sequence complete\r\n")));<br /> SignalStartedUsingReg(); // SignalStarted call with the right args<br /> <br /> } else {<br /> DEBUGMSG(ZONE_BOOTSEQ, (TEXT("DEVICE: No boot registry - skipping to boot phase 2\n")));<br /> g_BootPhase = 2;<br /> DevloadInit();<br /> SignalStarted(_wtol(lpCmdLine));<br /> }<br /><br /> // Boot phase 3 isn't any different from phase 2; just marks that we got here.<br /> DEBUGMSG(ZONE_BOOTSEQ,<br /> (TEXT("DEVICE: Finished loading primary drivers - entering boot phase 3\n")));<br /> g_BootPhase = 3; // 进入阶段3,同时也标志设备管理器开始运行了.<br /> <br /> CELOG_DeviceFinished (); // 记录日志.<br /> <br /> while (1) {<br /> WaitForSingleObject(g_hCleanEvt, INFINITE);<br /><br /> // check for auto-deregister devs first as they may end up queuing <br /> // themselves on the dying devs list<br /> ProcessAutoDeregisterDevs();<br /> ProcessDyingDevs();<br /> ProcessDyingOpens();<br /> }<br /> <br /> return 1; // should not ever be reached<br />}<br /><br /><br /><br />加载设备的函数,DevloadInit()事实上也是调用InitDevices来实现,只不过事先清空了Acitve下的注册表内容<br /><br />void DevloadInit(void)<br />{<br /> DEBUGMSG(ZONE_INIT, (TEXT("DEVICE!DevloadInit\r\n")));<br />#define PHASE_1_BUSNAME TEXT("BuiltInPhase1")<br /> //<br /> // Delete the HLM\Drivers\Active key since there are no active devices at<br /> // init time.<br /> // 清空注册表Active下的内容.<br /> RegDeleteKey(HKEY_LOCAL_MACHINE, s_ActiveKey);<br /><br />#ifdef DEBUG<br /> v_NextDeviceNum = 0xFFFFFFF0; // expect wraparound<br />#else // DEBUG<br /> v_NextDeviceNum = 1;<br />#endif // DEBUG<br /> g_bSystemInitd = FALSE;<br /> InitDevices(PHASE_1_BUSNAME);<br />}<br /><br /><br /><br />InitDevices(LPCTSTR lpBusName )<br />{<br /> HKEY RootKey;<br /> DWORD status;<br /> DWORD ValType;<br /> DWORD ValLen;<br /> TCHAR RootKeyPath[REG_PATH_LEN];<br /> TCHAR BusName[DEVKEY_LEN];<br /> REGINI reg[1];<br /> DWORD dwRegCount=0;<br /><br /> //<br /> // Open HLM\Drivers key<br /> // 打开注册表HLM\Drivers.<br /> status = RegOpenKeyEx(<br /> HKEY_LOCAL_MACHINE,<br /> DEVLOAD_DRIVERS_KEY, // DEVLOAD_DRIVERS_KEY= "Drivers"<br /> 0,<br /> 0,<br /> &RootKey);<br /> <br /> if (status != ERROR_SUCCESS) {<br /> DEBUGMSG(ZONE_ROOT|ZONE_ERROR,<br /> (TEXT("DEVICE!InitDevices RegOpenKeyEx(%s) returned %d.\r\n"),<br /> DEVLOAD_DRIVERS_KEY, status));<br /> return;<br /> }<br /><br /> //<br /> // Look for root key value; if not found use current Root Key as default,<br /> // otherwise open new root key<br /> // 查询注册表中 RootKey的值,一般这个值是Devices\BuildIn.将查询的值保存到RootKeyPath.<br />// 如果没有指定,则使用Devices来替代.<br /> ValLen = sizeof(RootKeyPath);<br /> status = RegQueryValueEx(<br /> RootKey,<br /> DEVLOAD_ROOTKEY_VALNAME, // DEVLOAD_ROOTKEY_VALNAME =RootKey<br /> NULL,<br /> &ValType,<br /> (PUCHAR)RootKeyPath,<br /> &ValLen);<br /> RootKeyPath[ARRAYSIZE(RootKeyPath) - 1] = 0;<br /> <br /> if (status != ERROR_SUCCESS) {<br /> // Root key value not found, thus root key is Drivers<br /> _tcscpy(RootKeyPath, DEVLOAD_DRIVERS_KEY); // 没有找到,使用Devices来替代.<br /> }<br /><br /> // Close previous root key<br /> RegCloseKey(RootKey);<br /> DEBUGMSG(1,<br /> (L"DEVICE!InitDevices: Root Key is %s.\r\n",<br /> RootKeyPath));<br />// 为ActiveDeviceEx准备参数reg. 如果输入参数lpBusName指定了,则从参数lpBusName获得,<br />// 否则从注册表中读取.<br /> if (lpBusName!=NULL) {<br /> reg[0].lpszVal = DEVLOAD_BUSNAME_VALNAME;<br /> reg[0].dwType = DEVLOAD_BUSNAME_VALTYPE;<br /> reg[0].pData = (PBYTE) lpBusName ;<br /> reg[0].dwLen = (_tcslen( lpBusName ) + 1) * sizeof(TCHAR);<br /> dwRegCount = 1;<br /> }<br /> else {<br /> status = RegOpenKeyEx( HKEY_LOCAL_MACHINE, RootKeyPath,0,0, &RootKey);<br /> if (status == ERROR_SUCCESS ) {<br /> ValLen = sizeof( BusName);<br /> status = RegQueryValueEx(<br /> RootKey,<br /> DEVLOAD_BUSNAME_VALNAME,<br /> NULL,<br /> &ValType,<br /> (PUCHAR)BusName,<br /> &ValLen); <br /> if (status == ERROR_SUCCESS && ValType==DEVLOAD_BUSNAME_VALTYPE) {<br /> // We found Bus Name. This is new bus driver model. So we use new format.<br /> BusName[DEVKEY_LEN-1] = 0;<br /> reg[0].lpszVal = DEVLOAD_BUSNAME_VALNAME;<br /> reg[0].dwType = DEVLOAD_BUSNAME_VALTYPE;<br /> reg[0].pData = (PBYTE)BusName;<br /> reg[0].dwLen = ValLen;<br /> dwRegCount = 1;<br /> }<br /> // Close previous root key<br /> RegCloseKey(RootKey); <br /> }<br /> }<br /> // Someday we'll want to track the handle returned by ActivateDevice so that<br /> // we can potentially deactivate it later. But since this code refers only to<br /> // builtin (ie, static) devices, we can just throw away the key.<br /> if (dwRegCount) <br /> ActivateDeviceEx(RootKeyPath,reg,dwRegCount,NULL); <br /> else<br /> ActivateDevice(RootKeyPath, 0);<br />} // InitDevices<br /><br />至此,已经明确了系统是通过InitDevice()来加载驱动,更具体的InitDevice()会调用ActivateDeviceEx()来加载驱动,但是,这里只加载了一个驱动啊,难道系统就只加载一次?<br />这个唯一被加载的驱动是BusEnum.dll(在CE4.2是RegEnum.dll)这个驱动位于public下,它枚举了BuiltIn下所有的设备,逐个加载,并在Active下记录成功加载的设备. |
|