第9章设备管理与模块机制设备分类与识别设备转换表设备注册与注销块设备的请求队列设备驱动的基本原理设备驱动的编写方法模块机制9.1Linux设备管理Linux利用一种通用的方法来对所有的输入/输出设备进行控制,从而完成数据的输入和输出操作,即设计了一个统一而简单的输入/输出系统调用接口。输入/输出子系统分为上下两部分:一部分是下层的与设备有关的部分,常称为设备驱动程序,它直接与相应设备打交道,并且向上层提供一组访问接口;另一部分是上层的与设备无关的I/O软件,它根据上层用户的输入/输出请求,向下通过特定的设备驱动程序接口和设备进行通信。Linux的设备管理在Linux系统中,用户通过文件系统与设备接口。利用标准的系统调用可在设备上进行打开、关闭、读取或写入操作。当用户进程发出I/O请求时,系统将请求处理的权限放在文件系统,文件系统通过驱动程序提供的接口将任务下放到驱动程序。驱动程序根据需要,对设备控制器进行操作,设备控制器再去控制设备本身进行I/O操作。驱动程序向文件系统提供的接口屏蔽了设备的物理特性。用户进程硬件设备本身设备控制器设备驱动程序文件系统中的设备文件进程请求设备服务的流程•在内核中设备文件和普通文件的索引节点有区别,可以确认出是硬件设备还是普通文件,确定要访问相应的设备驱动程序还是文件。•设备文件在磁盘上只有一个索引节点,没有任何用于存放数据的块组。设备文件设备类型[root@edu]#more/proc/devices主设备号与次设备号[root@edu/proc]#ls-1/dev/had*设备文件在与设备驱动程序通信时,内核常常使用设备类型、主设备号和次设备号来标识一个具体的设备。Linux将设备文件放在目录/dev或其子目录下6设备文件Linux使用设备文件来统一对设备的访问接口,将设备文件放在/dev/目录下设备的命名一般为设备文件名+数字或者字母表示的子类,例如/dev/hda1,/dev/hda2等,/dev/hda代表系统中的第一个IDE硬盘,/dev/hdb代表系统中的第二个IDE硬盘;hda1代表第1个分区,hda2代表第2个分区用于用户访问设备进行输入和输出操作。应用程序可以打开、关闭和读写这些设备文件,完成对设备的操作,就像操作普通的数据文件一样。7设备文件常见的设备文件/dev/hd*IDE接口的硬盘(IDE接口的设备)/dev/sd*SCSI/USB设备/dev/cua*串口设备/dev/lp*并口设备/dev/tty*终端设备/dev/consol控制台设备/dev/eth*以太网设备/dev/cdromIDE光驱/dev/fd*软驱/dev/audio音频设备/dev/scdSCSI的光驱/dev/pppPPP设备/dev/isdn*ISDN设备设备文件通常包含在/dev目录中一些设备文件的例子9设备号为了管理设备,系统为设备编了号,每个设备号又分为主设备号和次设备号。主设备号用来区分不同种类的设备次设备号用来区分同一类型的多个设备主设备号相同的设备使用相同的驱动程序,次设备号用于区分具体设备的实例对于常用设备,Linux有约定俗成的编号,如硬盘的主设备号是3。动态获取主设备号/usr/src/linux-2.4.20-8/include/linux/major.h文件中定义设备号:Linux采用主设备号和次设备号来标志一个具体设备。主设备号用来标志设备类型次设备号用来区分不同的具体设备系统创建一个设备驱动程序时,设备驱动需要使用一个主设备号向内核注册此驱动。创建一个设备节点的方法:mknod设备名设备类型主设备号次设备号例:mknodttyS0c644申请字符设备的设备号在建立一个字符设备之前,驱动程序首先要做的就是获得一个或者多个设备的编号。intregister_chrdev(unsignedintmajor,constchar*name,structfile_operations*fops);完成该工作的函数如下:其中,major是为设备驱动程序向系统申请的主设备号,如果为0则系统为此驱动程序动态地分配一个主设备号。name是设备名。fops是各个调用的入口点的说明。此函数返回0表示成功。返回-EINVAL表示申请的主设备号非法。返回-EBUSY表示所申请的主设备号正在被其它设备驱动程序使用。如果是动态分配主设备号成功,此函数将返回所分配的主设备号。如果register_chrdev操作成功,设备名就会出现在/proc/devices文件里。释放字符设备的设备号不再使用设备时要释放设备编号,函数如下:参数列表包括要释放的主设备号和相应的设备名。参数中的设备名会被内核用来和主设备号参数所对应的已注册设备名进行比较,如果不同,则返回-EINVAL。如果主设备号超出了所允许的范围,则内核同样返回-EINVAL。申请和释放块设备设备号intregister_blkdev(unsignedintmajor,constchar*name,structfile_operations*fops);intunregister_blkdev(unsignedintmajor,constchar*name);设备号操作宏文件/usr/include/linux/kdev_t.h中定义了以下几个宏。MKDEV():linux内核中,根据主、次设备号通过宏MKDEV合成了一个变量dev。MAJOR():由dev获取主设备号MINOR():由dev获取次设备号14查看硬件配置的相关命令lspci查看主板信息:可以通过lspci-v来查看硬件的irq中断号等,主要是用来列出机器中的PCI设备,比如声卡、显卡、猫、网卡等,主板集成设备也能列出来;free查内存fdisk-l查硬盘空间df-h查硬盘15查看硬件配置的相关命令dmesg:是一个显示内核缓冲区系统控制信息的工具;比如系统在启动时的信息会写到/var/log/dmesg|grepCPU:cpu的信息dmesg|grephd:IDE硬盘信息dmesg|grepsd:SCSI硬盘信息dmesg|grepmem:内存信息dmesg|grepXXX:就是检索xxx的信息dmesg-c注:清理掉缓冲区,下次开机的时候还会自动生成16查看硬件配置的相关命令查看所有硬件的型号dmidecode|more查看memory信息cat/proc/meminfo|more查看CPU信息cat/proc/cpuinfoLinux设备的分类字符设备(c)所有能够象字节流一样访问的设备都通过字符设备来实现,通常在/dev/目录下面无需缓冲直接读写设备,通常只允许按顺序访问。如打印机、键盘,终端等。一般要包含open,read,write,close等系统调用的实现块设备(b)通常是指诸如磁盘、内存、Flash等可以容纳文件系统的存储设备。将数据按可寻址的块为单位进行处理,可以随机访问,利用缓冲技术块设备也是通过文件系统来访问Linux设备的分类(续)网络接口设备通常它指的是硬件设备,但有时也可能是一个软件设备(如回环接口loopback),它们由内核中网络子系统驱动,负责发送和接收数据包。它们的数据传送往往不是面向流的,因此很难将它们映射到一个文件系统的节点上。查看系统中的设备:/proc/devices。查看设备及其类型“ls-l/dev”9.2Linux设备管理数据结构每个设备都对应文件系统中的一个VFSinode,都有一个设备文件名。在设备文件对应的VFSinode中,i_mode域的值标明了它的类型:S_IFBLK:表示它是一个块设备;S_IFCHR:表示它是一个字符设备;同时,设备文件对应的VFSinode中没有块列表,但却有一个名为i_rdev的域,其中存储着它所标识设备的主、次设备号。内核可以根据该域将设备文件名转化为设备的主、次设备号。应用程序通常可以通过系统调用open()打开设备文件,建立起与目标设备的连接。对设备的使用类似于对文件的存取。设备驱动程序都是系统内核的一部分,它们必须为系统内核或者它们的子系统提供一个标准的接口。设备驱动程序也使用一些标准的内核服务,如内存分配等注意:字符设备与块设备具有独立的编号,例如,块设备(3,0)不同于字符设备(3,0)设备文件通常可以表示一个硬件设备,例如磁盘/dev/hda或硬件设备的某一物理或逻辑分区,例如磁盘分区/dev/hda2或一个虚拟的逻辑设备(不会与任何硬件设备相关联),例如/dev/null代表一个“黑洞”对内核而言,一个设备文件的名字是无关紧要的,关键在于设备文件的类型及其主次设备号如果一个系统含有两个具有相同主设备号和次设备号的设备文件,而且都是字符设备。当有两个进程想要同时打开这个字符设备时,会发生什么情况?关闭这个设备时又会发生什么情况?当有两个进程想要同时打开这个字符设备时,它将在各自的文件表中增加一次引用计数值。关闭这个设备时可能会发生导致对这个设备是一个无法辨认的状态。从而使这个设备变成一个无用的设备。linux内核中用主、次设备号标识一个设备,但是,从用户角度而言,这一方法不大实用,因为用户不可能记住每一个设备号。用户希望用统一的方式来访问各个设备,因此linux中的设备管理应用了设备文件这个概念。系统试图使它对各类设备的输出、输入看起来就象是对普通文件一样。因此,把设备映射为一种特殊的文件。Devfs设备文件使用主、次设备号标识设备存在局限性在/dev中的大多数设备是不存在的8位长的主次设备号不够用不容易记忆上述原因以及其他的一些因素综合起来,促使了devfs设备文件的产生Linux2.4以后引入了设备文件系统(devfs)的概念,所有的设备文件作为一个可以挂装的文件系统,这样就可以被文件系统统一管理,从而设备文件就可以挂装到任何需要的地方。一般将主设备建立一个目录,再将具体的子设备文件建立在此目录下。例如,/dev/mtdblock0设备文件列表Devfs设备文件有了Devfs设备文件之后,文件系统允许设备驱动程序通过名字而不是主次设备号注册设备,例如所有的磁盘可以放在/dev/disks目录下/dev/hda/dev/disks/disc0/dev/hdb/dev/disks/disc1使用devfs文件系统的I/O驱动程序通过调用devfs_register()注册设备一个注册了的设备文件,自动出现在devfs的虚拟目录下设备文件的VFS处理进程访问普通文件时,通过文件系统访问磁盘分区中的数据块当进程访问设备文件时,却可以驱动硬件设备途径:VFS在设备文件打开时使用与设备相关的函数调用替换其缺省的文件操作这些设备相关函数调用对硬件设备进行操作2个重要的数据结构驱动程序使用的2个重要结构structfilestructfile_operations设备文件:structfile数据结构structfile{structdentry*f_dentry;//文件对应的目录项结构structfile_operations*f_op;//文件操作的结构指针unsignedshortf_flags;//文件标志,主要进行阻塞/非阻塞型操作时检查undignedshortf_count;mode_tf_mode;//标识文件的读写权限Loff_tf_pos;当前读写位置unsignedlongf_reada,f_ramax,f_reddb,f_rawin;structfile*f_next,f_prev;structfown_structf_owner;intf_error;unsignedlongf_version;void*private_data;//驱动程序一般将它指向已经分配的数据structinode*f_inod