《[精选]第10章设备管理-PowerPointPresenta7664.pptx》由会员分享,可在线阅读,更多相关《[精选]第10章设备管理-PowerPointPresenta7664.pptx(62页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、第第10章章设备管理设备管理第第10章章 主要内容主要内容 本章主要介绍了设备管理方面的有关知识:本章主要介绍了设备管理方面的有关知识:系统管理设备的方式。系统管理设备的方式。驱动程序运作过程。驱动程序运作过程。驱动程序的具体实例。驱动程序的具体实例。第第10章章 目录目录 10.1 设备管理结构设备管理结构 10.2 驱动程序驱动程序 10.3 驱动程序编写实例驱动程序编写实例第第10章章 目录目录 10.1 设备管理结构设备管理结构 10.2 驱动程序驱动程序 10.3 驱动程序编写实例驱动程序编写实例10.1 设备管理结构:设备管理即输入输出子系统,分为上下两部分:1.上层的上层的,与设
2、备无关的,这部分根据输入输出请求,通过特定的设备驱动程序接口,来与设备进行通信。2.下层的下层的,与设备有关的,常称为设备驱动程序,它直接与相应设备打交道,并且向上层提供一组访问接口。概述概述10.1 设备管理结构:概述 设备管理的目标是对所有的外接设备进行良好的读、写、控制等操作。待解决问题:待解决问题:怎样将任意的一个设备的所有操作进行归纳,设计出统一的接口。内核常常使用设备类型、主设备号和次设备号来标识一个具体的设备。10.1 设备管理结构:概述概述 Linux中的设备管理应用了设备文件设备文件这个概念来统一设备的访问接口。简单的说,系统试图使它对所有各类设备的输入、输出看起来就好像对普
3、通文件的输入、输出一样。如图10-1所示,应用程序通过Linux的系统调用与内核通信。10.1 设备管理结构:概述 由于Linux中将设备当作文件来处理,所以对设备进行操作的系统调用和对文件操作的类似,主要包括open()、read()、write()、ioctl()、close()等。应用程序发出系统调用指令以后,会从用户态转换到内核态,通过内核将open()这样的系统调用转换成对物理设备的操作。10.1 设备管理结构:字符设备以字节为单位进行数据处理字符设备以字节为单位进行数据处理。字符设备通常只允许按顺序访问,一般不使用缓存技术。如鼠标,声卡等。块设备以块为单位进行处理块设备以块为单位进
4、行处理,块的大小通常为0.5KB到32KB等。字符设备与块设备字符设备与块设备10.1 设备管理结构:字符设备与块设备 大多数块设备允许随机访问,而且常常采用缓存技术。块设备有硬盘、光盘驱动器等。可以查看文件/proc/devices获得。这里主要讨论字符设备,有兴趣的读者可参考其它书籍中有关块设备的内容。10.1 设备管理结构:设备管理中,除了设备类型(字符设备或块设备)以外,内核还需要一对称做主、主、次设备号次设备号的参数,才能唯一表示设备。主设备号和次设备号主设备号和次设备号10.1 设备管理结构:主设备号和次设备号主设备号和次设备号 主设备号(major number)相同的设备使用相
5、同的驱动程序,而次设备号(minor number)用来区分具体设备的实例。例如例如:第一IDE接口上的所有磁盘及其分区共用同一主设备号3,而次设备号则为0,1,2,3。10.1 设备管理结构:Linux习惯上将设备文件放在目录/dev或其子目录之下。设备文件命名(通常由两部分组成)规则为:第一部分通常较短,可能只有2或3个字母组成,用来表示设备大类。例如例如:普通硬盘如IDE接口的为“hd”,软盘为“fd”。Linux设备命名习惯设备命名习惯10.1 设备管理结构:Linux设备命名习惯设备命名习惯 第二部分通常为数字或字母用来区别设备实例。例如例如:/dev/hda、/dev/hdb、/d
6、ev/hdc表示第一、二、三块硬盘;而 dev/hda1、/dev/hda2、/dev/hda3则表示第一硬盘的第一、二、三分区。第第10章章 目录目录 10.1 设备管理结构设备管理结构 10.2 驱动程序驱动程序 10.3 驱动程序编写实例驱动程序编写实例10.2 驱动程序:在Linux操作系统中驱动程序是操作系统内核与硬件设备之间的桥梁,它屏蔽了硬件的细节(如总线协议、DMA操作等),在应用程序看来硬件设备只是一个特殊的文件。驱动程序基本功能驱动程序基本功能10.2 驱动程序:驱动程序基本功能驱动程序基本功能 1.对设备初始化和释放。如对音频设备而言包括向内核注册设备,设置音频的输入输出
7、参数(如采样频率、采样宽度等)、分配音频设备使用的内核内存等工作。2.对设备进行管理。包括实时参数设置以及提供对设备的操作接口。驱动程序的基本功能为:10.2 驱动程序:驱动程序基本功能驱动程序基本功能 3.读取应用程序传送给设备文件的数据并回送应用程序请求的数据。这需要在用户空间、内核空间、总线及外设之间传输数据。4.检测和处理设备出现的错误。10.2 驱动程序:驱动程序的运作过程驱动程序的运作过程 当一个程序读/dev/tty文件(此为键盘)时,就会执行系统调用sys_read()(在fs/read_write.c中),该系统调用在判别出所读文件是一个字符设备文件时,即会调用rw_char
8、()函数(在fs/char_dev.c中),该函数则会根据所读设备的设备类型,主、次设备号等参数,由字符设备读写函数表(设备开关表)调用rw_tty(),最终调用到这里的终端读操作函数tty_read()10.2 驱动程序:驱动程序的运作过程驱动程序的运作过程 当用户在键盘上键入了一个字符时,会引起键盘中断响应,此时键盘中断处理程序就会从键盘控制器读入对应的键盘扫描码,然后根据使用的键盘扫描码映射表译成相应字符,放入tty读队列read_q中。10.2 驱动程序:驱动程序的运作过程驱动程序的运作过程 然后调用中断处理程序的do_tty_interrupt()函数,它又直接调用行规则函数copy
9、_to_cooked()对该字符进行过滤处理,并放入tty辅助队列secondary中,供上述tty_read()读取。10.2 驱动程序:驱动程序的运作过程驱动程序的运作过程 同时把该字符放入tty写写队列write_q中,并调用写控制台函数con_write()。此时如果该终端的回显(echo)属性是设置的,则该字符会显示到屏幕上(注:do_tty_interrupt()和copy_to_cooked()函数在tty_io.c中实现)。10.2 驱动程序:open():打开设备,并初始化设备准备进行操作。可以为NULL,这样每次打开设备总会成功,而且不通知设备驱动程序。read():从设备
10、中读数据,需要提供字符串指针。write():向字符设备写数据,需要提供所写内容指针。ioctl():控制设备,例如控制光盘的弹出等。需要提供符合设备预先定义的命令字。常用接口介绍常用接口介绍10.2 驱动程序:常用接口介绍常用接口介绍 llseek():重新定位读、写位置,需要提供偏移量参数。flush():清除内容。release():关闭设备,并释放资源等。mmap():将设备内存映射到进程地址空间。通常只有块设备驱动程序使用。10.2 驱动程序:struct file_operations struct module*owner;loff_t(*llseek)(struct file*
11、,loff_t,int);ssize_t(*read)(struct file*,char*,size_t,loff_t*);ssize_t(*write)(struct file*,const char *,size_t,loff_t*);int(*readdir)(struct file*,void*,filldir_t);常用函数原型常用函数原型1.设备操作函数原形 unsigned int(*poll)(struct file*,struct poll_table_struct*);int(*ioctl)(struct inode*,struct file*,unsigned int,
12、unsigned long);int(mmap)(struct file*,struct vm_area_struct*);int(*open)(struct inode*,struct file*);int(*flush)(struct file*);int(*release)(struct inode*,struct file*);10.2 驱动程序:常用函数原型 int(*fsync)(struct file,struct dentry*,int datasync);int(*fasync)(int,struct file*,int);int(*lock)(struct file*,in
13、t struct file_lock*);ssize_t(*readv)(struct file*,const struct iovec*,unsigned long,loff_t*);ssize_t(*writev)(struct file*,const struct iovec*,unsigned long,loff_t*);10.2 驱动程序:常用函数原型int register_chrdev(unsigned int major,const char*name,struct file_operations*fops)if(major=0)write_lock(&chrdevs_lock
14、);2向系统注册的函数原形10.2 驱动程序:常用函数原型 for(major=MAX_CHRDEV-1;major0;major-)if(chrdevsmajor.fops=NULL)chrdevsmajor.name=name;chrdevsmajor.fops=fops;write_unlock(&chrdevs_lock);return major;10.2 驱动程序:常用函数原型 write_unlock(&chrdevs_lock);return-EBUSY;if(majorMAX_CHRDEV)return-EINVAL;write_lock(&chrdevs_lock);10.
15、2 驱动程序:常用函数原型 if(chrdevsmajor.fops&chrdevsmajor.fops!=fops)write_unlock(&chrdevs_lock);return-EBUSY;chrdevsmajor.name=name;chrdevsmajor.fops=fops;write_unlock(&chrdevs_lock);return 0;第第10章章 目录目录 10.1 设备管理结构设备管理结构 10.2 驱动程序驱动程序 10.3 驱动程序编写实例驱动程序编写实例10.3 驱动程序编写实例 为了更清楚地讲述Linux中设备驱动程序的编写,加深读者对启动程序的了解。下
16、面介绍一个简单的设备驱动的实现过程设备驱动的实现过程。由于基于特殊的硬件设备实现的驱动程序难度较大,而且不方便验证,下面举一个虚拟设备驱动程序虚拟设备驱动程序的例子。10.3 驱动程序编写实例:实现虚拟设备的写入、读出等操作。这个驱动程序并不是基于特定硬件设备的,实际上仅仅是对内存进行读、写操作。设备功能介绍设备功能介绍10.3 驱动程序编写实例:设备功能介绍设备功能介绍 1.函数mydrv_read()的功能是从mybuf100中读取字符串,并传递给调用的进程。2.函数mydrv_write()的功能是将调用的进程传入的字符串赋值给mybuf,如果字符串的长度超过100,则只取前100个字符
17、。3.函数mydrv_ioctl()中仅仅实现了一个控制功能:清除mybuf存储区。10.3 驱动程序编写实例:首先,要根据设备功能的需要,编写首先,要根据设备功能的需要,编写file_operations结构中的操作函数。结构中的操作函数。其次,要向系统注册该设备,包括字符设备的注册,其次,要向系统注册该设备,包括字符设备的注册,devfs节点的注册与中断响节点的注册与中断响应函数的注册。然后就可以利用对应的文件进行设备操控了。应函数的注册。然后就可以利用对应的文件进行设备操控了。具体如下具体如下:具体实现具体实现10.3 驱动程序编写实例:具体实现具体实现#include#include#
18、include#include#include#include#include#include#include 1源程序:10.3 驱动程序编写实例:具体实现具体实现#define MYDRV_CLS_IO(c,0 x01)/定义清存储区命令字char mybuf100;/存储区域int mydrv_major=99;/主设备号devfs_handle_t dev_handle;/保存设备文件系统的注册句柄/第一步:编写file_operations函数10.3 驱动程序编写实例:具体实现具体实现 ssize_t mydrv_read(struct file*filp,char*buf,siz
19、e_t count,loff_t*f_pos);/函数声明static ssize_t mydrv_write(struct file*filp,const char*buf,size_t count,loff_t*ppos);static int mydrv_ioctl(struct inode*inode,struct file*file,unsigned int cmd,unsigned long arg);int mydrv_open(struct inode*inode,struct file*filp);int mydrv_release(struct inode*inode,st
20、ruct file*filp);/函数声明10.3 驱动程序编写实例:具体实现具体实现struct file_operations mydrv_ops=/设备函数接口 open:mydrv_open,/实现对设备的操作 read:mydrv_read,write:mydrv_write,ioctl:mydrv_ioctl,release:mydrv_release;/mydrv_read()将内核空间的mybuf中的字符串赋给用户空间的buf区10.3 驱动程序编写实例:具体实现具体实现ssize_t mydrv_read(struct file*filp,char*bur,size_t co
21、unt,loff_t*f_pos)/filp:指向设备文件的指针;f_pos:偏移量int length=strlen(mybuf);if(count 99)count=99;/忽略大于100部分count=length-*f_pos;/计算字符个数的技巧10.3 驱动程序编写实例:具体实现具体实现if(copy_to_user(buf,mybuf,count)/重内核区复制到用户区 printk(error reading,copy_to_usern”);retum-EFAULT;*f_pos+=count;/下一个retum count;/mydtv_write()将用户空间的buf字符串
22、赋给内核空间的mybuf 数组中10.3 驱动程序编写实例:具体实现具体实现static ssize_t mydrv_write(struct file*filp,const char*buf,size_t count,loff_t*ppos)int num;num=counti_rdev);if(mydrv_num)return-1;10.3 驱动程序编写实例:具体实现具体实现if(dev =MAX_MYDRV_DEV)return-ENODEV;filp-f_ap=&mydrv_ops;/指向操作函数printk(“open successn”);MOD_INC_USE_COUNT;/只是
23、简单地加1return 0;/关闭mydrv设备,这里只是将引用次数减1int mydrv_release(struct inode*inode,struct file*filp)MOD_DEC_USE_COUNT;return 0;10.3 驱动程序编写实例:具体实现具体实现/第二步:向系统注册该设备/module的安装,采用两种方式进行了设备的注册int init_module(void)int result;printk(“initing.n”);result=devfs_register_chrdev(mydrv_major,“mydrv”,&mydrv_ops);10.3 驱动程序编
24、写实例:具体实现具体实现if(result 0)printk(KERN_WARNING“mydrv:unable to get major%d n”,mydrv_major);return result;dev_handle=devfs_register(NULL,“mydrv,DEVFS_FL_DEFAULT,99,0,S_IFCHR,&mydrv_ops,NULL);/devfs_register(devfs_handle_t dir,const char*name,unsigned int flags,/unsigned int major,unsigned int minor,umod
25、e_t mode,void*ops,void*info)10.3 驱动程序编写实例:具体实现具体实现if(mydrv_major:=0)mydrv_major=result;strcpy(mybuf,Hello,please write anything(length 100)to mydrv.”);printk(“succeed in getting buffer n);printk(%s n,mybuf);retum 0;/module的卸载,进行设备的注销10.3 驱动程序编写实例:具体实现具体实现void cleanup_module(void)devfs_unregister_chr
26、dev(mydrv_major,“mydrv”);devfs_unregister(dev_handle);printk(exiting.n);10.3 驱动程序编写实例:具体实现具体实现2设备驱动程序编译和安装 采用下面的命令可以对mydrv.c进行编译:rootLinux root#gcc-c mydrv.c D_KERNEL_-DMODULE-O2-g-Wall-o如果没有出错的话,将会在本目录下生成一个mydrv.o文件。10.3 驱动程序编写实例:具体实现具体实现 下面的操作必须是以root身份身份进行的(用命令su转换成root身份):先执行模块的插入操作,rootUnuxroot
27、#/sbin/insmod mydrv.o10.3 驱动程序编写实例:具体实现具体实现 如果设备文件系统已经应用起来的话,此时在设备文件系统挂接的目录(通常是dev)下,就可以找到mydrv文件节点了。如果没有应用设备文件系统,则需要手工为设备添加文件节点:rootLinuxdev#mknod mydrv c 99 0此时就可以对设备进行读、写、ioctl等操作了。10.3 驱动程序编写实例:具体实现具体实现 当不再需要对设备进行操作时,可以采用下面的命令卸载模块:rootLinuxdev#/sbin/rmmod mydrv#include int main()FILE*fp;char buf
28、l00;printf(Please input file name:);scanf(%s,buf);3设备的使用设备的使用下面的小程序可以对任何文件进行先写后读的操作:下面的小程序可以对任何文件进行先写后读的操作:10.3 驱动程序编写实例:具体实现具体实现if(fp=fopen(buf,wb)=NULL)/buf:文件名;wb:模式(只写、二进制)printf(Could not opened!n);return-1;else printf(File open ok!n);printf(Please input(100):);scanf(%s,buf);10.3 驱动程序编写实例:具体实现具
29、体实现if(fputs(buf,fp)=EOF)printf(Error writing file!);return-2;fgets(but,100,fp);/由文件读取一字符串 printf(the File content is:%s n,buf);fclose(fp);return 0;10.3 驱动程序编写实例:具体实现具体实现 直接用直接用gcc编译生成可执行文件之后,就可编译生成可执行文件之后,就可以用该程序对以用该程序对mydrv设备的文件节点进行操作。设备的文件节点进行操作。当然,也可以采用当然,也可以采用cat命令得到命令得到mydrv设备设备的输出内容。的输出内容。本章主要介绍了设备管理方面的有关知识.首先介绍了系统是怎样来管理设备的,即把设备看作一种的特殊的文件,从而实现了对设备的有关操作。然后,说明了驱动程序运作过程。最后,结合一个具体实例,阐明了驱动程序的具体的编写方法。练习题练习题1.操作系统是怎么实现对设备进行管理的?2.举出5个驱动程序的常用接口函数。3.编写驱动程序一般有几个步骤,具体各是什么?