资源预览内容
第1页 / 共63页
第2页 / 共63页
第3页 / 共63页
第4页 / 共63页
第5页 / 共63页
第6页 / 共63页
第7页 / 共63页
第8页 / 共63页
第9页 / 共63页
第10页 / 共63页
亲,该文档总共63页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
第11章设备管理 Linux和其他操作系统一样 支持众多的 各式各样的外接设备 但是 面对层出不穷的新硬件产品 必须有人不断编写新的驱动程序 以便让这些设备能够在Linux下正常工作 从这个意义上讲 讲述驱动程序的编写就是一件非常有意义的工作 本章也涉及到Linux下设备管理的原则和方法 举例来说 Linux下的驱动程序仅仅是为相应的设备编写几个基本函数 并向VFS注册就可以安装成功了 当应用程序需要设备时 可以访问该设备对应的文件节点 利用VFS调用该设备的相关处理函数 本章主要介绍了设备管理方面的有关知识 系统管理设备的方式 驱动程序运作过程 驱动程序的具体实例 11 1设备管理结构 11 1 1概述 设备管理即输入输出子系统 可分为上下两部分 一部分是上层的 与设备无关的 这部分根据输入输出请求 通过特定的设备驱动程序接口 来与设备进行通信 另一部分是下层的 与设备有关的 常称为设备驱动程序 它直接与相应设备打交道 并且向上层提供一组访问接口 设备管理的目标是对所有的外接设备进行良好的读 写 控制等操作 首先要解决的问题就是怎样将任意的一个设备的所有操作进行归纳 设计出统一的接口 内核常常使用设备类型 主设备号和次设备号来标识一个具体的设备 但用户希望能用同样的应用程序和命令来访问设备和普通文件 为此 Linux中的设备管理应用了设备文件这个概念来统一设备的访问接口 简单的说 系统试图使它对所有各类设备的输入 输出看起来就好像对普通文件的输入 输出一样 如图11 1所示 应用程序通过Linux的系统调用与内核通信 图11 1Linux内核体系结构 由于Linux中将设备当作文件来处理 所以对设备进行操作的系统调用和对文件操作的类似 主要包括open read write ioctl close 等 应用程序发出系统调用指令以后 会从用户态转换到内核态 通过内核将open 这样的系统调用转换成对物理设备的操作 11 1 2字符设备与块设备 字符设备以字节为单位进行数据处理 字符设备通常只允许按顺序访问 一般不使用缓存技术 如鼠标 声卡等 块设备以块为单位进行处理 块的大小通常为0 5KB到32KB等 大多数块设备允许随机访问 而且常常采用缓存技术 块设备有硬盘 光盘驱动器等 可以查看文件 proc devices获得 我们这里主要讨论字符设备 有兴趣的读者可参考其它书籍中有关块设备的内容 11 1 3主设备号和次设备号 设备管理中 除了设备类型 字符设备或块设备 以外 内核还需要一对称做主 次设备号的参数 才能唯一表示设备 主设备号 majornumber 相同的设备使用相同的驱动程序 而次设备号 minornumber 用来区分具体设备的实例 例如 第一IDE接口上的所有磁盘及其分区共用同一主设备号3 而次设备号则为0 1 2 3 11 1 4Linux设备命名习惯 Linux习惯上将设备文件放在目录 dev或其子目录之下 设备文件命名 通常由两部分组成 规则为 第一部分通常较短 可能只有2或3个字母组成 用来表示设备大类 例如 普通硬盘如IDE接口的为 hd 软盘为 fd 第二部分通常为数字或字母用来区别设备实例 例如 dev hda dev hdb dev hdc表示第一 二 三块硬盘 而dev hda1 dev hda2 dev hda3则表示第一硬盘的第一 二 三分区 11 2驱动程序 11 2 1驱动程序基本功能 在Linux操作系统中驱动程序是操作系统内核与硬件设备之间的桥梁 它屏蔽了硬件的细节 如总线协议 DMA操作等 在应用程序看来硬件设备只是一个特殊的文件 驱动程序的基本功能为 1 对设备初始化和释放 如对音频设备而言包括向内核注册设备 设置音频的输入输出参数 如采样频率 采样宽度等 分配音频设备使用的内核内存等工作 2 对设备进行管理 包括实时参数设置以及提供对设备的操作接口 3 读取应用程序传送给设备文件的数据并回送应用程序请求的数据 这需要在用户空间 内核空间 总线及外设之间传输数据 4 检测和处理设备出现的错误 11 2 2驱动程序的运作过程 为了便于读者理解 在此结合大家比较熟悉的键盘来了解其运作过程 如图11 2所示 图11 2驱动程序的实现过程 当一个程序读 dev tty文件 此为键盘 时 就会执行系统调用sys read 在fs read write c中 该系统调用在判别出所读文件是一个字符设备文件时 即会调用rw char 函数 在fs char dev c中 该函数则会根据所读设备的设备类型 主 次设备号等参数 由字符设备读写函数表 设备开关表 调用rw tty 最终调用到这里的终端读操作函数tty read 当用户在键盘上键入了一个字符时 会引起键盘中断响应 此时键盘中断处理程序就会从键盘控制器读入对应的键盘扫描码 然后根据使用的键盘扫描码映射表译成相应字符 放入tty读队列read q中 然后调用中断处理程序的do tty interrupt 函数 它又直接调用行规则函数copy to cooked 对该字符进行过滤处理 并放入tty辅助队列secondary中 供上述tty read 读取 同时把该字符放入tty写队列write q中 并调用写控制台函数con write 此时如果该终端的回显 echo 属性是设置的 则该字符会显示到屏幕上 注 do tty interrupt 和copy to cooked 函数在tty io c中实现 11 2 2常用接口介绍 open 打开设备 并初始化设备准备进行操作 可以为NULL 这样每次打开设备总会成功 而且不通知设备驱动程序 read 从设备中读数据 需要提供字符串指针 write 向字符设备写数据 需要提供所写内容指针 ioctl 控制设备 例如控制光盘的弹出等 需要提供符合设备预先定义的命令字 llseek 重新定位读 写位置 需要提供偏移量参数 flush 清除内容 release 关闭设备 并释放资源等 mmap 将设备内存映射到进程地址空间 通常只有块设备驱动程序使用 11 2 3常用函数原型 1 设备操作函数原形structfile 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 intstructfile lock ssize t readv structfile conststructiovec unsignedlong loff t ssize t writev structfile conststructiovec unsignedlong loff t 2 向系统注册的函数原形intregister chrdev unsignedintmajor constchar name structfile operations fops if major 0 write lock for major MAX CHRDEV 1 major 0 major if chrdevs major fops NULL chrdevs major name name chrdevs major fops fops write unlock write unlock if chrdevs major fops 11 3驱动程序编写实例 为了更清楚地讲述Linux中设备驱动程序的编写 加深读者对启动程序的了解 下面介绍一个简单的设备驱动的实现过程 由于基于特殊的硬件设备实现的驱动程序难度较大 而且不方便验证 下面举一个虚拟设备驱动程序的例子 11 3 1设备功能介绍 实现虚拟设备的写入 读出等操作 这个驱动程序并不是基于特定硬件设备的 实际上仅仅是对内存进行读 写操作 当执行写入操作时 将会对特定的存储空间进行写入 当执行读出操作时 将会对该存储空间进行数据的读取 同时还可以利用ioctl进行清除该存储空间的操作 这个mydrv设备的实现文件是mydrv c 其中的文件接口flle operations 提供了mydrv open mydrv release mydrv read mydrv write mydrv ioctl等函数 1 函数mydrv read 的功能是从mybuf 110 中读取字符串 并传递给调用的进程 2 函数mydrv write 的功能是将调用的进程传入的字符串赋值给mybuf 如果字符串的长度超过110 则只取前110个字符 3 函数mydrv ioctl 中仅仅实现了一个控制功能 清除mybuf存储区 11 3 2具体实现 首先 要根据设备功能的需要 编写file operations结构中的操作函数 其次 要向系统注册该设备 包括字符设备的注册 devfs节点的注册与中断响应函数的注册 然后就可以利用对应的文件进行设备操控了 具体如下 1 源程序 include include include include include include include include include defineMYDRV CLS IO c 0 x01 定义清存储区命令字charmybuf 110 存储区域intmydrv major 99 主设备号devfs handle tdev handle 保存设备文件系统的注册句柄 第一步 编写file operations函数 ssize tmydrv read structfile filp char buf size tcount loff t f pos 函数声明staticssize tmydrv write structfile filp constchar buf size tcount loff t ppos staticintmydrv ioctl structinode inode structfile file unsignedintcmd unsignedlongarg intmydrv open structinode inode structfile filp intmydrv release structinode inode structfile filp 函数声明 structfile operationsmydrv ops 设备函数接口open mydrv open 实现对设备的操作read mydrv read write mydrv write ioctl mydrv ioctl release mydrv release mydrv read 将内核空间的mybuf中的字符串赋给用户空间的buf区 ssize tmydrv read structfile filp char bur size tcount loff t f pos filp 指向设备文件的指针 f pos 偏移量intlength strlen
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号