距离开发windows驱动已经快要满一年了,从一开始的小白什么都不知道,到现在,也算是有不少心得,准备抽时间写一些比较详细的经验分享,关于驱动开发的文章相对比较少,写的较深入的也不多,所以我想只有大家多共享一些内容,才能进步的更快!话不多说,开始。

本章主要讲述一些入门的概念性内容,有些部分可能会显得不好记,不用慌,等看了后续的文章用到的时候,再回头复习一下,就能理解它的用处了。

大家都知道,最早的windows驱动为NT式驱动,这个架构过于的旧,所以也就不在我的文章范围里面了,我主要介绍WDM/WDF的驱动,当然了,WDM/WDF驱动其实也有很多NT驱动的影子,这些共有的部分,我也会做简单介绍。下面是一个DriverEntry实例:

NTSTATUS

DriverEntry(

IN PDRIVER_OBJECT DriverObject,

IN PUNICODE_STRING RegistryPath

)

{

WDF_DRIVER_CONFIG   config;

NTSTATUS            status;

WDF_DRIVER_CONFIG_INIT(

&config,

EvtDeviceAdd

);

status = WdfDriverCreate(DriverObject,

RegistryPath,

WDF_NO_OBJECT_ATTRIBUTES,

&config,

WDF_NO_HANDLE);

if (!NT_SUCCESS(status)) {

//KdPrint(("WdfDriverCreate failed with status 0x%x\n", status));

}

return status;

}

NT以及WDM/WDF的驱动,每一个驱动的入口例程都是DriverEntry,和编写普通应用程序一样,驱动程序也会有类似Main函数的例程,它就是DriverEntry。它的原型为DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath),这个例程主要对驱动程序进行初始化,它是被系统进程所调用的,是的,就是进程管理器里面的system进程了。系统线程调用驱动程序的DriverEntry时,同时传进上述的两个参数,DriverObject式指向刚才被创建驱动对象的指针,RegistryPath则是指向设备服务键的键名字符串的指针。另外,这个RegistryPath有时候是需要保存下来的,因为这个字符串并不是长期存在的,函数返回时有可能会消失,如果以后想要用这个串的话,那就必须先把它复制到安全的地方。这个字符串的内容一般会是\REGISTRY\MACHINE\SYSTEM\ControlSet\Services\[服务名],另外,在驱动程序中,字符串需要用UNICODE来表示。

在DriverEntry例程中,一般设置卸载例程和IRP的派遣函数,另外的一部分代码则负责创建设备对象,在非NT驱动中,需要添加AddDevice函数,此回调函数为WDM/WDF驱动程序独有,作用为创建设备对象并由PNP(即插即用)管理器调用。同时也需要设置IRP_MJ_PNP回调函数,对PNP的IRP处理,是NT驱动和WDM驱动的重大区别之一。另外,在驱动程序中,所有的函数和变量要被指明加载到分页内存或非分页内存中,其中DriverEntry需要放在INIT标志的内存中,INIT标志指明该函数只在加载的时候载入内存,成功加载之后,可以从内存中卸载。下面是一个AddDevice实例:

NTSTATUS

EvtDeviceAdd(

IN WDFDRIVER        Driver,

IN PWDFDEVICE_INIT  DeviceInit

)

{

WDF_IO_QUEUE_CONFIG        queueConfig;

WDF_OBJECT_ATTRIBUTES      attributes;

NTSTATUS                   status;

WDFDEVICE                  device;

PFDO_DEVICE_DATA           deviceData;

PNP_BUS_INFORMATION        busInfo;

WDFQUEUE                   queue;

WDFDEVICE                  hDevice;

UNREFERENCED_PARAMETER(Driver);

PAGED_CODE ();

WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_BUS_EXTENDER);

WdfDeviceInitSetExclusive(DeviceInit, TRUE);

WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, FDO_DEVICE_DATA);

status = WdfDeviceCreate(&DeviceInit, &attributes, &device);

if (!NT_SUCCESS(status)) {

//KdPrint(("WdfDriverCreate FDO_DEVICE_DATA failed with status 0x%x\n", status));

return status;

}

//

// Get the device context.

//

deviceData = FdoGetData(device);

WDF_OBJECT_ATTRIBUTES_INIT(&attributes);

WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(

&queueConfig,

WdfIoQueueDispatchParallel

);

queueConfig.EvtIoDeviceControl = EvtIoDeviceControl;

status = WdfIoQueueCreate(device,

&queueConfig,

WDF_NO_OBJECT_ATTRIBUTES,

&queue

);

if (!NT_SUCCESS(status)) {

//KdPrint(("WdfIoQueueCreate failed with status 0x%x\n", status));

return status;

}

status = WdfDeviceCreateDeviceInterface(

device,

&GUID_DEVINTERFACE_HELLO,

NULL // No Reference String

);

if (!NT_SUCCESS(status)) {

//KdPrint(("WdfDriverCreateDeviceInterface failed with status 0x%x\n", status));

return status;

}

return status;

}

windows操作驱动的一些基本概念,win32子系统是最纯正的windows子系统,提供了大量的API函数。windows API分为三类,USER函数,GDI函数,KERNEL函数,分别对应了user32.dll,gdi32.dll,kernel32.dll。操作系统除了将应用程序加载到内存中,同时也会将这三个dll文件加载到内存中。大部分win32子系统的API,都通过Native API实现。Native API的函数一般都是在win32 API上加上Nt两个字母,例如CreateFile函数对应NtCreateFile函数,所有Native API都是在Ntdll.dll中实现的。同时,Native API负责从用户模式穿越进入内核模式。

看了以上这些,相信你也肯定对驱动有了一些基础的概念了,那么,操作系统是如何去使用驱动程序的呢?对于WDM/WDF驱动来说,一般都是基于分层的,完成一个设备的操作,至少需要两个驱动设备共同完成。一个是物理设备对象(PDO),另一个是功能设备对象(FDO),其关系是“附加”与“被附加”的关系。物理设备驱动也就是WDF中的KMDF,在系统总线枚举驱动发现插入了新设备之后,会由总线驱动创建PDO,PDO无法单独操作设备,需配合FDO一起,此时系统会去寻找相对应的UMDF,即设备功能驱动,如果找到了,这个设备就可以正常运行了。

刚有提到WDM/WDF驱动是分层的,那么这个分层该怎么去理解呢?当一个设备的功能驱动安装成功之后,PDO设备对象的子域AttachedDevice会记录FDO的位置。PDO被称作底层驱动或下层驱动,而FDO会被称作高层驱动或上层驱动。这里的“上层”即是接近发出IO请求的地方,而“下层”指的是靠近物理设备的地方。这就是它的分层,当然,这是最简单的情况,假如PDO与FDO之间存在过滤驱动时,在FDO上面的过滤驱动被称作上层过滤驱动(High FiDO),在FDO的下层的驱动,被称作下层过滤驱动(Low FiDO)。其实设备对象中,有个StackSize子域,表明操作这个设备对象需要几层才能到达最下层的物理设备,例如刚才举的例子里,High FiDO(StackSize=4)-- FDO(StackSize=3)--Low FiDO(StackSize=2)--PDO(StackSize=1)。DRIVERENTRY入参的驱动对象DRIVER_OBJECT中有个DriverExtension,里面有AddDevice子域,用来设置AddDevice例程的函数地址,目的就是将FDO附加在PDO之上。

概述大概就写到这里,下一章的话会介绍驱动中的IO请求如何去处理。

Windows驱动开发(一)WDM/WDF驱动概述相关推荐

  1. Windows驱动开发VXD/WDM/WDF/DDK/WDK的联系和区别

    背景介绍 首先,先从基础的东西说起,做任何程序的开发,你都需要一个配套的开发套件,专业术语叫做SDK(Software Development Kit,软件开发套件).比如:开发JAVA程序,我们可能 ...

  2. Linux SD卡驱动开发(五) —— SD 卡驱动分析Core补充篇

    Core层中有两个重要函数 mmc_alloc_host 用于构造host,前面已经学习过,这里不再阐述:另一个就是 mmc_add_host,用于注册host 前面探测函数s3cmci_probe, ...

  3. Linux驱动开发(外传)---驱动开发调试方法

    前文回顾 <Linux驱动开发(一)-环境搭建与hello world> <Linux驱动开发(二)-驱动与设备的分离设计> <Linux驱动开发(三)-设备树> ...

  4. i.MX 6ULL 驱动开发 六:beep 驱动

    一.原理分析 通过原理图可以确定 beep 连接到 SNVS_TAMPER1 引脚上.根据 beep 原理,当 SNVS_TAMPER1 输出低电平时,beep 鸣叫. 通过数据手册确定 SNVS_T ...

  5. STM32MP157驱动开发——多点电容触摸屏驱动

    STM32MP157驱动开发--多点电容触摸屏驱动 一.简介 二.电容触摸屏驱动框架简介 多点触摸(MT)协议详解 三.驱动开发 1.添加 FT5426 设备节点 2.FT5426 节点配置 3.驱动 ...

  6. STM32MP157驱动开发——Linux块设备驱动

    STM32MP157驱动开发--Linux块设备驱动 一.简介 二.驱动开发 1.使用请求队列的方式 2.测试① 3.不使用请求队列的方式 4.测试② 参考文章:[正点原子]I.MX6U嵌入式Linu ...

  7. Linux驱动开发:字符设备驱动开发实战

    Linux驱动开发:字符设备驱动开发实战 一.工程创建 VSCode 创建工程,设置 C/C++ 配置,导入 linux kernel 源码目录,方便 vscode 写代码自动补全,vscode 配置 ...

  8. Linux下驱动开发_块设备驱动开发(硬件上采用SD卡+SPI协议)

    一.前言 块设备主要为存储设备设计的框架. 在前面章节Linux下驱动开发_块设备驱动开发(内存模拟存储) 里介绍了块设备驱动编写思路,并且利用内存模拟了硬件存储,完成了块设备驱动开发测试.这一篇文章 ...

  9. Linux嵌入式驱动开发01——第一个驱动Hello World(附源码)

    文章目录 全系列传送门 引言 驱动介绍 Hello World 1. 包含头文件 2. 驱动模块的入口和出口 3. 声明信息 4. 功能实现 完整代码 编译 第一种方法 第二种方法 编译成模块 第一步 ...

  10. 九七的Windows内核驱动开发 WIN10-2004+VS2019+WDK驱动开发环境安装及配置

    WIN10-2004+VS2019+WDK驱动开发环境安装及配置 一.定义介绍   本节介绍如何在Windows10系统(2004版本,操作步骤中有如何查看版本)中安装VS2019及WDK开发包,并进 ...

最新文章

  1. linux中exit()和 _exit()说明
  2. 揭秘Sponge:统一Hadoop、Spark、SDS、Swift的大数据操作系统
  3. Py修行路 python基础 (九)作用域 函数嵌套 闭包
  4. atitit。wondows 右键菜单的管理与位置存储
  5. python基础总结(6)
  6. java des3加密_JAVA加密算法(3)- 对称加密算法(DES、3DES、AES)
  7. 从excel导入数据库过程中遇到的空格转义符(#160;)
  8. 1、Fiddler 打断点 bpu
  9. BZOJ 1085: [SCOI2005]骑士精神( IDDFS + A* )
  10. 基础数据结构-线性表-顺序表的连续操作
  11. 计算机网络实验(二)2交换机的基本配置与管理
  12. Matlab PCA+SVM人脸识别(二)——GUI界面设计
  13. 经典面试题 Ipv4 和 Ipv6 是什么
  14. 多线程爬取图片(生产者-消费者模式)
  15. 《Python数据分析与应用》第7章 机器学习模型的应用 实训部分
  16. 给IT新人的15点建议
  17. 微信小程序纯前端生成海报并保存本地
  18. 绿色手动安装MySQL数据库
  19. k8s安装dashboard及账号密码登陆
  20. linux系统如何安装adobe flash player

热门文章

  1. 移动端车牌识别要做到那一步?
  2. texstudio如何安装cjk宏包_Latex+CJK从安装到使用【1】
  3. UA用Mode-Driven的使用笔记
  4. 【零基础】speech driven animation中文安装使用指南
  5. vb.net 简单取摄像头图片_简单的BP网络识别液晶字符
  6. 修路【NOIP2016提高组模拟】
  7. vs2013调试nginx
  8. awk&sed替换字符串
  9. ImageNet数据集编号对应的类别内容
  10. CNI插件之bridge plugin