您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 管理学资料 > VxWorks驱动开发笔记
VxWorks驱动开发笔记普通应用软件的开发,客户都会提出很明确的需求如功能、用户界面、外部接口以及开发周期经费等等要求,这些要求一般都相对直观且容易理解。但是对于驱动程序的开发开说,开发周期以及经费这些需求往往都比较容易理解,可是对于功能、用户界面以及外部接口等需求就很难描述了,因为这需要对底层操作系统的理解,否则就无法提出适宜的需求来,而对底层操作系统的理解才是驱动程序开发之所以困难的主要原因。1.1驱动程序的结构驱动程序有两大基本特征:一是它实现了对硬件设备的访问(最根本目的),二是它实现了一系列与硬件设备无关的的访问接口。通过这些接口,上层软件在控制此类硬件设备时无需对硬件进行详细的了解就可以进行访问,此外,当硬件设备更换时,只需要修改设备驱动的硬件相关的部分,而上层软件无需做任何更改。这两个基本特征也正好决定了驱动程序的主体结构。如图1.1所示,图中的阴影部分为设备驱动程序。图1.1驱动程序的结构1.2驱动程序的工作流程不同设备在操作系统中完成的工作是不同的,但是就是工作流程来说,大致可以分为两个阶段。第一个阶段是初始化阶段,在初始化阶段,驱动程序主要完成硬件以及设备驱动相关数据结构的初始化。第二个阶段是硬件的访问阶段,根据设备工作模式的不同,可以分为中断模式和轮询模式,无论何种模式都可以通过与硬件设备无关的通用接口进行硬件设备的访问。2.1串口驱动原理串口因为调试简单在许多数据量不大的场合依然较为流行,可以借助串口对目标机中操作系统的运行情况进行监控等等。下图为Tornado开发软件通过串口对目标机上运行的VxWorks操作系统进行监控的结构原理图。图2.1Tornado通过串口对vxWorks操作系统进行监控设备的驱动程序分为与硬件相关部分和硬件无关部分,而硬件相关部分则负责具体的硬件实现,硬件无关部分实现了一系列通用的数据接口,其中硬件无关部分实现是create、remove、open、close、read、write、ioctl等7个通用的函数接口。使用这7个基本的函数,不但能够访问串口,而且还能够对网络、磁盘文件等多类设备进行访问。这7个函数的原型在文件ioLib.c中进行定义。分别为:intcreat(constchar*name,intflag):该函数创建了一个文件描述符fd。其中name为一个抽象文件的文件路径,这个抽象可以指硬盘上保存的一个文件,也可以是一个以字符串表示的一个设备,当文件描述符创建完毕后自动以参数flag打开该文件。STATUSremove(constchar*name):移除文件,name表明文件路径。intopen(constchar*name,intflags,intmode);打开文件,准备访问。name为文件路径,flags为打开方式如只读、只写、读写以及不存在可创建等,mode为打开模式只有在NFS文件系统下才有效。打开成功后返回文件描述符。STATUSclose(intfd);关闭文件。fd为文件描述符。intread(intfd,char*buffer,size_tmaxbytes);从文件描述符fd指定的文件中读取最多maxbytes个字节,保存在buffer指定的位置。可能会由于文件长度的原因,实际读取的字节数小于maxbytes,函数返回实际读出的字节数。intwrite(intfd,char*buffer,size_tnbytes);向文件描述符fd指定的文件中写入nbytes个字节的数据,原数据保存在buffer只能的内存中。可能会由于buffer空间等原因,实际写入的字节数小于nbytes,函数返回实际写入的字节数。intioctl(intfd,intfunction,intarg);控制函数,主要用于设置或读取设备的工作方式等特性。上述这7个通用接口,也就是串口驱动的一个最根本的需求,即通过这几个函数就可以实现对串口控制芯片i8250的操作。而函数库iosLib中则是上述各个接口的较为底层的实现。它首先根据访问设备类型的不同(普通磁盘文件和硬件设备)而将其分为两类,并用不同的数据结构描述,这里主要对结构DRV_ENTRY进行分析。如图2.3。图2.3iosLib库提供的数据结构结构数组drvTable的每个元素drvTable[i]对应一类设备,因此其下表i将是不同类型设备之间区分的一个重要的参考。由于0通常表示无效,因此drvTable[0]为空,不代表任何设备。图2.4给出了ioLib提供的通用函数和结构DRV_ENTRY的基本关系。图中的箭头表示调用关系,有调用者指向被调用者。图2.4ioLib库与iosLib库的内部关系由于数组drvTable的每个元素drvTable[i]对应一类设备,如果要使用某一类设备中的一个,如系统中两个串口的一个,就必须指明是哪个串口。在函数库ioLib中的7个通用函数中都有一个重要的参数name,表明文件的路径或者设备的名称,该名称具有唯一性,也就是一个name指向唯一一个文件或者唯一一个设备。下面要引入的数据结构是设备描述符,如图2.5所示,它在函数库iosLib中定义。图2.5设备描述符基本的设备描述符的数据结构为DEV_HDR,它描述了一些最为基本的信息,数组decTable的下标devnum和设备名称name,该设备序号即是ioLib库中使用的文件描述符fd。综合起来设备描述符DRV_HDR、结构DRV_ENTRY以及7个通用函数库的关系可以用图2.6来描述。图2.6DRV_HDR、DRV_ENTRY及通用接口之间的关系上述通用接口可以满足网卡、串口等外围设备的需要,对于具体的外部设备,则需要对图2.6所说的通用接口进行扩展,如图2.7所示,这个扩展主要采用了两种手段,一是继承,即通过对结构DEV_HDR进行继承得到如串口、终端以及网卡等特殊类型的设备;而是多态,也就是对一个通用的接口,根据具体设备的不同而采取不同的函数。C不是面向对象语言,没有明确的类、继承和多态的概念,但是可以灵活地使用C达到同样的目的。图2.7通用接口通过多态和继承得到扩展图2.8则更为详细地描述了VxWorks操作系统对多个设备的管理。对每类设备的操作函数,系统创建了一个DRV_ENTRY结构数组来描述,每个DRV_ENTRY结构变量对应一类设备的操作函数,对某类设备的具体操作方式的设置则是通过设定DRV_ENTRY结构变量中个函数指针来实现的;对于同一类的设备,系统为其从DEV_HDR派生了一个数据结构,而每个结构变量则是对应该类设备中的每一个具体的设备,不同的设备通过双向链表链接在一起。图2.8VxWorks对系统中多个设备的管理结构2.3串口驱动程序函数库分析为了进一步加深对IO设备管理数据结构的理解,本节将分别对函数库ioLib、iosLib进行分析。2.3.1函数库ioLibioLib库为上层提供了7个基本的函数接口:creat(),remove(),open(),close(),read(),write()以及ioctl()。上层用户只需要对这7个函数进行操作就能够完成对硬件的访问。下面一次分析ioLib库中各个函数库的功能。1.intcreat(constchar*name,intflag)该函数提供了一个与设备无关的通用接口,用于创建一个文件(可以是普通的磁盘文件也可以是抽象的设备文件),该文件的路径为name,创建完毕后自动打开,打开的参数为flag。该函数的正常返回值为文件描述符,否则将会返回ERROR。对照图2.8,该函数根据设备的名称,从链表中找到该设备对应的设备号drmNum(该数值即为函数返回的文件描述符),然后以此为下标就可以找到该类设备的de_create函数指针,从而找到该设备的create函数。2.intopen(constchar*name,intflags,intmode)该函数打开一个文件以方便进行读、写或者更新,打开后返回该文件的文件描述符。open()函数的参数为文件名以及访问方式:lO_RDONLY(0)以只读方式打开lO_WRONLY(1)以只写方式打开lO_RDWR(2)以读写方式打开lO_CREAT(0x0200)如果文件不存在,就创建一个文件并打开。3.LOCALintioCreateOrOpen(constchar*name,intflags,intmode,BOOLcreate)这个函数其实是函数create()和open()函数的实现主体。create()和open()函数只是根据参数create简单调用函数ioCreateOrOpen()而已,真正的实现在函数ioCreateOrOpen()中。4.STATUSunlink(char*name)该函数主要是和posix兼容,它的功能与remove完全相同。5.STATUSremove(constchar*name)调用函数iosDelete来删除文件。如果有符号链接,则需要沿着符号链接直接找到文件并删除。6.STATUSclose(intfd)调用函数ioClose函数关闭文件。7.intrename(constchar*oldname,constchar*newname)修改文件名。并不是所有的设备都支持重命名操作,比如通常的dosFS和rt11FS都是支持重命名操作的,而netDrv和nfsDrv则不支持,因此在使用这个函数前需要明确设备是否支持重命名操作。重命名操作主要通过调用函数ioctl(fd,FIORENAME,(int)newname)完成。注意:调用函数ioctl(fd,FIORENAME,(int)newname)重命名前需要先打开文件open()。8.intread(intfd,char*buffer,size_tmaxbytes)调用函数iosRead实现读操作,maxbytes为读取的最大字节数,读取之后存放在buffer指定的地址空间,不过可能由于文件中字节数的限制等因素,实际读取的字节数可能会小于maxbytes,因此需要在最终的返回值中返回实际读取的字节数。9.intwrite(intfd,char*buffer,size_tnbytes)调用函数iosWrite向指定的文件中写入数据,nbytes为期望写入的字节数,但是实际上可能会由于文件本身的限制导致实际写入的字节数小于nbytes,因此需要在返回值中记录实际写入的字节数。10.intioctl(intfd,intfunction,intarg)直接调用函数iosIoctl实现对文件的控制操作。11.intlseek(intfd,longoffset,intwhence)设定一个文件的读写指针,下次读写操作将从设定的位置开始。参数whence有三个数值:lSEEK_SET(0)设定到相对于文件起始位置偏移offset位置。lSEEK_CUR(1)设定到当前位置偏移offset的位置。lSEEK_END(2)相对于文件结束位置偏移offset的位置。注意:如果指定的地址是无效的地址(超出了文件的范围),那么将返回错误指示。12.intreadv(intfd,structiovec*iov,intiovcnt)从设备fd中读取数据,保存在iov起始地址为iov的数组中。iovcnt为结构iovec数组iov的元素的个数。iov是一个数组指针,它指向一个iovec结构数组,iovec结构中的元素iov_base指定了数据保存起始位置地址,而iovcnt则指定了iov数组的元素个数,因此总的读出的字节数为各个数组元素中保存数据的字节数之和。如图2.9所示。图2.9iovec结构示意图13.intwritev(intfd,registerstructiovec*iov,intiovcnt)该函数调用iosWrite函数将几段分散的数据写入到fd设备中。14.STATUSioFullFileNameGet(char*pathName,DEV_HDR**ppDevHdr,char*fullFileName)通常来说,一个完整的文件的
本文标题:VxWorks驱动开发笔记
链接地址:https://www.777doc.com/doc-6708218 .html