用DriverStudio开发USB驱动程序
很多写Windows Device Driver的开发人员基本上都是使用Windows DDK进行开发的。但是,现在也有不少人都开始借助一些辅助工具。笔者去年开始接触到DriverStudio,发现它真的是一个不错的开发工具,不仅写代码的时候思路清晰,而且和DDK的结合很好。
当然,也有很多人觉得用DriverStudio不够正宗,或者说不能很好的理解Windows Device Driver的架构。我感觉这就有点像MFC和SDK的关系,关于这个问题在很多地方都有争论,比如在万千新闻组上,就讨论了将近2个月。每个人都有自己的最爱,都有自己的习惯,只要你能把事情做好,我想用什么方法应该都是一样的。如果你已经习惯了用DDK开发,那完全还可以继续用下去;如果你觉得DriverStudio不错,那尝试用一个可以给你按照OOP概念来编程的工具有什么不好呢?
在驱动开发网上,经常看到有人询问一些关于DriverStudio的使用的问题。我正好很有幸用它作了几个驱动程序,包括VXD, KMD和WDM,稍微有点心得,因此想写下来给大家作一个小小的参考。如果其中有错误,欢迎大家给我指出,谢谢。
下面我就介绍一下用DriverStudio开发一个USB驱动程序的过程。这个USB设备有3个双向端点,每个端点的配置如下:
EP 类型 地址 buffer(Bytes)
0 IN/OUT Control 0x80/0x00 16/16
1 IN/OUT Bulk 0x81/0x01 16/16
2 IN/OUT Bulk 0x82/0x02 64/64
我们的驱动程序需要实现的功能就是控制设备上的LED灯的亮和灭,以及通过Endpoint 2对设备进行读写。
由于DriveStudio由几个部分组成,我们写这个驱动程序只要用到DriverWorks,因此下面我们就简称它为DW。在这里,我们假定读者已经正确的安装了DW,并且已经编译好了各个库文件。
1. 首先,我们通过快捷方式“Setup DDK and Start MSVC“来启动VC IDE。这个快捷方式所指向的程序,会进行一些必要的设置,然后再启动VC IDE,这样我们的程序就可以使用DDK和DW的头文件和库了。
2. 从VC IDE的菜单"DriverStudio"中选择"DriverWizard", 在如图1所示的对话框中, 写上项目名称. 在这里, 我们将这个项目称为: TEST, 所在的目录为D:\TEST. 然后点按钮"Next >".
图1
3. 在接下来的这个对话框中(如图2), 我们需要选择驱动程序的类型. 由于USB设备驱动程序是WDM类型的, 所以我们选择第二项并且点按钮"Next >".
图2
4. 在第3个对话框中(如图3), 选择我们的驱动程序所操作的总线类型. 这里, 我们选择USB. 在USB Vendor ID和USB Product ID中填入USB设备的VID和PID. 假定我们的USB设备的VID和PID分别是16进制的0471和1801. 然后点按钮"Next >". 关于VID和PID的规定请参考USB-IF的规范.
图3
5. 在接下来的对话框中(如图4), 我们需要加入Endpoint 1和Endpoint 2的定义. 由于在USB中规定Endpoint 0是必须存在的, 所以我们不需要对Endpoint 0进行定义. 点"Add..."按钮, 弹出一个如图5所示的对话框. 我们将它修改成如图6所示. 其中, 按照USB的规定, 对于端点, 它的地址是1; 按照前面说明的设备的特点, Endpoint 1的最大的包大小为16字节, 因此在"Max Transer Size"中填入16; Endpoint Name可以通过"Suggest Name"得到. 按照这些原则, 继续设置其他的配置, 以使对话框4变成如图7所示. 接下来, 继续按"Next >"按钮.
图4
图5
图6
图7
6. 在如图8所示的对话框中, 可以填入我们需要的Driver Class的名字和文件名. 一般我们不需要更改. 继续按"Next >"按钮.
图8
7. 在如图9所示的对话框中, 因为不需要给其他的驱动程序提供接口, 也不需要提供Flush功能, 所以不需要任何修改, 直接按"Next >"按钮.
图9
8. 在如图10所示的对话框中, 我们选择给端点2产生BULK Read的代码, 并且按"Next >"按钮. DW会给我们产生一套对端点2进行读的代码, 不用修改, 就可以直接使用.
图10
9. 在如图11所示的对话框中, 我们选择给端点2产生BULK Write的代码, 并且按"Next "按钮. 这样, DW也会给我们产生一套对端点2进行写的代码, 不用修改, 就可以直接使用.
图11
10. 对于如图12的对话框, 我们直接按"Next >"按钮. 这里是设置是否要将I/O请求排队, 在这里, 我们不需要排队.
图12
11. 在如图13所示的对话框中, 我们不需要创建任何注册表项, 所以直接按"Next >"按钮.
图13
12. 如图14所示的对话框, 是让我们设置一些驱动程序的属性, 比如接口, 缓冲区之类的. 一般的都可以使用缺省设置. 继续按"Next >"按钮.
图14
13. 在如图15所示的对话框中, 是让我们给驱动程序增加一些IOCTL接口. 我们只增加一个如图16所示的IOCTL来控制USB设备的LED灯. 然后按"Next >"按钮.
图15
图16
14. 在最后一个如图17所示的对话框中, 可以设置一些驱动程序的属性, 产生一个console测试程序. 按下"Finish"按钮, 就结束了Wizard.
图17
这样, 我们就创建好了一个基本的驱动程序, 下面来看看还要做哪些工作才可以和我们的设备以及上层的应用程序通讯.
把函数NTSTATUS TESTDevice::TEST_IOCTL_LED_Handler(KIrp I)改成如下面的样子:
NTSTATUS TESTDevice::TEST_IOCTL_LED_Handler(KIrp I)
{
NTSTATUS status = STATUS_INVALID_PARAMETER;
t << "Entering TESTDevice::TEST_IOCTL_LED_Handler, " << I << EOL;
__try
{
// TODO: Verify that the input parameters are correct
// If not, return STATUS_INVALID_PARAMETER
if(I.IoctlOutputBufferSize() || !I.IoctlBuffer() ||
(I.IoctlInputBufferSize() != sizeof(UCHAR)))
__leave;
// TODO: Handle the the ZBUARD_IOCTL_LED_ON request, or
// defer the processing of the IRP (i.e. by queuing) and set
// status to STATUS_PENDING.
PURB pUrb = m_Lower.BuildVendorRequest(
NULL, // transfer buffer
0, // transfer buffer size
0, // request reserved bits
(UCHAR)(*(PUCHAR)I.IoctlBuffer()), // request. 1 = LED_ON, 0 = LED_OFF
0 // Value
);
// transmit
status = m_Lower.SubmitUrb(pUrb, NULL, NULL, 5000L);
}
__finally
{
// TODO: Assuming that the request was handled here. Set I.Information
// to indicate how much data to copy back to the user.
I.Information() = 0;
I.Status() = status;
}
return status;
}
这个函数是控制LED灯的,它是通过USB Vendor Request来向设备传送的。其中,request=1的时候表示让LED亮,request=0的时候让LED灭。它是通过DeviceIoControl由上层应用程序传下来。
再看看读写部分,经过检查NTSTATUS TESTDevice::Read(KIrp I)和NTSTATUS TESTDevice::Write(KIrp I)可以发现,DW已经给我们写好了读写的代码,我们可以直接使用了。这些代码就是在上面的第8和第9步中产生的代码。
最后,修改编译一下DriverStudio产生的测试程序Test_TEST程序,我们就可以通过命令行来测试我们的驱动程序了。对于LED的控制,我们可以直观的在设备上看到,但对于读写的操作就需要和firmware程序配合,这已经超出了本文的范围,不在这里讨论了。
通过上面的讲解,我们可以看到有了DriverStudio,就可以快速的产生一个驱动程序,然后在里面作一些小的改动就可以使用了。即使是写一个比较复杂的USB驱动程序,我们也可以不用管一些系统的IRP处理,只要专注于我们自己的特定应用就可以了。而且它把一个驱动程序概括成几个类的概念,并且DW还附带有一些很有用的STL类,在VC IDE里面有了一个很清晰直观的表示。这样,对一些从上层应用转向驱动程序的开发人员,或者一些对C++/OOP很熟悉但不太了解系统内核的开发人员,都比较容易上手。即使对于推崇直接用DDK编程的人来说,通过阅读DriverStudio附带的源代码,也可以对驱动程序的开发有一个更加深入的了解
用DriverStudio开发USB驱动程序的更多相关文章
- USB2.0学习笔记连载(三):通用USB驱动程序解析
对于USB驱动的开发,读者可以使用Windows DDK.DriverStudio等多种开发工具来实现USB的驱动,但是驱动程序的开发过程都比较复杂,而且很容易致使USB主机内存泄露而死机.那么对于笔 ...
- 驱动07.USB驱动程序
1 了解USB识别的过程 eg:在Windows系统下的一个现象:把手机的USB设备接到PC 1. 右下角弹出"发现android phone" 2. 跳出一个对话框,提示你安装驱 ...
- 获取 Google USB 驱动程序
获取 Google USB 驱动程序 另请参阅 安装 USB 驱动程序 使用硬件设备 使用任何 Google Nexus 设备进行 ADB 调试时,只有 Windows 需要 Google ...
- USB驱动程序之USB设备驱动程序1简单编写
1.驱动编写分析 (1)usb总线驱动程序在我们接入USB设备的时候会帮我们构造一个新的usb_device.注册到总线里面来.左边这一块已经帮我们做好了,我们要做的是右边这一块.我们要构造一个usb ...
- USB驱动程序之USB总线驱动程序学习笔记
USB总线驱动程序的作用 1. 识别USB设备 1.1 分配地址 1.2 并告诉USB设备(set address) 1.3 发出命令获取描述符 描述符的信息可以在include\linux\usb\ ...
- usb驱动程序小结(六)
title: usb驱动程序小结 tags: linux date: 2018/12/20/ 17:59:51 toc: true --- usb驱动程序小结 linux中为usb驱动也提供了一套总线 ...
- USB驱动程序之概念介绍学习笔记
现象:把USB设备接到PC 1. 右下角弹出"发现android phone" 2. 跳出一个对话框,提示你安装驱动程序 问1. 既然还没有"驱动程序",为何能 ...
- USB驱动程序涉及的概念及框架
引入:当我们把一个USB设备接入PC机时,会出现什么样的现象? 现象:把USB设备接到PC1.右下角弹出“发现android phone”2.跳出一个对话框,提示你安装驱动程序 首先来看一下,USB驱 ...
- LDD3 第13章 USB驱动程序
通用串行总线(USB)是主机和外围设备之间的一种连接.最新USB规范修订增加了理论上高达480Mbps的高速连接. 从拓扑上看,USB子系统并不是以总线的方式来布置的,它是一颗由几个点对点的连接构建而 ...
随机推荐
- linux下iptables配置模板
linux下iptables配置模板 # Flush all policy iptables -F iptables -X iptables -Z iptables -t nat -F iptable ...
- PHP正则匹配与文件编码关系
虽然多数高手认为正则会影响程序效率,但是做数据采集的时候,却很难避免使用正则, 强大的正则表达式用起来很舒服,但是在匹配中文的时候,会出现,明明正则表达式没问题,字符数据里包含符合正则表达式的数据,可 ...
- 【OCR技术系列之三】大批量生成文字训练集
放假了,终于可以继续可以静下心写一写OCR方面的东西.上次谈到文字的切割,今天打算总结一下我们怎么得到用于训练的文字数据集.如果是想训练一个手写体识别的模型,用一些前人收集好的手写文字集就好了,比如中 ...
- vsftpd安装和使用 Linux系统和window系统
vsftpd 安装(Linux)一.安装系统环境 centos 6.9 64位二.vsftpd版本 vsftpd-2.2.2-24.el6.x86_64三.安装步骤1.安装 执行 yum -y ins ...
- dubbo中Listener的实现
这里继续dubbo的源码旅程,在过程中学习它的设计和技巧,看优秀的代码,我想对我们日程编码必然有帮助的.而那些开源的代码正是千锤百炼的东西,希望和各位共勉. 拿ProtocolListenerWrap ...
- 洛谷 [P2825] 游戏
二分图匹配的匈牙利算法 这道题,如果没有硬石头的限制,那么就与ZJOI 2007矩阵游戏完全一样,但是如果有了硬石头的限制,我们就不能将整行整列作为元素建图,我们可以以硬石头为边界,将每一行.每一列分 ...
- 让XtraMessageBox按钮显示中文
需要定义一个继承子Localizer的类,然后重写GetLocalizedString public class MessboxClass : Localizer { public override ...
- 使用sed修改配置项的值
起先我的想法是根据等号来求得配置项所在的行号, sed -n '/aaa/=' config.ini 然后根据行号删除这一行,再增加一行比如行号是9 sed -i '9d' config.ini s ...
- 剑指offer试题(PHP篇四)
16.合并两个排序的链表 题目描述 输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则. 时间限制:1秒 空间限制:32768K <?php /*c ...
- Promise对象的简单用法
要了解一个东西,首先要从,它是什么.用来做什么以及怎么取用它这三个方面来了解. 首先,promise是什么? 我们来参考一下MDN对它的定义: Promise 对象用于一个异步操作的最终完成(或失败) ...