驱动开发之六 --- 一个简单的显示驱动之一 [译文]

原文链接: http://blog.sina.com.cn/s/blog_6ef955fa0100m4ew.html

这个系列的文章在网上到处都是 这里也不清楚谁才是原文作者 我这里做个整理,标注一下希望大家能看的更加舒服一点

目录

(一)驱动开发一个简单的显示驱动

(二)驱动开发一个简单的显示驱动

(三)驱动开发一个简单的显示驱动

(四)驱动开发一个简单的显示驱动

(五)驱动开发一个简单的显示驱动

(六)驱动开发一个简单的显示驱动

 

 

理论:

本篇我们将介绍下如何写一个简单的显示驱动。显示驱动是一种特殊类型的驱动,必须要满足一个框架,它不像我们前面讲的那些驱动。

 

示例程序演示了如何写一个简单的显示驱动,这个驱动无需关联任何硬件。它能实现图形到内存,然后由一个应用程序来显示这些图形。

显示驱动的体系结构

首先介绍的是windows NT下显示驱动的体系结构。在这里要特别说明的是windows vista使用了一种新的显示驱动模型,叫做LDDM.它是vista最新桌面窗口管理器的核心部分。就兼容方面,vista仍然可以与老的窗口管理器一起协作支持老的显示驱动。

 

显示驱动模型包括两部分,迷你小端口驱动和显示驱动。迷你小端口驱动加载到系统空间,负责枚举设备和管理设备资源。显示驱动加载到会话空间,负责实现实际的GDI图形调用。显示驱动完全控制怎样划线或者怎样实现透明效果。

下面的图表显示了windows显示驱动的体系结构。

迷你小端口驱动

迷你小端口驱动加载到系统空间,负责管理显示设备资源和枚举设备。这个驱动使用其它的驱动(VIDEOPRT.SYS)作为它的框架。你的驱动会使用VIDEOPRT.SYS导出的API. 很奇怪驱动可以导出API吧?驱动使用pe格式,也有导入表和导出表。你可以从你的驱动中导出api,并且允许其他驱动链接使用它们,就像调用一个dll一样。实际上你使用的这些API连接着内核和其他驱动。

 

在这里要注意连接内核模式驱动和用户模式的驱动有些不同。如果一个驱动连接另一个驱动,而那个驱动当前没有加载到内存。那么那个驱动将会被加载进内存,然而那个驱动的DriverEntry不会被调用。DriverEntry自身不会被调用,只有使用ZwLoadDriver加载驱动,系统加载驱动或者使用我们前面展示过的服务api记载驱动才会调用DriverEntry。任何时候,你都可以从一个驱动中导出API,然后在另一个驱动中使用这些api. 在内核中没有类似于"GetProcAddress"的api,你需要自己写一个。

你的迷你小端口驱动会调用VideoPrt.SYS导出的api。VideoPrt.SYS驱动做了很少的事情,其中之一就是实现了通用代码。所以视频驱动的开发者就不需要重新再写同样的代码。这个代码包括在win32子系统(win32k.sys)和你的迷你小端口驱动之间进行视频设备枚举。VideoPrt.SYS还创建了一个显示用的设备对象,当你调用这个初始化例程时,他会使你的驱动对象入口点指向VideoPrt.SYS

所有的VideoPrt.SYS API都是"VideoPort"开头的。你第一个调用的API应该是"VideoPortInitialize".如果你注意的话,可以看到开头的两个参数就是传递给你的DriverEntry例程的,他们被称作"Context1"和"Context2",仿佛你的视频迷你小端口驱动是特别的。不要被这些迷惑,第一参数"Context1"实际上就是你的驱动对象。一旦你传递你的驱动对象给VideoPortInitialize,所有你的驱动入口点都会指向VideoPrt.Sys的。除此之外,你还要传递给VIDEO_HW_INITIALIZATION_DATA结构不同的函数指针,VideoPrt.SYS在需要的时候会用到这些。

这意味着你不要直接处理在视频迷你小端口驱动中的IRP. VideoPrt.SYS会处理他们。你需要处理的是"VRP"(视频请求包),本质上讲它其实是一种简化的用不同数据结构的IRP版本。你需要简单的返回,不需要像IRP那样对这个数据结构进行处理。

 

在迷你小端口驱动中,你除了使用"VideoPort"开头的api外,由于它是系统层的驱动,你还可以使用内核的api.

由于我们没有任何硬件,因此我们的迷你小端口驱动会比较简单,下面的代码演示了如何编写视频迷你小端口驱动DriverEntry。

ULONG DriverEntry(PVOID pContext1, PVOID pContext2)

{

    VIDEO_HW_INITIALIZATION_DATA hwInitData;

    VP_STATUS vpStatus;

  

    VideoPortZeroMemory(&hwInitData, sizeof(VIDEO_HW_INITIALIZATION_DATA));

    hwInitData.HwInitDataSize                = sizeof(VIDEO_HW_INITIALIZATION_DATA);

    hwInitData.HwFindAdapter                 = FakeGfxCard_FindAdapter;

    hwInitData.HwInitialize                  = FakeGfxCard_Initialize;

    hwInitData.HwStartIO                     = FakeGfxCard_StartIO;

    hwInitData.HwResetHw                     = FakeGfxCard_ResetHW;

    hwInitData.HwInterrupt                   = FakeGfxCard_VidInterrupt;

    hwInitData.HwGetPowerState               = FakeGfxCard_GetPowerState;

    hwInitData.HwSetPowerState               = FakeGfxCard_SetPowerState;

    hwInitData.HwGetVideoChildDescriptor     =FakeGfxCard_GetChildDescriptor;

    vpStatus = VideoPortInitialize(pContext1, pContext2, &hwInitData, NULL);

    return vpStatus;

}

将VideoPortInitialize的返回值作为DriverEntry函数的返回值,返回调用者。

 

在你直接简单的传递DriverObject给VideoPrt.SYS之前,你还需要填充一个数据结构,这个数据结构中包含了你驱动中的入口点,这些入口点会被VideoPrt.SYS驱动调用来执行不同的动作。"HwStartIO"是指你可以处理IOCTLs,在显示驱动和视频迷你小端口驱动之间,你可以使用IOCTLs。显示驱动只需要简单调用"EngDeviceIoControl",迷你小端口驱动中的HwStartIO就会处理IOCTL。代码如下:

 

#pragma alloc_text(PAGE, FakeGfxCard_GetPowerState)
#pragma alloc_text(PAGE, FakeGfxCard_SetPowerState)
#pragma alloc_text(PAGE, FakeGfxCard_GetChildDescriptor)
#pragma alloc_text(PAGE, FakeGfxCard_FindAdapter)
#pragma alloc_text(PAGE, FakeGfxCard_Initialize)
#pragma alloc_text(PAGE, FakeGfxCard_StartIO)

BOOLEAN FakeGfxCard_ResetHW(PVOID HwDeviceExtension,
                                 ULONG Columns, ULONG Rows)
{
   return TRUE;
}


BOOLEAN FakeGfxCard_VidInterrupt(PVOID HwDeviceExtension)
{
   return FALSE;
}


VP_STATUS FakeGfxCard_GetPowerState(PVOID HwDeviceExtension,
          ULONG HwId, PVIDEO_POWER_MANAGEMENT VideoPowerControl)
{            
   return NO_ERROR;
}

 

VP_STATUS FakeGfxCard_SetPowerState(PVOID HwDeviceExtension,
          ULONG HwId, PVIDEO_POWER_MANAGEMENT VideoPowerControl)
{
return NO_ERROR;

}

 

ULONG FakeGfxCard_GetChildDescriptor (PVOID HwDeviceExtension,

      PVIDEO_CHILD_ENUM_INFO ChildEnumInfo, PVIDEO_CHILD_TYPE pChildType,

      PVOID pChildDescriptor, PULONG pUId, PULONG pUnused)

{

   return ERROR_NO_MORE_DEVICES;

}

 

VP_STATUS FakeGfxCard_FindAdapter(PVOID HwDeviceExtension,

            PVOID HwContext, PWSTR ArgumentString,

            PVIDEO_PORT_CONFIG_INFO ConfigInfo, PUCHAR Again)

{

   return NO_ERROR;

}

 

BOOLEAN FakeGfxCard_Initialize(PVOID HwDeviceExtension)

{

   return TRUE;

}

 

BOOLEAN FakeGfxCard_StartIO(PVOID HwDeviceExtension,

                PVIDEO_REQUEST_PACKET RequestPacket)

{

   RequestPacket->StatusBlock->Status      = 0;

   RequestPacket->StatusBlock->Information = 0;

   return TRUE;

}

 

由于我没有任何硬件,对于迷你小端口驱动,简单实现就足够了。如果我需要在系统上访问或者执行一个操作,显示驱动靠它自己有限的API函数集是不能做到的。我会用到的唯一的API就是"StartIO"。可是在这个实现中,我们不需要做什么。记住,迷你小端口驱动的主要用途就是枚举硬件设备/资源和管理他们。如果你没有什么硬件设备/资源,那么为了让驱动模型高兴,除了必需的外删除其他的。

猜你喜欢

转载自blog.csdn.net/zb774095236/article/details/101015330
今日推荐