Linux设备驱动程序设计第一章简介参考书籍•《Linux设备驱动程序》(第三版)•JonatbanCorbet等著魏永明等译•中国电力出版社•《Linux设备驱动开发详解》(第二版)•宋宝华著人民邮电出版社•《Linux设备驱动开发技术及应用》•(韩)俞永昌著人民邮电出版社•《Linux内核设计与实现》(第二版)•RobertLove著陈莉君等译•Linux设备驱动的现状高需求Linux内核的绝大多数代码为设备驱动新设备、新芯片、新驱动的需求高门槛涉及到大量硬件操作涉及到内核基础知识涉及到并发控制与同步复杂的软件结构框架高回报内核空间和用户空间系统态:在Linux系统中,内核在最高级执行,也称为“系统态”,在这一级任何操作都可以执行。用户态:而应用程序则用户态执行在最低级,所谓的“用户态”,在这一级处理器禁止对硬件的直接访问和对内存的未授权访问。内核空间:模块运行的空间是在所谓的“内核空间”;用户空间:应用程序运行的空间是在“用户空间”。它们分别引用不同的内存映射,也就是程序代码使用不同的“地址空间”。Linux内核功能划分–进程管理–内存管理–文件系统–设备管理–网络连接(strcutnet_device)Linux内核功能•进程管理–进程管理负责创建和销毁进程,并处理它们与外界之间的通信–控制进程如何共享CPU的调度器–总之,在单个或者多个CPU上实现了多个进程的抽象•内存管理–内核在有限的可用资源之上为每一个进程创建了独立的虚拟内存空间(MMU)–内核的各个部分在和内存管理系统交互的时候都使用相同的一组函数调用,包括简单的malloc/free和其他一些复杂的函数Linux内核功能•文件系统–文件系统是Linux基础–内核在没有结构的硬件系统上面构造了结构化的文件系统–Linux支持多种文件系统类型•YAFFS(YetAnotherFlashFileSystem)•ROMFS•RAMFS•JFFS2(JournalingFlashFileSystem)•设备控制–几乎每一个系统操作都会映射到物理设备上–除去CPU,内存以及其他几个很有限的对象之外,几乎所有的设备控制操作都由与被控制设备相关的代码(设备驱动程序)来完成内核模块的构造和运行•设备驱动程序的存在形式•可卸载模块–内核提供的特性可以在运行时进行扩展–可在运行时添加到内核中的代码被称为“模块”–常用模块•设备驱动和文件系统–灵活•编译进内核–与内核其他的功能模块静态编译在一起,不可卸载内核态和用户态•多数操作系统都把内核和应用程序分为2个层次管理–内核态•有较高的权限,可以控制处理器内存的映射和内存的分配方式•访问外设空间和处理器的特殊状态寄存器,•控制中断和DMA–用户态•权限低,优先级低•处理器控制着对硬件的直接访问以及对内存的非授权访问–具有不同的内存映射(指针的传递处理)•get_user,put_user,copy_from_user,copy_to_user–应用程序执行系统调用或者被硬件中断的时候由用户态转换为内核态,内核代码代表应用程序执行操作,能够访问进程地址空间的所有数据可装载模块Linux:内核提供的特性可在运行时进行扩展模块可在运行时添加到内核中的代码,包括但不限于设备驱动程序insmod将模块连接到正在运行的内核rmmod移除连接嵌入式Linux的设备管理Linux将设备分成两大类:一类是块设备,类似磁盘以记录块或扇区为单位,成块进行输入/输出的设备;另一类是字符设备,类似键盘以字符为单位,逐个进行输入/输出的设备。网路设备是介于块设备和字符设备之间的一种特殊设备。块设备接口仅支持面向块的I/O操作,所有I/O操作都通过在内核地址空间中的I/O缓冲区进行,它可以支持随机存取的功能。文件系统通常都建立在块设备上。字符设备接口支持面向字符的I/O操作,由于它们不经过系统的快速缓存,所以它们负责管理自己的缓冲区结构。字符设备接口只支持顺序存取的功能,一般不能进行任意长度的I/O请求,而是限制I/O请求的长度必须是设备要求的基本块长的倍数。处理器与设备间数据交换方式处理器与外设之间传输数据的控制方式通常有3种:查询方式、中断方式和直接内存存取(DMA)方式。1.查询方式设备驱动程序通过设备的I/O端口空间,以及存储器空间完成数据的交换。例如,网卡一般将自己的内部寄存器映射为设备的I/O端口,而显示卡则利用大量的存储器空间作为视频信息的存储空间。利用这些地址空间,驱动程序可以向外设发送指定的操作指令。通常来讲,由于外设的操作耗时较长,因此,当处理器实际执行了操作指令之后,驱动程序可采用查询方式等待外设完成操作。驱动程序在提交命令之后,开始查询设备的状态寄存器,当状态寄存器表明操作完成时,驱动程序可继续后续处理。查询方式的优点是硬件开销小,使用起来比较简单。但在此方式下,CPU要不断地查询外设的状态,当外设未准备好时,就只能循环等待,不能执行其他程序,这样就浪费了CPU的大量时间,降低了处理器的利用率。2.中断方式查询方式白白浪费了大量的处理器时间,而中断方式才是多任务操作系统中最有效利用处理器的方式。当CPU进行主程序操作时,外设的数据已存入端口的数据输入寄存器,或端口的数据输出寄存器已空,此时由外设通过接口电路向CPU发出中断请求信号。CPU在满足一定条件下,暂停执行当前正在执行的主程序,转入执行相应能够进行输入/输出操作的子程序,待输入/输出操作执行完毕之后,CPU再返回并继续执行原来被中断的主程序。这样,CPU就避免了把大量时间耗费在等待、查询外设状态的操作上,使其工作效率得以大大提高。中断方式的原理示意图如图6.1所示。能够向CPU发出中断请求的设备或事件称为中断源。中断源向CPU发出中断请求,若优先级别最高,则CPU在满足一定的条件时,可中断当前程序的运行,保护好被中断的主程序的断点及现场信息,然后根据中断源提供的信息,找到中断服务子程序的入口地址,转去执行新的程序段,这就是中断响应。CPU响应中断是有条件的,如内部允许中断、中断未被屏蔽、当前指令执行完等。CPU响应中断以后,就会中止当前的程序,转去执行一个中断服务子程序,以完成为相应设备的服务。系统引入中断机制后,CPU与外设处于“并行”工作状态,便于实现信息的实时处理和系统的故障处理。3.直接访问内存(DMA)方式利用中断,系统和设备之间可以通过设备驱动程序传送数据,但是,当传送的数据量很大时,因为中断处理上的延迟,利用中断方式的效率会大大降低。而直接内存访问(DMA)可以解决这一问题。DMA可允许设备和系统内存间在没有处理器参与的情况下传输大量数据。设备驱动程序在利用DMA之前,需要选择DMA通道并定义相关寄存器,以及数据的传输方向,即读取或写入,然后将设备设定为利用该DMA通道传输数据。设备完成设置之后,可以立即利用该DMA通道在设备和系统的内存之间传输数据,传输完毕后产生中断以便通知驱动程序进行后续处理。在利用DMA进行数据传输的同时,处理器仍然可以继续执行指令。什么是设备驱动程序(DD)?•在Linux内核中扮演特殊角色,使某个特定硬件响应一个定义良好的内部编程接口,该接口完全隐藏设备的工作细节•DD的任务是将用户的标准化调用作用于实际硬件的设备特有操作上•为什么要编写设备驱动程序?Linux的设备驱动程序•硬件设备与应用程序之间的一个中间软件层•它使得某个特定硬件能够响应一个定义良好的内部编程接口,同时完全隐蔽了设备的工作细节•用户通过一组与具体设备无关的标准化的调用来完成相应的操作•驱动程序的任务就是把这些标准化的系统调用映射到具体设备对于实际硬件的特定操作上•驱动程序是内核的一部分,可以使用中断、DMA等操作•驱动程序在用户态和内核态之间传递数据设备驱动程序的作用•机制:需要提供什么功能•策略:如何使用这些功能•分层的思想•由于不同的环境需要不同的方式来使用硬件,因此应尽可能做到让驱动程序不带策略•驱动程序应当处理如何使硬件可用的问题,而将如何使用硬件留给上层应用程序设备驱动程序主要功能•设备驱动程序主要完成如下功能:–检测设备和初始化设备–使设备投入运行和退出服务–从设备接收数据并提交给内核–从内核接收数据送到设备–检测和处理设备错误•另一角度:•驱动程序可看作应用程序与实际设备之间的软件层•即使对于相同的设备不同驱动程序可能提供不同功能,需要在许多因素间作出平衡•三方面因素:•提供给用户尽可能多的选项•编写驱动程序占用的时间•尽量保持程序简单嵌入式Linux驱动程序介绍嵌入式Linux驱动已经支持的设备门类齐全,已成为linux相对其他嵌入式操作系统的一大优势工业控制常用的串口,并口人机输入设备鼠标、键盘,触摸屏彩色、黑白液晶显示输出网络的完善支持,包括tcp/ip,udp,firewall,WLAN,ipforwarding,ipsec,vpnUsb的全面支持,包括usb硬盘、u盘,usb摄像头支持丰富的文件系统,包括fat32,ntfs嵌入式驱动程序的作用驱动程序直接操控硬件收发通讯数据读写存储介质,比如flash或硬盘操作输出设备和执行机,例如打印,开关门襟等等PDF文件使用pdfFactoryPro试用版本创建嵌入式驱动程序的作用驱动程序提供软件访问硬件的机制应用软件通过驱动程序安全高效的访问硬件驱动程序文件节点可以方便的提供访问权限控制驱动程序作为一个隔离的中间层软件,将底层细节隐藏起来,提高了软件的可移植性访问Linux设备驱动的方法设备提供dev文件系统节点和proc文件系统节点应用程序通过dev文件节点访问驱动程序应用程序通过proc文件节点可以查询设备驱动的信息驱动程序在哪儿驱动程序在哪儿•驱动程序位于drivers目录下•驱动程序占kernel代码50%或以上Linux驱动程序编译方式Linux中驱动程序的使用可以按照两种方式进行编译:一种是静态编译进内核;另一种是编译成模块以供动态加载。注意:对于uCLinux而言,由于其不支持模块动态加载,而且嵌入式Linux不能够象桌面Linux那样灵活的使用insmod/rmmod加载、卸载设备驱动程序,因而通常在uCLinux中采用的是将设备驱动程序静态的编译进内核。Linux驱动程序开发•建立嵌入式Linux平台,移植和编写驱动程序往往是最具挑战的工作•驱动程序的开发周期一般较长,对产品的面世时间有着重要影响•驱动程序质量的好坏,直接关系到系统工作效能和稳定性,对项目的成败起着关键作用设备驱动程序的分类•字符设备–所有能够象字节流一样访问的设备都通过字符设备来实现–它们被映射为文件系统中的节点,通常在/dev/目录下面–一般要包含openreadwriteioctlclose等系统调用的实现•块设备–通常是指诸如磁盘、内存、Flash等可以容纳文件系统的存储设备。–块设备也是通过文件系统来访问,与字符设备的区别是:内核管理数据的方式不同–它允许象字符设备一样以字节流的方式来访问,也可一次传递任意多的字节。•网络接口设备–通常它指的是硬件设备,但有时也可能是一个软件设备(如回环接口loopback),它们由内核中网络子系统驱动,负责发送(hard_start_xmit())和接收数据包。–它们的数据传送往往不是面向流的,因此很难将它们映射到一个文件系统的节点上。Linux下设备驱动程序组成自动配置和初始化子程序:负责检测所要驱动的硬件设备是否工作正常,如果该设备正常,则对这个设备及其相关驱动程序所需要的软件状态进行初始化。这部分驱动程序仅在初始化的时候被调用一次。服务于I/O请求的子程序:该子程序称为驱动程序的上半部。这部分程序在执行时,系统仍认为与进行调用的进程属于同一个进程,只是由用户态变成了核心态,可以在其中调用sleep()等与进程运行环境有关的函数。中断服务子程序:称为驱动程序的下半部,由Linux系统来接收硬件中断,再由系统调用中断服务子程序。基本概念