8.1实验目的了解Linux操作系统中的设备驱动程序的组成编撰简单的字符设备驱动程序并进行测试编撰简单的块设备的驱动程序,并进行测试理解Linux操作系统的设备管理机制8.2打算知识8.2.1设备驱动程序简介8.2.2设备驱动程序与外界的插口8.2.3设备驱动程序的组织结构手动配置和初始化子程序服务于I/O恳求的子程序中断服务子程序8.2.4设备驱动程序的代码设备驱动程序是一些函数和数据结构的集合,这种函数和数据结构是为实现设备管理的一个简单插口。操作系统内核使用这个插口来恳求驱动程序对设备进行I/O操作。甚至,我们可以把设备驱动程序看成是一个具象数据类型,它为计算机中的每位硬件设备都构建了一个通用函数插口。因为一个设备驱动程序就是一个模块,所以在内核内部用一个file结构来辨识设备驱动程序,但是内核使用file_operations结构来访问设备驱动程序中的函数。字符设备的注册Linux系统通过调用register_chrdev()向系统注册字符型设备驱动程序register_chrdev()定义如下:#include#includeintregister_chrdev(unsignedintmajor,constchar*name,structfile_operations*ops)块设备驱动程序描述符是一个blk_dev_struct类型的数据结构,其定义如下:structblk_dev_structqueue_proc指向的队列必须为原子操作,即指令的执行是一次性完成的,不能间断。
request_queue_trequest_queuequeue_proc*queuevoid*datastaticstructconstchar*name;structblock_device_operations*bdops;对块设备驱动程序进行注册的调用格式为:intregister_blkdev(unsignedintmajor,constchar*name,structblock_device_operations*bdops)块设备的注册字符设备驱动程序要用到的数据结构定义:structdevice_structconstchar*name;structfile_operations*chops;staticstructdevice_structchrdevs[MAX_CHRDEV];typedefstructScull_Devvoid**data;intquantum;当前容量的大小。intqset;当前字段的大小。unsignedlongsize;unsignedintaccess_key;由sculluid和scullpriv使用的存取数组。unsignedintusage;//当字符设备正使用时加锁。
structScull_Dev*next;scull;8.4.1字符类型设备的驱动程序字符设备的结构device_struct即字符设备的开关表。当字符设备注册到内核后,字符设备的名子和相关操作被添加到device_struct结构类型的chrdevs全局字段中,称chrdevs为字符设备的开关表。下边以一个简单的事例说明字符设备驱动程序中字符设备结构的定义:(假定设备名为scull)staticintscull_open(structinode*inode,structfile*filp);//打开字符设备。staticintscull_release(structinode*inode,structfile*filp);//释放字符设备。staticssize_tscull_write(structinode*inode,structfile*filp,constchar*buffer,intcount);//将数据送往字符设备。staticssize_tscull_read(structinode*inode操作系统原理linux,structfile*filp,char*buffer,intcount);//从字符设备读出数据,写入用户空间。
staticintscull_ioctl(structinode*inode,structfile*filp,unsignedlongintcmd,unsignedlongarg);//字符设备的控制操作。字符设备的结构structfile_operationschr_fopsseek,改变字符设备的操作位置。scull_read,read,字符设备的读操作。scull_write,//write,字符设备的写操作。NULL,readdir,读取某个子目录中的内容。NULL,poll,容许应用程序响应来自字符设备的风波。scull_ioctl,ioctl,字符设备的控制操作。NULL,mmap,字符设备地址空间到用户地址空间的映射。scull_openlinux软件,open,字符设备的打开操作。NULL,flush,冲掉缓冲区的数据,对字符设备无用。scull_release,//release,字符设备的释放操作。NULLredhat linux,fsync,同步显存与c盘上的数据状态,把输出缓冲区里仍未讲到c盘的数据写出去。NULL,fasync,改变字符设备行为。NULL,checkmediachange,检测自先前操作后,介质(软驱和CD-ROM)是否更换。
NULL,revalidate,若更换了介质,则更新信息。NULL字符设备驱动程序入口点字符设备驱动程序入口点主要包括初始化字符设备、字符设备的I/O调用和中断。在引导系统时,每位设备驱动程序通过其内部的初始化函数init()对其控制的设备及其自身初始化。字符设备初始化函数为chr_dev_init(),包含在/linux/drivers/char/mem.c中,它的主要功能之一是在内核中登记设备驱动程序。具体调用是通过register_chrdev()函数。register_chrdev()函数定义如下:#include#includeintregister_chrdev(unsignedintmajor,constchar*name,structfile_operation*fops);用于字符设备的I/O调用主要有:open()、release()、read()、write()和ioctl()。open()函数staticintscull_open(structinode*inode,structfile*filp)MOD_INC_USE_COUNT;returnrelease()函数staticintscull_release(structinode*inode,structfile*filp)MOD_DEC_USE_COUNT;return函数scull_open()的流程图图8-5函数scull_write()的流程图图8-6函数scull_read()的流程图图8-7函数scull_ioctl()的流程图图8-8函数scull_release()的流程图图8-9字符设备驱动程序的测试函数流程图测试函数:#cat/proc/devicesawk”\$2==”chrdev”{print\$1}”图8-108.4.2块类型设备的驱动程序structdevice_structconstchar*name;structfile_operations*chops;staticstructdevice_structblkdevs[MAX_BLKDEV];structsbull_devvoid**data;intquantum;当前容量的大小。
intqset;当前链表的大小。unsignedlongsize;unsignedintaccess_key;由sbulluid和sbullpriv使用的存取数组。unsignedintusage;//当块设备正使用时加锁。unsignedintnew_msg;structsbull_dev*next;externstructsbull_dev*sbull;块设备的结构块设备的结构即块设备的开关表。当块设备注册到内核后,块设备的名子和相关操作被添加到device_struct结构类型的blkdevs全局链表中,称blkdevs为块设备的开关表。下边以一个简单的反例说明块设备驱动程序中块设备结构的定义:(假定设备名为sbull)structfile_operationsblk_fopsseek,改变块设备的操作位置。block_read,//块设备的读操作,为内核函数。block_write操作系统原理linux,//块设备的写操作,为内核函数。NULL,readdir,读取某个子目录中的内容。NULL,poll,容许应用程序响应来自块设备的风波。
sbull_ioctl,ioctl,块设备的控制操作。NULL,mmap,块设备地址空间到用户地址空间的映射。sbull_open,open,块设备的打开操作。NULL,flush,冲掉块设备缓冲区的数据。sbull_release,release,块设备的释放操作。block_fsync,//同步显存与c盘上的数据状态,把输出缓冲区里仍未讲到c盘的数据写出去。为内核函数。