CE5.0关于设备管理器的源码分析

来源:互联网 发布:淘宝限时抢购是真的吗 编辑:程序博客网 时间:2024/05/17 04:28

 系统下面许多设备,比如键盘,串口,触摸屏,硬盘......这些设备什么时候被系统使用的?这些设备怎样被系统使用的?加载过程是怎么样的?设备如何加入系统协同工作的?为什么系统能检测到并使用即插即用的设备(如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 WINAPI WinMain(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.

//[HKEY_LOCAL_MACHINE/Drivers]

    "RootKey"="Drivers//BuiltIn"

// 如果没有指定,则使用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下记录成功加载的设备.


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/dhdahai/archive/2009/06/09/4253891.aspx

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 中维世纪监控密码忘记了怎么办 原店主营业执照不注销怎么办新的 苹果手机铃声调到最大还小怎么办 投标时措施费忘记套价了怎么办 美团商家更改手机号和银行卡怎么办 淘宝买的衣服颜色发错了怎么办 在淘宝买的衣服颜色不一样怎么办 新买的木柜气味好重怎么办 淘宝店铺动态评分一直很低怎么办? 刚生下来的宝宝睡觉不吃奶怎么办 宝宝吐奶咳嗽了可能被呛到怎么办 床下面的液压支架支撑不了了怎么办 沙发的海绵垫坐着感觉太硬怎么办 修公路占地补偿盖房子房产证怎么办 哺乳期乳房有硬块挤不出来怎么办 老公投的公司倒闭了钱怎么办 小丑鱼老在缸上边游不下去怎么办 海缸养珊瑚又想养蝴蝶鱼怎么办 被几个月的小狗咬了怎么办 木本植物继代长出大量愈伤怎么办 钱兜树叶子发黄掉叶怎么办 手机qq群200人满了怎么办 支票被背书人的章盖浅了怎么办 没病装病的心理病患者怎么办 20多岁被骗40多万怎么办 一个学生上课爱捣乱班级课堂怎么办 军训的时候大姨妈来了怎么办 笔记本连接无线网说链接限制怎么办 12306密码和邮箱都忘了怎么办 烦恼都是自找的新书散页了怎么办 白色衣服被红色衣服染了怎么办 手机微信里面不能拍手功怎么办 肇事逃逸轻伤且对方不私了怎么办 数学差怎么办脑子不好啊数学学不老 手机号丢失微信密码丢失怎么办找回 悦借钱输入五次密码被锁怎么办 生源地助学贷款密码忘了怎么办 生源地助学贷款登录密码忘了怎么办 助学贷款支付宝密码忘了怎么办 微信密码忘记了手机号也换了怎么办 换手机号了微信密码忘记了怎么办