北京邮电大学电子工程学院满毅北京邮电大学设备管理•1设备管理概述•2I/O控制方式•3设备分配•4Linux中的设备管理•5.Linux设备驱动程序编写1设备管理概述▫1.1I/O设备的类型•按设备的所属关系可以将I/O设备分为以下两类。(1)系统设备•系统设备是在系统生成时已登记于系统中的标准设备,属于系统的基本配置。(2)用户设备•用户设备是在系统生成时未登记在系统中的非标准设备。•按设备的信息交换的单位可将I/O设备分为以下两类。(1)字符设备(b)•字符设备是以字符为单位进行输入和输出的设备。(2)块设备(c)•块设备的输入和输出是以数据块为单位的。•特征•在对字符设备发出读/写请求时,实际的硬件I/O一般就紧接着发生了。•块设备则利用一块系统内存作缓冲区,当缓冲区中的数据能满足用户对设备的操作要求,就返回请求的数据,如果不能,就调用请求函数来进行实际的I/O操作。•块设备是主要针对磁盘等慢速设备设计的,以免耗费过多的CPU时间来等待。•按设备的共享属性可将I/O设备分为以下三类。(1)独占设备•所有的字符设备都是独占设备。独占设备是指一段时间内只允许一个用户(进程)访问的设备,即临界资源。(2)共享设备•块设备都是共享设备。共享设备是指一段时间内允许多个进程同时访问的设备。(3)虚拟设备•通过虚拟设备技术把一台独占设备变换为若干台逻辑设备,供若干个用户(进程)同时使用,以提高设备的利用率。▫1.2设备管理的任务和功能•设备管理是对计算机的输入/输出系统的管理,它是操作系统中最具有多样性和复杂性的部分。其主要任务如下所述。•(1)选择和分配I/O设备以便进行数据传输操作。•(2)控制I/O设备和CPU(或内存)之间交换数据。•(3)为用户提供一个友好的透明接口,把用户和设备硬件特性分开,使得用户在编制应用程序时不必涉及具体设备,由系统按用户的要求来对设备的工作进行控制。另外,这个接口还为新增加的用户设备提供一个和系统核心相连接的入口,以便用户开发新的设备管理程序。•(4)提高设备和设备之间、CPU和设备之间以及进程和进程之间的并行操作程度,以使操作系统获得最佳效率。•为了完成上述主要任务,设备管理程序一般要提供下述功能。•(1)提供和进程管理系统的接口•(2)进行设备分配•(3)实现设备和设备、设备和CPU等之间的并行操作•(4)进行缓冲管理•(5)设备控制与驱动▫1.3设备控制器•设备控制器是CPU与I/O设备之间的接口,它接收从CPU发来的命令并去控制I/O设备工作。设备控制器是一个可编址设备,当它仅控制一个设备时,它只有一个惟一的设备地址;当它控制多个设备时,则应具有多个设备地址,使每一个地址对应一个设备。•为实现设备控制器的功能,大多数设备控制器都由以下三部分组成。1.设备控制器与处理机的接口2.设备控制器与设备的接口3.I/O逻辑图10.1设备控制器的组成▫1.4I/O通道•设置I/O通道的目的是使一些原来由CPU处理的I/O任务转由通道来承担,从而把CPU从繁杂的I/O任务中解脱出来。•在设置了通道后,CPU只需向通道发送一条I/O指令。通道在收到该指令后,便从内存中取出本次要执行的通道程序,然后执行该通道程序,仅当通道完成了规定的I/O任务后,才向CPU发中断信号。•实际上,I/O通道是一种特殊的处理机,它具有执行I/O指令的能力,并通过执行通道(I/O)程序来控制I/O操作。•通道有两种基本类型:选择通道和多路通道。图10.2单通路I/O系统图10.3多通路I/O系统▫1.6设备驱动•设备驱动程序的主要任务,是接收上层软件发来的抽象要求,如read或write命令,再把它转换为具体要求,发送给设备控制器;此外,它也将由设备控制器发来的信号传送给上层软件,从而完成两者间的相互通信。•设备驱动程序的处理过程。(1)将抽象要求转换为具体要求(2)检查I/O请求的合法性(3)读出和检查设备的状态(4)传送必要的参数(5)工作方式的设置(6)启动I/O设备2I/O控制方式▫2.1程序I/O方式•图10.4示出了程序I/O方式的流程。向I/O控制器发读命令读I/O控制器的状态检查状态?从I/O控制器中读入字向存储器中写字传送完成?下一条指令完成未完就绪出错未就绪图10.4程序I/O方式的流程▫2.2中断驱动I/O控制方式•在现代计算机系统中,都毫无例外地引入了中断机构,致使对I/O设备的控制,广泛采用中断驱动(InterruptDriven)方式。即当某进程要启动某个I/O设备工作时,便由CPU向相应的设备控制器发出一条I/O命令,然后立即返回继续执行原来的任务,设备控制器则按照该命令的要求去控制指定I/O设备。此时,CPU与I/O设备并行操作。•例如,在输入时,当设备控制器收到CPU发来的读命令后,便去控制相应的输入设备读数据。一旦数据进入数据寄存器,控制器便通过控制线向CPU发送一个中断信号,由CPU检查输入过程中是否出错,若无错,便向控制器发送取走数据的信号,然后再通过控制器及数据线,将数据写入内存指定单元中。图10.5示出了中断驱动I/O控制方式的流程。向I/O控制器发读命令读I/O控制器的状态检查状态?从I/O控制器中读入字向存储器中写字传送完成?下一条指令完成未完就绪出错中断CPU做其他事图10.5中断驱动I/O控制方式的流程▫2.3DMA控制方式•DMA方式的基本思想是,在外围设备和内存之间开辟直接的数据交换通路。在DMA控制器中,除了控制状态寄存器和数据缓冲寄存器外,还包括传送字节计数器和内存地址寄存器以及控制电路等。因此,DMA控制器可用来代替CPU,以实现内存和设备之间进行成批的数据交换。DMA方式的传送结构如图10.6所示。图10.6DMA方式的传送结构▫3.2设备分配时应考虑的因素1.设备的固有属性2.设备分配算法•I/O设备的分配,除了与I/O设备的固有属性有关之外,还与系统所采用的设备分配算法有关。I/O设备的分配与进程调度很相似,同样可采用如下一些算法。(1)先来先服务(2)优先级最高者优先3.设备分配中的安全性•从进程运行的安全性方面考虑,设备分配方式有以下两种。(1)静态分配(2)动态分配4.设备独立性•为了提高系统的可适应性和可扩展性,应使所编制的用户程序与实际使用的物理设备无关,即应用程序独立于具体使用的物理设备,这就是所谓的设备独立性。Linux中的设备管理▫Linux设备管理概述•在Linux系统中,用户是通过文件系统与设备接口的。所有设备都作为特别文件,从而在设备管理上具有下列特性:•1.每个设备都对应文件系统中的一个索引节点(i-node),都有一个文件名。•2.应用程序通常可以通过系统调用open()打开设备文件,建立起与目标设备的连接。•3.对设备的使用类似于对文件的存取。•4.设备驱动程序都是系统内核的一部分,它们必须为系统内核或者它们的子系统提供一个标准的接口。•5.设备驱动程序使用一些标准的内核服务,如内存分配等。图10.18设备驱动分层结构设备驱动程序的主要功能1。对设备初始化和释放。2。把数据从内核传送到硬件和从硬件读取数据。3。读取应用程序传送给设备文件的数据和回送应用程序请求的数据。4。检测和处理设备出现的错误。在用户进程调用驱动程序时,系统进入核心态,这时不再是抢先式调度。也就是说,系统必须在驱动程序的子函数返回后才能进行其他的工作。设备驱动程序#define__NO_VERSION__#includelinux/modules.h#includelinux/version.hcharkernel_version[]=UTS_RELEASE;structfile_operations{int(*seek)(structinode*,structfile*,off_t,int);int(*read)(structinode*,structfile*,char,int);int(*write)(structinode*,structfile*,off_t,int);int(*readdir)(structinode*,structfile*,structdirent*,int);int(*select)(structinode*,structfile*,int,select_table*);int(*ioctl)(structinode*,structfile*,unsinedint,unsignedlong);int(*mmap)(structinode*,structfile*,structvm_area_struct*);int(*open)(structinode*,structfile*);int(*release)(structinode*,structfile*);int(*fsync)(structinode*,structfile*);int(*fasync)(structinode*,structfile*,int);int(*check_media_change)(structinode*,structfile*);int(*revalidate)(dev_tdev);}设备驱动程序-一个简单的例子#includelinux/types.h#includelinux/fs.h#includelinux/mm.h#includelinux/errno.h#includeasm/segment.hunsignedinttest_major=0;staticintread_test(structinode*node,structfile*file,char*buf,intcount){intleft;if(verify_area(VERIFY_WRITE,buf,count)==-EFAULT)return-EFAULT;for(left=count;left0;left--){__put_user(1,buf,1);buf++;}returncount;}staticintwrite_test(structinode*inode,structfile*file,constchar*buf,intcount){returncount;}staticintopen_test(structinode*inode,structfile*file){MOD_INC_USE_COUNT;return0;}staticvoidrelease_test(structinode*inode,structfile*file){MOD_DEC_USE_COUNT;}structfile_operationstest_fops={NULL,read_test,write_test,NULL,/*test_readdir*/NULL,NULL,/*test_ioctl*/NULL,/*test_mmap*/open_test,release_test,NULL,/*test_fsync*/NULL,/*test_fasync*//*nothingmore,fillwithNULLs*/};驱动程序可以按照两种方式编译。1.编译进kernel,会增加内核的大小,还要改动内核的源文件,而且不能动态的卸载,不利于调试2.编译成模块(modules),不会增加内核的体积,能动态加载。设备驱动程序编译方式module方式的装载和卸载intinit_module(void){intresult;result=register_chrdev(0,test,&test_fops);if(result0){printk(KERN_INFOtest:can'tgetmajornumber\n);returnresult;}if(test_major==0)test_major=result;/*dynamic*/return0;}voidcleanup_module(void){unr