驱动入口函数
- 格式:doc
- 大小:30.00 KB
- 文档页数:4
现在介绍在windows XP下开发虚拟串口的方法。
可以开发一个虚拟串口,将读写请求传递给USB驱动,这样就可以利用现成的串口调试工具向USB设备读取了。
1、DDK串口开发框架DDK对串口驱动提供了专门接口。
只要编写的驱动满足这些接口,并按照串口标准的命名方法,不管是真实的串口设备,还是虚拟设备,Windows操作系统都会认为这个设备是一个标准的串口设备。
用标准的串口调试工具都可以与这个设备进行通信。
1、1 串口驱动的入口函数本章的实例程序是在HelloWDM驱动的基础上修改而来,入口函数依然是DriverEntry,在DriverEntry函数中指定各种IRP的派遣函数,以及AddDevice 例程、卸载例程等。
[cpp]view plaincopy1./************************************************************************2.* 函数名称:DriverEntry3.* 功能描述:初始化驱动程序,定位和申请硬件资源,创建内核对象4.* 参数列表:5. pDriverObject:从I/O管理器中传进来的驱动对象6. pRegistryPath:驱动程序在注册表的中的路径7.* 返回值:返回初始化驱动状态8.*************************************************************************/9.#pragma INITCODE10.extern"C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,11. IN PUNICODE_STRING pRegistryPath)12.{13. KdPrint(("Enter DriverEntry\n"));14.15. pDriverObject->DriverExtension->AddDevice = HelloWDMAddDevice;16. pDriverObject->MajorFunction[IRP_MJ_PNP] = HelloWDMPnp;17. pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HelloWDMDispatchControlp;18. pDriverObject->MajorFunction[IRP_MJ_CREATE] = HelloWDMCreate;19. pDriverObject->MajorFunction[IRP_MJ_CLOSE] = HelloWDMClose;20. pDriverObject->MajorFunction[IRP_MJ_READ] = HelloWDMRead;21. pDriverObject->MajorFunction[IRP_MJ_WRITE] = HelloWDMWrite;22. pDriverObject->DriverUnload = HelloWDMUnload;23.24. KdPrint(("Leave DriverEntry\n"));25.return STATUS_SUCCESS;26.}其中在AddDevice例程中,需要创建设备对象,这些都是和以前的HelloWDM驱动程序类似。
密级状态:绝密()秘密()内部(√)公开()RK平台Realtek WiFi驱动移植说明(系统产品一部)文件状态:[]正在修改[√]正式发布当前版本:V1.0作者:胡卫国完成日期:2015-03-13审核:完成日期:福州瑞芯微电子有限公司Fuzhou Rockchips Semiconductor Co.,Ltd(版本所有,翻版必究)版本历史版本号作者修改日期修改说明备注V1.0胡卫国2015-03-13初始版本目录1REALTEK驱动基本情况说明 (2)2WIFI驱动移植 (3)2.1WIFI驱动入口函数 (3)2.2电源控制及SDIO识别操作 (4)2.3M AKEFILE配置修改 (5)2.4使用自定义W I F I MAC地址 (6)3BT固件更新 (7)1Realtek驱动基本情况说明Realtek系列WiFi BT芯片,如RTL8188EU,RTL8189ES,RTL8723系列,驱动移植包都是类似的目录结构,驱动代码目录结构也类似。
以RTL8188EUS_RTL8189ES_linux_v4.1.8_9499.20131104.zip为例解压之后里面包含文档、驱动源码包、android reference代码等内容,具体如下:Android部分RK一般都已经移植好集成到SDK中,由于Realtek驱动更新比较频繁,所以客户最常遇到的事情就是更新WiFi驱动。
2WiFi驱动移植可对比SDK Kernel中已经移植好的驱动与Realtek的驱动进行合并。
驱动在以下目录drivers/net/wireless/rockchip_wlan/针对kernel3.10版本drivers/net/wireless/针对kernel3.0版本2.1wifi驱动入口函数Realtek提供的驱动入口函数为:module_init(rtw_drv_entry);module_exit(rtw_drv_halt);在以下文件中:os_dep\linux\sdio_intf.c针对sdio接口wifios_dep\linux\usb_intf.c针对usb接口wifiRK平台做了稍微修改,主要是为了增加RK版本信息打印及wifi gpio电源控制,启动sdio 识别。
接触windows驱动开发有一个月了,感觉Windows驱动编程并不像传说中的那么神秘。
为了更好地为以后的学习打下基础,记录下来这些学习心得,也为像跟我一样致力于驱动开发却苦于没有门路的菜鸟朋友们抛个砖,引个玉。
我的开发环境:Windows xp 主机+ VMW ARE虚拟机(windows 2003 server系统)。
编译环境:WinDDK6001.18002。
代码编辑工具:SourceInsight。
IDE:VS2005/VC6.0。
调试工具:WinDBG,DbgView.exe, SRVINSTW.EXE上面所有工具均来自互联网。
对于初学者,DbgView.exe和SRVINSTW.EXE是非常简单有用的两个工具,一定要装上。
前者用于查看日志信息,后者用于加载驱动。
下面从最简单的helloworld说起吧。
Follow me。
驱动程序的入口函数叫做DriverEntry(PDRIVER_OBJECT pDriverObj,PUNICODE_STRING pRegisgryString)。
两个参数,一个是驱动对象,代表该驱动程序;另一个跟注册表相关,是驱动程序在注册表中的服务名,暂时不用管它。
DriverEntry 类似于C语言中的main函数。
它跟main的差别就是,main完全按照顺序调用的方法执行,所有东西都按照程序员预先设定的顺序依次发生;而DriverEntry则有它自己的规则,程序员只需要填写各个子例程,至于何时调用,谁先调,由操作系统决定。
我想这主要是因为驱动偏底层,而底层与硬件打交道,硬件很多都是通过中断来与操作系统通信,中断的话就比较随机了。
但到了上层应用程序,我们是看不到中断的影子的。
说到中断,驱动程序中可以人为添加软中断,__asm int 3或者Int_3();前者是32位操作系统用的,后者是64位用的。
64位驱动不允许内嵌汇编。
下面是我的一个helloworld的源码:注意第16行的宏。
DDK驱动开发笔记1、windows驱动分为NT式驱动和WDM式驱动,前者为非即插即用,后者为即插即用驱动。
需要头文件分别为NTDDK.h和WDM.h2、驱动的入口函数均为extern "C" NTSTA TUS DriverEntry(IN PDRIVER_OBJECTpDriverObject, IN PUNICODE_STRING pRegistryPath),它由I/O管理器负责调用,前参数为传递进来的驱动对象,后参数为Unicode字符串,指向此驱动的注册表。
3、驱动程序向windows的I/O管理器注册一些回调函数,回调函数是由程序员定义的函数,由操作系统负责调用,只要把地址告诉操作系统即可如:pDriverObject->DriverUnload=HelloDDKUnload;4、使用CreateDevice函数创建驱动设备对象如:CreateDevice(pDriverObject);返回NTSTATUS类型5、KdPrint是一个宏,用于打印输出信息,在Checked中会使用DbgPrint代替,在Free版本中无效果,用法和TRACE一致。
6、Windows的设备管理是使用线性链表进行管理,每一个节点记录了设备对象的地址,每次要对指定驱动进行操作,就必须先遍历设备对象链表。
7、设备对象函数NextDevice域记录下一个设备对象的地址,IoDeleteDevice用于删除设备对象如:IoDeleteDevice(pDevExt->pDevice),IoDeleteSymbolicLink用于删除设备符号链接。
8、DDK环境编译驱动源程序,需要使用两个自己创建的脚本makefile和Sources,最好使用二进制文本格式,makefile的内容固定为:!INCLUDE $(NTMAKEENV)\makefile.def。
sources文件记录了驱动的名称、驱动类型、编译输出目录、include目录、指定源文件。
kmdf 驱动开发实例驱动开发是通过编写内核模块来与操作系统进行交互的一种技术。
而在Windows操作系统中,驱动开发的一种常见框架是Kernel-Mode Driver Framework(KMDf)。
本篇文章将以KMDf驱动开发实例为主题,逐步解释该实例的步骤和过程。
第一步:准备环境和工具在进行KMDf驱动开发之前,首先需要准备好相应的环境和工具。
这包括一台运行Windows的计算机、安装好Windows Driver Kit(WDK)和Visual Studio等开发工具。
第二步:创建驱动项目打开Visual Studio,选择新建项目(New Project),在模板(Templates)中找到"Kernel Mode Driver (KMDF)",然后填写项目名称和所需的目标Windows版本等信息。
这样就创建了一个KMDf驱动项目。
第三步:配置驱动项目在创建驱动项目后,需要对其进行配置。
这包括设置编译选项、指定目标平台、选择所需的驱动框架版本等。
配置完成后,可以开始编写驱动代码。
第四步:编写驱动代码在KMDf驱动项目中,主要的代码文件是驱动的入口点(DriverEntry),该函数在驱动加载时被调用。
在该函数中,可以进行一些初始化操作,如注册驱动、创建设备对象、为设备对象添加I/O回调函数等。
接下来,可以根据实际需求,编写其他的驱动逻辑代码。
例如,可以添加设备控制代码、I/O处理代码、定时器代码等。
这些代码将在驱动运行时被调用,以实现相应的功能。
第五步:编译和生成驱动在编写完驱动代码后,可以进行编译和生成驱动。
在Visual Studio中,选择生成解决方案(Build Solution),这将会将源代码编译成二进制文件。
生成的驱动文件会放置在指定的输出目录中。
第六步:安装和加载驱动生成驱动文件后,需要将其安装到操作系统中并加载。
在Windows中,可以使用DevCon等命令行工具来完成这一步骤。
在驱动中调用其它驱动的函数(fastcall)--作者:赖玉平(Auly)aulyp@在嵌入式系统中,一些通信口是公用的,如IIC口,串口等,这些口的驱动一般OEM厂商会帮写好驱动,而且这些驱动是经过测试的,比较稳定,我们在开发其它要用到这些通信口的设备的驱动时,没有必要另外去写一个IIC驱动,只要调用一次相应的IOCtrol就可以像使用自已的函数那样使用相关的操作了,方法:(1)声明一个fastcall变量I2C_FASTCALL fc; // I2C Fastcall driver-to-driver entrypoints(2)在驱动的XXX_Init打开IIC驱动hI2C = CreateFile( L"I2C0:",GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL, OPEN_EXISTING, 0, 0);(3)精髓部份:if ( !DeviceIoControl(hI2C, IOCTL_I2C_GET_FASTCALL,NULL, 0,&fc, sizeof(fc),&bytes, NULL) ){dwErr = GetLastError();return NULL;}经过上面的动作,本驱动就可以很方便地使用IIC驱动里面的Read,Write等函数了(4)例如,实现IIC 读操作// use the driver-to-driver callretVal = (short int)fc.I2CRead(fc.Context,SlaveAddr,// SlaveAddress((PI2C_IO_DESC)lpBuffer)->WordAddr, // WordAddresspuc,((PI2C_IO_DESC)lpBuffer)->Count);fc.I2CRead 这就是调用了IIC驱动里对应的HW_Read函数;写操作也是同样用法:retVal = (short int)fc.I2CWrite(fc.Context,SlaveAddr, // SlaveAddressWordAddr, // WordAddressWriBuffer,1);原理:为什么只通过一次DeviceIoControl()就能实现使用目标驱动里的函数呢?原因是在IIC的驱动里面,I2C_IOControl里面提供了IOCTL_I2C_GET_FASTCALL的接口,在该接口里,给外部调用映射了两个函数的空间:((PI2C_FASTCALL)pBufOut)->I2CRead = HW_Read;((PI2C_FASTCALL)pBufOut)->I2CWrite = HW_Write;这就是精妙所在了。
摘自/szh_515/blog/static/29076175200941811218677/TI公司为开发DSP的外设驱动程序,推出了DSP/BIOS Device Driver Kit(DDK),定义了标准的设备驱动模型,并提供了一系列的API接口。
外设驱动程序分为两层:①类驱动(class driver)。
类驱动程序用来为应用程序提供接口。
这部分程序与设备无关,主要功能包括维护设备数据缓冲区,向上提供API接口供应用层程序调用,并协调应用程序对外设操作的同步和阻塞;向下提供适配层与迷你驱动层相连,实现API接口函数到迷你驱动层程序的映射。
类驱动程序与硬件无关,只要外设驱动模型选定了,类驱动程序就定下来了,不需要做多少修改。
②迷你驱动(mini driver)。
迷你驱动程序与设备相关,所以设计迷你驱动程序是外设驱动开发中的重点。
迷你驱动程序与类驱动层的接口格式是统一的,但迷你驱动程序对底层硬件的操作是根据硬件平台的不同而变化的。
迷你驱动接收类驱动层发出的IOM_Packet命令包,决定对底层硬件进行什么样的操作。
外设驱动程序模型又可以分为以下3类:①PIP/PIO模型。
基于数据管道的I/O模型,每个管道都在维护自己的一个缓冲区。
当数据写入缓冲区,或从缓冲区取出数据时,便会激发notifyReader()和notifyWriter()函数实现数据的同步。
②SIO/DIO模型。
基于数据流的I/O模型,一个数据流是单向的,要么是输入,要么是输出,而且SIO/DIO模型使用异步方式来操作I/O,对于数据的读写、处理可以同时进行。
③GIO模型。
通用的I/O模型,灵活性很强,且没有适配层,直接操作迷你驱动程序,主要用来设计新型的设备驱动模型。
比较PIO、SIO和GIOPIO支持更底层的通信,适合设计比较简单的外设驱动程序。
例如在TI公司的6X11DSK板上实现的音频采集和回放,一般都是基于PIO模型的。
i2c驱动程序总结I2C驱动程序总结由于6410没有合适的i2c参考驱动,本总结主要基于TQ2440的AT24C02⼀、TQ2440电路⼆、I2c驱动程序分析1写⼊⼝函数at24cxx_init()在⼊⼝函数中主要有⼀个增加设备驱动的函数i2c_add_driver(),该函数会调⽤i2c_register_driver(THIS_MODULE, 驱动名字)完成注册。
2写出⼝函数at24cxx_exit()在出⼝函数⾥主要有⼀个删除设备驱动的函数i2c_del_driver(),这个函数功能有从设备驱动链表中删除驱动,卸载注册的驱动等3修饰⼊⼝函数和出⼝函数module_init(at24cxx_init); 这样,使⽤insmod命令加载驱动模块时,⼊⼝函数at24cxx_init()就会被调⽤module_exit(at24cxx_exit); 这样,使⽤rmmod命令加载驱动模块时,⼊⼝函数at24cxx_exit()就会被调⽤4写I2C驱动主要是:分配⼀个i2c_driver结构体设置填充i2c_driver结构体注册(前⾯1、2、3步)staticstruct i2c_driver at24cxx_driver={.driver = {.name = “at24cxx”,}.attach_adapter = at24cxx_attach,.detach_client = at24cxx_detach};函数at24cxx_attach()和at24cxx_detach需要⾃⼰构造5构造at24cxx_attach()函数和at24cxx_detach()函数Static int at24cxx_attach(struct i2c_adapter *adapter){return i2c_probe(adapter,&addr_data,at24cxx_detect);}I2c_probe函数主要是通过适配器adapter发送结构体addr_data的地址,这个地址就是i2c设备的地址,需要⾃⼰根据硬件原理图定义的,如果收到回应,就是说有这个i2c设备,就调⽤at24cxx_detect处理,这个函数需要⾃⼰去构造的。
这个驱动程序包含了三个函数:DriverEntry、HelloDDKUnload和HelloDDKDispatchRoutine。
其中DriverEntry是驱动程序的入口函数,相当于C/C++程序的main函数,HelloDDKUnload函数是驱动卸载函数。
而HelloDDKDispatchRuntine则是IRP的派遣函数,因为驱动程序主要是处理IO 请求,而IO请求大多是在派遣函数中处理的。
先来看看这个驱动程序的第一个函数:DriverEntry
/****************************************************************
* 函数名称:DriverEntry
* 功能描述:初始化驱动程序,定位和申请硬件资源,创建内核对象
* 参数列表:
pDriverObject:从I/O管理器中传来的驱动对象
pRegistryPath:驱动程序在注册表中的路径
* 返回值:返回初始化驱动状态
****************************************************************/
#pragma INITCODE
extern "C" NTSTATUS DriverEntry( IN PDRIVER_OBJECT pDriverObject,
IN PUNICODE_STRING pRegistryPath )
{
NTSTATUS status;
KdPrint( ( "Enter DriverEntry!\n" ) );
//注册其它驱动调用函数入口
pDriverObject->DriverUnload = ( PDRIVER_UNLOAD ) HelloDDKUnload; pDriverObject->MajorFunction[IRP_MJ_CREATE] = HelloDDKDispatchRoutine; pDriverObject->MajorFunction[IRP_MJ_CLOSE] = HelloDDKDispatchRoutine; pDriverObject->MajorFunction[IRP_MJ_WRITE] = HelloDDKDispatchRoutine; pDriverObject->MajorFunction[IRP_MJ_READ] = HelloDDKDispatchRoutine;
//创建驱动设备对象
status = CreateDeivce( pDriverObject );
KdPrint( ( "DriverEntry end!\n" ) );
return status;
}
这个函数的第一句代码是一个#pragma预处理指令:
#pragma INITCODE
这段代码表明将此函数加入INIT内存区域。
在函数头中的“extern "C"”是指定编译器的编译方式,若不加此修饰,编译器则会按C++的编译方式来编译,会导致编译错误。
NTSTATUS是函数的返回状态,用来检测函数的状态是否正确,常用的NTSTATUS 值有:
#define STATUS_SUCCESS
#define STATUS_BUFFER_OVERFLOW
#define STATUS_UNSUCCESSFUL
#define STATUS_NOT_IMPLEMENTED
#define STATUS_ACCESS_VIOLATION
#define STATUS_INVALID_HANDLE
#define STATUS_INVALID_PARAMETER
接着是函数参数中的IN修饰,该修饰是定义参数的类型,“IN”修饰表示是一个输入参数,“OUT”修饰表示是一个输出参数,“INOUT”修饰表示是一个输入输出参数。
接下来就得了解了解驱动程序中的第一个结构体:PDRIVER_OBJECT,该结构体我在帮助文档里找了半天也没找到,最后在“wdm.h”中找到了其定义:
typedef struct _DRIVER_OBJECT {
CSHORT Type;
CSHORT Size;
PDEVICE_OBJECT DeviceObject;
ULONG Flags;
PVOID DriverStart;
ULONG DriverSize;
PVOID DriverSection;
PDRIVER_EXTENSION DriverExtension;
UNICODE_STRING DriverName;
PUNICODE_STRING HardwareDatabase;
PFAST_IO_DISPATCH FastIoDispatch;
PDRIVER_INITIALIZE DriverInit;
PDRIVER_STARTIO DriverStartIo;
PDRIVER_UNLOAD DriverUnload;
PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];
} DRIVER_OBJECT;
typedef struct _DRIVER_OBJECT *PDRIVER_OBJECT;
该结构体共有15个成员,这个结构体表示的是一个驱动对象,是驱动的一个实例,类似于用户模式下的线程句柄一类。
该对象在DriverEntry函数中被始化,然后由内核中的I/O管理器来加载,确切的加载函数是IoCreateDevice。
下面要说说该结构体中的几个重要成员:
DeviceObject:这是一个设备对象的结构体。
一个驱动程序会创建多个设备对象,每个设备对象都有指向下一个设备对象的指针,最后一个设备象的指针为空。
此处的DeviceObject指向驱动程序的第一个设备对象,
DriverName:驱动名称。
其数据类型为UNICODE_STRING,该字符串一般为“\\driver\\[驱动名称]”,UNICODE_STRING字符串的赋值用RtlInitUnicodeString函数。
DriverUnload:指定驱动卸载时使用的回调函数地址。
MajorFunction:该成员是一个PDRIVER_DISPATCH结构体组数指针,其定义如下:
__drv_functionClass(DRIVER_DISPATCH)
__drv_requiresIRQL(PASSIVE_LEVEL)
__drv_sameIRQL
typedef
NTSTATUS
DRIVER_DISPATCH (
__in struct _DEVICE_OBJECT *DeviceObject,
__inout struct _IRP *Irp
);
typedef DRIVER_DISPATCH *PDRIVER_DISPATCH;
每个指针指向一个函数,这个函数就是处理IRP的派遣函数。
FastIoDispatch:文件驱动中用到的派遣函数。
派遣函数相当于WIN32子系统下的事件响应函数,驱动程序的主要功能是负责处理IO请求,而绝大多数的IO请求是在派遣函数中处理的。
关于IRP派遣函数的相关解释另作笔记。
在PDRIVER_OBJECT中有一个PDEVICE_OBJECT成员,下面再来说说这个结构体,其定义在“wdm.h”中。
该结构体保存的是设备对象指针链表,其成员包含了当前设备对象指针和下一个设备对象指针。
在卸载驱动时要遍历驱动程序的所有设备对象,并用IoDeleteDevice来删除所有设备对象。
好了,再来看看DriverEntry的函数体,在对以上的几个概念作了了解后,函数体的作用就容易理解了。
函数体只有两个功能,一是初始化DRIVER_OBJECT结构体,二是创建设备对象。
糊里糊涂的写完了这篇笔记,没想一个只有十来行的驱动函数涉及的内容居然如此之多。
虽然还是云里雾里的,但对驱动对象PDRIVER_OBJECT还是有了一点了解,在下一篇笔记中再来好好研究研究CreateDevice函数。
在敲这第一个驱动程序的代码时,老把Driver和Device敲错,到不是不知道这两个单词的意思,只是不知道在哪些地方该用驱动对象(DRIVER_OBJET),哪些地方用设备对象(DEVICE_OBJECT)。