linux字符设备驱动机制探索论文_第1页
linux字符设备驱动机制探索论文_第2页
linux字符设备驱动机制探索论文_第3页
linux字符设备驱动机制探索论文_第4页
linux字符设备驱动机制探索论文_第5页
已阅读5页,还剩19页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

LINUX字符设备驱动机制探索论文课程名称LINUX内核设计与实现姓名王华山班级10计科(嵌入式)学号1031301224院系数计学院专业计算机科学与技术目录1一字符设备概述2二相关数据结构之间的关系说明10三字符设备驱动实例12四字符设备驱动中的并发控制19五字符设备的阻塞与非阻塞操作21六参考文献23七心得体会24一字符设备概述1字符设备是指在I/O传输过程中以字符为单位进行传输的设备,例如键盘,打印机等。但以字符为单位并不一定是指以字节为单位。字符设备驱动程序中会涉及到许多有关设备的概念,如什么是设备文件、什么是主次设备号、如何注销设备号、字符设备中有哪些主要的数据结构及它们的作用各是什么、各种函数调用方法等等,下面介绍部分相关概念。(1)设备文件及其作用概念LINUX设备文件就是一个实实在在看得见的文件,只不过这个文件是“设备类型”,它是用来代表一个设备的,一般在设备驱动加载之后创建,在设备驱动卸载后移除。有了设备文件,如果想对设备进行等操作。只需对设备文件进行等操作即可。实现流程设备文件操作系统内核设备驱动硬件设备,设备文件也是一个文件,C库中对文件的操作包括打开、写、读、定位等,分别是通过FOPEN、FWRITE、FREAD、FSEEK等C库函数实现的。作用设备驱动的作用就是将这些对设备文件的打开、读、写、定位等操作转化为对硬件设备的打开、读、写、定位等操作。创建设备文件的方法1手工创建MKNOD方法MKNOKFILENAMETYPEMAJORMINOR(MAJOR主设备号;MINOR次设备号;TYPE设备类型可取C(字符设备),B(块设备)执行此命令之后就可以看到在当前目录下生成了一个名为FILENAME的文件。2自动创建(2)主次设备号及其作用概念设备号就是系统为设备分配的一个编号。在/DEV目录下LL,可以看到有每个设备文件都有两个号,他们就是主次设备号。作用主设备号是用来标识与设备文件相连的驱动程序,主设备号用来反映设备类型;次设备号被驱动程序用来辨别操作的是哪个设备,次设备号用来区分同类型的设备。设备文件需要设备号才能创建;设备驱动也需要设备号才能装载。设备文件正是通过主设备号找到它的驱动;设备驱动正是利用次设备号才知道他要操作的具体是哪个设备。内核中描述设备号的方法内核中用DEV_T类型来描述,其实质是是UNSIGNEDINT32位整数,其中高12位为主设备号,低20位为次设备号用宏MAJORDEV_TDEV)解出主设备号,MINORDEV_TDEV)分解出次设备号。(3)LINUX内核分配主次设备号的静态申请1根据/DOCUMENTATION/DEVICESTXT,确定一个没有使用的主设备号2使用REGISTER_CHRDEV_REGION函数注册设备号INTREGISTER_CHRDEV_REGIONDEV_TFROM,UNSIGNEDCOUNT,CONSTCHARNAME)(FROM希望使用的设备号;COUNT望申请使用的设备号数目;NANMESHEBEIMING(体现在/PROC/DEVICES)静态注册的缺点是移植时容易发生冲突,但是简单。动态分配使用ALLO_CHRDEV_REGION分配设备号INTALLO_CHRDEV_REGION(DEV_TDEV,UNSIGNEDBASEMINOR,UNSIGNEDCOUNT,CONSTCHARNAME)(DEV非配到的设备号)BASEMINOR起始次设备号COUNT需要分配的设备号数目;NAME设备名)(4)注销设备号的方法设备号是宝贵的资源,都应该在不再使用它们时释放这些设备号VOIDUNREGISTER_CHRDEV_REGIONDEV_TFROM,UNSIGNEDCOUT|释放从FROM开始的COUNT个设备号2在LINUX系统中,字符设备以特别文件方式在文件目录树中占据位置并拥有相应的I结点。I结点中的文件类型指明该文件是字符设备文件。可以使用与普通文件相同的文件操作命令对字符设备文件进行操作,例如打开、关闭、读、写等。字符设备是最基本、最常用的设备。概括的说,字符设备驱动主要要做三件事1、定义一个结构体STATICSTRUCTFILE_OPERATIONS变量,其内定义一些设备的打开、关闭、读、写、控制函数;2、在结构体外分别实现结构体中定义的这些函数;3、向内核中注册或删除驱动模块。下面我们来假设一个非常简单的虚拟字符设备这个设备中只有一个4个字节的全局变量INTGLOBAL_VAR,而这个设备的名字叫做“SIMCHR”。对“SIMCHR”设备的读写等操作即是对其中全局变量GLOBAL_VAR的操作。驱动程序是内核的一部分,因此我们需要给其添加模块初始化函数,该函数用来完成对所控设备的初始化工作,并调用REGISTER_CHRDEV函数注册字符设备STATICINT_INITGOBALVAR_INITVOIDIFREGISTER_CHRDEVMAJOR_NUM,“SIMCHR“,其中参数INODE为设备特殊文件的INODE索引结点结构的指针,参数FILE是指向这一设备的文件结构的指针。OPEN的主要任务是确定硬件处在就绪状态、验证次设备号的合法性次设备号可以用MINORINODEIRDEV取得、控制使用设备的进程数、根据执行情况返回状态码0表示成功,负数表示存在错误等;RELEASE函数当最后一个打开设备的用户进程执行CLOSE系统调用时,内核将调用驱动程序的RELEASE函数VOIDRELEASESTRUCTINODE,STRUCTFILERELEASE函数的主要任务是清理未结束的输入/输出操作、释放资源、用户自定义排他标志的复位等。READ函数当对设备特殊文件进行READ系统调用时,将调用驱动程序READ函数SSIZE_TREADSTRUCTFILE,CHAR,SIZE_T,LOFF_T用来从设备中读取数据。当该函数指针被赋为NULL值时,将导致READ系统调用出错并返回EINVAL(“INVALIDARGUMENT,非法参数”)。函数返回非负值表示成功读取的字节数(返回值为“SIGNEDSIZE”数据类型,通常就是目标平台上的固有整数类型)。GLOBALVAR_READ函数中内核空间与用户空间的内存交互需要借助第2节所介绍的函数STATICSSIZE_TGLOBALVAR_READSTRUCTFILEFILP,CHARBUF,SIZE_TLEN,LOFF_TOFFCOPY_TO_USERBUF,WRITE函数当设备特殊文件进行WRITE系统调用时,将调用驱动程序的WRITE函数SSIZE_TWRITESTRUCTFILE,CONSTCHAR,SIZE_T,LOFF_T向设备发送数据。如果没有这个函数,WRITE系统调用会向调用程序返回一个EINVAL。如果返回值非负,则表示成功写入的字节数。GLOBALVAR_WRITE函数中内核空间与用户空间的内存交互需要借助第2节所介绍的函数STATICSSIZE_TGLOBALVAR_WRITESTRUCTFILEFILP,CONSTCHARBUF,SIZE_TLEN,LOFF_TOFFCOPY_FROM_USERIOCTL函数该函数是特殊的控制函数,可以通过它向设备传递控制信息或从设备取得状态信息,函数原型为INTIOCTLSTRUCTINODE,STRUCTFILE,UNSIGNEDINT,UNSIGNEDLONGUNSIGNEDINT参数为设备驱动程序要执行的命令的代码,由用户自定义,UNSIGNEDLONG参数为相应的命令提供参数,类型可以是整型、指针等。如果设备不提供IOCTL入口点,则对于任何内核未预先定义的请求,IOCTL系统调用将返回错误(ENOTTY,“NOSUCHIOCTLFORDEVICE,该设备无此IOCTL命令”)。如果该设备方法返回一个非负值,那么该值会被返回给调用程序以表示调用成功。LLSEEK函数该函数用来修改文件的当前读写位置,并将新位置作为(正的)返回值返回,原型为LOFF_TLLSEEKSTRUCTFILE,LOFF_T,INTPOLL函数POLL方法是POLL和SELECT这两个系统调用的后端实现,用来查询设备是否可读或可写,或是否处于某种特殊状态,原型为UNSIGNEDINTPOLLSTRUCTFILE,STRUCTPOLL_TABLE_STRUCT设备“GOBALVAR”的驱动程序的这些函数应分别命名为GOBALVAR_OPEN、GOBALVAR_RELEASE、GOBALVAR_READ、GOBALVAR_WRITE、GOBALVAR_IOCTL,因此设备“SIMCHR”的基本入口点结构变量GOBALVAR_FOPS赋值如下STRUCTFILE_OPERATIONSGOBALVAR_FOPSREADGOBALVAR_READ,WRITEGOBALVAR_WRITE,3LINUX字符驱动设备程序集成在内核中,是处理或操作硬件控制器的软件。本质上就是常驻内存的低级硬件处理程序的共享库,即设备驱动程序是内核中具有高特权级的、常驻内存的、可共享的下层硬件处理程序。字符设备驱动程序软件封装了如何控制这些设备的技术细节,并通过特定的接口导出一个规范的操作集合,如下图1所示4字符设备驱动程序与外界的接口每一种类型的驱动程序,不管是字符设备还是块设备都为内核提供相同的调用接口,故内核能以相同的处理不同的设备。LINUX为每一种不同类型的设备驱动程序维护相应的数计结构,以便定义统一的接口并实现驱动程序的装载性和动态性。LINUX字符驱动设备程序与外界接口可以分为三个部分(1)字符设备驱动与操作系统内核的接口这是通过数据结构FILE_OPERATIONS来完成的(2)字符设备驱动与系统引导的接口这部分利用驱动程序对设备进行初始化(3)字符设备驱动与设备的接口这部分描述理了驱动程序如何与设备进行交互,这与具体设备密切相关5字符设备的注册图3字符设备驱动框架图由上图可知,字符设备的注册分为四个步骤(1)分配CDEV,即分配空间分配是对于指针而言,静态的不需要分配STRUCTCDEV的分配可使用CEDV_ALLOC函数来完成。定义STRUCTCDEVCDEV_ALLOCVOID。分配完成后返回分配到的STRUCTCDEV函数指针(2)初始化CDEV结构STRUCTCDEV的初始化可使用CEDV_INIT函数来完成。定义VOIDCDEV_INITSTRUCTCEDVCDEV,CONSTSTRUCTFILE_OPERATIONSFOPS参数CDEV待初始化的CDEV结构FOPS设备对应的操作函数集(3)添加CDEV(即注册字符设备驱动)STRUCTCDEV的注册可使用CEDV_ADD函数来完成。定义INTCDEV_ADDSTRUCTCDEVP,DEV_TDEV,UNSIGNEDCOUNT参数P待添加到内核的字符设备结构,要注册的字符设备DEV设备号,驱动程序对应的主设备号COUNT添加的设备个数(4)CDEV设置完成,通知内核STRUCTCDEV的信息(在执行这步之前必须确定你对STRUCTCDEV的以上设置已经完成)6设备操作(注册完之后要实现STRUCTFILE_OPERATIONS结构中相关的设备操作)(1)对应OPEN方法在设备文件上的第一操作,可以不实现此方法,没有(即该项为NULL)时则认为永远打开成功。函数调用INTOPENSTRUCTINODE,STRUCTFILE(2)对应CLOSE方法当设备文件被关闭时调用这个操作。RELEASE也可以没有。函数调用VOIDRELEASESTRUCTINODE,STRUCTFILE(3)从设备中读取数据,函数调用SSIZE_TREADSTRUCTFILE,CHAR_USER,SIZE_T,LOFF_T(4)向设备发送数据,函数调用SSIZE_TWRITESTRUCTFILE,CONSTCHAR_USER,SIZE_T,LOFF_T(5)对应SELECT系统调用,函数调用UNSIGNEDINTPOLLSTRUCTFILE,STRUCTPOLL_TABLE_STRUCT(6)控制设备,函数调用INTIOCTLSTRUCTINODE,STRUCTFILE,UNSIGNEDINT,UNSIGNEDLONG(7)将设备映射到进程虚拟地址空间中,函数调用INTMMAPSTRUCTFILE,STRUCTVM_AREA_STRUCT将设备映射到进程虚拟地址空间中。(8)修改文件的当前读写位置,并将新位置作为返回值。函数调用OFF_TLLSEEKSTRUCTFILE,LOFF_T,INT对上述中调用的OPEN方法、RELEASE方法、WRITE方法、READ方法等方法的解析OPEN方法OPEN方法是驱动程序用来为以后的操作完成初始化准备工作的。在大部分驱动程序中,OPEN完成如下工作A初始化设备,设置寄存器等B标明主次次设备号,这样驱动程序才知道操作哪个设备将设备描述结构指针赋值给文件私有数据指针,然后在读写操作函数中就能知道该操作哪个设备C检查设备特定的错误(如设备未就绪或硬件问题)D如有必要,更新F_OP指针E分配并填写置于FILPPRIVATE_DATA里的数据结构RELEASE方法RELEASE方法的作用正好与OPEN相反。这个设备方法有时也称为CLOSE,它应该关闭设备,应完成的工作如下A释放由OPEN分配的、保存在FILEPRIVATE_DATA中的所有内容B在最后一次关闭操作时关闭设备READ和WRITE方法读和写方法都完成类似的工作从设备中读取数据到用户空间;将数据传递给驱动程序。它们的原型也相当类似定义SSIZE_TXXX_READSTRUCTFILEFILP,CHAR_USERBUFF,SIZE_TCOUNT,LOFF_TOFFP定义SSIZE_TXXX_WRITESTRUCTFILEFILP,CHAR_USERBUFF,SIZE_TCOUNT,LOFF_TOFFP参数对于这两个方法,其参数含义如下FILP是文件指针,内核构造后传给此函数的COUNT是请求传输的数据量。来自用户空间BUFF参数指向数据缓存。来自用户空间OFFP支出文件当前的访问位置。来自内核7字符设备注销当不再使用驱动程序的时候应该把驱动程序注销掉。字符设备的注销使用CDEV_DEL函数来完成。定义INTCDEV_DELSTRUCTCDEVP参数P要注销的字符设备结构8字符设备注册和注销(SCULL模型函数)的内存使用流程图如下图4SCULL模型框架图SCULL模型函数的结构体代码如下REPRESENTATIONOFSCULLQUANTUMSETSSTRUCTSCULL_QSETVOIDDATASTRUCTSCULL_QSETNEXTSTRUCTSCULL_DEVSTRUCTSCULL_QSETINTQUANTUMINTQSETUNSIGNEDLONGSIZEUNSIGNEDINTACCESS_KEYSTRUCTSEMAPHORESEMSTRUCTCDEVCDEVSCULL驱动程序引入了两个LINUX内核中用于内存管理的核心函数,它们的定义都在中VOIDKMALLOCSIZE_TSIZE,INTFLAGSVOIDKFREEVOIDPTR以下是SCULL模块中的一个释放整个数据区的函数(类似清零),将在SCULL以写方式打开和SCULL_CLEANUP_MODULE中被调用INTSCULL_TRIMSTRUCTSCULL_DEVDEVSTRUCTSCULL_QSETNEXT,DPTRINTQSETDEVQSETINTIFORDPTRDEVDATADPTRDPTRNEXTIFDPTRDATAFORI0IDATAIKFREEDPTRDATADPTRDATANULLNEXTDPTRNEXTKFREEDPTRDEVSIZE0DEVQUANTUMSCULL_QUANTUMDEVQSETSCULL_QSETDEVDATANULLRETURN0以下是SCULL模块中的一个沿链表前行得到正确SCULL_SET指针的函数,将在READ和WRITE方法中被调用FOLLOWTHELISTSTRUCTSCULL_QSETSCULL_FOLLOWSTRUCTSCULL_DEVDEV,INTNSTRUCTSCULL_QSETQSDEVDATAIFQSQSDEVDATAKMALLOCSIZEOFSTRUCTSCULL_QSET,GFP_KERNELIFQSNULLRETURNNULLMEMSETQS,0,SIZEOFSTRUCTSCULL_QSETWHILENIFQSNEXTQSNEXTKMALLOCSIZEOFSTRUCTSCULL_QSET,GFP_KERNELIFQSNEXTNULL其实这个函数的实质是如果已经存在这个SCULL_SET,就返回这个SCULL_SET的指针。如果不存在这个SCULL_SET,一边沿链表为SCULL_SET分配空间一边沿链表前行,直到所需要的SCULL_SET被分配到空间并初始化为止,就返回这个SCULL_SET的指针。二相关数据结构之间的关系说明字符设备驱动主要应用了三种数据结构STRUCTFILE_OPERATIONS结构,这是设备驱动程序所提供的一组用一个结构向系统进行说明的入口点,它的内容需要驱动程序来填写的。它是一个函数指针(指向函数的指针)的集合。结构中的成员指向驱动函数中的函数,这些函数实现一个特定的操作,对于不支持的操作保留为NULL。实际是一张对应表,把应用程序中的操作转换成驱动程序操作。内核为什么只定义这些操作呢因为这些操作足以完全控制任何一个硬件设备。驱动程序只需完成这些操作的是实现,其他的问题交给应用程序来处理。每个驱动程序都会定义一个STRUCTFILE_OPERATION类型的变量,并把编写好的操作函数(读写打开等函数)的指针赋给这个结构变量的成员,而这个变量的指针会被赋给在驱动程序定义的STRUCTCDEV类型的变量,然后随STRUCTCDEV一同注册到内核中。重要成员STRUCTMODULEOWNER它并不是一个操作,它是指向“拥有”该结构的内核模块的指针,内核使用这个字段以避免在模块的操作正在使用时被卸载。LOFF_T(LLSEEK)(STRUCTFILE,LOFF_T,INT)LLSEEK方法用来修改文件当前读写位置,并且返回新位置SSIZE_T(READ)(STRUCTFILE,CHAR_USER,SIZE_T,LOFF_T)用来从设备中读取数据SSIZE_T(WRITE)(STRUCTFILE,CHAR_USER,SIZE_T,LOFF_T)用来向设备中写取数据INT(OPEN)(STRUCTINODE,STRUCTFILE)一般为对设备文件执行的第一个操作,但不是必须的。STRUCTFILE结构,主要用于与文件系统对应的设备驱动程序。代表一个打开的文件,它由内核在OPEN时创建,并传递给在该文件上进行操作的所有函数,直到碰到最后的CLOSE函数。在文件的所有实例都被关闭之后,内核会释放这个数据结构,它的内容由内核填写的。每个文件在打开的时候,内核都会为他创建一个STRUCTFILE类型的变量,存放与该文件相关的操作。重要成员LOFF_TF_POS文件读写的位置(LOFF是内核定义的一种数据类型,其实是整型)STRUCTFILE_OPERATIONSF_OP文件在打开的时候,内核会根据设备号(从文件的对应INODE结构变量中找到)找到在内核中找到具有相同设备号的那个驱动,从而找到指向指向驱动FILE_OPERATION变量的指针。STRUCTINODE结构,提供了关于特殊设备文件/DEV/MYDEV的信息,它的内容也是由内核来填写的。每创建一个设备文件时,就会定义一个STRUCTINODE结构体类型的变量,用来存放该文件的位置,设备号等物理信息。重要成员DEV_TI_RDEV设备号在创建设备文件时,把命令中的设备号赋给它。STRUCTCDEVI_CDEVSTRUCTCDEV也是一个模子,他是用来描述一类设备的,用这个模子生产出来的变量都是用来描述设备一类的,它的内容是由驱动程序来填写的。那I_CDEV变量描述的是哪类设备的呢I_CDEV变量描述的就是INODE结构变量所描述的这个设备文件的想关联的这类设备。设备驱动程序在创建的时候会定义一个STRUCTCDEV结构的变量,把自己相关的信息的值赋给CDEV变量的成员,在设备驱动装载的时候它会被注册到内核中。当设备文件没有被打开的时候STRUCTINODE中的I_CDEV变量值为NULL;当设备文件被打开时,内核就会在已注册到内核中的所有STRUCTCDEV变量中找出与当前打开的设备文件具有相同主设备号的那个,然后把这个STRUCTCDEV变量的指针赋给I_CDEV。具体的过程需要进行内核分析。由此可见,设备文件是通过设备号与设备驱动关联起来的。各个数据结构的定义如下(1)STRUCTFILE_OPERATIONS结构STATICCONSTSTRUCTFILE_OPERATIONSMY_FOPSOWNERTHIS_MODULELLSEEKMY_LLSEEKREADMY_READWRITEMY_WRITEOPENMY_OPENRELEASEMY_RELEASEUNLOCKED_IOCTLIOCTL(2)STRUCTFILE结构1)读STATICSSIZE_TMY_READSTRUCTFILEFILP,CHAR_USERBUF,SIZE_TSIZE,LOFF_TPPOS2)写STATICSSIZE_TMY_WRITESTRUCTFILEFILP,CONSTCHAR_USERBUF,SIZE_TSIZE,LOFF_TPPOS3)SEEK文件定位STATICLOFF_TMY_LLSEEKSTRUCTFILEFILP,LOFF_TOFFSET,INTWHENCE4)IO控制STATICINTIOCTLSTRUCTFILEFILE,UNSIGNEDINTCMD,UNSIGNEDLONGARG(3)STRUCTINODE结构1)打开INTMY_OPENSTRUCTINODEINODE,STRUCTFILEFILP2)释放INTMY_RELEASESTRUCTINODEINODE,STRUCTFILEFILP三字符设备驱动实例字符设备驱动程序的运行过程如下图所示1编写SIMCHRC文件打开终端,创建文件夹MKDIRDRIVER,进入文件夹DRIVER里面创建文件GEDITSIMCHRC文件GLOBALVARC源代码如下INCLUDEINCLUDEINCLUDEINCLUDEINCLUDEMODULE_LICENSE“GPL“INTSIMCHR_OPENSTRUCTINODE,STRUCTFILEINTSIMCHR_RELEASESTRUCTINODE,STRUCTFILESSIZE_TSIMCHR_READSTRUCTFILE,CHAR,SIZE_T,LOFF_TSSIZE_TSIMCHR_WRITESTRUCTFILE,CONSTCHAR,SIZE_T,LOFF_TINTDEV_MAJOR0INTDEV_MINOR0STRUCTFILE_OPERATIONSSIMCHR_FOPSOWNERTHIS_MODULE,OPENSIMCHR_OPEN,RELEASESIMCHR_RELEASE,READSIMCHR_READ,WRITESIMCHR_WRITE,STRUCTSIMCHR_DEVINTSIMCHR_VARSTRUCTCDEVCDEVSTRUCTSIMCHR_DEVMY_DEVSTATICVOID_EXITSIMCHR_EXITVOIDDEV_TDEVNOMKDEVDEV_MAJOR,DEV_MINORCDEV_DELKFREEMY_DEVUNREGISTER_CHRDEV_REGIONDEVNO,1/注销已注册的驱动程序PRINTK“SIMCHRUNREGISTERSUCCESSN“STATICINT_INITSIMCHR_INITVOID/初始化模块的操作INTRET,ERRIFDEV_MAJORDEV_TDEVNOMKDEVDEV_MAJOR,DEV_MINORRETREGISTER_CHRDEV_REGIONDEVNO,1,“SIMCHR“ELSERETALLOC_CHRDEV_REGION/动态分配设备号DEV_MAJORMAJORDEVNO/保存动态分配的主设备号IFRETGLOBAL_VAR0/设备变量初始化为0CDEV_INIT/初始化设备中的CDEV结构MY_DEVCDEVOWNERTHIS_MODULE/初始化CDEV中的所有者字段ERRCDEV_ADD/向内核添加CDEV结构的信息IFERRI_CDEV,STRUCTSIMCHR_DEV,CDEVFILPPRIVATE_DATADEV/保存数据指针RETURN0/释放操作INTSIMCHR_RELEASESTRUCTINODEINODE,STRUCTFILEFILPRETURN0/读操作SSIZE_TSIMCHR_READSTRUCTFILEFILP,CHARBUF,SIZE_TLEN,LOFF_TOFFSTRUCTSIMCHR_DEVDEVFILPPRIVATE_DATA/获取已指向分配数据的指针IFCOPY_TO_USERBUF,RETURNSIZEOFINT/返回读取数据的大小/写操作SSIZE_TSIMCHR_WRITESTRUCTFILEFILP,CONSTCHARBUF,SIZE_TLEN,LOFF_TOFFSTRUCTSIMCHR_DEVDEVFILPPRIVATE_DATA/获取已指向分配数据的指针IFCOPY_FROM_USERRETURNSIZEOFINT/返回写数据的大小MODULE_INITSIMCHR_INITMODULE_EXITSIMCHR_EXIT2编写MAKEFILE文件在DRIVER文件夹下创建MAKEFILE文件GEDITMAKEFILEIFNEQKERNELRELEASE,OBJMGLOBALVAROELSEKDIR/LIB/MODULES/30012GENERIC/BUILDALLMAKECKDIRMPWDMODULESCLEANRMFKOMODCMODOSYMVERSENDIF3编译模块MAKE4加载模块SUDOINSMODSIMCHRKO5查看LSMOD或管道查询LSMOD|GREPSIMCHR6查看动态生成的设备号CAT/PROC/DEVICES7得到主设备号CAT/PROC/DEVICES|GREPSIM8查询模块文件LS/DEV|GREPSIM9创建设备节点文件SUDOMKNODM666/DEV/SIMCHRC250010查看字符设备LS/DEV/SIMCHR11编写测试程序创建文件GEDITTESTC编写TESTC源代码如下INCLUDEINCLUDEINCLUDEINCLUDEDEFINEDEV_NAME“/DEV/SIMCHR1“INTMAININTFD,NUMFDOPENDEV_NAME,O_RDWR,S_IRUSR|S_IWUSRIFFDINCLUDEINCLUDEINCLUDEINCLUDEINCLUDEMODULE_LICENSE“GPL“DEFINEMAJOR_NUM254STATICSSIZE_TSIMCHR_READSTRUCTFILE,CHAR,SIZE_T,LOFF_TSTATICSSIZE_TSIMCHR_WRITESTRUCTFILE,CONSTCHAR,SIZE_T,LOFF_TSTRUCTFILE_OPERATIONSSIMCHR_FOPSREADSIMCHR_READ,WRITESIMCHR_WRITE,STATICINTGLOBAL_VAR0STATICSTRUCTSEMAPHORESEMSTATICWAIT_QUEUE_HEAD_TOUTQSTATICINTF

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论