打印

CE5.0关于设备管理器的源码分析(偶很懒!)

[复制链接]
1941|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
high|  楼主 | 2007-11-22 02:48 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
原来认真写**是多么辛苦的事啊!佩服老hot那么高产...
大家有空请指正.
----------

系统下面许多设备,比如键盘,串口,触摸屏,硬盘......这些设备什么时候被系统使用的?这些设备怎样被系统使用的?加载过程是怎么样的?设备如何加入系统协同工作的?为什么系统能检测到并使用即插即用的设备(如usb鼠标)?系统是怎么控制设备的电源的?

CE管理设备的程序叫做DEVICE.EXE,这是一个独立的用户级进程,它主要负责跟踪,维护系统的设备信息并对设备资源进行调配.设备管理器包括即插即用设备管理,电源管理,io资源管理等等.

结构示意图:


目录树:c:\WINCE500\PRIVATE\WINCEOS\COREOS\DEVICE\

[DEVCORE]                     设备管理器的核心代码部分.
Devapi.c
Devcore.c
Devfile.c
Devfsd.c
Devload.c
De***p.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()
// 这将启动一个线程.它的具体实现在de***p.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];
    DWORD  dwRegCount=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下记录成功加载的设备.

相关帖子

沙发
high|  楼主 | 2007-11-22 02:56 | 只看该作者

写的不好.写完发现来龙去脉没有交代清楚.

使用特权

评论回复
板凳
hotpower| | 2007-11-22 06:35 | 只看该作者

强烈要求红衣教主穿裤子~~~

使用特权

评论回复
地板
McuPlayer| | 2007-11-22 09:43 | 只看该作者

强烈要求菜鸟先去锻炼身体再来看老High的此帖

使用特权

评论回复
5
hqgboy| | 2007-12-4 10:45 | 只看该作者

呵呵...开始行动了...顶.

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

99

主题

1078

帖子

0

粉丝