[精选]第10章设备管理.pptx

上传人:茅**** 文档编号:87847116 上传时间:2023-04-18 格式:PPTX 页数:65 大小:484.75KB
返回 下载 相关 举报
[精选]第10章设备管理.pptx_第1页
第1页 / 共65页
[精选]第10章设备管理.pptx_第2页
第2页 / 共65页
点击查看更多>>
资源描述

《[精选]第10章设备管理.pptx》由会员分享,可在线阅读,更多相关《[精选]第10章设备管理.pptx(65页珍藏版)》请在得力文库 - 分享文档赚钱的网站上搜索。

1、第第10章章 设备管理设备管理 Linux和其他操作系统一样,支持众多的、各式各样的外接设备。但是,面对层出不穷的新硬件产品,必须有人不断编写新的驱动程序,以便让这些设备能够在 Linux 下正常工作,从这个意义上讲,讲述驱动程序的编写就是一件非常有意义的工作。本章也涉及到Linux下设备管理的原则和方法。举例来说,Linux下的驱动程序仅仅是为相应的设备编写几个基本函数,并向VFS注册就可以安装成功了。当应用程序需要设备时,可以访问该设备对应的文件节点,利用VFS调用该设备的相关处理函数。本章主要介绍了设备管理方面的有关知识:系统管理设备的方式。驱动程序运作过程。驱动程序的具体实例。10.1

2、 设备管理结构设备管理结构10.1.1 概述 设备管理即输入输出子系统,可分为上下两局部:一局部是上层的,与设备无关的,这局部根据输入输出请求,通过特定的设备驱动程序接口,来与设备进行通信。另一局部是下层的,与设备有关的,常称为设备驱动程序,它直接与相应设备打交道,并且向上层提供一组访问接口。设备管理的目标是对所有的外接设备进行良好的读、写、控制等操作。首先要解决的问题就是怎样将任意的一个设备的所有操作进行归纳,设计出统一的接口。内核常常使用设备类型、主设备号和次设备号来标识一个具体的设备。但用户希望能用同样的应用程序和命令来访问设备和普通文件。为此,Linux中的设备管理应用了设备文件这个概

3、念来统一设备的访问接口。简单的说,系统试图使它对所有各类设备的输入、输出看起来就好似对普通文件的输入、输出一样。如图10-1所示,应用程序通过Linux的系统调用与内核通信。由于Linux中将设备当作文件来处理,所以对设备进行操作的系统调用和对文件操作的类似,主要包括open、read、write、ioctl、close等。应用程序发出系统调用指令以后,会从用户态转换到内核态,通过内核将open这样的系统调用转换成对物理设备的操作。10.1.2 字符设备与块设备字符设备与块设备 字符设备以字节为单位进行数据处理。字符设备通常只允许按顺序访问,一般不使用缓存技术。如鼠标,声卡等。块设备以块为单位

4、进行处理,块的大小通常为0.5KB到32KB等。大多数块设备允许随机访问,而且常常采用缓存技术。块设备有硬盘、光盘驱动器等。可以查看文件/proc/devices获得。我们这里主要讨论字符设备,有兴趣的读者可参考其它书籍中有关块设备的内容。10.1.3 主设备号和次设备号主设备号和次设备号 设备管理中,除了设备类型字符设备或块设备以外,内核还需要一对称做主、次设备号的参数,才能唯一表示设备。主设备号major number相同的设备使用相同的驱动程序,而次设备号 minor number 用来区分具体设备的实例。例如,第一IDE接口上的所有磁盘及其分区共用同一主设备号3,而次设备号则为0,1,

5、2,3。10.1.4 Linux设备命名习惯设备命名习惯:Linux习惯上将设备文件放在目录/dev或其子目录之下。设备文件命名通常由两局部组成规则为:第一局部通常较短,可能只有2或3个字母组成,用来表示设备大类。例如,普通硬盘如IDE接口的为“hd,软盘为“fd。第二局部通常为数字或字母用来区别设备实例。例如,/dev/hda、/dev/hdb、/dev/hdc表示第一、二、三块硬盘;而 dev/hda1、/dev/hda2、/dev/hda3则表示第一硬盘的第一、二、三分区。10.2 驱动程序驱动程序10.2.1 驱动程序基本功能 在Linux操作系统中驱动程序是操作系统内核与硬件设备之间

6、的桥梁,它屏蔽了硬件的细节 如总线协议、DMA操作等,在应用程序看来硬件设备只是一个特殊的文件。驱动程序的基本功能为:1.对设备初始化和释放。如对音频设备而言包括向内核注册设备,设置音频的输入输出参数 如采样频率、采样宽度等、分配音频设备使用的内核内存等工作。2.对设备进行管理。包括实时参数设置以及提供对设备的操作接口。3.读取应用程序传送给设备文件的数据并回送应用程序请求的数据。这需要在用户空间、内核空间、总线及外设之间传输数据。4.检测和处理设备出现的错误。10.2.2 驱动程序的运作过程 为了便于读者理解,在此结合大家比较熟悉的键盘来了解其运作过程。如图10-2所示.当一个程序读/dev

7、/tty文件此为键盘时,就会执行系统调用sys_read在fs/read_write.c中,该系统调用在判别出所读文件是一个字符设备文件时,即会调用rw_char函数在fs/char_dev.c中,该函数则会根据所读设备的设备类型,主、次设备号等参数,由字符设备读写函数表设备开关表调用rw_tty,最终调用到这里的终端读操作函数tty_read 当用户在键盘上键入了一个字符时,会引起键盘中断响应,此时键盘中断处理程序就会从键盘控制器读入对应的键盘扫描码,然后根据使用的键盘扫描码映射表译成相应字符,放入tty读队列read_q中。然后调用中断处理程序的do_tty_interrupt函数,它又直

8、接调用行规则函数copy_to_cooked对该字符进行过滤处理,并放入tty辅助队列secondary中,供上述tty_read读取。同时把该字符放入tty写队列write_q中,并调用写控制台函数con_write。此时如果该终端的回显echo属性是设置的,则该字符会显示到屏幕上注:do_tty_interrupt和copy_to_cooked函数在tty_io.c中实现。10.2.2 常用接口介绍open:翻开设备,并初始化设备准备进行操作。可以为NULL,这样每次翻开设备总会成功,而且不通知设备驱动程序。read:从设备中读数据,需要提供字符串指针。write:向字符设备写数据,需要提

9、供所写内容指针。ioctl:控制设备,例如控制光盘的弹出等。需要提供符合设备预先定义的命令字。llseek:重新定位读、写位置,需要提供偏移量参数。flush:去除内容。release:关闭设备,并释放资源等。mmap:将设备内存映射到进程地址空间。通常只有块设备驱动程序使用。10.2.3 常用函数原型1.1.设备操作函数原形设备操作函数原形struct file_operationsstruct file_operations struct module*owner;struct module*owner;loff_tloff_t*llseek*llseek struct file*,lof

10、f_t,intstruct file*,loff_t,int;ssize_tssize_t*read*read struct file*,char*,size_t,loff_t struct file*,char*,size_t,loff_t*;ssize_tssize_t*write*writestruct file*,const char struct file*,const char*,size_t,loff_t*,size_t,loff_t*;int int*readdir*readdirstruct file*,void*,filldir_tstruct file*,void*,fi

11、lldir_t;unsigned intunsigned int*poll*pollstruct file*,struct struct file*,struct poll_table_struct*poll_table_struct*;int int*ioctl*ioctlstruct inode*,struct file struct inode*,struct file*,unsigned*,unsigned int,unsigned long int,unsigned long;int int mmapmmapstruct file*,struct vm_area_struct str

12、uct file*,struct vm_area_struct*;int int*open*openstruct inode*,struct file*struct inode*,struct file*;int int*flush*flushstruct file*struct file*;intint*release*releasestruct inode*,struct file*struct inode*,struct file*;int int*fsync*fsync struct file,struct dentry*,int struct file,struct dentry*,

13、int datasyncdatasync;int int*fasync*fasync int,struct file*,intint,struct file*,int;int int*lock*lockstruct file*,int struct file_lock*struct file*,int struct file_lock*;ssize_tssize_t*readv*readvstruct file*,const struct struct file*,const struct iovec iovec*,unsigned long,loff_t*,unsigned long,lof

14、f_t*;ssize_tssize_t*writev*writevstruct file*,const struct struct file*,const struct iovec iovec*,unsigned long,loff_t*,unsigned long,loff_t*;2向系统注册的函数原形int register_chrdevunsigned int major,const char*name,struct file_operations*fopsif major=0 write_lock&chrdevs_lock;forformajor=MAX_CHRDEV-1;major0

15、;major-major=MAX_CHRDEV-1;major0;major-if if chrdevsmajor.fops=NULLchrdevsmajor.fops=NULL chrdevsmajor.name=name;chrdevsmajor.name=name;chrdevsmajor.fops=fops;chrdevsmajor.fops=fops;write_unlock write_unlock&chrdevs_lock&chrdevs_lock;return major;return major;write_unlock&chrdevs_lock;return-EBUSY;i

16、fmajorMAX_CHRDEV return-EINVAL;write_lock&chrdevs_lock;if ifchrdevsmajor.fops&chrdevsmajor.fops&chrdevsmajorchrdevsmajor.fops!=fopsfops!=fops write_unlockwrite_unlock&chrdevs_lock&chrdevs_lock;return-EBUSY;return-EBUSY;chrdevsmajor.name=name;chrdevsmajor.name=name;chrdevsmajor.fops=fops;chrdevsmajor

17、.fops=fops;write_unlockwrite_unlock&chrdevs_lock&chrdevs_lock;return 0;return 0;10.3 驱动程序编写实例驱动程序编写实例 为了更清楚地讲述Linux中设备驱动程序的编写,加深读者对启动程序的了解。下面介绍一个简单的设备驱动的实现过程。由于基于特殊的硬件设备实现的驱动程序难度较大,而且不方便验证,下面举一个虚拟设备驱动程序的例子。10.3.1 设备功能介绍 实现虚拟设备的写入、读出等操作。这个驱动程序并不是基于特定硬件设备的,实际上仅仅是对内存进行读、写操作。当执行写入操作时,将会对特定的存储空间进行写入;当执行读

18、出操作时,将会对该存储空间进行数据的读取;同时还可以利用ioctl进行去除该存储空间的操作。这个mydrv设备的实现文件是mydrv.c,其中的文件接口flle_operations提供了mydrv_open、mydrv_release、mydrv_read、mydrv_write、mydrv_ioctl等函数。1.函数mydrv_read的功能是从mybuf100中读取字符串,并传递给调用的进程。2.函数mydrv_write的功能是将调用的进程传入的字符串赋值给mybuf,如果字符串的长度超过100,则只取前100个字符。3.函数mydrv_ioctl中仅仅实现了一个控制功能:去除mybu

19、f存储区。10.3.2 具体实现 首先,要根据设备功能的需要,编写file_operations结构中的操作函数。其次,要向系统注册该设备,包括字符设备的注册,devfs节点的注册与中断响应函数的注册。然后就可以利用对应的文件进行设备操控了。具体如下:1 1源程序源程序#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#define MYDRV_CLS_IO

20、c,0 x01 /定义清存储区命令字char mybuf100;/存储区域int mydrv_major=99;/主设备号devfs_handle_t dev_handle;/保存设备文件系统的注册句柄/第一步:编写file_operations函数ssize_t ssize_t mydrv_readmydrv_readstruct file*filp,char*buf,struct file*filp,char*buf,size_t count,loff_t*f_possize_t count,loff_t*f_pos;/;/函数声明函数声明static ssize_t static ssi

21、ze_t mydrv_writemydrv_writestruct file*struct file*filp,const char*buf,size_t count,loff_t*pposfilp,const char*buf,size_t count,loff_t*ppos;static int static int mydrv_ioctlmydrv_ioctl struct inode*struct inode*inode,struct file*file,unsigned int cmd,unsigned inode,struct file*file,unsigned int cmd,

22、unsigned long arglong arg;int int mydrv_openmydrv_open struct inode*inode,struct file struct inode*inode,struct file*filp*filp;int int mydrv_releasemydrv_releasestruct inode*inode,struct struct inode*inode,struct file*filpfile*filp;/;/函数声明函数声明struct struct file_operations mydrv_opsfile_operations my

23、drv_ops=/设备函数接口设备函数接口 open:mydrv_open,open:mydrv_open,/实现对设备的操作实现对设备的操作 read:mydrv_read,read:mydrv_read,write:mydrv_write,write:mydrv_write,ioctl:mydrv_ioctl,ioctl:mydrv_ioctl,release:mydrv_release;release:mydrv_release;/mydrv_read/mydrv_read将内核空间的将内核空间的mybufmybuf中的字符串中的字符串赋给用户空间的赋给用户空间的bufbuf区区ssiz

24、e_t mydrv_readstruct file*filp,char*bur,size_t count,loff_t*f_pos/filp:指向设备文件的指针;f_pos:偏移量int length=strlenmybuf;ifcount 99 count=99;/忽略大于100局部count=length-*f_pos;/计算字符个数的技巧if ifcopy_to_usercopy_to_userbuf,mybuf,countbuf,mybuf,count /重内核区复制到用户区重内核区复制到用户区 printk printkerror reading,copy_to_usernerror

25、 reading,copy_to_usern;retum-EFAULT;retum-EFAULT;*f_pos+=count;/*f_pos+=count;/下一个下一个retum count;retum count;/mydtv_write/mydtv_write将用户空间的将用户空间的bufbuf字符串赋给内字符串赋给内核空间的核空间的mybuf mybuf 数组中数组中static ssize_t static ssize_t mydrv_writemydrv_writestruct file*struct file*filp,const char*buf,size_t count,lo

26、ff_t*pposfilp,const char*buf,size_t count,loff_t*ppos int num;int num;num=count100?count:100;num=counti_rdev;ifmydrv_num return-1;if if dev =MAX_MYDRV_DEVdev =MAX_MYDRV_DEVreturn-ENODEV;return-ENODEV;filp-f_ap=&mydrv_ops;/filp-f_ap=&mydrv_ops;/指向操作函数指向操作函数printkprintk“open successn“open successn;MOD

27、_INC_USE_COUNT;/MOD_INC_USE_COUNT;/只是简单地加只是简单地加1 1return 0;return 0;/关闭关闭mydrvmydrv设备,这里只是将引用次数减设备,这里只是将引用次数减1 1int int mydrv_releasemydrv_releasestruct inode*inode,struct struct inode*inode,struct file*filpfile*filp MOD_DEC_USE_COUNT;MOD_DEC_USE_COUNT;return 0;return 0;/第二步:向系统注册该设备第二步:向系统注册该设备第二步:

28、向系统注册该设备第二步:向系统注册该设备/module/module的安装,采用两种方式进行了设备的注册的安装,采用两种方式进行了设备的注册int init_moduleint init_modulevoidvoid int result;int result;printkprintk“initing.n“initing.n;result=result=devfs_register_chrdevdevfs_register_chrdevmydrv_major,mydrv_major,“mydrv“mydrv,&mydrv_ops,&mydrv_ops;if if result 0result

29、0 printkprintkKERN_WARNING“mydrv:unable to get KERN_WARNING“mydrv:unable to get major%d nmajor%d n,mydrv_major,mydrv_major;return result;return result;dev_handle=dev_handle=devfs_registerdevfs_register NULL,“mydrv,NULL,“mydrv,DEVFS_FL_DEFAULT,99,0,DEVFS_FL_DEFAULT,99,0,S_IFCHR,&mydrv_ops,NULLS_IFCHR

30、,&mydrv_ops,NULL;/devfs_register/devfs_registerdevfs_handle_t dir,const char devfs_handle_t dir,const char*name,unsigned int flags,*name,unsigned int flags,/unsigned int major,unsigned int minor,umode_t/unsigned int major,unsigned int minor,umode_t mode,void*ops,void*infomode,void*ops,void*infoif my

31、drv_major:=0 mydrv_major=result;strcpymybuf,Hello,please write anything length 100to mydrv.;printk“succeed in getting buffer n;printk%s n,mybuf;retum 0;/module的卸载,进行设备的注销void cleanup_modulevoid devfs_unregister_chrdevmydrv_major,“mydrv;devfs_unregister dev_handle;printkexiting.n;2设备驱动程序编译和安装采用下面的命令可

32、以对mydrv.c进行编译:rootLinux root#gcc-c mydrv.c D_KERNEL_-DMODULE-O2-g-Wall-o 如果没有出错的话,将会在本目录下生成一个mydrv.o文件。下面的操作必须是以root身份进行的用命令su转换成root身份:先执行模块的插入操作,rootUnuxroot#/sbin/insmod mydrv.o 如果设备文件系统已经应用起来的话,此时在设备文件系统挂接的目录通常是dev下,就可以找到mydrv文件节点了。如果没有应用设备文件系统,则需要手工为设备添加文件节点:rootLinuxdev#mknod mydrv c 99 0 此时就可

33、以对设备进行读、写、ioctl等操作了。当不再需要对设备进行操作时,可以采用下面的命令卸载模块:rootLinuxdev#/sbin/rmmod mydrv3设备的使用下面的小程序可以对任何文件进行先写后读的操作:#include int mainFILE*fp;char bufl00;printfPlease input file name:;scanf%s,buf;iffp=fopenbuf,wb=NULL/buf:文件名;wb:模式只写、二进制 printfCould not opened!n;return-1;else printfFile open ok!n;printfPlease

34、 input 100:;scanf%s,buf;iffputsbuf,fp=EOF printfError writing file!;return-2;fgetsbut,100,fp;/由文件读取一字符串 printfthe File content is:%s n,buf;fclosefp;return 0;直接用gcc编译生成可执行文件之后,就可以用该程序对mydrv设备的文件节点进行操作。当然,也可以采用cat命令得到mydrv设备的输出内容。10.4 本章小结本章小结 本章主要介绍了设备管理方面的有关知识.首先介绍了系统是怎样来管理设备的,即把设备看作一种的特殊的文件,从而实现了对设备的有关操作。然后,说明了驱动程序运作过程。最后,结合一个具体实例,说明了驱动程序的具体的编写方法。练习题1.操作系统是怎么实现对设备进行管理的?2.举出5个驱动程序的常用接口函数。3.编写驱动程序一般有几个步骤,具体各是什么?

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 技术资料 > 其他杂项

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知得利文库网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号-8 |  经营许可证:黑B2-20190332号 |   黑公网安备:91230400333293403D

© 2020-2023 www.deliwenku.com 得利文库. All Rights Reserved 黑龙江转换宝科技有限公司 

黑龙江省互联网违法和不良信息举报
举报电话:0468-3380021 邮箱:hgswwxb@163.com