嵌入式系统嵌入式系统第十章嵌入式Linux设备驱动程序第十章嵌入式Linux设备驱动程序1第十章Agenda10.1Linux的设备介绍10.2Linux设备驱动程序介绍的设备10.3Linux的设备驱动程序的模块结构10.4Linux的设备驱动程序的编撰举例动程序的模块结构210.1Linux的设备介绍10.1.1Linux的设备分类10.1.2设备文件10.1.3设备号310.1.1Linux的设备分类Linux支持三类硬件设备:字符设备:指这些无须缓冲直接读写的设备块设备:只能以块为单位进行读写,典型的块大小为512或1024字节小为512或1024字节。网路设备:可以通过BSD套插口访问410.1.2设备文件Linux具象了对硬件的处理linux关机命令,所有的硬件设备都可以作为普通文件来看待;它们可以使用和操作系统相同的、标准的系统调用插口来打开关掉读写和控制I/O的操作来打开、关闭、读写和控制I/O的操作,而驱动程序的主要任务也就是要实现这种系统调用函数。而5设备文件Linux系统中的所有硬件设备都使用一个特殊的设备文件来表示诸如,系统中的第一个IDE硬碟用/dev/had来表示并口可以用/dev/stty0来表示示。
并口可以用/dev/stty0来表示.6因为引入了设备文件这一概念,Linux为文件和设备提供了一致的用户插口。对用户来说,设备文件与普通文件并无区别。10.1.3设备号每位设备文件都对应有两个设备号:一个是主设备号,表示该设备的种类,也标示了该设备所使用的驱动程序;另一个是次设备号另个是次设备号,标示使用同序的不同硬件设备。使用mknod命令可以创建指定类型的设备文件,同时为其分配相应的主设备号和次设备号。[root@xsbaseroot]#mknod/dev/lp0c60标示使用同一设备驱动程7设备驱动程第十章Agenda10.1Linux的设备介绍10.2Linux设备驱动程序介绍的设备10.3Linux的设备驱动程序的模块结构10.4Linux的设备驱动程序的编撰举例动程序的模块结构810.2Linux设备驱动程序介绍10.2.1设备驱动的层次10.2.2设备驱动程序与外界的插口9设备驱动程序设备驱动程序是操作系统内核和机器硬件之间的插口。设备驱动程序为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,应用程序可以象操作普通文件一样对硬件设备进行操作操作。
设备驱动程序主要完成以下功能:对设备初始化和释放。把数据从内核传送到硬件和从硬件读取数据。读取应用程序传送给设备文件的数据和回送应用程序恳求的数据。检查和处理设备出现的错误。1010.2.1设备驱动的层次Linux下的设备驱动程序是内核的一部份,运行在内核模式,也就是说设备驱动程序为内核提供了一个I/O插口,用户使用这个插口实现对设备的操作。Linux的设备驱动程序介于(设备)文件系统与化学设备动程序介设备中间。用户通过应用程序进程输入输入恳求,从而调用(设备)文件系统,(设备)文件系统通过设备驱动程序控制化学设备进行设备的操作,如进行c盘文件的读出和写入操作等等,如图所示。Linux设备驱动程序包含了中断处理程序和设备服务子程序。11设备件系与物设备驱动的层次用户程序的进程输入/输出恳求输入/输出响应12(设备)文件系统设备驱动程序设备服务子程序中断处理程序化学设备化学设备控制器10.2.2设备驱动程序与外界的插口打开的设备在内核内部由file结构标示,内核使用file_operations结构访问驱动程序的函数。file_operations结构是一个定义在中的函数表针字段,这就是一般所说的设备驱动程中的函数表针数就是序与外界的插口。
每位文件都与它自己的函数集相关联(通过包括指向file_operations结构的一个名为f_op的表针数组)。这种操作主要负责系统调用的实现,并因而被命名为open、read等。13常所说的设备驱动程file_operationsstructfile_operations{structmodule*owner;loff_t(*llseek)(structfile*,loff_t,int);ssize_t(*read)(structfile*,char*,size_t,loff_t*);ssize_t(*write)(structfile*,constchar*,size_t,loff_t*);int(*readdir)(structfile*,void*,filldir_t);unsignedint(*poll)(structfile*,structpoll_table_struct*);int(*ioctl)(structinode*,structfile*,unsignedint,unsignedlong);int(*mmap)(structfile*,structvm_area_struct*);int(*open)(structinode*,structfile*);int(*flush)(structfile*);int(*release)(structinode*,structfile*);int(*fsync)(structfile*,structdentry*,intdatasync);int(*fasync)(int,structfile*,int);int(*lock)(structfile*,int,structfile_lock*);ssize_t(*readv)(structfile*,conststructiovec*,unsignedlong,loff_t*);ssize_t(*writev)(structfile*,conststructiovec*,unsignedlong,loff_t*);ssize_t(*sendpage)(structfile*,structpage*,int,size_t,loff_t*,int);unsignedlong(*get_unmapped_area)(structfile*,unsignedlong,unsignedlong,unsignedlong,unsignedlong);#ifdefMAGIC_ROM_PTRint(*romptr)(structfile*,structvm_area_struct*);#endif/*MAGIC_ROM_PTR*/};14Ownermodule的拥有者。
Llseek重新定位读写位置。Read从设备中读取数据。Write向字符设备中写入数据。Readdir只用于文件系统,对设备无用。Ioctl控制设备,除读写操作外的其他控制命令。Mmap将设备显存映射到进程地址空间,一般只用于块设备。Open打开设备并初始化设备。15Flush清理内容,通常只用于网路文件系统中。Release关掉设备并释放资源。Fsync实现显存与设备的同步,如将显存数据写入硬碟。Fasync实现显存与设备之间的异步通信。Lock文件锁定,用于文件共享时的互斥访问。Readv在进行读操作前要验证地址是否可读。Writev在进行写操作前要验证地址是否可写。第十章Agenda10.1Linux的设备介绍10.2Linux设备驱动程序介绍的设备10.3Linux的设备驱动程序的模块结构10.4Linux的设备驱动程序的编撰举例动程序的模块结构1610.3Linux的设备驱动程序的模块结构Linux中的可加载模块(loadablemodule)是Linux内核支持的动态可加载模块(dynamicloadablemodule),它们是内核的一部份,然而并没有编译到内核上面去。
模块可以单独编译成目标代码,以.o的目标文件方式存在。它可以按照须要在系统启动后动态加载到系统内核之中。当模块不再被须要时,可以动态地写在出系统内核。Linux中地大多数设备驱动程序都以模块地方式存在。17模块模块的装载和卸载有两种形式:可以通过超级用户运行insmod和rmmod命令显式地将模块载入内核或从内核中卸载;内核自身也可以在须要时,恳求守护进程(kerneld)装载和卸载模块。18模块形式对性能的影响:采用了一些额外的代码和数据结构linux设备驱动程序 电子书,它们占用了一部份显存。用户进程通过模块对内核资源进行的访问是间接的,不可防止地增加了内核资源地访问效率。常用命令lsmod:列举当前系统中加载的模块。insmod,modprobe:用于加载当前模块,但insmod不会手动解决依存关系,而modprobe则可以按照模块间依存关系以及/etc/modules/conf按照模依存关系文件中的内容手动插入模块。rmmod:把某个不再使用的模块从内核中卸载。depmod:制造模块相关文件(moduledependencyfile),便于前面要使用insmod命令拿来查询模块的具体位置19第十章Agenda10.1Linux的设备介绍10.2Linux设备驱动程序介绍的设备10.3Linux的设备驱动程序的模块结构10.4Linux的设备驱动程序的编撰举例动程序的模块结构20字符设备驱动程序一个最简单的字符设备驱动程序该字符设备具备4个基本操作bytedevice_open(),bytedevice_write(),bytedeviceread(),bytedevicerelease()tedevice_read(),bytedevice_release()实现的基本功能为向这个新建的字符设备先写入一些数据,之后再从这个设备中读取这种数据。
211主要数据结构和全局变量file_operations{}Structbytedevice.c222主要插口函数bytedevice_open,bytedevice_release:主要是对设备进行初始化和释放,实现了设备的打开和关掉功能。bytedevice_read:当设备文件执行该函数调用时,表面上看像时从设备中读取数据,实际上是从时表面看像时从设备中读取数据内核空间的数据队列中读取,通过copy_to_user()函数,把数据从内核空间传送到用户空间,致使用户空间的其他代码(测试代码)可以访问那些数据。bytedevice_write:和bytedevice_read()函数相像,只不过数据传送的方向发生了变化,即把参数中的count字节数从用户空间的缓冲区buf复制到硬件或则内核的缓冲区中。23实际是从3模块加载采取模块加载的方法:init_module和cleanup_module函数主要使用了驱动程序的注册与注销中的egitehde()和register_chrdev()和unregister_chrdev()。
244驱动安装过程完成前面的工作后,对上面的代码进行编译,并通过insmod的形式加载其到内核中。例如bytedevice源代码置于/usr/src/bytedevice下,可以这样编译linux设备驱动程序 电子书,生成bytedevice.o文件:$gccbytedevice.c–I/usr/src/bytedevice/include–cbytedevicecDKERNELbytedevice.c–D__KERNEL__-DMODULE接出来把目标文件加载到内核。可以使用命令:$insmod–fbytedevice.o假如早已成功安装linux系统介绍,在/proc/devices文件中就可以找到设备bytedevice,而且可以看见它的主设备号(内核动态分配所得)。假如要卸载模块,运行:$rmmodbytedevice创建一个设备文件,通过设备文件就可以访问驱动程序DMODULE2510.4Linux的设备驱动程序的编撰举例作业在Linux系统上编撰/编译/加载/使用这个驱动程序26EndofChapter1027