驱动程序打开别的驱动程序创建的Device的几种方法

合集下载

通过设备接口打开设备的步骤

通过设备接口打开设备的步骤

通过设备接口打开设备的步骤一、驱动程序1.驱动程序框架的创建(1)用VC建立一个新工程。

在VC IDE环境中选择File|New,弹出New对话框。

在对话框中,选择Project选项卡。

在Project选项卡中,选择Win32 Application 。

设置工程名为OpenGuid.如图1所示,单击OK,进入下一个对话框,在对话框中选择一个空的工程。

如图2。

图1图2(2).新建两个文件GuidOpen.h与GuidOpen.cpp.这两个文件的具体写法,详见程序编写。

也能够直接添加现成的已经写好的文件,张帆这本书中,通常都是用的HelloWDM.h与HelloWDM.cpp.(3).增加新的编译版本,去掉Debug与Release版本。

在Build | Configuration如图3与图4。

图3图4(4).修改工程属性。

选择Project|Setting,在弹出的对话框中,选择General选项卡,将Intermediate files 与Output files改为MyDriver_Check,这个名字英语C/C++中,所设置的Fo与Fd后面的文件名相一致。

如图5。

图5将C/C++选项卡中,原有的Project Options内容全部删掉,换成一下内容。

/nologo /Gz /MLd /W3 /WX /Z7 /Od /D WIN32=100 /D_X86_=1 /D WINVER=0x500 /D DBG=1/Fo"MyDriver_Check/" /Fd"MyDriver_Check/" /FD /c其中:/nologo:表示不显示编译的版本信息/Gz:默认函数调用使用标准调用(_stdcall)/MLd/W3:使用第三级警告模式/WX:将警告信息转换为错误信息,最大程度保证代码可靠/Z7:用Z7模式产生调试信息?/Od:关闭调试模式,VC的调试命令不能调试内核下的程序/D WIN32=100 /D_X86_=1 /D WINVER=0x500 /D DBG=1:定义4个宏(不明白为什么)/Fo"MyDriver_Check/:MyDriver_Check/为Output Directories中“创建”的文件夹,存放中间生成的目标代码路径/Fd"MyDriver_Check/": MyDriver_Check/为存放.PDB文件的文件夹/FD:生成文件依奈/c:只进行编译,不连接图6选择Link选项卡,将原有的Project Options 内容全部删除,替换成如下内容:wdm.lib /nologo /base:"0x10000" /stack:0x400000,0x1000 /entry:"DriverEntry" /subsystem:console/incremental:no /pdb:"MyDriver_Check/GuidOpen.pdb" /debug /machine:I386 /nodefaultlib/out:"MyDriver_Check/GuiOpen.sys" /pdbtype:sept /subsystem:native /driver /SECTION:INIT,D /IGNORE:4078 其中:wdm.lib:链接WDM库/nologo:链接时不显示版本信息/base:"0x10000":加载驱动时,设定加载到虚拟内存的地址/stack:0x400000,0x1000:设定函数使用堆栈的地址与大小/entry:"DriverEntry":入口函数的地址(为符合标准函数调用的)/subsystem:console:设置子系统/incremental:no:非递曾式链接/pdb:"MyDriver_Check/GuidOpen.pdb":设置pdb文件的文件名为GuidOpen,储存于MyDriver_Check文件夹下面C/C++属性页中的设置一样。

windows设备驱动程序WDF开发(1)

windows设备驱动程序WDF开发(1)

windows设备驱动程序WDF开发(1)武安河另外讲WDM的书是《windows 2000/xp wdm设备驱动开发》KDMF 构建在WDM之上,内核级,sys⽂件UDMF ⽤户级,dll⽂件第1章 Windows 2000和WDM驱动程序1.中断优先级(IRQL): 32个中断级别,可打断0 : PASSIVE_LEVEL, 常规线程1:APC_LEVEL, 异步调⽤过程2:DISPATCH_LEVEL, 延迟过程调⽤3~26: DIRQL, 硬件中断2. 在DISPATCH_LEVEL 运⾏代码时,访问⾮分页内存是⼀个根本原则第2章 KMDF驱动程序框架1. 环境变量结构_DEVICE_CONTEXT{}pDeviceContext = GetDeviceContext(Device);2. 创建对象的⽅法KMDF控制的对象⽣命周期:WDFDRIVER, WDFDEVICE, WDFFILEOBJECT, WDFREQUEST (IRP)3. KMDF结构1)DriverEntry:设置 EvtDeviceAdd (安装时调),WdfDriverCreate 创建驱动对象2) EvtDriverDeviceAdd: 新设备被枚举时会调⽤,职责:创建设备对象,I/O队列,GUID接⼝,事件回调例程,WdfDeviceCreate, WdfDeviceCreateDeviceInterface, WdfDeviceInitSetExclusive(DeviceInit,TRUE); // 独占,只允许⼀个应⽤打开WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig, WdfIoQueueDispatchSequential); // IO为串⾏ WdfIoQueueCreate // io队列WdfDeviceCreateDeviceInterface // guid接⼝3)I/O处理例程WDF_FILEOBJECT_CONFIG_INIT(&FileConfig,EvtDeviceFileCreate, EvtFileClose, EvtFileCleanup);ioQueueConfig.EvtIoDeviceControl = PCI9056WDF_EvtIoDeviceControl; // DeviceIoControl 调⽤ioQueueConfig.EvtIoRead = PCI9056WDF_EvtIoRead; // ReadFileioQueueConfig.EvtIoWrite = PCI9056WDF_EvtIoWrite; // WriteFile第3章基本对象1. WDFREQUEST: I/O请求,即IRPWdfRequestComplete :完成请求WdfRequestCompleteWithInformation :完成请求,完成的传输字节数WdfRequestRetrieveInputBuffer: 获取输⼊缓冲器地址WdfRequestRetrieveInputMemory: 获取输⼊缓冲器地址,形式为WDFMEMORYWdfRequestRetrieveInputWdmMdl: 获取输⼊缓冲器地址,形式为MDLWdfRequestGetIoQueue:返回队列对象WdfRequestGetFileObject: 返回⽂件对象WdfRequestGetInformation: 完成的传输字节数WdfRequestCreate: 创建IO请求2. IO请求(IRP)基本操作取消IO请求:编写取消例程向下传递IO请求3. WDFQUEUE 队列, WdfIoQueueDispatchSequential 串⾏初始化默认队列 WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUEWdfIoQueueCreateWdfIoQueueStart : 启动接收和分发IRPWdfIoQueueStop:暂停分发,但还接收WdfIoQueueDrain: 停⽌接收,但分发WdfIoQueuePurge: 停⽌接收,取消队列中的IRP4. WDFTIMER, WDFDPC, WDFWORKITEM, WDFMEMORY5. 数据同步1)⾃旋锁运⾏在DISPATCH_LEVEL(⾃动提升),因此不能访问分页内存WdfSpinLockCreate, WdfSpinLockAcquire, WdfSpinLockRelease2)WDFWAITLOCK 运⾏在PASSIVE_LEVEL, 同步锁WdfWaitLockCreate, WdfWaitLockAcquire, WdfWaitLockRelease6. 字符串CHAR, WCHAR, STRING, UNICODE_STRINGWDFSTRING: WdfStringCreate串处理函数:strlen之类7. 队列编程 QueueSample// 因为取消例程等要⽤环境变量,所以⽤⼀个设备对象范围同步(重要)deviceAttr.SynchronizationScope = WdfSynchronizationScopeDevice;调⽤例程,取消例程,定时器回调例程,都⽤了设备对象范围同步,所以运⾏在DISPATCH_LEVEL,不能⽤分页内存。

解决计算机硬件设备冲突的实用方法

解决计算机硬件设备冲突的实用方法

解决计算机硬件设备冲突的实用方法计算机硬件设备冲突是使用计算机时常遇到的一个问题。

当我们安装新的硬件设备或更新驱动程序时,不同硬件设备之间可能会发生冲突,导致计算机无法正常工作。

在本文中,我将介绍一些实用的方法,帮助您解决计算机硬件设备冲突。

首先,我们需要确定出现冲突的设备。

在Windows系统中,我们可以通过设备管理器来查看所有已安装的硬件设备。

要打开设备管理器,可以按下Win+X键,然后选择“设备管理器”。

在设备管理器中,我们可以看到计算机上安装的所有硬件设备的列表。

如果设备存在冲突,它们将以黄色感叹号或红色叉的形式显示在列表中。

一种常见的硬件设备冲突是资源冲突,即多个设备试图使用相同的资源,例如IRQ(中断请求),I/O地址或内存地址。

解决这种冲突的一种方法是重新分配资源。

在设备管理器中,我们可以右键单击冲突的设备,选择“属性”并切换到“资源”选项卡。

在此选项卡上,我们可以更改设备使用的资源设置,也可以选择“自动配置”来让系统自动为设备分配可用资源。

通过重新分配资源,我们可以解决大多数资源冲突问题。

另一个常见的硬件设备冲突是驱动程序冲突。

驱动程序是计算机硬件设备与操作系统通信的桥梁。

如果两个或多个设备使用相同的驱动程序,可能会导致冲突。

解决这种冲突的方法是更新或更改驱动程序。

在设备管理器中,如果右键单击冲突的设备并选择“更新驱动程序”,系统将尝试从互联网上获取最新的驱动程序。

如果无法解决冲突,我们也可以尝试手动下载和安装适当的驱动程序。

此外,物理连接也可能导致硬件设备冲突。

例如,如果我们安装了一个新的内部硬件设备,我们必须确保其与计算机主板的插槽兼容,并正确安装。

如果电缆连接不良或插槽不正确,设备可能无法正常工作。

解决这种冲突的方法是检查物理连接,确保它们正确牢固地连接在一起。

还有一种常见的硬件设备冲突是设备驱动程序的冲突。

设备驱动程序是使硬件设备正常工作所必需的软件。

如果我们在安装新设备时没有正确安装其驱动程序,或者设备驱动程序与其他已安装的驱动程序不兼容,可能会导致冲突。

wince设备管理器[1]

wince设备管理器[1]
4. ActivateDevice在 [HKEY_LOCAL_MACHINE\Drivers\Acti ve下创建一个新的键值。
wince设备管理器[1]
驱动的加载过程
wince设备管理器[1]
驱动加载API
l 设备驱动程序也能通过应用程序进行手动 的安装,这是ActivateDeviceEx的一个首 选的功能。
l 安装驱动一个更老的方法是使用 RegisterDevice 与 DeregisterDevice
wince设备管理器[1]
驱动是如何工作的
1. When CE启动时, Device.exe根据注册表中 的设置安装所有的驱动程序。
2. 当安装mydriver.dll时, device.exe 调用 DEM1_Init。
wince设备管理器[1]
ActivateDeviceEx
l ActivateDeviceEx负责加载驱动程序,并将驱动程序的注 册值添加到注册表的Active项中。
l ActivateDevice函数根据注册表的信息,把对应的驱动DLL 加载到Device.exe的地址空间内;然后在注册表 HKEY_LOCAL_MACHINE\Drivers\Active键下面添加一个 子键,来记录已经加载的驱动程序。
l 它的源代码是公开的,在
%_WINCEROOT%\PUBLIC\COMMON\OAK\D RIVERS\BUSENUM\BUSENUM\下
wince设备管理器[1]
总线枚举的过程
加载
内核
Device.exe
加载
BusEnum.dll
加载
BusEnum.dll (加载ISA设备驱动)
BusEnum.dll
wince设备管理器

解决Windows上的驱动程序问题的方法

解决Windows上的驱动程序问题的方法

解决Windows上的驱动程序问题的方法在使用Windows操作系统的过程中,我们经常会遇到驱动程序问题。

驱动程序是连接硬件和操作系统之间的桥梁,确保硬件设备能够正常运行。

然而,由于各种原因,我们可能会遇到驱动程序不兼容、缺失或损坏的情况,导致设备无法正常工作。

针对这些问题,本文将介绍几种解决Windows上驱动程序问题的方法。

一、自动更新驱动程序在Windows系统中,我们可以利用系统自带的设备管理器来自动更新驱动程序。

步骤如下:1. 右键点击“开始”按钮,选择“设备管理器”。

2. 在设备管理器中找到需要更新驱动程序的设备,一般在“显示适配器”、“声音、视频和游戏控制器”等分类下。

3. 右键点击设备名称,选择“更新驱动程序”。

4. 在弹出的对话框中选择“自动搜索更新的驱动程序软件”。

5. 系统将自动搜索并下载最新的驱动程序,并进行安装。

通过以上步骤,我们可以很方便地自动更新驱动程序,以解决驱动程序不兼容或缺失的问题。

二、手动下载和安装驱动程序如果自动更新无法解决问题,我们可以尝试手动下载和安装驱动程序。

步骤如下:1. 确定设备型号和厂商名称。

可以在设备管理器中查看设备的详细信息,或者参考设备的说明书。

2. 进入设备的厂商官方网站,找到支持页面或下载中心。

3. 在支持页面或下载中心中,按照设备型号、操作系统版本等信息搜索需要的驱动程序。

4. 下载适用于Windows系统的最新驱动程序,并保存到本地磁盘。

5. 双击下载的驱动程序文件,按照提示完成安装过程。

通过手动下载和安装驱动程序,我们可以解决因为驱动程序损坏、无法自动更新等原因导致的设备无法正常工作的问题。

三、使用驱动程序更新工具除了手动下载和安装驱动程序,我们还可以借助第三方驱动程序更新工具来解决驱动程序问题。

这些工具可以自动检测、下载和安装最新的驱动程序,提供更加便捷的解决方案。

以下是两个常用的驱动程序更新工具:1. 驱动人生:驱动人生是一款常用的驱动程序更新工具,它可以自动检测计算机中的驱动程序,并提供最新版本的下载和安装。

电脑驱动提示unknowndevice怎么办

电脑驱动提示unknowndevice怎么办

电脑驱动提示unknown device怎么办有很多网友在安装驱动时受到系统的提示,表示“unknown device”,一些网友会因此将其误以为是一种驱动的名字,满世界的找它,其实它的意思是unknown device驱动是无法是被的驱动器,那么我们该怎么做呢?今天店铺就为大家带来了电脑驱动提示unknown device的解决方法,希望能够帮到大家。

电脑驱动提示unknown device的解决方法步骤一:停用 USB 2.0 控制器根据不同的操作系统做以下操作:在 Windows 2000 Pro 操作系统中,依次点击“开始”→“控制面板”→“系统”。

在 Windows XP/Server 2003 操作系统中,依次点击“开始”→“控制面板”→“性能和维护”→“系统”。

在 Windows Vista 操作系统中,依次点击“开始”→“控制面板”→“性能和维护”→“系统”→“设备管理器”。

如图1 设备管理器所示:图 1: 设备管理器在 Windows 7 操作系统中,依次点击“开始”→“控制面板”→“系统和安全”→“设备管理器”。

如图 2 设备管理器所示:图 2: 设备管理器注:本文以Windows XP 操作系统的操作方法为例,其他操作系统的操作方法可作参考。

在“系统属性”窗口中,从“硬件”选项卡中点击“设备管理器”按钮。

如图 3 系统属性所示:图 3: 系统属性在“设备管理器”窗口中,展开“通用串行总线控制器”主项,点击“USB2 Enhanced”子项。

如图 4 USB 2.0 子项所示:图 4: USB 2.0 子项注:本文以Intel (R) 82801 主板芯片组为例,其他厂商芯片组的操作方法可以作参考。

在“设备管理器”窗口中,依次点击“操作”→“停用”。

如图5 停用 USB 2.0 控制器所示注 :如果您使用的是 USB 接口的键盘和鼠标,需要先改用 PS/2 接口的键盘和鼠标,以免停用USB 2.0 控制器后无法正常使用这些设备。

嵌入式linux(贺丹丹等编著)课后习题答案

嵌入式linux(贺丹丹等编著)课后习题答案

嵌入式linux(贺丹丹等编著)课后习题答案第八章一、填空题。

1、ARM-Linux内核的配置系统由三个部分组成,它们分别是Makefile、配置文件和配置工具。

2、配置工具一般包括配置命令解释器和配置用户界面,前者主要作用是对配置脚本中使用的配置命令进行解释;而后者则是提供基于字符界面、基于Ncurses图形界面以及基于X Window图形界面的用户配置界面。

3、Makefile文件主要包含注释、编译目标定义和适配段。

4、Linux内核常用的配置命令有make oldconfig、make config、make menuconfig和make xconfig。

其中以字符界面配置的命令是make config。

5、内核编译结束后,会在“/arch/arm/boot/”目录下面和根目录下面生成一个名为zImage的内核镜像文件。

二、选择题C AD D B三、叙述题1、Linux内核各个部分与内核源码的各个目录都是对应起来的,比如有关驱动的内容,内核中就都组织到“drive”这个目录中去,有关网络的代码都集中组织到“net”中。

当然,这里有的目录是包含多个部分的内容。

具体各个目录的内容组成如下:arch:arch目录包括了所有和体系结构相关的核心代码。

include:include 目录包括编译核心所需要的大部分头文件,例如与平台无关的头文件在include/linux 子目录下;init:init 目录包含核心的初始化代码(不是系统的引导代码),有main.c 和Version.c 两个文件;mm:mm 目录包含了所有的内存管理代码。

与具体硬件体系结构相关的内存管理代码位于arch/*/mm 目录下;drivers:drivers 目录中是系统中所有的设备驱动程序。

它又进一步划分成几类设备驱动,每一种有对应的子目录,如声卡的驱动对应于drivers/sound;ipc:ipc 目录包含了核心进程间的通信代码;modules:modules 目录存放了已建好的、可动态加载的模块;fs:fs 目录存放Linux 支持的文件系统代码。

LINUX设备驱动开发详解

LINUX设备驱动开发详解

LINUX设备驱动开发详解概述LINUX设备驱动开发是一项非常重要的任务,它使得硬件设备能够与操作系统进行有效地交互。

本文将详细介绍LINUX设备驱动开发的基本概念、流程和常用工具,帮助读者了解设备驱动开发的要点和技巧。

设备驱动的基本概念设备驱动是连接硬件设备和操作系统的桥梁,它负责处理硬件设备的输入和输出,并提供相应的接口供操作系统调用。

设备驱动一般由设备驱动程序和设备配置信息组成。

设备驱动程序是编写解决设备驱动的代码,它负责完成设备初始化、IO操作、中断处理、设备状态管理等任务。

设备驱动程序一般由C语言编写,使用Linux内核提供的API函数进行开发。

设备配置信息是定义硬件设备的相关参数和寄存器配置的文件,它告诉操作系统如何与硬件设备进行交互。

设备配置信息一般以设备树或者直接编码在设备驱动程序中。

设备驱动的开发流程设备驱动的开发流程包括设备初始化、设备注册、设备操作函数编写和设备驱动注册等几个主要步骤。

下面将详细介绍这些步骤。

设备初始化设备初始化是设备驱动开发的第一步,它包括硬件初始化和内存分配两个主要任务。

硬件初始化是对硬件设备进行基本的初始化工作,包括寄存器配置、中断初始化等。

通过操作设备的寄存器,将设备设置为所需的状态。

内存分配是为设备驱动程序分配内存空间以便于执行。

在设备初始化阶段,通常需要为设备驱动程序分配一块连续的物理内存空间。

设备注册设备注册是将设备驱动程序与设备对象进行关联的过程,它使得操作系统能够正确地管理设备。

设备注册包括设备号分配、设备文件创建等操作。

设备号是设备在系统中的唯一标识符,通过设备号可以找到设备对象对应的设备驱动程序。

设备号分配通常由操作系统负责,设备驱动程序通过注册函数来获取设备号。

设备文件是用户通过应用程序访问设备的接口,它是操作系统中的一个特殊文件。

设备文件的创建需要通过设备号和驱动程序的注册函数来完成。

设备操作函数编写设备操作函数是设备驱动程序的核心部分,它包括设备打开、设备关闭、读和写等操作。

嵌入式面试笔试题目——附部分答案

嵌入式面试笔试题目——附部分答案

嵌⼊式⾯试笔试题⽬——附部分答案1 、如何⾃动创建设备⽂件?class_create device_create2、led驱动编写有⼏种⽅式?输⼊⼦系统字符设备驱动总线platform led⼦系统3、如何实现http服务器?tcp服务器:socket4、如何编写守护进程,简述syslog的作⽤?第⼀步:创建进程、杀死⽗进程第⼆步:创建新的会话第三步:改变⼯作路径路径第四步:修改⽂件掩码权限第五步:关闭⽂件描述符5、bootloader和uboot的区别?bootloader是启动装载。

这是⼀段很⼩的程序,⽤于在系统上电启动初期运⾏,初始化关键接⼝,如内存,串⼝,关闭中断,关闭看门狗,引导系统进⼊内核的⼀段初始化的程序。

它主要任务就是将内核映像从硬盘读到RAM中,然后跳转到内核的⼊⼝点去运⾏内核,从⽽建⽴系统运⾏的必要环境。

uboot:是bootloader的⼀种6、如何移植uboot?1、下载源码2、解压uboot源码并进⼊⽬录3、指定交叉编译⼯具链4、指定产品BOARD 底板5、编译u-boot7、传感器驱动如何编写?8、BL0,BL1,BL2,BL3的作⽤?BL0 ⽂件是存放在 CPU 内部 IROM 中的⼀段固化代码,CPU 上点之后,⾸先去运⾏soc中的BL0,运⾏时会将 BL1 拷贝到 CPU 的 IRAM 中,然后执⾏BL1;BL1⽂件执⾏起来之后会先进⾏内存的初始化,之后将 BL2 ⽂件拷贝到外部内存中,BL2会初始化BL3的运⾏环境,将BL3搬移到DRAM中,BL3会有⼀个⾃搬移的过程,从⽽启动内核⼊⼝。

BL0:CPU内部的固化代码BL1:三星提供的加密⽂件BL2:截取uboot.bin 前14kBL3:剩下的uboot 执⾏命令以及加载引导内核9、exynos4412 时钟 APLL,MPLL,VPLL的区别?------倍频锁相环APLL:⽤于 CPU_BLK (可产⽣⾼达1.4GHz的频率);作为 MPLL 的补充,它也可以给DMC_BLK 、LEFTBUS_BLK 、RIGHTBUS_BLK 和 CMU_TOP 提供时钟。

添加驱动程序的步骤

添加驱动程序的步骤

添加驱动程序的步骤.txt单身很痛苦,单身久了更痛苦,前几天我看见一头母猪,都觉得它眉清目秀的什么叫残忍?是男人,我就打断他三条腿;是公狗,我就打断它五条腿!为相应的设备写好基本驱动程序并向VFS(virtual file system)注册即可,当上层应用要使用该设备时,VFS就会调用相应的设备函数。

设备驱动程序可以归为以下3类:1 块设备(block)以块为单位,允许随机访问,多用缓存技术2 字符设备(char)以字节为单位,只能按顺序访问,不用缓存3 网络接口(net)设备号:系统用主设备号(MAJOR)和次设备号(MINOR)来唯一标示一般设备相同主设备号表示同一类设备,次设备号表示同类设备的个数,在(/dev目录)下有相应的文件,这样字符设备和块设备都可以通过文件操作的系统调用完成。

字符设备的驱动程序通过在device_struct数据结构的chrdevs向量中增加一项的方法来向内核注册自己注册:int resultresult=register_chrdev(主设备号,设备名,&结构体)(GPIO_MAJOR_NR,DEVICE_NAME,&gpio_fops)字符设备驱动驱动程序编译进内核的步骤:1 在uClinux-dist/linux2.4.x/drivers/char目录下编写驱动程序(gpio.h,gpio.c)2 修改uClinux-dist/linux2.4.x/dirvers/char/Config.in,在适当的位置添加一行:bool 'gpiotest support'CONFIG_GPIO在make menuconfig时看见的是gpiotest support 选择这个时,既配置了CONFIG_GPIO 3 修改uClinux-dist/linux2.4.x/dirvers/char/Makefile 在适当的位置添加一行:obj-$(CONFIG_GPIO) += gpio.o4 在uClinux-dist/linux2.4.x/dirvers/char/mem.c 中添加初始化#ifdef CONFIG_GPIOextern int gpio_init(void);//在内核启动的时候对GPIO驱动程序进行注册#endif在这个函数中 int __init chr_dev_init(void){#ifdef CONFIG_GPIOgpio_init();//在内核启动的时候对GPIO驱动程序进行注册#endif}测试(应用)程序的编写和添加内核配置make clean 清除之前编译好的make menuconfigvendor/Product Selection-->厂商和产品的选择选择samsung 44b0Kernel/Library/Defaults Selection内核和库的选择--Kernel is linux-2.4.x(uClibc)Libc Version压缩的libc 的库[ ] Default all settings(lose changes)[*] Customize Kernel Settings 内核的设定,添加驱动程序[*] Customize Vendor/User Settings根文件系统,ram fs 内核配置目录:Code maturity level options-->代码成熟度[]还在开发阶段的[]Loadable module support-->[]Enable Loadable module support内核模块的支持System Type -->系统类型 (Samsung)ARM system type[ ]Generate big endian code 大小端的选择[*]Set flash/sdram size and base addr 选择存储器的大小(0c000000)(S)DRAM Base Address(00800000)(S)DRAM Size(00000000)FLASH Base Address(00200000)FLASH Size 2M(RAM)Kernel executes from(S3C44B0X-MBA44) Board InplementationGeneral setup-->通用设定[ ]Support hot-pluggable devices热拔插[*]Networking support 网络的支持[ ]System V IPC进程间通信[ ]Reduced memory footprint[ ]BSD Process Accouting[ ]Sysct1 support[*]NMFPE math emulation模拟数字协处理器(ELF)Kernel core(/proc/kcore) format内核格式[*]Support uClinux FLAT format binaries 对没有MMU 的处理器的支持[*]Support FLAT format compressed binaries[ ]RISC OS personality[ ]Compiled-in Kernel Boot Parameter[*]Timer and CPU usage LEDs[*]Timer LED[*]CPU usage LED[ ]Kernel -mode alignment trap handler[ ]m68knommu-style attached romfs in RAM supportNetworking options-->网络选项Network device support网卡的支持Amateur Radio support 启动无线网络IrDA (infrared)supportATA/IDE/MFM/RLL supportSCSI support 一种存储接口ISDN subsystem数字电话的Parallel port support并行接口Memory Technology Devices(MTD)内存设备Plug and Play configuration即插即用设备Block devices块设备File systems文件系统Character devices字符设备USB supportI2O device supportKernel hackingCryptographic optionsLibrary routinesLoad an Alternate Configuration FileSave Configuration to an Alternate File进行应用程序的配置Core A[[lications 核心配置[*]init[*]enable console shell [*]execute firewall rulesLibrary Configuration 库的配置FLASH Tools Flash 一些工具Filesystem Applications 文件系统的应用Network Applications 网络配置Miscellaneous ApplicationsBusyBoxTinyloginMicroWindowsGamesNiscellaneous ConfiuggurationDebug Buildsgsm modemLED testS3C rtc testS3C adc testS3C ps2 testS3C eirq test再make depmake lib_onlymake user_onlymake romfs创建文件系统make image 创建镜像make。

解决计算机设备驱动程序问题的实用方法

解决计算机设备驱动程序问题的实用方法

解决计算机设备驱动程序问题的实用方法每个计算机设备都需要相应的驱动程序来正常运行。

然而,有时安装或更新驱动程序可能会出现问题,导致设备无法正常工作。

在本文中,我将介绍几种实用方法来解决计算机设备驱动程序问题,帮助您恢复设备的正常功能。

首先,您可以尝试使用Windows自带的设备管理器来解决驱动程序问题。

设备管理器是一个系统工具,用于管理计算机硬件设备和驱动程序。

按下Win + X键,然后选择设备管理器,或者通过控制面板中的设备管理器打开它。

在设备管理器中,您可以查看已安装的设备以及是否存在驱动程序问题。

如果驱动程序出现问题,设备管理器通常会显示一个感叹号或问号。

右键单击问题设备,选择“更新驱动程序”选项,然后选择自动更新驱动程序或手动更新驱动程序。

尝试此方法可解决常见的驱动程序问题。

其次,您可以访问设备制造商的官方网站来下载并安装最新的驱动程序。

搜索设备制造商的品牌和型号,然后导航到官方网站。

在支持或下载部分,找到适用于您的操作系统的最新驱动程序。

下载后,双击安装程序并按照提示完成安装。

这种方法通常能够解决由于驱动程序版本过旧或损坏而引起的问题。

此外,您可以使用第三方驱动程序更新工具来自动扫描并更新计算机中的驱动程序。

这些工具通常会检测和识别过时或损坏的驱动程序,并提供下载和安装最新驱动程序的选项。

请确保使用知名和可信赖的驱动程序更新工具,以避免安装恶意软件或驱动程序。

在使用任何第三方工具之前,请先进行一些背景调查,并阅读其他用户的评价和反馈。

如果您仍然无法解决驱动程序问题,您可以尝试还原系统来恢复到之前的稳定状态。

Windows系统提供了还原选项,允许您返回到之前的系统快照,其中驱动程序可能处于正常工作状态。

按下Win + R键,然后输入“rstrui”并按回车键打开还原向导。

请选择恢复点并完成还原过程。

请注意,还原系统将删除安装后的程序和更改,因此请确保备份重要的文件和数据。

最后,如果您面临着顽固的驱动程序问题,您可以考虑重新安装操作系统。

Linux字符设备中的两个重要结构体(file、inode)

Linux字符设备中的两个重要结构体(file、inode)

Linux字符设备中的两个重要结构体(file、inode)对于Linux系统中,⼀般字符设备和驱动之间的函数调⽤关系如下图所⽰上图描述了⽤户空间应⽤程序通过系统调⽤来调⽤程序的过程。

⼀般⽽⾔在驱动程序的设计中,会关系 struct file 和 struct inode 这两个结构体。

⽤户空间使⽤open()系统调⽤函数打开⼀个字符设备时(int fd = open("dev/demo", O_RDWR) )⼤致有以下过程:1. 在虚拟⽂件系统VFS中的查找对应与字符设备对应 struct inode节点2. 遍历字符设备列表(chardevs数组),根据inod节点中的 cdev_t设备号找到cdev对象3. 创建struct file对象(系统采⽤⼀个数组来管理⼀个进程中的多个被打开的设备,每个⽂件秒速符作为数组下标标识了⼀个设备对象)4. 初始化struct file对象,将 struct file对象中的 file_operations成员指向 struct cdev对象中的 file_operations成员(file->fops = cdev->fops)5. 回调file->fops->open函数⼀、inode结构体VFS inode 包含⽂件访问权限、属主、组、⼤⼩、⽣成时间、访问时间、最后修改时间等信息。

它是Linux 管理⽂件系统的最基本单位,也是⽂件系统连接任何⼦⽬录、⽂件的桥梁。

内核使⽤inode结构体在内核内部表⽰⼀个⽂件。

因此,它与表⽰⼀个已经打开的⽂件描述符的结构体(即file ⽂件结构)是不同的,我们可以使⽤多个file ⽂件结构表⽰同⼀个⽂件的多个⽂件描述符,但此时,所有的这些file⽂件结构全部都必须只能指向⼀个inode结构体。

inode结构体包含了⼀⼤堆⽂件相关的信息,但是就针对驱动代码来说,我们只要关⼼其中的两个域即可:1. dev_t i_rdev; 表⽰设备⽂件的结点,这个域实际上包含了设备号。

设备驱动接口函数DeviceIoControl使用实例

设备驱动接口函数DeviceIoControl使用实例

设备驱动接口函数DeviceIoControl使用实例1.通过API访问设备驱动程序Q 在NT/2000/XP中,我想用VC编写应用程序访问硬件设备,如获取磁盘参数、读写绝对扇区数据、测试光驱实际速度等,该从哪里入手呢?A 在NT/2000/XP中,应用程序可以通过API函数DeviceIoControl来实现对设备的访问—获取信息,发送命令,交换数据等。

利用该接口函数向指定的设备驱动发送正确的控制码及数据,然后分析它的响应,就可以达到我们的目的。

DeviceIoControl的函数原型为BOOL DeviceIoControl(HANDLE hDevice, // 设备句柄DWORD dwIoControlCode, // 控制码LPVOID lpInBuffer, // 输入数据缓冲区指针DWORD nInBufferSize, // 输入数据缓冲区长度LPVOID lpOutBuffer, // 输出数据缓冲区指针DWORD nOutBufferSize, // 输出数据缓冲区长度LPDWORD lpBytesReturned, // 输出数据实际长度单元长度LPOVERLAPPED lpOverlapped // 重叠操作结构指针);设备句柄用来标识你所访问的设备。

发送不同的控制码,可以调用设备驱动程序的不同类型的功能。

在头文件winioctl.h中,预定义的标准设备控制码,都以IOCTL或FSCTL开头。

例如,IOCTL_DISK_GET_DRIVE_GEOMETRY是对物理驱动器取结构参数(介质类型、柱面数、每柱面磁道数、每磁道扇区数等)的控制码,FSCTL_LOCK_VOLUME是对逻辑驱动器的卷加锁的控制码。

输入输出数据缓冲区是否需要,是何种结构,以及占多少字节空间,完全由不同设备的不同操作类型决定。

在头文件winioctl.h中,已经为标准设备预定义了一些输入输出数据结构。

重叠操作结构指针设置为NULL,DeviceIoControl将进行阻塞调用;否则,应在编程时按异步操作设计。

DriverWorks简明教程

DriverWorks简明教程

DriverW orks简明教程1.学会使用向导很多人不喜欢向导,可是一个从应用开发转做驱动开发的人可能更容易接受这种方式,但在今天我不打算使用过多的向导,而是手工写驱动代码,只是使用了DriverW orks的包装类,使用MFC可以反过来使我的SDK技术长进不少,那同样的使用DriverW orks我相信同样可以使我们的DDK技术得到锻炼.首先使用DDK Build Settings启动V isual C++ 6.01.1 点击DriverStudio工具栏上的Launch DriverWizard按钮,选择New Project中的"Start a New Driver Project"1.2 向导会自动选中DDK Source/makefile和V isual Studio 6,在Project Name里输入"hello"后点下一步1.3 project type页中选择"Kernel Mode Service"点下一步1.4 IRP Handlers页中把所有自动勾上的请求都去掉,因为我们要手工写DriverW orks代码以加深印象.点下一步1.5 在Additional页里把自动勾上的Generate SoftICE NMS file in custom build step去掉.点下一步1.6 预览工程,并点击完成:Project Summary For kruglinskiProject Name = helloProject Location = D:\W orkspace\helloProject Type = NT1.8 空的工程框架就会生成完毕.此时直接编译会出错,也许是DriverStudio的一个Bug,只要把sources中的:TARGETLIBS=$(DDK_LIB_PA TH)\ntstrsafe.lib$(DDK_LIB_PA TH)\csq.lib这一行去掉就可以编译通过了,让我们编试一下,一定感觉很不错吧!2.拨开云雾见日出2.1 现在我们要做的是清理掉所有会让我们眼花的东东(一大堆向导生成的代码),只留下编译环境,我喜欢在V isual Studio里直接编译的感觉,很讨厌总是看到那个黑黑的Build Console.切换到FileV iew初图,把除了makefile和sources文件以外的其它文件全部删除,然后我们只复制hello.dsp,sources和makefile三个文件到一个单独的文件夹helloworld里.选择File-Close W orkspace关闭刚向导出来的工程,再把copy出来的hello.dsp拖到V isual Studio 6中打开(这时会自动生成一个hello.dsw).2.2 现在要正式开工了,按Ctrl+N在Files页选择C++ Source File,在File栏里输入hello.cpp在hello.cpp里首先要#include "vdw.h" ,因为我们要用的DriverW orks包装类的头文件都由该文件包括.这里需要注意的是在#include "vdw.h"前应该加入一句#define VDW_MAIN因为DriverW orks的帮助文件里这样说(懒得译了,将就着看吧!!)Symbol VDW_MAIN must be #define'd in exactly one source module of the driver, generally the module that implements the driver class. If, as is true for most drivers, there is more than one source module, do not #define VDW_MAIN in any other modules. The definition must precede #include . The purpose of this symbol is to control the inclusion of certain source files in the DriverW orks library. These source files must be compiled in the context of the driver being built.2.3 我们定义一个驱动对象类,它派生自KDriver,必须提供一个纯虚函数DriverEntry的实现:class MyDriver:public KDriver{SAFE_DESTRUCTORS;public:virtual NTSTA TUS DriverEntry(PUNICODE_STRING RegistryPath);};DECLARE_DRIVER_CLASS(MyDriver,NULL)NTSTA TUS MyDriver::DriverEntry(IN PUNICODE_STRING RegistryPath){DbgPrint("Hello KMD world!");return STA TUS_SUCCESS;}这里还有一个DECLARE_DRIVER_CLASS(MyDriver,NULL)要注意,再copy一段帮助文档上的内容:One module of the driver must invoke macro DECLARE_DRIVER_CLASS. This macro actually inserts a small function that the framework calls during initialization. The function creates an instance of the driver class.现在已经可以编译成sys,用我的小工具Driver Logicl Tester可以测试一下效果,可以看到输出了一行"hello KMD W orld!",我想需要解释一下KDriver,KDriver是驱动对象,按照DriverW orks对象模型里的观念,一个驱动程序里至少要包括一个驱动对象,这个驱动对象可以包括一个或多个设备对象,Ring3的应用程序可以通过设备对象来于驱动程序交互.后面我会做简单的演示.3.打开潘多拉魔盒上面演示的东东其实本上没有多大实际的用处,当然可以在riverEntry里添加一个调用门让Ring3的应用程序有机会使用调用门进入Ring0.所以我们必须要做到可以控制驱动程序执行指定的代码完成指定的任务.3.1 设备对象与KDevice在DriverW orks里KDevice和KPnpDeivce做为设备对象类的抽像,因为这里想演示的是KMD而不是WDM,所以我在这里只使用KDevice,KPnpDeivce以后有空再说.在#define VDW_MAIN后#include "vdw.h"前加上以下几行:#define DRIVER_FUNCTION_DEVICE_CONTROL#define DRIVER_FUNCTION_CREA TE#define DRIVER_FUNCTION_CLOSE#define DRIVER_FUNCTION_CLEANUP当需要覆盖设备或是驱动对象基类的某个函数时,需要在include 之前定义这些宏.原因不要问,文档上要求这样做那就这样做咯.具体的可以查看DriverW orks源代码,这四个是设备对象要用到的,可以对应看下面的代码.现在我们实现一个设备对象的派生类MyDevice,它将负责与上层的驱动测试工具做交互.class MyDevice : public KDevice{public:SAFE_DESTRUCTORS;MyDevice();~MyDevice();DEVMEMBER_DISPA TCHERS;};DriverW orks帮助文档里说到如果没有SAFE_DESTRUCTORS这个宏,Unload例将工作的不太正常,所以不用问那么照做就是.而DEVMEMBER_DISPA TCHERS宏的功能是自动的定义所有的派遣函数,如果Create,Close,Cleanup...等.然后分别实现前面#define的那几个派遣函数:NTSTA TUS MyDevice::Create(KIrp I)DbgPrint(__FUNCTION__":IRP %p\n", I);rmation() = 0;plete(STA TUS_SUCCESS);return STA TUS_SUCCESS;}NTSTA TUS MyDevice::Close(KIrp I){DbgPrint(__FUNCTION__":IRP %p\n", I);rmation() = 0;plete(STA TUS_SUCCESS);return STA TUS_SUCCESS;}NTSTA TUS MyDevice::DeviceControl(KIrp I){DbgPrint(__FUNCTION__":IRP %p,CodeCode=%d\n", I,I.IoctlCode());rmation() = 0;plete(STA TUS_SUCCESS);return STA TUS_SUCCESS;}NTSTA TUS MyDevice::CleanUp(KIrp I)DbgPrint(__FUNCTION__":IRP %p\n", I);rmation() = 0;plete(STA TUS_SUCCESS);return STA TUS_SUCCESS;}3.2 构造一个设备对象在DriverEntry里创建这个设备对象,其实非常简单,只是调用一个new运算符函数.NTSTA TUS MyDriver::DriverEntry(PUNICODE_STRING RegistryPath){NTSTA TUS status = STATUS_SUCCESS;DbgPrint(__FUNCTION__"RegistryPath:%S\n",RegistryPath->Buff er);MyDevice* pDevice = new (L"HelloDevice",FILE_DEVICE_UNKNOWN,L"HelloDevice",0,DO_DIRECT_IO)MyDevice();if (pDevice == NULL){status = STA TUS_INSUFFICIENT_RESOURCES;}else{status = pDevice->ConstructorStatus();//读取设备对象构造后的状态if (!NT_SUCCESS(status)){delete pDevice;}elseDbgPrint(__FUNCTION__"Created HelloDevice!\n");}return status;}我想需要解释一下这个new运算符,它是KDevice的重载动算符,我使用的原型是:void* __cdecl operator new(size_t n,PCWSTR DeviceName,DEVICE_TYPE Type,PCWSTR LinkName=NULL,ULONG Characteristics=0,ULONG DeviceFlags=DO_BUFFERED_IO);这个new运算符函数的comment说到:// This is the form of new that allocates the storage for the class instance in// the system device object extension.在设备对象扩展里分配并存储类实例,我看了一下它的源代码在kfilter.cpp中,它会调用一个叫__construct的函数,而__construct函数会调用IoCreateDevice创建一个驱动设备对象(注意不是DriverW orks设备对象类),并分配一个大小为n(在这里是n=sizeof(MyDevice))的设备扩展用来存储这个设备对象类(包括它的数据成员,感觉确实是很方便啊!),并调用IoCreateSymbolLink在\DosDevice\创建一个符号链接供Ring3程序使用,我想LinkName使用一个GUID字符串更合适一些.呵呵!其实不需要把代码跟到这里看,只不过了解一些底下的东东也好,但我很赞成潘爱民老师所说的,做应用开发尽可能不要去读软件开发商提供的类库源代码.只看参考手册能够用的很熟练很巧就行了.所以我只看D.j.Kruglinski的Inside VC++而从不去看什么深入浅出MFC,我的MFC照样用的很好,也可以理解那些MFC底层如何实现,其实深入浅出MFC里的东西,Inside VC++里只用了几页纸就讲的非常清楚了,呵呵!话扯远了.也许每个人学习的思想和方法不一样.再搬出我的小工具,测试一下.可以看到我们写的几个函数都被调用到了,每按一下"IoControl"按钮,DeviceControl函数就会被调用.4.输入与输出4.1 简单的KMD与上层应用同步方法我想有了前面的基础,做输出输出已经不是什么难事,可以在DeviceIoControl里做,也可以在Read和Write派遣函数里做,不过我想通常的做法是,驱动创建一个同步事件,使用DriverW orks的KEvent对象,并使用这个成员函数原型进行初使化:VOID Initalize(KUstring& Name,EVENT_TYPE type);第一个参数可以填以\BaseNamedObjects\为前缀的事件对象名,后一个参数可以是SynchronizationEvents(同步事件)或是NotificationEvents(通知事件),然后Ring3的程序可以用CreateEvent打开这个对象,W aitForSingleObject做同步.当有数据时上层的程序会在第一时间得到通知.一般设备对象会添加几个容器成员,像前面分析的,它们会被会配并存储在设备扩展里,当然容器要使用的堆内存会是从PagedPool 或是NonPagedPool里分配出来的,一些常用的容器如KList,KLockableFifo,KInterlockedList...等等.这样,数据的排队和存储解决后,就是在派遣函数中处理它们了,或是从上层收到并存入容器,或是从容器里摘除并返回到上层.4.2 IO控制代码一般使用一个叫做CTL_CODE的宏来定义IO控制代码,在每个派遣函数有一个KIrp类型的参数,它也IRP请求包的包装类,KIrp::IoctlCode函数返回控制代码的引用,也就是说我们可以读也可以改写控制代码.通常在DeviceIoControl里根据不同的控制代码做不同的动作.类似于这样:NTSTA TUS MyDevice::DeviceControl(KIrp I){switch (I.IoctlCode()){case CTRL_SETUP_HOOK:.............break;case CTRL_REMOVE_HOOK:.............break;default:status = STA TUS_INV ALID_DEVICE_REQUEST;break;}...}而输入输出缓冲及大小分别由,KIrp::IoctlBuffer,KIrp::IoctlInputBufferSize和KIrp::IoctlOutputBufferSize来获得.这只是Buffered IO方式,还有Direct IO方式有空再说!完整的程序代码,我更喜欢看面向对象的代码结构,呵呵!//hello.cpp:#define VDW_MAIN#define DRIVER_FUNCTION_DEVICE_CONTROL#define DRIVER_FUNCTION_CREA TE#define DRIVER_FUNCTION_CLOSE#define DRIVER_FUNCTION_CLEANUP#define DRIVER_FUNCTION_UNLOAD#include "vdw.h"class MyDriver : public KDriver{SAFE_DESTRUCTORSpublic:virtual NTSTA TUS DriverEntry(PUNICODE_STRING RegistryPath);virtual VOID Unload(VOID);};DECLARE_DRIVER_CLASS(MyDriver,NULL)class MyDevice : public KDevice{public:SAFE_DESTRUCTORS;MyDevice();~MyDevice();DEVMEMBER_DISPA TCHERS};MyDevice::~MyDevice(){}MyDevice::MyDevice() :KDevice(){if (!NT_SUCCESS(m_ConstructorStatus)){DbgPrint(__FUNCTION__": Failed to create device MyDevice"); return;}}NTSTA TUS MyDevice::Create(KIrp I){DbgPrint(__FUNCTION__":IRP %p\n", I);rmation() = 0;plete(STA TUS_SUCCESS);return STA TUS_SUCCESS;NTSTA TUS MyDevice::Close(KIrp I){DbgPrint(__FUNCTION__":IRP %p\n", I);rmation() = 0;plete(STA TUS_SUCCESS);return STA TUS_SUCCESS;}NTSTA TUS MyDevice::DeviceControl(KIrp I){DbgPrint(__FUNCTION__":IRP %p,CodeCode=%d\n", I,I.IoctlCode());rmation() = 0;plete(STA TUS_SUCCESS);return STA TUS_SUCCESS;}NTSTA TUS MyDevice::CleanUp(KIrp I){DbgPrint(__FUNCTION__":IRP %p\n", I);rmation() = 0;plete(STA TUS_SUCCESS);return STA TUS_SUCCESS;VOID MyDriver::Unload(VOID){KDriver::Unload();}NTSTA TUS MyDriver::DriverEntry(PUNICODE_STRING RegistryPath){NTSTA TUS status = STATUS_SUCCESS;DbgPrint(__FUNCTION__"RegistryPath:%S\n",RegistryPath->Buff er);MyDevice* pDevice = new (L"HelloDevice",FILE_DEVICE_UNKNOWN,L"HelloDevice",0,DO_DIRECT_IO)MyDevice();if (pDevice == NULL){status = STA TUS_INSUFFICIENT_RESOURCES;else{status = pDevice->ConstructorStatus();if (!NT_SUCCESS(status)){delete pDevice;}elseDbgPrint(__FUNCTION__"Created HelloDevice!\n");}return status;}到现在为止,如果你是已经可以很熟练的用DDK写驱动肯定觉得这一切会有点繁琐,但这仅仅是开始,驱动的工程越大,代码量越多时使用DriverW orks表现出的效率会越明显.可以类比像MFC 与SDK玩玩DriverW orks(二)-读写数据这两天怎么老想玩DriverW orks今天抽了一个小时写个小驱动练习一下KIrp和KMemory配合访问三种IO方式中的数据.KIrp是对IRP请求对象的包装,它有很多成员函数用于操作IRP结构.1.Buffered IO:在Buffered IO方式中IO管理器会分配一块堆内存然后把用户态缓冲区数据copy进来再传给驱动程序,而输出时IO管理器会把堆内存中的数据copy回用户态缓冲区.我们使用下面这样的代码来得到输入/输出缓冲区和大小KIrp I;....ULONG inputSize = I.IoctlInputBufferSize();ULONG outputSize = I.IoctlOutputBufferSize();PVOID inputBuffer = I.IoctlBuffer();PVOID outputBuffer = I.IoctlBuffer();一目了然吧!我想要介绍一下这几个函数,但你实际上可以跳过下面的一小段因为用DriverW orks根本用不着知道这些细节.IoctlBuffer,IoctlInputBufferSize,IoctlOutputBufferSize函数实现非常简单:inline PVOID& KIrp::IoctlBuffer(void){return m_Irp->AssociatedIrp.SystemBuffer;}inline ULONG& KIrp::IoctlOutputBufferSize(EStackLocation s) {V alidateStackLocation(s);if (s == CURRENT)return IoGetCurrentIrpStackLocation(m_Irp)->Parameters.DeviceIoControl.OutputBufferLength;elsereturn IoGetNextIrpStackLocation(m_Irp)->Parameters.DeviceIoControl.OutputBufferLength;}inline ULONG& KIrp::IoctlInputBufferSize(EStackLocation s) {V alidateStackLocation(s);if (s == CURRENT)return IoGetCurrentIrpStackLocation(m_Irp)->Parameters.DeviceIoControl.InputBufferLength;elsereturn IoGetNextIrpStackLocation(m_Irp)->Parameters.DeviceIoControl.InputBufferLength;}在IoctlOutputBufferSize和IoctlInputBufferSize中S有一个默认参数CURRENT,上面的代码就是这样调用它们的.可以看到其实是对IO_STACK_LOCATION结构直接的操作.2.Direct IO:Direct IO方式中IO管理器分将用户态缓冲区映射到核心态(地址不一样,但其实是一块内存),并锁定内存不要分页机制将内存交换到外存中.然后IO管理器将缓冲区在核心态的的地址传给驱动程序.Direct IO的分成METHOD_IN_DIRECT和METHOD_OUT_DIRECT2.1 在METHOD_IN_DIRECT中我们使用这样的代码来访问缓冲区及大小KIrp I;....KMemory Mem(I.Mdl());PUCHAR pBuffer = (PUCHAR) Mem.MapToSystemSpace(); ULONG writeSize = I.WriteSize();ULONG bytesSent = 0;2.2 在METHOD_OUT_DIRECT中要像这样来访问缓冲区及大小KIrp I;....KMemory Mem(I.Mdl());PUCHAR pBuffer = (PUCHAR) Mem.MapToSystemSpace(); ULONG readSize = I.ReadSize();ULONG bytesRead = 0;I.Mdl函数是这样实现的:inline PMDL& KIrp::Mdl(void){return m_Irp->MdlAddress;}它直接返回IRP结构的MdlAddress字段,而MapToSystemSpace 的实现代码是这样的:inline PVOID KMemory::MapToSystemSpace(void){return GetSystemAddressForMdl(m_pMdl);}它调用下面这个函数,这里我不太明白为什么不直接调用MmGetSystemAddressForMdlinline PVOID GetSystemAddressForMdl(PMDL pMdl){CSHORT canFail; // original fail flag in MDLif(!(pMdl->MdlFlags &(MDL_MAPPED_TO_SYSTEM_V A | MDL_SOURCE_IS_NONPAGED_POOL))) {// get the current fail flagcanFail = (CSHORT)(pMdl->MdlFlags & MDL_MAPPING_CAN_FAIL);// set 'mapping can fail' so we don't bugcheck// if MmMapLockedPages failspMdl->MdlFlags |= MDL_MAPPING_CAN_FAIL;// try to map the bufferpMdl->MappedSystemV a =(PVOID)(((ULONG_PTR)MmMapLockedPages(pMdl, KernelMode)) |MmGetMdlByteOffset(pMdl));// set the original flag back in the MDLif(!canFail) {pMdl->MdlFlags &= ~MDL_MAPPING_CAN_FAIL;}}return pMdl->MappedSystemV a;}3 Neither IO:在Neither IO,IO管理器直接把用户态的缓冲区地址和大小传给驱动,不做任何处理.这是很危险的,通常情况下,我们需要写一些小的助手驱动以进入Ring0或是调用一些底层功能,如果可以肯定驱动的派遣函是运行在被动级并且在我们自己指定程序的进程上下文里,那么用用这种方式也无所谓.除此以外尽可能不用这样的IO方式.通常需要使用这样的代码来访问缓冲区和大小: KIrp I;....ULONG inputSize = I.IoctlInputBufferSize();ULONG outputSize = I.IoctlOutputBufferSize();PVOID inputBuffer = I.IoctlType3InputBuffer();PVOID outputBuffer = erBuffer();IoctlType3InputBuffer和UserBuffer的实现代码:inline PVOID& KIrp::IoctlType3InputBuffer(EStackLocation s) {V alidateStackLocation(s);if (s == CURRENT)return IoGetCurrentIrpStackLocation(m_Irp)->Parameters.DeviceIoControl.Type3InputBuffer;elsereturn IoGetNextIrpStackLocation(m_Irp)->Parameters.DeviceIoControl.Type3InputBuffer;}inline PVOID& KIrp::UserBuffer(void){return m_Irp->UserBuffer;}4. 现在可以总结一下,根据这些我们可以学到在DDK层面上应该怎么操作这些IO方式中的缓冲区:4.1 在驱动的派遣函数中可以使用IoGetCurrentIrpStackLocation 得到IO_STACK_LOCATION可以根据它的Control字段确定是什么派遣函数(因为可以将多个派遣函数地址指向一个派遣函数来处理多个请求).在Control等于IRP_MJ_DEVICE_CONTROL 时来要根据DeviceIoControl的子字段IoControlCode来确定是什么控制代码.4.2 对于Buffered IO和Neither IO可以使用它的DeviceIoControl 字段和三个子字段来访问缓冲区和大小参数:typedef struct _IO_STACK_LOCA TION {....union {...struct {ULONG OutputBufferLength;ULONG InputBufferLength;ULONG IoControlCode;PVOID Type3InputBuffer;} DeviceIoControl;...}....} IO_STACK_LOCA TION, *PIO_STACK_LOCA TION;4.3 对于Direct IO则要使用MmGetSystemAddressForMdl来将IRP结构的MdlAddress(内存描述表)字段映射到内核地址空间并锁定,得到一个内核空间地址才能进一步操作.Direct IO方式中的输入输出大小参数由IO_STACK_LOCA TION的Read.Length和Write.Length指示typedef struct _IO_STACK_LOCA TION {....union {...struct {ULONG Length;ULONG Key;LARGE_INTEGER ByteOffset;} Read;struct {ULONG Length;ULONG Key;LARGE_INTEGER ByteOffset;} Write;...}....} IO_STACK_LOCA TION, *PIO_STACK_LOCA TION;说不看库源代码的又忍不住开始分析,呵呵!其实可以把DriverW orks的对象类搞清楚怎么用就可以了.如果是想顺便把自己的DDK开发能力也提高一下的话,库的源代码也可以参考.有了昨天的DriverW orks基本介绍,我想下面的代码应该不是很难懂吧!//Interface.h#ifndef __INTERFACE_H__#define __INTERFACE_H__#define DEVICE_NAME L"IoDemoDevice"#define FILE_DEVICE_IODEMO 0x8000#define IOCTL_DO_BUFFERED_IO \CTL_CODE(FILE_DEVICE_IODEMO,0x800,METHOD_BUFFE RED,FILE_ANY_ACCESS)#define IOCTL_DO_DIRECT_IN \CTL_CODE(FILE_DEVICE_IODEMO,0x801,METHOD_IN_DIRECT,FILE_ANY_ACCESS)#define IOCTL_DO_DIRECT_OUT \CTL_CODE(FILE_DEVICE_IODEMO,0x802,METHOD_OUT_DI RECT,FILE_ANY_ACCESS)#define IOCTL_DO_NEITHER_IO \CTL_CODE(FILE_DEVICE_IODEMO,0x803,METHOD_NEITHE R,FILE_ANY_ACCESS)#endif//IODemo.cpp#define VDW_MAIN#define DRIVER_FUNCTION_UNLOAD#define DRIVER_FUNCTION_CREA TE#define DRIVER_FUNCTION_CLOSE#define DRIVER_FUNCTION_CLEANUP#define DRIVER_FUNCTION_DEVICE_CONTROL#include "vdw.h"#include "Interface.h"class IoDemoDriver:public KDriver{SAFE_DESTRUCTORS;public:virtual NTSTA TUS DriverEntry(IN PUNICODE_STRING RegistryPath);virtual VOID Unload();};DECLARE_DRIVER_CLASS(IoDemoDriver,NULL)class IoDemoDevice:public KDevice{SAFE_DESTRUCTORS;public:IoDemoDevice();DEVMEMBER_DISPA TCHERS;};IoDemoDevice::IoDemoDevice():KDevice(){if (!NT_SUCCESS(m_ConstructorStatus)){DbgPrint(__FUNCTION__": Failed to create device MyDevice"); return;}}NTSTA TUS IoDemoDevice::Create(KIrp I){DbgPrint(__FUNCTION__":IRP 0x%08X\n",I); rmation()=0;plete(STA TUS_SUCCESS);return STA TUS_SUCCESS;}NTSTA TUS IoDemoDevice::Close(KIrp I){DbgPrint(__FUNCTION__":IRP 0x%08X\n",I); rmation()=0;plete(STA TUS_SUCCESS);return STA TUS_SUCCESS;}NTSTA TUS IoDemoDevice::CleanUp(KIrp I) {DbgPrint(__FUNCTION__":IRP 0x%08X\n",I); rmation()=0;plete(STA TUS_SUCCESS);return STA TUS_SUCCESS;}NTSTA TUS IoDemoDevice::DeviceControl(KIrp I) {DbgPrint(__FUNCTION__":IRP 0x%08X\n",I);switch(I.IoctlCode()){case IOCTL_DO_BUFFERED_IO:{DbgPrint(__FUNCTION__":IOCTL_DO_BUFFERED_IO\n",I); ULONG inputSize = I.IoctlInputBufferSize();ULONG outputSize = I.IoctlOutputBufferSize();PVOID inputBuffer = I.IoctlBuffer();PVOID outputBuffer = I.IoctlBuffer();//显示出传进来的字符串if(inputSize)DbgPrint("inputBuffer:%s",(char*)inputBuffer);//返回一个字符串char chDoBufferedIO[]="DO_BUFFERED_IO";strncpy((char*)outputBuffer,chDoBufferedIO,outputSize);rmation()=strlen(chDoBufferedIO);}break;case IOCTL_DO_DIRECT_IN:{DbgPrint(__FUNCTION__":IOCTL_DO_DIRECT_IN\n",I);KMemory Mem(I.Mdl());PUCHAR pBuffer = (PUCHAR) Mem.MapToSystemSpace(); ULONG writeSize = I.WriteSize();ULONG bytesSent = 0;if(writeSize)DbgPrint("pBuffer:%s",(char*)pBuffer);rmation()=0;}break;case IOCTL_DO_DIRECT_OUT:{DbgPrint(__FUNCTION__":IOCTL_DO_DIRECT_OUT\n",I); KMemory Mem(I.Mdl());PUCHAR pBuffer = (PUCHAR) Mem.MapToSystemSpace(); ULONG readSize = I.ReadSize();ULONG bytesRead = 0;if(readSize){char chDirectOut[]="DO_DIRECT_OUT";strncpy((char*)pBuffer,chDirectOut,readSize);rmation()=strlen(chDirectOut);}}break;case IOCTL_DO_NEITHER_IO:{DbgPrint(__FUNCTION__":IOCTL_DO_NEITHER_IO\n",I); ULONG inputSize = I.IoctlInputBufferSize();ULONG outputSize = I.IoctlOutputBufferSize();PVOID inputBuffer = I.IoctlType3InputBuffer();PVOID outputBuffer = erBuffer();//显示出传进来的字符串if(inputSize)DbgPrint("inputBuffer:%s",(char*)inputBuffer);//返回一个字符串char chDoNeitherIo[]="DO_NEITHER_IO";strncpy((char*)outputBuffer,chDoNeitherIo,outputSize);rmation()=strlen(chDoNeitherIo);}break;default:rmation()=0;plete(STA TUS_INV ALID_DEVICE_REQUEST);return STA TUS_INV ALID_DEVICE_REQUEST;}plete(STA TUS_SUCCESS);return STA TUS_SUCCESS;}NTSTA TUS IoDemoDriver::DriverEntry(IN PUNICODE_STRING RegistryPath){NTSTA TUS status = STATUS_SUCCESS;DbgPrint(__FUNCTION__":RegistryPath:%S\n",RegistryPath->Buf fer);IoDemoDevice* pDevice = new (DEVICE_NAME,FILE_DEVICE_UNKNOWN,DEVICE_NAME,0,DO_DIRECT_IO)IoDemoDevice();if (pDevice == NULL){status = STA TUS_INSUFFICIENT_RESOURCES;}else{status = pDevice->ConstructorStatus();if (!NT_SUCCESS(status)){delete pDevice;}elseDbgPrint(__FUNCTION__":Created IoDemoDevice!\n"); }return status;}VOID IoDemoDriver::Unload(){DbgPrint(__FUNCTION__);KDriver::Unload();}最后可以用我的小工具测试一下,Load驱动后可以点Content 按钮编辑数据包,也可以查看驱动返回的数据,显示方式是十六进制,注意根据IO控制代码的定义选择不同的Method,DeviceId 和ControlCode组合方式.个人感觉这个小工具还是比较好用的,呵呵!玩玩DriverW orks(三)-串行化IO请求周末实在不太想写我的数据库程序,又花了一个小时练习了一下DriverW orks里的排队IO请求模型,其实这和DDK中的模型基本上是一样的,因为参考了Programming the Microsoft Windows Driver Model里的一些代码,并且少看了DriverW orks关于排队IO的一句话,我还得到了一个BSOD,不过这个BSOD让我注意到了帮助文档上我没有注意到的地方,呵呵!废话不多说,来一个段代码!#define VDW_MAIN#define DRIVER_FUNCTION_UNLOAD#define DRIVER_FUNCTION_CREA TE#define DRIVER_FUNCTION_CLEANUP#define DRIVER_FUNCTION_CLOSE#define DRIVER_FUNCTION_READ#define DRIVER_FUNCTION_WRITE#define DRIVER_FUNCTION_STARTIO#define DRIVER_FUNCTION_DEVICE_CONTROL#include "vdw.h"//Begin Device Code/////////////////////////////////////////////////////// class CQueueDevice:public KDevice{SAFE_DESTRUCTORS;public:CQueueDevice();NTSTA TUS ComplateIrp(KIrp I);DEVMEMBER_DISPA TCHERS;DEVMEMBER_CANCELIRP(CQueueDevice,CancelIo);NTSTA TUS SerialRead(KIrp I);NTSTA TUS SerialWrite(KIrp I);NTSTA TUS SerialIoControl(KIrp I);};CQueueDevice::CQueueDevice():KDevice(L"CQueueDevice",FILE _DEVICE_UNKNOWN,L"CQueueDevice",0,DO_DIRECT_IO) {if(!NT_SUCCESS(ConstructorStatus())){DbgPrint(__FUNCTION__":Failed to Create Device\n");}}NTSTA TUS CQueueDevice::ComplateIrp(KIrp I){rmation()=0;plete(STA TUS_SUCCESS);return STA TUS_SUCCESS;}NTSTA TUS CQueueDevice::Create(KIrp I) {DbgPrint(__FUNCTION__"\n");return ComplateIrp(I);}NTSTA TUS CQueueDevice::CleanUp(KIrp I) {DbgPrint(__FUNCTION__"\n");return ComplateIrp(I);}NTSTA TUS CQueueDevice::Close(KIrp I) {DbgPrint(__FUNCTION__"\n");return ComplateIrp(I);NTSTA TUS CQueueDevice::DeviceControl(KIrp I) {DbgPrint(__FUNCTION__"\n");//排队并设置取消例程return QueueIrp(I,LinkTo(CancelIo));}NTSTA TUS CQueueDevice::Read(KIrp I){DbgPrint(__FUNCTION__"\n");//排队并设置取消例程return QueueIrp(I,LinkTo(CancelIo));}NTSTA TUS CQueueDevice::Write(KIrp I){DbgPrint(__FUNCTION__"\n");。

应用程序调用驱动的方式

应用程序调用驱动的方式

有两种方式可以让设备和应用程序之间联系:1.通过为设备创建的一个符号链;2.通过输出到一个接口WDM驱动程序建议使用输出到一个接口而不推荐使用创建符号链的方法。

这个接口保证PDO 的安全,也保证安全地创建一个惟一的、独立于语言的访问设备的方法。

一个应用程序使用Win32APIs来调用设备。

在某个Win32 APIs和设备对象的分发函数之间存在一个映射关系。

获得对设备对象访问的第一步就是打开一个设备对象的句柄。

用符号链打开一个设备的句柄为了打开一个设备,应用程序需要使用CreateFile。

如果该设备有一个符号链出口,应用程序可以用下面这个例子的形式打开句柄:hDevice = CreateFile(""""".""OMNIPORT3",GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ,NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL ,NULL);文件路径名的前缀“""."”告诉系统本调用希望打开一个设备。

这个设备必须有一个符号链,以便应用程序能够打开它。

有关细节查看有关Kdevice和CreateLink的内容。

在上述调用中第一个参数中前缀后的部分就是这个符号链的名字。

注意:CreatFile中的第一个参数不是Windows 98/2000中驱动程序(.sys文件)的路径。

是到设备对象的符号链。

如果使用DriverWizard产生驱动程序,它通常使用类KunitizedName来构成设备的符号链。

这意味着符号链名有一个附加的数字,通常是0。

例如:如果链接名称的主干是L“TestDevice”那么在CreateFile中的串就该是“"""".""TestDevice0”。

CAN驱动及使用流程

CAN驱动及使用流程

本文档基于于常青师兄的《流程090808.rtf》文档所做,和容其内有些不同,希望大家参照使用。

/************************* 步骤*****************************/1.添加CAN驱动(1)安装Tornado 2.2.1/VxWorks 5.5.1 for Pentium服务器和客户端,BSPs/Drivers for VxWorks 5.5.1: Pentium即可.将D:\软件备份\vxworks安装程序\can\target中的文件复制到F:\Tornado2.2\target 中.将D:\软件备份\vxworks安装程序\can\pid20中的文件复制到F:\Tornado2.2中.创建一个Bootable的Tornado工程,这时Tools菜单中会出现wnCAN选项->Build wnCAN Library,选择奔腾3gnu.(2)将Yanxiang-can压缩包中的文件对照文件名分别拷贝到对应的文件夹中,可用搜索法在安装目录中查找Yanxiang-can压缩包中的文件名:\target\h\CAN ->头文件所在位置\target\src\drv\CAN ->esd_pc104_200.C、hcan2.C、can_api.C、wncanDevIO.C、wnCAN.C、sja1000.C、i82527.C、shTahoeAmanda.C、msmcan.C、 esd_pci_200.C、shbiscayne.C、canFixedLL.C、canController.C、canBoard.C、Makefile。

\target\config\comps\src\CAN ->biscayne_cfg.C、esd_pc104_200_cfg.C、esd_pci_200_cfg.C、msmcan_pc104_cfg.C、ppc5xx_cfg.C、sys_esd_pci_200.c、tahoeamanda_cfg.c、wnCAN_show.c。

usb_modeswitch使用详解

usb_modeswitch使用详解

一、介绍USB_ModeSwitch是一种模式切换工具,用于控制具有“多种模式”的USB设备。

越来越多的USB设备(特别是高速WAN上网卡,它基于一些手机芯片,能够改变它们的USB连接模式)都会板载它们自己的MS Windows驱动程序,当首次插入电脑时,它们会被识别为一个闪存设备,然后开始安装存储于其中的驱动程序。

在安装完驱动程序之后(后面还需要再插拔一次),驱动程序就会再内部切换USB设备的连接模式,存储设备会消失(大多数情况下),然后会出现一个新的设备(例如,一个USB调制解调器)。

调制解调器制造商会“可选地”调用“ZeroCD (TM)”特性,因为它会消除对用于承载一个独立驱动程序载体的需求。

起初,这方面的东西没有任何形式的文档记录,而且也几乎没有任何Linux支持可用。

从好的方面来看,大多数已知的设备在两种模式下都可以工作,使用诸如“usb-storage”或“option”(一种经过优化的串行驱动程序,高速3G调制解调器的Linux标准)的Linux 驱动程序。

那么唯一的问题便是如何从存储设备切换至调制解调器设备,或者其他应该做的事情。

幸运的是,我们还有人类的理性、USB嗅探程序和“libusb”。

MS Windows的驱动程序存在通信被窃听的可能性,但是,在Linux或BSD变种系统的规则之下,可以隔离触发模式切换的命令或动作,并且可以复制相同的东西。

在“libusb”的有力帮助之下,USB_ModeSwitch可以从一个配置文件中获取重要的参数,然后完成全部的初始化和通信工作,这样便使得用户可以轻松地处理这个过程。

它主要是自动使用的—通过udev事件和规则—不需要任何用户操作便能完成模式切换。

但是它还可以作为一个命令行工具来运行,通常会在尝试使用某种未知设备时使用这种方式。

这个工具是大多数主流发型版的部件之一,你应当不用从源码包进行编译安装,除非运行时遇到问题,或者想要使用最新的版本。

“驱动程序在

“驱动程序在

“驱动程序在 DeviceHarddisk1 上检测到控制器错误”的解决⽅法故障现象:事件查看器显⽰类似如下1.驱动程序在 \Device\Harddisk0\D 上检测到控制器错误。

2.在 \Device\Ide\IdePort0 上检测到奇偶错误。

引起“驱动程序在 \Device\******* 上检测到控制器错误。

”的原因⼤致有以下⼏个⽅⾯:解决⽅法:⼀般先检测数据线或电源线和磁盘接触是否不良,再⽤磁盘修复软件检测并修复或尝试更新驱动或返回驱动。

请务必按照顺序进⾏如下检查:1。

请确定你使⽤了80芯的硬盘排线;确认硬盘数据线处在正常接触中;2。

连接磁盘的数据线或电源线出现松动,导致接触不良。

(把数据线或电源线拔出重插)3。

磁盘本⾝出现硬件问题,⽐如坏道等。

(⽤磁盘修复软件检测并修复)4。

磁盘驱动程序错误或者IDE控制器的驱动有问题,请确定主板的驱动已经正确安装(可以尝试更新驱动或返回驱动)5。

系统是否⾃⾏关闭了DMA模式。

请检查设备管理器⾥的IDE ATA/ATAPI 控制器,双击“主要IDE通道”和“次要IDE通道”在⾼级设置⾥查看当前传输模式是否变为了PIO模式?如果是,请按照以下步骤进⾏修改:1、单击“设备管理器”;.展开“IDE ATA/ATAPI 控制器”节点;双击您要为其恢复典型 DMA 传送模式的控制器;单击“驱动程序”选项卡;单击“卸载”。

2、当此过程完成后,重新启动您的计算机。

当 Windows 重新启动后,将重新枚举硬盘控制器,同时与该控制器相连的每个设备的传送模式将重置为默认值。

但这样只是把硬盘设备的传送模式重置为默认值,当我们再使⽤挂起系统时系统⼜会⾃⾏关闭DMA模式!所以我们还要做以下操作:A.单击“开始”,单击“运⾏”,键⼊ Regedit,然后单击“确定”。

B.在注册表中找到并单击以下项:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E96A-E325-11CE-BFC1-08002BE10318}\0001和HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E96A-E325-11CE-BFC1-08002BE10318}\0002C.在“编辑”菜单上,指向“新建”,然后单击“DWORD 值”。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
3通过设备指针去调用其他驱动程序
可以用IoGetDeviceObjectPointer函数通过设别名获得文件对象,而不是设备句柄。调用IoGetDeviceObjectPointer会使文件对象引用计数增加1,用完后可以用ObDerefernceObject减少引用计数值。用这个函数打开的设备得到的是文件对象,所以不能再用ZwReadFile和ZwWriteFile函数去读写设备,这个时候需要自己创建IRP,创建Irp的函数大至有4个,IoBuildSynchronousFsdRequest,IoBuildAsynchronousFsdRequest,IoBuildDeviceIoControlRequest,还有就是IoAllocateIrp!创建后调用IoGetNextIrpStackLocation,和IoCallDriver函数进行发送(这里有个问题,书上说IoCallDriver函数会使Irp堆栈向后移,必须用IoGetNextIrpStackLocation,IoSkipCurrentIrpStackLocation等函数使堆栈向前,我的理解是IoCallDriver函数需要的是下移个堆栈,因此需要这号链接是内核层与应用层的唯一识别路基。应用层想要打开设备,必须通过符号链接,同样内核层打开内核层设别也可以通过符号链接,可以利用ZwOpenSymbolicLinkObject函数得到符号链接句柄,然后使用ZwQuerySymbolicLinkObject得到设备名,有了设备名酒可以通过上面的方法打开设备。这里为什么要这样绕圈子呢,如果你是在应用层去控制一个驱动程序去打开另外一个驱动程序的时候,由于是应用层,是得不到那个驱动程序创建的设备名的,只能得到符号链接,这个时候就必须用这种方法。
驱动程序打开别的驱动程序创建的Device的几种方法
2010-09-03 20:44:40
标签:职场 程序 驱动 Device 休闲
1,最简单的也是最常用的应该是算ZwCreateFile,
跟应用程序API,CreateFile一样(其实CreateFile最终会调用ZwCreateFile,只不过一个事在应用层,一个是在内核层)来大打开一个设备,但是有一点不同,应用层当文件不存在时可以创建,但是ZwCreateFile仅仅是打开,不存在的时候就不创建(貌似跟这个名字不是很符合),打开方式有2中一种是同步打开,一种是异步打开!这个也跟应用层CreateFile一样不在累赘,打开设别后得到设备的句柄就可以读写该设备,也跟应用层读文件一样,ZwReadFile,或者ZwWriteFile,这2个函数会在目标设备创建相应的IRP,进行传递!同步打开的话没什么可以说的,会一直等到ZwReadFile/ZwWriteFile返回时才继续执行下去!异步打开的话就立即返回了,这里有2中方法来得到目标设备何时完成IRP,1是在跟应用程的ReadFile/WriteFile一样,他的其中一个参数是一个回调函数,当目标进程用IoCompleteRequest的时候会调用该回调函数,在回调函数设置事件,就可以得到何时结束IRP,比如:ZwReadFile(hDevice,NULL,CompleteRoutine,&event,&iostatus,NULL,0,&offset,NULL);再在次之前初始化event,事件为同步事件,CompleteRoutine是回调函数的地址,然后在回调函数中KeSetEvent((PKEVENT)context,IO_NO_INCREMENT,FALSE);就可以通知Read的Irp已经结束,WaitForSingleObject,阻塞消失!第二种方法是可以通过文件对象判断读取是否完成,打开一个设备会关联一个文件对象,利用ObReferenceObjectByHandle可以获得该文件对象指针。
4用ObReferenceObjectByName函数获得设备指针
ObReferenceObjectByName函数没有在DDK.h文件中声明,因此需要自己手动声明,同样用到的常量也学要手动声明,该函数可以得到设备对象的指针,他会增加设别对象的引用值,因此要用ObDereferenceObject减少引用值,
相关文档
最新文档