开发usb驱动程序的方法

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

开发驱动程序的方法(连载一)
开始驱动程序设计
下面的文字是从的帮助中节选出来的,它让我们明白在开始设计驱动程序应该注意些什么问题,这些都是具有普遍意义的开发准则。

应该支持哪些请求在开始写任何代码之前,应该首先确定我们的驱动程序应该处理哪些例程。

如果你在设计一个设备驱动程序,你应该支持和其他相同类型设备的驱动程序相同的和请求代码。

如果你是在设计一个中间层驱动程序,应该首先确认你下层驱动程序所管理的设备,因为一个高层的驱动程序必须具有低层驱动程序绝大多数例程入口。

高层驱动程序在接到请求时,在确定自身当前堆栈单元参数有效的前提下,设置好中下一个低层驱动程序的堆栈单元,然后再调用将请求传递给下层驱动程序处理。

一旦决定好了你的驱动程序应该处理哪些,就可以开始确定驱动程序应该有多少个例程。

当然也可以考虑把某些处理的例程合并为同一例程处理。

例如在和里,对和处理的例程就是同一函数。

对和处理的例程也是同一个函数。

应该有多少个对象?
一个驱动程序必须为它所管理的每个可能成为请求的目标的物理和逻辑设备创建一个命名对象。

一些低层的驱动程序还可能要创建一些不确定数目的对象。

例如一个硬盘驱动程序必须为每一个物理硬盘创建一个对象,同时还必须为每个物理磁盘上的每个逻辑分区创建一个对象。

一个高层驱动驱动程序必须为它所代表的虚拟设备创建一个对象,这样更高层的驱动程序才能连接它们的对象到这个驱动程序的对象。

另外,一个高层驱动程序通常为它低层驱动程序所创建的对象创建一系列的虚拟或逻辑对象。

尽管你可以分阶段来设计你的驱动程序,因此一个处在开发阶段的驱动程序不必一开始就创建出所有它将要处理的所有对象。

但从一开始就确定好你最终要创建的所有对象将有助于设计者所要解决的任何同步问题。

另外,确定所要创建的对象还有助于你定义对象的的内容和数据结构。

开始驱动程序开发
驱动程序的开发是一个从粗到细逐步求精的过程。

的\ 目录下有一个庞大的样板代码,几乎覆盖了所有类型的设备驱动程序、高层驱动程序和过滤器驱动程序。

在开始开发你的驱动程序之前,你应该在这个样板库下面寻找是否有和你所要开发的类似类型的例程。

例如我们所开发的驱动程序,虽然对描述得不是很详细,我们还是可以在\\目录发现很多和设备有关的驱动程序。

下面我们来看开发驱动程序的基本步骤。

最简的驱动程序框架
、写一个例程,在里面调用创建一个对象。

、写一个处理请求的例程的基本框架 (参见 4.4.3描述的一个例程所要完成的最基本工作。

当然写了例程后,要在例程为初始化例程入口)。

如果驱动程序创建了多于一个对象,则必须为请求写一个例程,该例程通常情况下可以和共用一个例程,参见参见。

、编译连接你的驱动程序。

用下面的方法来测试你的驱动程序。

首先按上面介绍的方法安装好驱动程序。

其次我们还得为逻辑设备名称和目标对象名称之间建立起符号连接,我们在前面已经知道对象名称对用户模式是不可见的,是不能直接通过来访问的,只能访问逻辑设备名称。

我们可以通过修改注册表来建立这两种名称之间的符号连接。

运行在\\ \ \\ \ 下建立起符号连接(这种符号连接也可以在驱动程序里调用函数来创建)。

重新启动系统。

编写一个简单的测试程序调用函数以刚才你命名的逻辑设备名打开这个设备。

如果打开成功,那么你也就成功地写出了一个最简单的驱动程序了。

支持更多的设备请求
例如你的驱动程序可能需要对请求做出响应(完成后可用函数进行测试)。

如果你的驱动程序需要能够手工卸载,那么还必须对做出响应。

为你所需要处理写好处理例程,并在里面初始化好这些例程入口。

一个低层的驱动程序可能需要最起码一个,和例程,可能需要一个例程,如果设备使用了,那么可能还需要一个例程。

关于这些例程,请参考相应文档。

对于高层驱动程序可能需要一个或多个例程,最起码完成检查状态块然后调用的工作。

如果需要,还要对数据结构和内容做些修改
开发驱动程序的方法(连载二)
还有更多其他的对象,例如中断对象、对象、定时器对象等等,但在我们开发的驱动程序中并没有用到,因此在这里不做介绍。

缓冲策略
很明显的,驱动程序和客户应用程序经常需要进行数据交换,但我们知道驱动程序和客户应用程序可能不在同一个地址空间,因此操作系统必须解决两者之间的数据交换。

这就就设计到设备的缓冲策略。

读写请求的缓冲策略
前面说到通过设置对象的可以选择控制处理读写请求的缓冲策略。

下面对这些缓冲策略分别做一介绍。

、缓冲()
在读写请求的一开始,管理器检查用户缓冲区的可访问性,然后分配与调用者的缓冲区一样大的非分页池,并把它的地址放在的域中。

驱动程序就利用这个域来进行实际数据的传输。

对于读请求,管理器还把的域设置成调用者缓冲区的用户空间地址。

当请求完成时,管理器利用这个地址将数据从驱动程序的系统空间拷贝回调用者的缓冲区。

对于写请求,被设置为,并把用户缓冲区的数据拷贝到系统缓冲区中。

、直接()
管理器首先检查用户缓冲区的可访问性,并在物理内存中锁定它。

然后它为该缓冲区创建一个内存描述表(),并把的地址存放在的域中。

和都被设置为。

驱动程序可以调用函数得到用户缓冲区的系统空间地址,从而进行数据操作。

这个函数将调用者的缓冲区映射到非份页的地址空间。

驱动程序完成请求后,系统自动从系统空间解除缓冲区的映射。

、这两种方法都不是
这种情况比较少用,因为这需要驱动程序自己来处理缓冲问题。

管理器仅把调用者缓冲区的用户空间地址放到的域中。

我们并不推荐这种方式。

缓冲区的缓冲策略
请求涉及来自调用者的输入缓冲区和返回到调用者的输出缓冲区。

为了理解请求,我们先来看看函数的原型。

(
, 设备句柄
, 请求操作代码
, 输入缓冲区地址
, 输入缓冲区大小
, 输出缓冲区地址
, 输出缓冲区大小
, 存放返回字节数的指针
用于同步操作的结构体指针
);
请求有四种缓冲策略,下面一一介绍。

、输入输出缓冲()
管理器首先分配一个非分页池,它足够大地存放调用者的输入或输出缓冲区(不管哪个更大)。

非分页缓冲区的地址放在的域中,然后把的输入数据拷贝到这个非份页缓冲区中,并把的域设置成调用者输出缓冲区的用户空间地址。

当驱动程序完成请求时,管理器将这个非份页缓冲区中的数据拷贝到调用者的输出缓冲区。

注意这里同一个非份页池同时用于输入和输出缓冲区,因此驱动程序在向缓冲区写东西之前应该把输入的所有数据读出来。

、直接输入缓冲输出()
管理器首先检查调用者输入缓冲区的可访问性,并在物理内存中将其锁定。

然后为该输入缓冲区创建一个,并把指定该的指针存放到的域中。

同时,管理器还在非份页池中分配一输出缓冲区,并把这个缓冲区的地址存放在的域中,并把的域设置成调用者输出缓冲区的用户空间地址。

当驱动程序完成请求时,管理器将非份页缓冲区中的数据拷贝到调用者的输出缓冲区。

、缓冲输入直接输出()
管理器首先检查调用者输出缓冲区的可访问性,并在物理内存中将其锁定。

然后为该输出缓冲区创建一个,并把指定该的指针存放到的域中。

同时,管理器还在非份页池中分配一输入缓冲区,并把这个缓冲区的地址存放在的域中,同时把调用者用户输入缓冲区中的数据拷贝到系统缓冲区中,并把的域设置为。

、上面三种方法都不是()
管理器把调用者的输入缓冲区的地址放到当前堆栈单元的域中,把输出缓冲区的地址存放到的域中。

这两个地址都是用户空间地址。

从上面的说明可以看出,在执行缓冲时,管理器将在非份页池中分配内存,如果调用者的缓冲区比较大时,分配的非份页池也将比较大。

非份页池是系统比较宝贵的资源,因此,如果调用者的缓冲区比较大时,我们一般采用直接的方式(例如磁盘读写请求等),这样不仅节省系统资源,另一方面由于省去了管理器在系统缓冲区和调用者缓冲区之间的数据拷贝,也提高了效率,这对存在大量数据传送的驱动程序尤其明显。

可以注意到中的下,几乎所有的例程的读写请求都是直接的,而对于请求则是缓冲区的居多
开发驱动程序的方法(连载三)
驱动程序的分层结构
驱动程序是指管理某个外围设备的一段程序代码。

采用更灵活的分层驱动方法,允许杂应用程序和硬件之间存在几个驱动程序层次。

分层机制允许更加广泛地定义驱动程序,包括文件系统、逻辑卷管理器和各种网络组件,各种物理设备驱动程序等等。

、设备驱动程序
这些是管理实际数据传输和控制特定类型的物理设备的操作的驱动程序,包括开始和完成操作,处理中断
和执行特定的设备要求的任何差错处理。

、中间驱动程序
允许在物理设备驱动程序上分层任意数目的中间驱动程序。

这些中间层次提供扩展系统的功能一种方法,而不必修改底层的驱动程序。

这也是微软鼓吹的他们的系统灵活的一面!实际上我觉得这样反而牺牲了一些效率上的东西。

、文件系统驱动程序()
是一类比较特殊的驱动程序,通常负责维护各种文件系统所需要的磁盘结构。

注意我们并不能使用来开发,而必须使用的文件系统开发人员工具包。

一般比较少写中间过滤驱动程序,过滤驱动程序它截获和修改高层发送给类驱动程序的请求。

这样就允许利用现有类驱动程序的功能,而不必从头开始写所有程序。

内核模式对象在我们的实际开发过程中的对象是设备,由于端口驱动程序已经隐藏了硬件控制操作,因此我在这里不讲述跟硬件相关的部份。

如果今后的开发对象不同,需要对硬件进行操作的时候,可能会对中断、等有比较详细的了解,这些内容可以参考帮助。

设备开发实例
通用串行总线( ),是一种快速、灵活的总线接口。

与其它通信接口比较,接口的最大特点是易于使用,这也是的主要设计目标。

作为一种高速总线接口,适用于多种设备,比如数码相机、播放机、高速数据采集设备等。

易于使用还表现在接口支持热插拔,并且所有的配置过程都由系统自动完成,无需用户干预。

接口支持(低速)、(全速)和高达( 规范)的数据传输速率,扣除用于总线状态、控制和错误监测等的数据传输,的最大理论传输速率仍达或,远高于一般的串行总线接口。

接口芯片价格低廉,一个支持规范的接口芯片价格大多在$~之间,跟一个或接口芯片价格差不多,这也大大促进设备的开发与应用。

在进行一个设备开发之前,首先要根据具体使用要求选择合适的控制器。

目前,市场上供应的控制器主要有两种:带接口的单片机()或纯粹的接口芯片。

带接口的单片机从应用上又可以分成两类,一类是从底层设计专用于控制的单片机,比如公司的7C (低速)、7C(全速),但由于价格、开发工具以及单片机性能有限等问题,所以一般不推荐选用。

另一类是增加了接口的普通单片机,例如公司的(基于)、(基于高速、增强的)、公司的-(基于),选择这类控制器的最大好处在于开发者对系统结构和指令集非常熟悉,开发工具简单,但对于简单或低成本系统,价格高将会是最大的障碍。

一般来说,后者的价格是前者价格的倍。

纯粹的接口芯片仅处理通信,必须有一个外部微处理器来进行协议处理和数据交换。

典型产品有公司的(2C接口)、(并行接口),公司的(并行接口),公司的等。

接口芯片的主要特点是价格便宜、接口方便、可靠性高,尤其适合于产品的改型设计(硬件上仅需对并行总线和中断进行改动,软件则需要增加微处理器的中断处理和数据交换程序、机的接口通信程序,无需对原有产品系统结构作很大的改动)。

在选定控制器以后,如果是带接口的单片机,则是一般单片机应用系统的开发;反之,就是如何把接口芯片与单片机应用系统融合的问题,一般接口芯片都支持多种并行总线结构(复用非复用),可以方便的与多种单片机接口。

硬件设计中要注意的就是接口芯片的时钟速度比较高,如果芯片内部没有来倍频,则外部晶体振荡电路(多数在)的设计就应该特别注意,包括晶体的选择(负载电容大小)、匹配网络的设计以及布线。

设备的软件设计主要包括两部分:一是设备端的单片机软件,主要完成协议处理与数据交换(多数情况下是一个中断子程序)以及其它应用功能程序(比如转换、解码等)。

二是端的程序,由通信程序和用户服务程序两部分组成,用户服务程序通过通信程序与系统( )通信,由系统完成协议的处理与数据传输。

端程序的开发难度比较大,程序员不仅要熟悉协议,还要熟悉体系结构并能熟练运用工具。

接口软件主要完成协议的处理和数据的交换,一定要严格遵循规范第九章的规定(详见 : )。

要快捷、成功的开发一个设备,正确、合理的调试方法是必不可少的环节。

调试基本分三步进行:首先对外部设备(单片机部分)借助调试软件(芯片生产商提供或从网上下载-、等调试软件)将设备端的协议(主要有描述符请求、端口配置、地址设置以及基本数据交换)调通。

然后,用调试好的设备接口来开发、调试软件,这一步相对比较容易。

最后,加上设备端的其它用户程序,对整个完整的系统进行系统调试。

下面从硬件、软件两方面具体介绍作者设计的一个便携式数据采集设备,重点介绍接口部分。

该数据采集系统以公司的带通道位、路位的内核单片机作为系统控制器,采用公司的作为接口芯片。

由于系统中需要断电后保存采集数据,扩展了两片28F,因此在这里把与的接口采用了总线复用方式,通过信号把数据分离出来,并把低空间全留给(的空间有1M,分页管理,每页,共页,对应寄存器值~,占第页,即=),地址线()作为的指令数据选择线,则地址写指令、读写数据;单片机的口线提供的复位信号,接非门是保证单片机复位时也复位。

与单片机的数据交换采用中断方式(),实际应用中如果系统中断资源不够(特别是系统改型设计时),也可以接成查询方式,只是注意查询间隔不要超过接口的最大等待时间(最大)。

的指示灯()在通信时会闪烁,常亮或一直不亮说明接口有问题,调试时非常有用。

采用倍频产生系统时钟,只需外接低频晶体,设计比较方便。

单片机软件设计主要注意以下几点:
* 的中断输出引脚只要中断寄存器不为就保持低电平,所以单片机的对应中断()应设置成电平触发;中断处理后要用读上次传输状态寄存器清除中断寄存器中对应位(-)。

* 靠软件控制端口的连接,程序在系统初始化处理完后软件设置连接到端口,然后开中断。

* 对内部寄存器的读写没有边界限制,程序设计中一定不要读写超过端点深度的数据。

特别对于描述符请求,由于其长度大于
深度(),要分几个数据周期传输。

* 述符一定要设置正确,并且注意协议中所有字数据均定义为低字节在前传输(),例如的为,应在中定义成、。

* 在接收到包后,一定要用指令来重新使能和
端点。

向端点写数据后,要用
指令使数据可以在下一个数据周期发送。

从端点读数据后,要用
指令来清空缓冲区,否则后面周期传输的数据将被丢弃(返回)。

*协议的处理一定要按规范要求进行,对无效请求,用指令将和
端点即可。

机软件作者用开发,分接口通信程序和应用程序两部分,其开发以及系统调试过程与前文所述相同,此处不再赘述。

相关文档
最新文档