资源描述
湖南大学毕业设计(论文) 第 III 页
毕业设计(论文)
设计论文题目:
嵌入式Linux下USB驱动程序的研究与开发
学生姓名:
学生学号:
专业班级:
学院名称:
指导老师:
学院院长:
年 5月 25 日
毕业设计(论文) 第 V 页
嵌入式Linux下USB驱动程序的研究与开发
摘 要
嵌入式是一个快速发展的领域,目前50%左右的项目选择源代码开放的Linux作为嵌入式操作系统。但嵌入式Linux操作系统仍然没有做到在硬件配置上的即插即用。 通用串行总线(USB)是一种高传输速率的串行接口总线, 综合了一个多平台标准,其低成本,兼容性强,可连接大量的外部设备,融合先进的功能等优点,使其在嵌入式系统领域得到了广泛的应用。因此,研究和开发嵌入式Linux系统下的USB设备驱动程序就具有很好的应用价值。
本文首先介绍了嵌入式开发的基础知识,包括Linux环境下的makefile程序编译,目标机与宿主机的交叉编译环境的建立以及交叉编译的步骤, USB的系统组成、传输方式以及嵌入式Linux下设备驱动程序的开发模式,最后针对JXARM-2410平台,具体实现了一个USB设备驱动程序, 通过模块加载,表明该USB设备驱动程序能够实现对U盘的挂接,读取U盘中的数据。
关键词:Linux; 源代码开放; 嵌入式; 即插即用; USB驱动
Research and development of USB drivers under Embedded Linux
Abstract
Embedded System is a rapidly developing area; currently about 50 percent of Embedded System projects choose the open-source Linux as the embedded operating system. However, Embedded Linux operating system hasn’t solved the problem on the hardware configuration of plug-and-play yet. Universal Serial Bus (USB) is a high-speed serial interface bus, a comprehension of multi-platform standards. Its low cost, compatibility,the ability of connecting a large number of external equipments simultaneously and the integration of advanced functions,made Linux widely used in Embedded System areas. Therefore, it is of good value to research and develop the USB device driver under Embedded Linux.
This paper introduces the knowledge of how to develop USB device drive under embedded Linux environment, including the compiler procedures using makefile tools, as well as the steps of establishing a cross-compiler environment. It also introduces USB transmission and the development model of embedded Linux device driver. Finally, a concrete realization of the USB device driver was made, which was loaded onto JXARM-2410 platform through module loading, showing that the USB device driver can achieve certain tasks such as articulated U, read U disk data.
Keyword: Linux;plug-and-play;Open-Source;Embedded;USB Driver
目 录
1 引言 1
1.1 嵌入式系统的发展 1
1.2 国内外研究状况 1
1.3 课题背景及目的 2
2 基础知识 3
2.1 ARM简介 3
2.2 Linux下程序的编译:makefile 3
2.2.1 Makefile的书写规则 4
2.2.2 Makefile的自动推导 4
2.2.3清空目标文件的规则 5
2.3 交叉编译环境 5
2.3.1开发环境的建立 5
2.3.2 交叉编译步骤 6
3 USB系统组成 8
3.1 USB的物理层 8
3.2 USB设备 8
3.3 HUB 10
3.4即插即用 10
3.5设备的挂起 11
3.6 USB数据流模型 11
3.7 USB 传输类型 12
3.7.1 控制传送 12
3.7.2 批量传输 13
3.7.3 同步传输 14
3.7.4 中断传输 14
4 嵌入式LINUX下的设备驱动 15
4.1 设备类型分类 15
4.2 USB系统软件 17
4.3 USB驱动程序开发 18
4.4 调度对象 URB 19
4.5 类URB 队列 20
5 在JXARM-2410下配置USB设备 23
5.1 配置Linux内核以支持USB接口及U盘 23
5.2 编译Linux内核 23
5.3 运行内核并加载模块 24
5.4 在JXARM9-2410下使用U盘 24
总 结 26
致 谢 27
参 考 文 献 28
毕业设计(论文) 第 29 页
1 引言
1.1 嵌入式系统的发展
嵌入式系统最初的应用是基于单片机的。20世纪70年代单片机的出现,使得汽车、家电、工业机器人、通信装置以及成千上万种产品可以通过内嵌电子装置来获得更佳的使用性能、更易使用、速度更快、价格更低。这些装置已经初步具备了嵌入式的应用特点,但是这时的应用只是8位的芯片执行一些单线程的程序,还谈不上“系统”的概念。
20世纪80年代早期开始,嵌入式系统的程序员开始用商业级的“操作系统”编写嵌入式应用软件,这使得开发人员可以进一步缩短开发周期,降低开发成本并提高开发效率。1981年,Ready System开发出世界上第一个商业嵌入式实时内核 (VTRX32)。这个实时内核包含了许多传统操作系统的特征,包括任务管理、任务间通信、同步与互斥、中断支持、内存管理等功能。此后一些公司也纷纷推出了自己的嵌入式操作系统。这些嵌入式实时多任务操作系统的出现,使得应用开发人员从小范围的开发中解放出来,同时也促使嵌入式有了更为广阔的应用空间。20世纪90年代以后,随着对实时性要求的提高,软件规模的不断上升,实时内核的实时多任务操作系统 (RTOS),作为一种软件平台逐步成为目前国际嵌入式系统的主流。这时有更多的公司开始大力发展自己的嵌入式操作系统。如
Plam OS, Windows CE、嵌入式Linux, Lynx, Nucleus以及国内的Hopen, Delta OS等嵌入式操作系统。各个嵌入式操作系统的应用领域各异,如应用于航空、通讯领域的VXWORKS,应用于掌上电脑的Windows CE,应用于移动通讯设备的Nucleus等等[1]。
1.2 国内外研究状况
国际上有数以百计的嵌入式Linux开发计划,在国内,这方面的发展也有了较大进展。博利思软件公司在这方面做了一些有益的尝试,并于最近推出了一个嵌入式Linux操作系统PocketIX 预览版(下载网址为:
国内的嵌入式系统应用,一直以8位、16位单片机应用为主。由单片机完成过程控制,现场控制,仪器仪表的智能控制等,复杂的计算和数据处理送计算机完成。单片机在推动多个技术领域的进步方面起过很大作用[2]。
1.3 课题背景及目的
USB综合了一个多平台标准的优点,主要包括低成本,兼容性强,可连接大量的外部设备,融合先进的功能和品质等,使其逐步成为PC接口标准,进入了高速发展期。而在嵌入式领域,Linux同样获得了飞速发展,50%左右的项目选择Linux作为嵌入式操作系统。但Linux在硬件配置上仍然没有做到完全即插即用,因此对于Linux怎样配置和使用USB 设备,开发Linux系统的USB设备驱动程序就具有非常现实的应用价值。
2 基础知识
2.1 ARM简介
对于ARM.(Advanced RISC Machines),既可以认为是一个公司的名字,也可以认为是对微处理器的通称,还可以认为是一种技术的名字。1991年,ARM公司成立与英国剑桥。目前,采用ARM技术知识产权IP核的微处理器,已经占据了32位RISC微处理器70%以上的市场份额,基于ARM技术的产品正越来越贴近我们的日常生活。
2.2 Linux下程序的编译:makefile
什么是makefile?makefile关系到了整个工程的编译规则。一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。
makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。makefile成为了一种在工程方面的编译方法。一般来说,无论是C、C++,首先要把源文件编译成中间代码文件,在Windows下也就是 .obj 文件,UNIX下是 .o 文件,即 Object File,这个动作叫做编译(compile)。然后再把大量的Object File合成执行文件,这个动作叫作链接(link)。
编译时,编译器需要的是语法的正确,函数与变量的声明的正确。对于后者,通常是你需要告诉编译器头文件的所在位置(头文件中应该只是声明,而定义应该放在C/C++文件中),只要所有的语法正确,编译器就可以编译出中间目标文件。一般来说,每个源文件都应该对应于一个中间目标文件(O文件或是OBJ文件)。
链接时,主要是链接函数和全局变量,所以可以使用这些中间目标文件(O文件或是OBJ文件)来链接我们的应用程序。链接器并不管函数所在的源文件,只管函数的中间目标文件(Object File),在大多数时候,由于源文件太多,编译生成的中间目标文件太多,而在链接时需要明显地指出中间目标文件名,这对于编译很不方便,所以要给中间目标文件打个包,在Windows下这种包叫“库文件”(Library File),也就是 .lib 文件,在UNIX下,是Archive File,也就是 .a 文件。
源文件首先会生成中间目标文件,再由中间目标文件生成执行文件。在编译时,编译器只检测程序语法,和函数、变量是否被声明。如果函数未被声明,编译器会给出一个警告,但可以生成Object File。而在链接程序时,链接器会在所有的Object File中找寻函数的实现,如果找不到,那到就会报链接错误码(Linker Error),在VC下,这种错误一般是:Link 2001错误,意思说是说,链接器未能找到函数的实现。需要指定函数的Object File。make命令执行时,需要一个 Makefile 文件,以告诉make命令需要怎么样的去编译和链接程序。
2.2.1 Makefile的书写规则
1)如果这个工程没有编译过,那么我们的所有C文件都要编译并被链接。
2)如果这个工程的某几个C文件被修改,那么我们只编译被修改的C文件,并链接目标程序。
3)如果这个工程的头文件被改变了,那么我们需要编译引用了这几个头文件的C文件,并链接目标程序。
只要的Makefile写得够好,所有的这一切,只用一个make命令就可以完成,make命令会自动智能地根据当前的文件修改的情况来确定哪些文件需要重编译,从而自己编译所需要的文件和链接目标程序[3]。
2.2.2 Makefile的自动推导
GNU的make很强大,它可以自动推导文件以及文件依赖关系后面的命令,于是我们就没必要去在每一个[.o]文件后都写上类似的命令。因为,我们的make会自动识别,并自己推导命令。
只要make看到一个[.o]文件,它就会自动的把[.c]文件加在依赖关系中,如果make找到一个whatever.o,那么whatever.c,就会是whatever.o的依赖文件。并且 cc -c whatever.c 也会被推导出来。
2.2.3 清空目标文件的规则
每个Makefile中都应该写一个清空目标文件(.o和执行文件)的规则,这不仅便于重编译,也很利于保持文件的清洁。这是一个“修养”。一般的风格都是:
clean:
rm edit $(objects)
更为稳健的做法是:
.PHONY : clean
clean :
-rm edit $(objects)
PHONY意思表示clean是一个“伪目标”。而在rm命令前面加了一个小减号的意思就是,也许某些文件出现问题,但不要管,继续做后面的事。当然,clean的规则不要放在文件的开头,不然,这就会变成make的默认目标,相信谁也不愿意这样。不成文的规矩是——“clean从来都是放在文件的最后”。
2.3 交叉编译环境
2.3.1开发环境的建立
绝大多数Linux的软件开发都以native方式进行,即本机开发、调试,本机运行的方式。这种方式通常不适于嵌入式系统的软件开发,因为对于嵌入式系统的开发,它没有足够的资源在本机(即嵌入式系统平台)运行开发工具和调试工具。通常的嵌入式系统软件开发采用交叉编译调试的方式。交叉编译调试环境建立在宿主机上,对应的开发板叫做目标板(即嵌入式ARM2410系统)。
通常宿主机和目标板上的处理器不同,宿主机通常为Intel处理器,而目标板为SAMSUNG S3C2410,所以程序需要使用针对处理器特点的编译器才能生成在相应平台上可运行的代码。GNU编译器提供这样的功能,在编译时,可以选择开发所需的宿主机和目标机,从而建立开发环境。在进行嵌入式开发前的第一步工作就是把一台PC机作为宿主机开发机,并在其上安装指定的操作系统。对于嵌入式Linux,宿主机PC上应安装Linux系统。之后,在宿主机上建立交叉编译调试的开发环境。开发采用移植性很强的C语言在宿主机上编写驱动程序,再利用交叉编译调试工具编译链接生成可执行代码,最后向目标平台移植。
在Linux下,设备驱动程序可以看成Linux内核与外部设备之间的接口。设备驱动程序向应用程序屏蔽了硬件实现了的细节,使得应用程序可以像操作普通文件一样来操作外部设备,可以使用和操作文件中相同的、标准的系统调用接口函数来完成对硬件设备的打开、关闭、读写和I/O控制操作,而驱动程序的主要任务也就是要实现这些系统调用函数。本系统平台使用的嵌入式armLinux系统在内核主要功能上与Linux操作系统没本质区别,所以驱动程序要实现的任务也一样,只要编译时使用的编译器、部分头文件和库文件等要涉及到具体处理器体系结构,这些都可以在Makefile文件中具体指定。
Linux系统中把设备看成设备文件,在用户空间可以通过标准的I/O系统调用函数操作设备文件,从而达到与设备通信交互的目的。当然,在设备驱动中要提供对这些函数的相应支持。这里说明一下ioctl(int fd,int cmd,…)函数,它在用户程序中用来控制I/O通道。其中,fd代表设备文件描述符,cmd代表用户程序对设备的控制命令,省略号一般是一个表示类型长度的参数,也可没有[5]。
2.3.2 交叉编译步骤
创建编译环境。在这个过程中,将设置一些环境变量,创建安装目录,安装内核源代码和头文件等。
创建binutils。这个过程结束后,会创建类似arm-linux-ld等工具。
Binutils是一组开发工具,包括链接器,汇编器以及其他用于目标文件和档案的工具。首先要安装的软件包使binutils。这非常重要,因为glibc和gcc会针对可用的连接器和汇编器进行多种测试,以决定打开某些特性。
创建一个交叉编译版本的gcc。注意:在这个过程中只能编译C程序,而不能编译C++程序。
创建交叉编译版本的gcc,需要交叉编译版本的glibc及其头文件,而交叉编译版本的glibc是通过交叉编译版本的gcc创建的。面对这个先有鸡还是先有蛋的问题,解决办法是先只编译对C语言的支持,禁止支持线程。
创建一个交叉编译版本的glibc。这里最容易出现问题。glibc是一个提供系统调用和基本函数的C语言库,比如open,malloc和printf等,所有动态链接的程序都要用到它。创建glibc需要的时间更长。
创建一个交叉编译版本的gdb。在这个过程结束后,会创建ARM-Linux-gdb。
重新创建gcc,前面创建gcc的过程没有编译C++编译器,现在glibc已经准备好了,所以这个步骤将完善gcc的交叉编译并重新创建glibc。
如果在交叉编译过程中出现错误,那么需要检查:
(1)版本选择是否正确,以及是否安装了相应的补丁。
(2)库文件路径是否正确,系统环境变量是否设置正确。
3 USB系统组成
3.1 USB的物理层
USB的物理接口包括电气特性和机械特性
USB通过一个四线电缆来传输信号与电源如图3.1所示
图3.1 USB电缆定义
其中D+和D-是一对差模的信号线而VBus和GND则提供了5V的电源,它可以给一些设备(包括Hub)供电当然要有一定的条件限制。
USB提供了两种数据传输率一种是12Mb的高速(full speed)模式,另一种是1.5Mb的低速模式。这两种模式可以同时存在于一个USB系统中。而引入低速模式主要是为了降低要求不高的设备的成本,比如鼠标键盘等等。
USB信号线在高速模式下必须使用带有屏蔽的双绞线而且最长不能超过5m,而在低速模式时中可以使用不带屏蔽或不是双绞的线,但最长不能超过3m。这主要是由于信号衰减的限制为了提供信号电压保证,以及与终端负载相匹配在电缆的每一端都使用了不平衡的终端负载,这种终端负载也保证了能够检测外设与端口的连接或分离,并且可以区分高速与低速设备了。
所有的设备都有上行的接口。上行和下行的接头是不能互换的。这保证了不会有非法的连接出现。插头与插座有两个系列分别为A和B系列。A用于基本固定的外围设备,而系列B用于经常拔插的设备,这两个系列是不能互换的。
3.2 USB设备
USB设备包括Hub和功能设备。而功能设备又可以细分为定位设备字符设备等等。为了进一步叙述我们给出端点(endpoint)和管道(pipe)的概念。端点每一个USB设备在主机看来就是一个端点的集合。主机只能通过端点与设备进行通讯以使用设备的功能。每个端点实际上就是一个一定大小的数据缓冲区,这些端点在设备出厂时就已定义好。在USB系统中每一个端点都有唯一的地址,这是由设备地址和端点号给出的。每个端点都有一定的特性,其中包括传输方式,总线访问频率,带宽端点号,数据包的最大容量等等。端点必须在设备配置后才能生效(端点0除外)。端点0通常为控制端点用于设备初始化参数等端点12等一般用作数据端点存放主机与设备间往来的数据。
管道一个USB管道是驱动程序的一个数据缓冲区与一个外设端点的连接,它代表了一种在两者之间移动数据的能力。一旦设备被配置管道就存在了管道有两种类型数据流管道,其中的数据没有USB定义的结构与消息管道,其中的数据必须有USB定义的结构管道只是一个逻辑上的概念。
所有的设备必须支持端点0以作为设备的控制管道通过控制管道可以获取完全描述USB设备的信息,包括设备类型电源管理配置端点描述等等,只要设备连接到USB上并且上电端点0就可以被访问与之对应的控制管道就存在了[8]。
一个USB设备可以分为三个层图。图3.2最底层是总线接口用来发送与接收包中间层处理总线接口与不同的端点之间的数据流通。一个端点是数据最终的使用者或提供者,它可以看作数据的源或接收端最上层,就是USB设备所提供的功能比如鼠标或键盘等。
图3.2 USB设备结构层次
3.3 HUB
Hub在USB结构中是一个关键,它提供了附加的USB节点。这些节点被称为端口。Hub可以检测出每一个下行端口的状态并且可以给下端的设备提供电源。图3.3是一个典型的Hub。
图3.3 典型的USB集线器
3.4即插即用
USB设备可以即插即用,但在可以使用之前必须对设备进行配置。一旦设备连接到某一个USB的节点上,USB就会产生一系列的操作来完成对设备的配置。这种操作被称为总线枚举过程。
1.设备所连接的Hub检测出端口上有设备连接通过状态变化管道向主机报告。
2.主机通过询问Hub以获取确切的信息。
3.主机这时知道设备连接到哪个端口上于是向这个端口发出复位命令。
4.Hub发出的复位信号结束后端口被打开Hub向设备提供100mA的电源,这时设备上电所有的寄存器复位并且以缺省地址0以及端点0响应命令。
5.主机通过缺省地址与端点0进行通讯赋予设备一个独一的地址并且读取设备的配置信息。
6.最后主机对设备进行配置,该设备就可以使用了。
当该设备被移走时Hub依然要报告主机并且关闭端口。一旦主机接到设备移走的报告就会改写当前结构信息。
.
3.5设备的挂起
为了节电当设备在指定的时间内没有总线传输,USB设备自动进入挂起状态。如果设备所接的Hub的端口被禁止了,设备也将进入挂起状态(称之为选择挂起)。当然主机也可以进入挂起状态。
USB设备当总线活动时就会离开挂起状态。一个设备也可以通过电信号来远程唤醒进入挂起状态的主机。这个能力是可选的。如果一个设备具有这个能力,主机有能力禁止或允许使用这种能力。
3.6 USB数据流模型
USB 是一种基于令牌的、主从式、融合了计算机与通信技术的串行总线,对外设提供统一接口,具有易用性、支持热拔插、健壮性、成本低廉等特征。一个 USB 系统由一个 USB 主机与若干设备组成,USB 主机管理系统主机与设备之间的通信传输。USB 主机包括主机控制器、USBD、HCD 三个部分,其中 USBD 与 HCD 一起构成 USB 主机软件堆栈。USB 支持同步、中断、控制、批量四种传输类型,并为每种类型的传输分别定义了传输协议。
USB通信建立在主机缓冲区与设备端点之间的管道上。USB 设备的端点是 USB 设备唯一可识别的部分,是主机与设备间通信流的结束点。每个 USB 逻辑设备都由一个独立的端点集组成。在设备连接到 USB 系统时,主机为每个逻辑设备分配唯一的逻辑地址。设备的每个端点均具有唯一的标志符,即端点号。每个端点都有由设备决定的数据流方向,设备地址。
端点号与方向的组合唯一指定一个端点。每个端点都是一个简单的连接点,支持一个方向的数据流(输入或者输出)。端点的特性决定了它与客户软件进行的传送服务类型。
一个端点有以下特性:
总线访问频率/延时要求;带宽要求;端点号;对差错处理行为的要求;端点能接收或发送的最大包的大小;端点的传输类型;端点与主机的数据传输方向等。
3.7 USB 传输类型
USB 通过主机客户软件的存储缓冲区与 USB 设备端点之间的管道传输数据。USB 要求数据在管道上传送之前需要打包,但最终对在总线处理的数据有效负载中传输的数据进行格式化和解释,是使用这个管道的客户软件和功能设备的任务。
USB 提供了不同的传输类型,它们被优化,从而更符合使用管道的客户软件和功能设备的服务要求。
USB支持四种传输类型,每种传输类型都有不同的通信流特征,包括数据格式、通信流方向、数据包大小限制、总线访问限制、延迟限制、数据序列、要求的数据顺序与错误处理等方面。以下是USB支持的传输类型:
控制传输(Control Transfer):突发的、非周期的、主机软件初始化的请求/响应通信,用于命令/状态操作。
同步传输(Isochronous Transfer):主机与设备之间周期的、连续的通信,用于支持要求固定时延和带宽、周期性且固定速率的数据传输。
批量传输(Bulk Transfer):非周期的、大型包的突发通信,用于可以使用任何可用的带宽,
而且可以延时直到带宽可用的数据传输。
中断传输(Interrupt Transfer):低频的、延时有限的通信。
USB2.0 标准定义了三种不同的通信速度,分别为:
低速(LS/Low Speed):1.5Mb/s;
全速(FS/Full Speed):12Mb/s;
高速(HS/High Speed):480Mb/s。
USB1.1 规范只支持低速与全速通信。
3.7.1 控制传送
控制传输最少有 2 个事务阶段:建立(SETUP)与状态(STATUS),可以在建立和状态阶段之间包含一个数据阶段。
在建立阶段里,SETUP 事务用于将信息发送到功能设备的控制端点。SETUP 事务一般在数据时相上使用 DATA0 PID。接收 SETUP 的功能设备必须接受 SETUP 数据并用 ACK 响应,如果数据被损坏,则丢弃数据且不返回握手。
控制传输数据阶段(如果存在)由一个或多个 IN 或者 OUT 事务组成。数据阶段里的事务必须有相同的方向(即所有都是 IN 事务或者所有都是 OUT 事务)。在数据阶段处理的数据量与方向在建立阶段里指定。数据时相的使用与批量处理相同。状态阶段是控制传输的最后一个事务。状态阶段是以上一阶段的数据流方向的改变来描述,并且总是使用 DATA1 PID。如果数据阶段由输出事务构成,状态是一个单独的输入事务。如果数据阶段由输入事务构成,状态是一个单独的输出事务。如果控制传输没有数据阶段,那么它由建立阶段和其后的由输入事务构成的状态阶段构成。当控制端口在控制传输的数据和状态阶段中发送 STALL 握手的时候,必须对以后所有对此端口访问返回STALL握手,直到再次收到SETUP PID为止。端口收到建立PID之后,不应返回STALL握手。
3.7.2 批量传输
批量传输类型的特点是:通过错误检测和重试的方法保证主机和功能部件之间的无错传输。批量传输共有三个阶段:令牌、数据与握手包,在某些流控制和停止条件下,数据阶段被握手阶段替换。下图所示为批量传输事务顺序、数据时相图。
数据包同步通过使用数据序列触发位和 DATA0/DATA1 PID 的使用实现。当端口经历了任何配置事件之后,批量传输端口的触发序列被初始化为 DATA0。USB 主机通常将总线传输的首个事务初始化为带配置事件的 DATA0 PID。第二事务使用 DATA1 PID,并且,剩余的事务轮流切换。数据包发送器根据 ACK 的接收情况来切换而接收器根据数据包的接收和验收的情况切换。
图3.4 批量传输的读和写
3.7.3 同步传输
同步传输分令牌与数据两个阶段,没有握手阶段。USB 主机发送 IN 或者 OUT 令牌,后面紧跟数据阶段,同步处理不支持握手阶段与重试功能。全速同步处理不支持触发序列。每个微帧有一个处理的高速同步处理不支持触发序列。高带宽与高速同步处理支持数据 PID 序列。
3.7.4 中断传输
中断传输的事务分为 IN 事务与 OUT 事务两种。在收到一个 IN 令牌后,功能设备可以返回数据、NAK 或 STALL。如果端点没有新的中断信息(即没有中断等待)要返回,功能设备在数据阶段返回一个 NAK 握手。如果中断端点设置了停止特征,功能设备将返回一个 STALL 握手。如果有中断等待,功能设备将中断信息作为数据包返回。为了响应数据包,USB 主机发送一个 ACK握手(如果数据被无错接收)或不返回握手(如果接收的数据包被破坏)。
当端点要在实际的中断数据中使用中断传输机制时,它必须遵循数据触发协议。这就允许功能设备知道数据已经被 USB 主机接收,并且事件条件被清除。这保证了事件传输允许功能设备只发送中断信息知道它被 USB 主机接收,而不是在每次功能设备被查询的时候都发送中断数据知道USB 系统软件清除了中断为止。用于触发模式时,中断端点任何配置事件初始化为 DATA0 PID。
4 嵌入式Linux下的设备驱动
4.1 设备类型分类
字符设备(char device)。字符设备是Linux最简单的设备,可以向文件一样访问。
初始化字符设备时,它的设备驱动程序向Linux登记,并在字符设备向量表中增加一个device_struct数据结构条目,这个设备的主设备标识符用作这个向量表的索引。一个设备的主设备标识符是固定的。chrdevs向量表中的每一个条目,一个device_struct数据结构,包括两个元素:一个登记的设备驱动程序的名称的指针和一个指向一组文件操作的指针。参见include/linux/major.h.
块设备(block device)。是文件系统的物质基础,它也支持像文件一样被访问。
Linux用blkdevs向量表维护已经登记的块设备文件。它像chrdevs向量表一样,使用设备的主设备号作为索引.它的条目也是device_struct数据结构.与字符设备不同的是,块设备分为SCSI类和IDE类。类向Linux内核登记并向河心提供文件操作。一种块设备类的设备驱动程序向这种类提供和类相关的接口。参见fs/devices.c[10]。
每一个块设备驱动程序必须提供普通的文件操作接口和对于buffer cache的接口。每一个块设备驱动程序填充blk_dev向量表中的blk_dev_struct数据结构。这个向量表的索引还是设备的主设备号。这个blk_dev_struct数据结构包括一个请求例程的地址和一个指针,指向一个request数据结构的列表,每一个都表达buffer cache向设备读/写一块数据的一个请求。参见drivers/block/ll_rw_blk.c和include/linux/blkdev.h。
当buffer_cache从一个已登记的设备读/写一块数据,或者希望读写一块数据到其他位置时,他救灾blk_dev_struct中增加一个request数据结构。每个request数据结构都有一个指向一个或多个buffer_head数据结构的指针,每一个都是读/写一块数据的请求。如果buffer_head数据结构被锁定(buffer_cache),可能会有一个进程在等待这个缓冲区的阻塞进成完成。每一个request数据结构都是从all_request表中分配的。如果request增加到空的request列表,就调用驱动程序的request函数处理这个request队列,否则驱动程序只是简单的处理request队列中的每一个请求。
块设备驱动程序和字符设备驱动程序的主要区别是:在对字符设备发出读写请求时,实际的硬件I/O一般紧接着就发生了,块设备则不然,它利用一块系统内存作为缓冲区,当用户进程对设备请求能满足用户的要求时,就返回请求的数据,如果不能就调用请求函数来进行实际的I/O操作。块设备是主要针对磁盘等慢速设备的,以免耗费过多地CPU时间来等待。
设备驱动中关键数据结构:
file_operations:内核内部通过file结构识别设备,通过file_operations数据结构提供文件系统的入口点函数.file_operations定义在中的函数指针表.这个结构的每一个成员的名字都对应着一个系统调用。从某种意义上说,写驱动程序的任务之一就是完成file_operations中的函数指针。如果在2.4版本内核下开发的驱动很可能在2.6版本中无法使用,需要进行移植。
inode:文件系统处理的文件所需要的信息在inode(索引节点)中。
file:主要用于与文件系统对应的设备驱动程序使用。
网络设备驱动程序开发:
网络设备使用网络接口管理表dev_base.dev_base是一个指向device结构的指针,因为网络设备是通过device数据结构来表示的。网络驱动程序必须解决的两个问题:
(1)不是所有建立在Linux内核的网络设备驱动程序都会有控制的设备。
(2)系统中的以太网设备总是叫做/dev/eth0到/dev/eth7,而不管底层的设备驱动程序是什么。当驱动程序找到它的以太网设备时,它就填充它现在拥有的ethn的device数据结构。这时网络驱动程序也要初始化它控制的物理硬件,并找出它使用的IRQ,DMA等。一旦所有的8个标准的/dev/ethn都分配了,就不会再探测更多的以太网设备。
两个重要的数据结构:
device:这个数据结构是在系统中每一个设备的代表,它提供了多个设备方法,供操作系统或协议层使用。这其中就包括设备初始化时调用的init函数,打开和关闭设备的open和stop函数,处理数据包发送的hard_start_xmit函数等。
sk_buff:Linux网络各层之间的数据传送都是通过sk_buff(套接字缓冲区)完成的。每个sk_buff包括一些控制方法和一块数据缓冲区,这个区域存放了网络传输的数据包.控制方法按功能分为两种类型,一种是控制整个buffer链的方法,另一种是控制数据缓冲区的方法。sk_buff组成双向链表的形式,对链表的操作主要是
展开阅读全文