资源描述
,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,*,机械工业出版社,Page,*,2024/9/16,Page,1,第,10,章 嵌入式,Linux,设备驱动开发,设备驱动程序介于操作系统和硬件之间,屏蔽了硬件设备的物理细节,并提供了访问各种硬件设备的统一接口。驱动程序设计是嵌入式,Linux,开发中重要的一部分,也是比较困难的一部分,在进行这部分的开发时需要熟悉,Linux,的内核机制、驱动程序与用户级应用程序的接口,需要考虑系统对设备的并发操作,需要非常熟悉所开发硬件的工作原理。,2024/9/16,Page,2,第,10,章 嵌入式,Linux,设备驱动开发,Linux,设备驱动开发概述,10.1,设备驱动模块化编程,10.2,Linux,字符设备驱动,10.3,块设备驱动,10.4,2024/9/16,Page,3,第,10,章 嵌入式,Linux,设备驱动开发,本章小结,10.6,思考与练习,10.7,网络设备驱动,10.5,2024/9/16,Page,4,10.1 Linux,设备驱动开发概述,操作系统的目的之一就是掩盖掉各种硬件的特殊性,使得系统中的硬件设备对于用户而言是透明的。用来管理硬件控制器的软件通常叫做设备驱动程序。,Linux,驱动程序功能是对设备初始化和释放、把数据从内核传送到硬件和从硬件读取数据、读取应用程序传送给设备文件的数据和回送应用程序请求的数据、检测和处理设备出现的错误。,Linux,核心的设备驱动程序基本上是一些共享库,(Shared Library),,在库中含有一些用来处理底层硬件的例程。,Linux,的设备驱动程序用来处理各种硬件的多样性。,操作系统的基本功能之一是对设备处理的抽象化。所有的物理设备被当做正规的文件来处理,可以被“打开”、“关闭”、“读”和“写”,就像用系统调用处理文件一样。系统中每一个设备都对应一个设备特殊文件,例如,系统中的第一个,IDE,磁盘的设备文 件名是,/dev/,hda,。对于块设备,(,如磁盘,),和字符设备,它们的的设备特殊文件通常是通过,mknod,命令用主设备号和次设备号来描述和创建的。,2024/9/16,Page,5,10.1 Linux,设备驱动开发概述,Linux,设备驱动开发调试有两种方法:一种是直接编译到内核,随同,Linux,启动时加载,启动内核时就会驱动此硬件设备。这种方法称为静态链接。另一种是编译为可加载模块(,Loadable kernel modules,)的形式,编译生成一个,.o,文件,当应用程序需要时再动态加载进内核空间运行,这种方法称为动态链接。,Linux,提供了一批管理内核模块的命令,主要有,1smod,、,insmod,和,rmmod,等。,1smod,命令用于查看当前内核加载的模块信息;,insmod,命令将编译的模块直接插入内核,如果出现故障,可以使用,rmmod,命令从内核卸载模块,而不需要重新启动内核。,2024/9/16,Page,6,10.1 Linux,设备驱动开发概述,2024/9/16,Page,7,10.1 Linux,设备驱动开发概述,10.1.1,设备驱动和文件系统的关系,设备驱动程序的任务包括自动配置和初始化子程序,负责检测所要驱动的硬件设备是否存在和是否能正常工作。如果该设备正常,则对这个设备及其相关的设备驱动程序需要的软件状态进行初始化。这部分驱动程序仅在初始化的时候被调用一次。,10.1 Linux,设备驱动开发概述,服务于,I/O,请求的子程序,又称为驱动程序的上半部分。调用这部分是系统调用的结果。在执行这部分程序的时候,系统仍认为和进行调用的进程属于同一个进程,只是由用户态转换为核心态,并具有进行此系统调用的用户程序的运行环境,所以可以在其中调用,sleep( ),等与进程运行环境有关的函数,。,在系统内部,,I/O,设备的存取通过一组固定的入口点来进行,这组入口点是由每个设备的设备驱动程序提供的。,10.1.1,设备驱动和文件系统的关系,2024/9/16,Page,8,10.1 Linux,设备驱动开发概述,10.1.2,设备类型和设备号,1.,字符设备,2.,块设备,3.,网络设备,2024/9/16,Page,9,10.1 Linux,设备驱动开发概述,1.,字符设备,一个字符设备是一种字节流设备,对设备的存取只能按顺序按字节的存取而不能随机访问,字符设备没有请求缓冲区,所有的访问请求都是按顺序执行的。,Linux,下的大多设备都是字符设备。应用程序是通过字符设备节点来访问字符设备的。设备节点一般都由,mknod,命令创建在,/dev,目录下,字符设备文件的第一个标志是前面的“,c”,标志。如“,crw-rw,-”,、“,crw-r-”“crw-rw,-”,所代表的文件都是字符设备文件。,2024/9/16,Page,10,10.1 Linux,设备驱动开发概述,1.,字符设备,Linux,使用管理文件的方法来管理字符设备,所以每个字符设备在,/dev/,目录下都有一个对应的设备文件,即设备节点,它们包含了设备的类型、主,/,次设备号以及设备的访问权限控制等。每个字符设备文件都有自己的与普通文件相同的文件操作函数组结构(,struct,file_operations,)。字符设备驱动通常至少需要实现文件操作函数组中的,open(),、,release(),、,read(),和,write(),四种操作方法。常见的字符设备有鼠标、键盘等。,2024/9/16,Page,11,2.,块设备,存储设备一般属于块设备,块设备有请求缓冲区,并且支持随机访问而不必按照顺序去存取数据。,Linux,下的磁盘设备都是块设备,尽管在,Linux,下有块设备节点,但应用程序一般是通过文件系统及其高速缓存来访问块设备的,而不是直接通过设备节点来读写块设备上的数据。块设备文件的第一个标志是前面的“,b”,标志,如“,brw-rw,-”,所代表的就是块设备。,10.1 Linux,设备驱动开发概述,2024/9/16,Page,12,2.,块设备,块设备既可以作为普通的设备用来存放任意数据,也可以将块设备按某种文件系统类型的格式进行格式化,然后按照该文件系统类型的格式来读取块设备上的数据,但不管哪种方式,最后访问设备上的数据都必须通过调用设备本身的操作方法实现,区别在于前者直接调用块设备的操作方法,而后者则间接调用块设备的操作方法。常见的块设备有各种硬盘、,flash,磁盘、,RAM,磁盘等。,10.1 Linux,设备驱动开发概述,2024/9/16,Page,13,3.,网络设备,网络设备不同于字符设备和块设备,它是面向报文的而不是面向流的,它不支持随机访问,也没有请求缓冲区。在,Linux,里一个网络设备也可以叫做一个网络接口,应用程序是通过,Socket,而不是设备节点来访问网络设备,在系统里根本就不存在网络设备节点。内核使用一套与数据包传输相关的函数来与网络设备驱动程序通信,它们不同于字符设备和块设备的,read(),和,write(),方法。,10.1 Linux,设备驱动开发概述,2024/9/16,Page,14,3.,网络设备,Linux,系统通过设备号来区分不同设备。设备号由两部分组成:主设备号和次设备号。主设备号指明对应哪些设备驱动,这种对应关系是固定不变的并作为内核资源的一部分存在。需要注意的是,同一个主设备号可以对应两个不同的设备驱动,一个可以是字符设备另一个可以是块设备。,10.1 Linux,设备驱动开发概述,2024/9/16,Page,15,3.,网络设备,次设备号区分被一个设备驱动控制下的某个独立的设备。比如,同一个类型的,USB,设备可以在系统中存在几个,它们通过次设备号加以区分,而设备驱动可以只对应一个。,Linux,支持的各种设备的主设备号定义在,include/,linux/major.h,文件中,而已经在官方注册的主设备号和次设备号在,Documentation/,devices.txt,文件中可以找到。,10.1 Linux,设备驱动开发概述,2024/9/16,Page,16,模块是程序设计中一个十分重要的概念,它是一个具有独立逻辑功能的代码块,每个模块都可以被重复使用,模块化编程可以有效提高程序的编写效率,同时也能增强程序的可读性和易修改性。,10.2,设备驱动模块化编程,2024/9/16,Page,17,2024/9/16,Page,18,10.2,设备驱动模块化编程,10.2.1,设备驱动程序原理,Linux,设备驱动程序主要由驱动程序的注册与注销、设备的打开与释放、设备的读写操作、设备的控制操作、设备的中断和轮询处理等部分组成,每个部分都有与之对应的接口。,10.2,设备驱动模块化编程,10.2.1,设备驱动程序原理,Linux,内核在结构体,file_operations,中统一定义了设备文件的各个访问接口,,file_operations,结构定义在,/include/,linux/fs.h,中。设备驱动程序加载时,首先会在内核中注册对应的设备号和结构体,file_operations,。,应用程序通过系统调用访问设备时,内核会根据设备号查找到相应的结构体,file_operations,,然后再根据结构体,file_operations,中的接口调用具体放入设备访问函数。,2024/9/16,Page,19,2024/9/16,Page,20,10.2,设备驱动模块化编程,10.2.2,设备访问方式及实现,设备访问方式有多种,选择哪种访问方式不仅与设备本身有关,还与它的使用情况有关。,Linux,对查询方式、中断方式和,DMA,三种方式都提供了很好的支持。,10.2.2,设备访问方式及实现,1,、查询方式,在数据传送之前,对目标设备的状态进行查询,确知外设已经做好了传送数据的准备时再进行数据传送,否则,,CPU,等待并持续不断的查询,一旦外设准备好,则立即进行读或写操作,这种方式称为查询方式。,10.2,设备驱动模块化编程,2024/9/16,Page,21,10.2,设备驱动模块化编程,1,、查询方式,对于查询方式来说,一个数据传送过程由三个环节组成:,(1),从接口中读取状态字。,(2) CPU,检测状态字的对应位是否满足就绪条件,如果不满足,则回到前一步,继续读取状态字。,(3),如果状态字表明外设己处于就绪状态,则传送数据。,这种方式看上去似乎很浪费资源,效率低,但在某些情况下仍有使用的价值。例如当一个设备从打开计算机到关闭之前一直需要使用,而它又没有向系统发中断的功能,这种场合下查询方式还是很有用的。在,Linux,驱动程序中实现这种方式还是比较简单的。只要在驱动程序的,read(),程序中使用,while,语句一直判断外设的状态,状态一旦满足要求,则跳出循环,读取外设数据并返回,read(),函数就可以了。,2024/9/16,Page,22,2,、中断方式,在中断传送方式下,外设具有申请,CPU,服务的主动权,当输入设备已将数据准备好或者输出设备可以接收数据时,便可以向,CPU,发出中断请求,使,CPU,暂时停下目前的工作而和外设进行一次数据传输,等输入操作完成后,,CPU,继续进行原来的工作。可见中断传送方式就是外部设备中断,CPU,的工作,使,CPU,停止执行当前程序,而去执行一个为外部设备的数据输入输出服务程序,该服务程序称为中断处理子程序或中断服务子程序。中断子程序执行完后,,CPU,又转回来执行原来的程序。被外界中断时,程序中下一条指令所在处称为断点,从中断服务程序返回时,从断点处继续执行被中断的程序。,10.2,设备驱动模块化编程,2024/9/16,Page,23,2,、中断方式,采用这方式访问外设的前提是该外设能发出操作系统能识别的中断。在,Linux,驱动程序中采用中断方式访问外设需做到以下几点:,(1),向系统申请中断。,Linux,提供了函数,request_irq,(),来实现申请中断。申请成功与否的关键在于此函数的一个参数,irq,,它是希望申请的中断号。如果外设可以发中断,那该参数就填,2,。不过还有一点需要考虑的是如果想申请的中断号己被别的设备占用,那就需要想办法协调这两个设备了。可以使用命令,cat/proc/interrupts,来查看操作系统中现有中断号的使用情况。当然是否申请成功,也可以通过这条命令查看。,(2),释放中断。函数,free_irq,(),可以实现这个功能。,(3),实现中断函数。申请完中断号以后,希望系统响应该中断后做些什么全依赖此函数。其实该函数也没有特别的地方,无非就是做些读写设备的动作,采集需要的数据。不过需要说明的是该函数应该尽量的短,因为此时在独占,CPU,资源,系统很难响应别的事件。该函数的末尾应该调用函数,wake_up_interruptible,(),,来唤醒该设备队列中其它进程。,10.2,设备驱动模块化编程,2024/9/16,Page,24,3,、,DMA,方式,在,DMA,方式下,外部设备利用专门的接口电路直接和存储器进行数据传送,并不经过,CPU,。这样,进行传输就不必进行保护现场之类的一系列额外操作,数据传输的速度基本上决定于外设和存储器的速度。,DMA,方式传送数据则由,DMA,控制器来提供源和目的地址、修改地址、控制结束及发出控制信号。显然,采用,DMA,方式,数据传送的速度显著提高,而且,CPU,的负担也明显减轻了。同时也缩短了传送的响应时间。,10.2.2,设备访问方式及实现,2024/9/16,Page,25,3,、,DMA,方式,DMA,传送的基本过程如下:,(1),外部设备,(,或,CPU,利用指令,),向,DMA,控制器发出,DMA,传送请求。,(2) DMAC,向,CPU,发总线请求,要求,CPU,交出总线的管理和使用权,并在接到,CPU,的总线响应信号后接管系统总线的管理和使用权,从而变为系统的主设备。,(3) DMAC,将被访问存储单元地址送到地址总线上。,(4),向存储器和进行,DMA,传送的外设发出读写命令,则存储器和外设通过数据总线进行数据传送。,(5),若,DMA,传送己完成,则,DMAC,撤销对,CPU,的总线请求,交回系统总线的管理和使用权,回到从设备状态。,10.2.2,设备访问方式及实现,2024/9/16,Page,26,2024/9/16,Page,27,10.2,设备驱动模块化编程,10.2.3,内核与驱动程序的关系,操作系统中分为单体内核(,Monolithic kernel,)和微内核(,Micro kernel,)两种,单体内核是一个相对较大的程序,而微内核是一个较小的程序,操作系统的大部分功能运行在用户空间。,Linux,是一个单体内核,分成,5,个子系统,整个内核在一个地址空间。这样增加一个设备就比较麻烦,由于设备需要在内核空间运行,因此需要重新编译内核。,Linux,通过使用内核可以根据需要将各部分放入内核。,10.2.3,内核与驱动程序的关系,应用程序、库、内核、驱动程序的关系框图如图,10-2,所示:,2024/9/16,Page,28,2024/9/16,Page,29,10.2,设备驱动模块化编程,10.2.4,中断处理,中断处理是设备驱动程序的基本功能之一。,Linux,内核对所有的中断进行了统一编号,并把中断的相关信息存储在结构体数组,irq_desc,中。该数组定义在,/include/,linux/irq.h,中。每个数组元素对应一个中断,其中包含中断名、中断状态和硬件访问函数以及中断处理函数的入口地址等信息。,2024/9/16,Page,30,10.3 Linux,字符设备驱动,ARM,处理器的应用领域,Linux,字符设备驱动框架如下:,定义一个结构体,static,struct,file_operations,变量,其内定义一些设备的打开、关闭、读、写、控制函数;,在结构体外分别实现结构体中定义的这些函数;,向内核中注册或删除驱动模块。,字符设备驱动程序的框架的核心是数据结构,struct,file_operation,它是一系列指针的集合,每个被打开的文件都对应于一系列的操作,需要在驱动程序中加以实现。其定义如下(在,/include/,linux/fs.h,中定义):,struct,file_operations,int,(*seek) (,struct,inode,*,,,struct,file *,,,off_t,,,int,);,int,(*read) (,struct,inode,*,,,struct,file *,,,char,,,int,);,int,(*write) (,struct,inode,*,,,struct,file *,,,off_t,,,int,);,int,(*,readdir,) (,struct,inode,*,,,struct,file *,,,struct,dirent,*,,,int,);,int,(*select) (,struct,inode,*,,,struct,file *,,,int,,,select_table,*);,int,(*,ioctl,) (,struct,inode,*,,,struct,file *,,,unsined,int,,,unsigned long);,int,(*,mmap,) (,struct,inode,*,,,struct,file *,,,struct,vm_area_struct,*);,int,(*open) (,struct,inode,*,,,struct,file *);,int,(*release) (,struct,inode,*,,,struct,file *);,int,(*,fsync,) (,struct,inode,*,,,struct,file *);,int,(*,fasync,) (,struct,inode,*,,,struct,file *,,,int,);,int,(*,check_media_change,) (,struct,inode,*,,,struct,file *);,int,(*revalidate) (,dev_t,dev);,10.3 Linux,字符设备驱动,2024/9/16,Page,31,块设备接口主要是针对硬盘、软盘、,CD-ROM,等慢速设备设计的,以免耗费过多的,CPU,等待时间。它仅仅支持面向块的,I/O,操作,所有,I/O,操作都通过在内核地址空间中的,I/O,缓冲区进行。当多个请求同时提交给设备时,块设备访问的性能很大程度上取决于请求的顺序。由于块设备有可移动的单元,如果所有的请求是朝着同一个方向的,性能最佳。,10.4,块设备驱动,2024/9/16,Page,32,块设备驱动程序的特点如下:,1,、块设备接口相对复杂,不如字符设备明晰易用。,2,、块设备驱动程序对整个系统的性能影响较大,速度和效率是需要考虑的重要方面。,3,、系统中使用缓冲区与访问请求的优化管理来提高系统的性能。,10.4,块设备驱动,2024/9/16,Page,34,10.4,块设备驱动,10.4.1,块设备驱动简介,块设备(,block device,)是文件系统的物质基础,它也支持像文件一样被访问。这种为打开的块特殊文件提供正确的文件操作组的机制和字符设备的十分相似。,Linux,用,blkdevs,向量表维护已经登记的块设备文件。它像,chrdevs,向量表一样,使用设备的主设备号作为索引。它的条目也是,device_struct,数据结构。与字符设备不同,块设备进行分类,,SCSI,是其中一类,而,IDE,是另一类。,2024/9/16,Page,35,10.4,块设备驱动,10.4.2,块设备相关结构体,1.,struct,block_device_operations,结构体,2.,struct,gendisk,结构体,3.,struct,request_queue,结构体,4.,struct,hd_struct,结构体,5.,struct,bio,结构体,6.,struct,block_device,结构体,10.4,块设备驱动,struct,block_device_operations,结构体,块设备通过,struct,block_device_operations,结构使它们的操作对系统可用,定义在,/include/,linux/fs.h,中。,struct,block_device_operations,int,(*open) (,struct,inode,*,struct,file *); /*,打开设备*,/,int,(*release) (,struct,inode,*,struct,file *); /*,释放*,/,int,(*,ioctl,) (,struct,inode,*,struct,file *, unsigned, unsigned long);/*ioct1,系统调用的实现*,/,long (*,unlocked_ioctl,) (,struct,file *, unsigned, unsigned long);,long (*,compat_ioctl,) (,struct,file *, unsigned, unsigned long);,int,(*,direct_access,) (,struct,block_device,*,sector_t, unsigned long *);,int,(*,media_changed,) (,struct,gendisk,*);/*,用于检查驱动器介质是否改变*,/,int,(*,revalidate_disk,) (,struct,gendisk,*);/*,使介质有效*,/,int,(*,getgeo)(struct,block_device,*,struct,hd_geometry,*);/*,填充驱动器信息*,/,struct,module *owner; /*,模块拥有者*,/,;,2024/9/16,Page,36,2.,struct,gendisk,结构体,Linux,内核中,使用,struct,gendisk,结构体来表示一个独立的磁盘设备或者分区。,struct,gendisk,int,major; /*,主设备号*,/,int,first_minor,; /*,第,1,个次设备号*,/,int,minors; /*,最大次设备号数量,如果设备不能分区,该值为,1 */,char disk_name32; /*,主设备名 *,/,struct,hd_struct,*part; /*,分区信息*,/,int,part_uevent_suppress,;,struct,block_device_operations,*fops; /*,设备操作结构体*,/,struct,request_queue,*queue; /*,设备请求队列*,/,void *,private_data,; /*,私有数据*,/,sector_t,capacity; /*,扇区数*,/,int,flags; /*,设置驱动器状态的标志*,/,char devfs_name64;,int,number;,struct,device *,driverfs_dev,;,struct,kobject,kobj,;,10.4,块设备驱动,2024/9/16,Page,37,3.,struct,request_queue,结构体,struct,request_queue,结构体表征等待进行的请求队列。,struct,request_queue,struct,list_head,queue_head,;,struct,request *,last_merge,;,elevator_t,elevator;,request_fn_proc,*,request_fn,;,merge_request_fn,*,back_merge_fn,;,merge_request_fn,*,front_merge_fn,;,merge_requests_fn,*,merge_requests_fn,;,make_request_fn,*,make_request_fn,;,prep_rq_fn,*,prep_rq_fn,;,unplug_fn,*,unplug_fn,;,merge_bvec_fn,*,merge_bvec_fn,;,activity_fn,*,activity_fn,;,struct,timer_list,unplug_timer,;,int,unplug_thresh,;,unsigned long,unplug_delay,;,struct,work_struct,unplug_work,;,struct,backing_dev_info,backing_dev_info,;,10.4,块设备驱动,2024/9/16,Page,38,4.,struct,hd_struct,结构体,该结构体存储了磁盘上的分区信息。,struct,hd_struct,sector_ t,start_sect,;,sector_ t,nr_sects,;,struct,kobject,kobj,;,unsigned reads,read_sectors, writes,write_sectors,;,int,policy,partno,;,10.4,块设备驱动,2024/9/16,Page,39,5.,struct,bio,结构体,该结构用来描述内核以文件系统、虚拟内存子系统或系统调用的形式对块,I/O,设备进行的输入、输出数据的操作。,struct,bio, sector_ t,bi_sector,;,struct,bio *,bi_next,; /*,请求队列链表*,/,struct,block_device,*,bi_bdev,;,unsigned long,bi_flags,; /*,状态、命令等*,/,unsigned long,bi_rw,;,unsigned short,bi_vcnt,; /*,bio_vec,的个数*,/,unsigned short,bi_idx,; /*,bvl_vec,的当前索引*,/,unsigned short,bi_phys_segments,;,unsigned short,bi_hw_segments,;,unsigned,int,bi_size,; /*,剩余,I/O,数量*,/,unsigned,int,bi_hw_front_size,;,unsigned,int,bi_hw_back_size,;,unsigned,int,bi_max_vecs,; /*,最多可持有的,bvl_vecs,数量*,/,struct,bio_vec,*,bi_io_vec,; /*,实际的矢量表*,/,bio_end_io_t,*,bi_end_io,;,atomic_t,bi_cnt,;,void *,bi_private,;,bio_destructor_t,*,bi_destructor,; /*,销毁器*,/,;,10.4,块设备驱动,2024/9/16,Page,40,6.,struct,block_device,结构体,这个结构代表了内核中的一个设备,它可以表示整个磁盘或者一个特定的分区。当这个结构代表一个分区时,,bd_contains,指向包含这个分区的设备,,bd_part,指向设备的分区结构。当这个结构代表一个块设备时,,bd_disk,指向设备的,gendisk,结构。,struct,block_device,dev_t,bd_dev,;,struct,inode,*,bd_inode,; /*,分区节点*,/,int,bd_openers,;,struct,semaphore,bd_sem,; /*,打开,/,关闭锁*,/,struct,semaphore,bd_mount_sem,; /*,加载互斥锁*,/,struct,list_head,bd_inodes,;,void *,bd_holders,;,int,bd_holders,;,10.4,块设备驱动,2024/9/16,Page,41,Linux,系统具有比较完善的网络功能,,Linux,网络设备驱动是,Linux,网络应用的重要组成部分。在,Linux,网络系统中,其网络子系统主要是基于,BSD,unix,的,socket,机制。在网络子系统和驱动程序之间定义了专门的数据结构,sk_buff,进行数据传递。,Linux,系统提供支持对发送数据和接收数据的缓存,提供流量控制机制,提供对多协议的支持。,网络接口在内核层处理包的发送和接收,并不存在于进程中的,Linux,文件系统中。网络接口在文件系统中的角色就像被挂载的块设备,在内核中用,device,数据结构来表示,在做数据包的发送和接收时直接通过接口访问,不需要进行文件的操作。网络驱动程序和内核之间的交互一次处理一个网络包,这允许协议可以对驱动程序隐藏,而物理传输可以对协议隐藏。,10.5,网络设备驱动,2024/9/16,Page,42,Linux,网络设备驱动层次结构为:,1,、网络协议接口层,2,、网络设备接口层,3,、设备驱动功能层,4,、网络设备与媒介层,10.5,网络设备驱动,2024/9/16,Page,43,2024/9/16,Page,44,10.5,网络设备驱动,10.5.1,网络设备概述,常用的网络设备有中继器、网桥、路由器和网关。,中继器是局域网互连的最简单设备,它工作在,OSI,体系结构的物理层,接收并识别网络信号,然后再生信号并将其发送到网络的其他分支上。,网桥工作于,OSI,体系的数据链路层。网桥包含了中继器的功能和特性,不仅可以连接多种介质,还能连接不同的物理分支,能将数据包在更大的范围内传送。,2024/9/16,Page,45,10.5,网络设备驱动,10.5.2,网络设备的运行机制,在,Linux,中为了简化对设备的管理,通常将所有外围设备归为三类:字符设备、块设备和网络设备。为了将网络设备中的物理网络设备的多样性进行屏蔽,,Linux,对所有网络物理设备抽象并定义了一个统一概念:接口。对于所有网络硬件的访问都是通过接口进行的,接口实际上提供了一个对于所有类型网络硬件的一致化操作集合,用来处理对数据的发送和接收,10.5,网络设备驱动,10.5.2,网络设备的运行机制,网络接口定义在内核中的一个,struct,device,的数据结构中。每一个,device,的数据结构都是在驱动时创建的,,device,结构如图,10-5,所示。,2024/9/16,Page,46,2024/9/16,Page,47,10.5,网络设备驱动,10.5.3,sk_buff,数据结构,LinuxLinux,网络各层之间的数据传送都是通过,sk_buff,数据结构进行的,,sk_buff,提供了一套管理缓冲区的方法,是系统网络高效运行的关键,该结构在内核中处于网络子系统的核心地位。每个,sk_buff,包括一些控制方法和一块数据缓冲区,这个区域存放了网络传输的数据包。,10.5,网络设备驱动,其结构的示意图如图,10-6,所示:,2024/9/16,Page,48,2024/9/16,Page,49,10.5,网络设备驱动,10.5.4,数据包的发送和接收,网络设备的初始化主要由结构体,net_device,中的,init,函数指针所指向的初始化函数完成,当内核启动或加载网络驱动模块时,就会调用该函数。在初始化函数中通过检测物理设备的硬件特征判断网络物理设备是否存在,然后决定是否启动这个驱动程序。接下来对设备进行资源分配,最后对结构体,net_device,相应的成员变化量初始化,使得一个网络设备可以被系统使用。,2024/9/16,Page,50,10.5,网络设备驱动,10.5.5,网络设备驱动程序的加载,1.,网络设备驱动程序的内核启动加载,2.,网络设备驱动程序模块的加载,2024/9/16,Page,51,10.6,本章小结,本章介绍了,Linux,设备驱动和文件系统的关系、设备类型和设备号、设备驱动程序的开发流程、内核空间和用户空间、内核与驱动程序的关系、,Linux,字符设备驱动、块设备驱动、网络设备驱动的相关知识。重点是设备驱动的规范和工作原理。,2024/9/16,Page,52,10.7,思考与练习,概念题,(,1,),Linux,设备驱动程序有哪些特点?,(,2,)设备驱动和文件系统的关系?,(,3,),Linux,操作系统下有哪些主要的设备文件,(,4,)什么是模块编程,有什么特点?,(,5,)内核空间和用户空间有什么区别?,(,6,),Linux,字符设备驱动的框架?,操作题,(,1,)查找资料,实现一个,LED,驱动程序。,(,2,)查找资料,实现一个键盘驱动程序。,(,3,)编写一个字符设备的驱动程序,熟悉内核加载和系统调用的过程。,
展开阅读全文