这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » MCU » VxWorks Device Driver 机制分析(老站转)

共2条 1/1 1 跳转至

VxWorks Device Driver 机制分析(老站转)

菜鸟
2002-05-31 22:46:24     打赏
网友kola的一篇文章, 省略拉一些图片, 谢谢kola!!! VxWorks Device Driver 机制分析 一. 概述: 我们不可避免地经常要和device driver打交道,而device driver本身跟操作系统的相关性特别密切,而了解如何能做到屏蔽底层硬件提供标准且通用的接口给上层是我们研究device driver标准的基本目的,由于时间和篇幅的限制,而且我们的工作主要在VxWorks上进行device driver的开发,所以这里只对VxWorks下的标准device driver开发进行分析。 -------------------------------------------------------------------------------- 编辑 发表於:2002-01-22 - 17:02:03 IP: 211.97.*.* amine 版主 来自: 发表总数:519 查看   短消息   电子邮件 -------------------------------------------------------------------------------- 二. 详细分析: 1. VxWorks Device Driver的在系统中的层次概述: VxWorks 标准device driver基本都是通过I/O系统来存取的,这样做的好处是可以屏蔽底层硬件,对上层应用程序提供统一的接口。VxWorks的I/O系统由基本I/O及含buffer的I/O组成,它提供标准的C库函数,基本I/O库与Unix兼容,而含buffer的I/O则与ANSI C兼容。我们将在后面介绍基本I/O与含buffer的I/O。VxWorks的I/O系统有其独特的特性,使得它比其它I/O系统更快速、灵活,这在实时系统中非常重要。还有一些特殊的device driver 如End driver, Serial device driver由于其自身的特性,虽然不是通过标准I/O来进行存取的,但是也都有它们各自相关的规范.在这里我们只介绍通过I/O系统存取的标准的device driver. VxWorks的I/O设备和Unix的I/O设备很相似,它们都分为:字符设备和块设备。 字符设备是指在I/O传输的过程中以字符为单位进行传输的设备,如:键盘,鼠标,打印机等。 块设备是指以“块”为单位对数据进行存取的设备,如:硬盘,光驱,软驱,磁带等。 但是VxWorks下的I/O设备driver与Unix下的I/O设备driver也有区别,区别主要是: l VxWorks的device driver可以动态安装和删除。 l VxWorks的文件描述符是全局的,可以被任何一个任务存取,除了标准的输入,输出,错误输出外。 l VxWorks的ioctl控制命令与Unix的不同。 l Unix下的device driver执行在系统模式,没有优先级之分,而VxWorks的device driver有优先级之分,这取决于调用它的任务的优先级。 2. 系统中标准C的 I/O函数: Call Description creat( ) Create a file. remove( ) Remove a file. open( ) Open a file. (Optionally, create a file.) close( ) Close a file. read( ) Read a previously created or opened file. write( ) Write a previously created or opened file. ioctl( ) Perform special control functions on files or devices 一般来说在使用基本I/O函数时,经常使用文件描述符来对文件进行操作。有三个基本的系统保留的描述符: 0 = standard input 1 = standard output 2 = standard error output 这三个描述符的值是你在用open()和create()函数创建描述符时永远得不到的描述符,这就是我们分配的描述符永远都大于2的原因。注意VxWorks支持I/O重定向的功能,我们可以使用函数:ioGlobalStdSet(stdFd, newFd )来将系统保留的描述符stdFd(0,1,2)重定向到newFd上,这样做的好处是可以将标准输入/输出/错误输出重新定向到任何一个你喜欢的I/O设备上,如:串口,socket,文件等等,便于你跟踪调试。自然也可以使用ioGlobalStdGet(stdFd)读出现在系统的标准输入/输出/错误输出定向在哪个描述符上。更灵活的是我们可以使用ioTaskStdSet(tasked,stdFd,newFd)重定向某个指定任务的标准I/O. 在对任何一个设备操作前我们必须使用open()或create()取得文件描述符fd, 使用的方法是:fd = open ("name", flags, mode); File Access Flags Flag Hex Value Description O_RDONLY 0 Open for reading only. O_WRONLY 1 Open for writing only. O_RDWR 2 Open for reading and writing. O_CREAT 200 Create a new file. O_TRUNC 400 Truncate the file. 在操作完该设备后记得使用close函数来释放此文件描述符。面向文件的设备必须使用create()来创建文件,使用remove()来释放一个文件设备上的文件,记住在文件被cloes()之前不可以使用remove(),对于非文件系统,create()函数相当于open()而remove()则没有任何作用。 在使用open()或create()函数来取得文件描述符之后,我们可以通过该文件描述符用read(),write(),ioctl()函数来对设备进行操作。 3. 含有buffer的I/O: stdio VxWorks的含buffer的I/O库与Unix和Windows下的stdio库兼容。支持全部的ANSI C. Stdio库实现了读写大块数据的buffer机制,这对上层应用来说是透明的。通常使用fopen()来替换open()打开一个文件设备,它返回一个文件指针FILE*,也可以使用fp = fdopen (fd, "r");来打开一个已经打开了文件描述符的设备,在取得了FILE*后,可以使用fread, fwrite, putc, getc,来对设备进行操作。 4. 字符设备driver分析: l 如何在vxWorks上做标准的字符设备driver?这需要我们分析一下VxWorks字符设备driver的机制,通过分析我们发现。 1) 首先,VxWorks调用iosDrvInstall()函数将自己的device driver注册到系统的driver table, iosDrvInstall的原型是: int iosDrvInstall (FUNCPTR pCreate, FUNCPTR pDelete, FUNCPTR pOpen, FUNCPTR pClose, FUNCPTR pRead, FUNCPTR pWrite, FUNCPTR pIoctl); 由此我们可以看到,我们必须首先实现自己的设备的7个标准I/O函数,然后通过调用iosDrvInstall函数,将自己设备的标准I/O函数的指针作为参数,传递给系统,这时系统会在将这些函数的指针加入到Driver table中,并返回一个driver number给device driver, 以后则可以通过此driver number使用标准的ioLib对该设备进行操作。 2) 当调用iosDrvInstall()注册IO函数成功后,必须使用iosDevAdd()函数将此设备加入到I/O系统的device list中,iosDevAdd的原型: STATUS iosDevAdd (DEV_HDR *pDevHdr, char *name, int drvnum); 其中DEV_HDR是一个指向DEV_HDR的指针,DEV_HDR结构中的第一项是指向下一个device的DEV_HDR的指针。 这时device driver已经安装到VxWorks中了,我们可以使用open, close, create, remove, read , write等通用系统IO函数对该device进行存取。 在设备的命名上通常将NFS网络设备命名为以斜线”/”开头的名字,如:/usr.将非NFS网络设备命名为”远程机器名字:”的形式,如:”host:”。其他的名字命名为远程主机的远程目录内的文件名字。文件系统使用dosFs经常用大写字母与数字加上“:”形成,如:”DEV1:”。记住“/“不能单独作为设备的名字。 l Cache的一致性问题: 很多时候在我们开发板卡驱动程序的时候我们对分配的内存带的cache会产生迷惑,我们什么时候应该分配带cache的内存,有 cache有什么好处,应该要注意哪些问题,有可能会出现哪些问题等等太多的问题不明确,所以我们在这里就简单介绍一下有关的cache问题。 首先cache的最大的好处是,解决CPU与内存之间的瓶颈,我们现在使用的SDRAM的速度一般都在3ns~10ns左右,而CPU的速度已经到了1G,甚至十几G或几十G的速度,很明显这样的速度差异会导致CPU在存取内存时经常要等待数据在内存上的操作,这将致命地影响系统的性能。所以人们引进了cache机制,因为造价及物理上的限制cache通常都不大只有256K或512K,但是速度很快,它的位置一般在CPU与内存之间,它有一些列的快速算法来保证下次CPU存取内存的数据在cache内的高机率。这样CPU在存取数据如果数据在cache内则直接对cache进行存取而无须与缓慢的内存打交道。 为板卡开发的driver必须保证cache的一致性,即cache中的数据必须与内存中的数据保持同步,因为在使用异步方式读取内存时有可能产生内存与cache失步。数据cache是为了减少存取内存的次数,而加快系统的性能,数据cache通常有两种放式:writethrough和copyback。Writethrough是指在写内存时同时也往cache中写。保证cache的在输出上一致,但不保证在输入时一致。Copyback仅将数据写到cache中,它保证数据在输入和输出时都一致。 当CPU写一个DMA设备上的内存时,数据首先被写到cache中,当DMA设备从RAM中传输数据时,不保证内存中的数据与cache中的数据一致。这样输出到设备的数据也许不是最新的,最新的数据应该在cache内。可以在数据传输到DMA设备之前将cache数据刷新到内存中。 当CPU读一个DMA设备上的内存时,数据读可以来自cache的buffer而不是从设备传输到内存的数据,可以确保cache buffer已经被标记(屏蔽)来解决读出的数据来自内存而非cache. Driver可以通过分配无cache buffers(使用cacheDmaMalloc())或刷新和使cache无效来解决CPU与设备之间数据传输的cache一致性问题。分配无cache buffers常用于分配静态buffers,它需要MMU的支持。无cache buffers频繁地被动态分配和释放将导致大量的内存被标记为无cache.一个择中的方法来使用动态无cache buffer是人为地刷新(使用cacheFlush()函数)和屏蔽cache (使用cacheInvalidate( )).注意在设备读数据之前用cacheFlush( )保证数据一致,而在设备写内存后用cacheInvalidate( )保证将cache和内存数据的一致。 5. 块设备: VxWorks的块设备与字符设备有微小的差别,它们的唯一区别是块设备不能与I/O系统直接打交道而是在其与I/O系统之间必须有文件系统,如dosFs, rt11Fs, rawFs或tapeFs等。这种层次关系允许同一个块设备上存在不同的文件系统,减少driver中必须支持的I/O函数的数量。 作为一个块设备必须提供一个设备结构BLK_DEV来存取该设备。在该结构中应该定义一些与该设备相关的变量,如块大小,块数目。还应该定义一个函数列表,里面包括实现本设备read, write, ioctl, reset, check state of device的函数。通常还会定义一些成员来表示设备在文件系统上的特定条件,如磁盘改变等。当driver创建块设备时,设备没有名字或文件系统与其相联。在设备初始化函数中选择文件系统后才会使设备与文件系统相联。块设备的底层driver与字符设备driver不同,它并没有被安装到I/O driver table中,而是由每个文件系统作为一个driver安装到I/O driver table上。应用程序与设备的所有通讯都是先通过I/O系统<-->文件系统<-->设备driver<-->设备。所以driver必须提供设备与VxWorks之间的接口。基本上这些接口都是与硬件相关的,每个设备都有其独特的处理过程,但是提供给VxWorks的接口应该是统一的。 Driver通常需要一个初始化函数,它所执行的操作应该只执行一次。它有一个原则就是初始化函数操作影响整个设备控制器,而其它后继的操作只影响特殊的设备。块设备的通用初始化函数包括: l 初始化硬件。 l 分配和初始化设备数据结构。 l 创建互斥量。(用于多个任务存取) l 初始化中断向量表。 l 开设备中断。 块设备driver必须创建一个逻辑盘或连续的设备,所谓的逻辑盘设备可以仅仅是一个大的物理设备的一部分,设备driver必须可以跟踪任何一个块偏移值或其他可以将逻辑设备与物理设备的实际位置对上的方法。VxWorks文件系统的块序号通常以零开始,一个可以连续存取的设备的块大小通常是可变或多样的。大多数应用程序使用的都是可变的块大小。设备的create函数一般来说都会分配一个设备描述符结构,用于driver对设备的控制,这个结构的第一个成员必须是VxWorks定义的块设备结构(BLK_DEV or SEQ_DEV),因为文件系统在调用设备driver时需要使用这个块设备结构,下面定义的是BLK_DEV 和SEQ_DEV的成员: Table 3-14: Fields in the BLK_DEV Structure Field Value bd_blkRd Address of the driver routine that reads blocks from the device. bd_blkWrt Address of the driver routine that writes blocks to the device. bd_ioctl Address of the driver routine that performs device I/O control. bd_reset Address of the driver routine that resets the device (NULL if none). bd_statusChk Address of the driver routine that checks disk status (NULL if none). bd_removable TRUE if the device is removable (for example, a floppy disk); FALSE otherwise. bd_nBlocks Total number of blocks on the device. bd_bytesPerBlk Number of bytes per block on the device. bd_blksPerTrack Number of blocks per track on the device. bd_nHeads Number of heads (surfaces). bd_retry Number of times to retry failed reads or writes. bd_mode Device mode (write-protect status); generally set to O_RDWR. bd_readyChanged TRUE if the device ready status has changed; initialize to TRUE to cause the disk to be mounted. Table 3-15: Fields in the SEQ_DEV Structure Field Value sd_seqRd Address of the driver routine that reads blocks from the device. sd_seqWrt Address of the driver routine that writes blocks to the device. sd_ioctl Address of the driver routine that performs device I/O control. sd_seqWrtFileMarks Address of the driver routine that writes file marks to the device. sd_rewind Address of the driver routine that rewinds the sequential device. sd_reserve Address of the driver routine that reserves a sequential device. sd_release Address of the driver routine that releases a sequential device. sd_readBlkLim Address of the driver routine that reads the data block limits from the sequential device. sd_load Address of the driver routine that either loads or unloads a sequential device. sd_space Address of the driver routine that moves (spaces) the medium forward or backward to end-of-file or end-of-record markers. sd_erase Address of the driver routine that erases a sequential device. sd_reset Address of the driver routine that resets the device (NULL if none). sd_statusChk Address of the driver routine that checks sequential device status (NULL if none). sd_blkSize Block size of sequential blocks for the device. A block size of 0 means that variable block sizes are used. sd_mode Device mode (write protect status). sd_readyChanged TRUE if the device ready status has changed; initialize to TRUE to cause the sequential device to be mounted. sd_maxVarBlockLimit Maximum block size for a variable block. sd_density Density of sequential access media. l 对于直接存取的块设备的读函数原型是: STATUS xxBlkRd ( DEVICE * pDev, /* pointer to device descriptor */ int startBlk, /* starting block to read */ int numBlks, /* number of blocks to read */ char * pBuf /* pointer to buffer to receive data */ ) pDev是指向块设备描述符的指针。 startBlk是开始读的块的起始位置。 numBlks指需要读的块的数目。 PBuf是存储接收的数据的buffer的指针。 l 对于连续块设备的读原型是: STATUS xxSeqRd ( DEVICE * pDev, /* pointer to device descriptor */ int numBytes, /* number of bytes to read */ char * buffer, /* pointer to buffer to receive data */ BOOL fixed /* TRUE => fixed block size */ ) pDev是指向块设备描述符的指针。 numBytes指需要读的字节的数目。 buffer是存储接收的数据的buffer的指针。 Fixed是指是读函数是从连续设备的可变大小的块读还是从有多种大小的块读。 l 一般来说块设备driver有单独的函数对设备进行复位。它应该只复位指定的块设备而非所有的块设备。 l 一般来说块设备driver还应该有取设备状态的函数,它可以检测出当前设备的状态,这对可热插拔的设备来说很重要,当设备出错或被拔出时,这个函数返回Error,这时文件系统就不会继续往下操作,而当一个新的设备插上时,它设置BLK_DEV中的bd_readyChanged项,然后返回OK,这时open及create函数可以继续操作。新的设备可以自动地加入到系统中。 -------------------------------------------------------------------------------- 编辑 发表於:2002-01-22 - 17:08:01 IP: 211.97.*.* amine 版主 来自: 发表总数:519 查看   短消息   电子邮件 -------------------------------------------------------------------------------- 三. VxWorks中的常见设备的driver分析: VxWorks的最大好处就是提供对很多设备的driver的支持,这也是为什么至今Windows比Linux更受欢迎的一个原因,下面我们对VxWorks提供的常用的设备driver进行分析,以利于大家更清楚地了解VxWorks的工作原理。 Table 3-6: Drivers Provided with VxWorks Module Driver Description TtyDrv Terminal driver PtyDrv Pseudo-terminal driver pipeDrv Pipe driver memDrv Pseudo memory device driver NfsDrv NFS client driver NetDrv Network driver for remote file access ramDrv RAM driver for creating a RAM disk ScsiLib SCSI interface library - Other hardware-specific drivers 1. Serial I/O Devices (Terminal and Pseudo-Terminal Devices) VxWorks提供终端(tty)和伪终端(pty)设备driver, 所谓伪终端也就是终端仿真。伪终端对于应用程序很有用,最常见的如 Remote login facilities. VxWorks的Serial I/O Devices属于含buffer的连续字节流设备,每一个设备有一个输入和输出环形buffer,从一个tty设备读/写数据实际上是从输入/输出环形buffer中读/写数据,每个环行buffer的大小在系统初始化时创建设备确定。 我们可以通过标准的ioctl来对tty设备控制,并可带一些可选项: Table 3-7: Tty Options Library Description OPT_LINE Select line mode. (See Raw Mode and Line Mode.) OPT_ECHO Echo input characters to the output of the same channel. OPT_CRMOD Translate input RETURN characters into NEWLINE (\n); translate output NEWLINE into RETURN-LINEFEED. OPT_TANDEM Respond to X-on/X-off protocol (CTRL+Q and CTRL+S). OPT_7_BIT Strip the most significant bit from all input bytes. OPT_MON_TRAP Enable the special ROM monitor trap character, CTRL+X by default. OPT_ABORT Enable the special target shell abort character, CTRL+C by default. (Only useful if the target shell is configured into the system; see 9. Target Shell in this manual for details.) OPT_TERMINAL Set all of the above option bits. OPT_RAW Set none of the above option bits. Ioctl的常用的命令有: Table 3-9: I/O Control Functions Supported by tyLib Function Description FIOBAUDRATE Set the baud rate to the specified argument. FIOCANCEL Cancel a read or write. FIOFLUSH Discard all bytes in the input and output buffers. FIOGETNAME Get the file name of the fd. FIOGETOPTIONS Return the current device option word. FIONREAD Get the number of unread bytes in the input buffer. FIONWRITE Get the number of bytes in the output buffer. FIOSETOPTIONS Set the device option word. tty设备通常工作在两种模式:raw mode(无缓冲区)或line mode. Raw mode是缺省的模式, Line mode可由上面的OPT_LINE来选择。在raw mode每个输入的字符可以在用户输入时立即生效,一个工作在raw mode的tty设备,除非控制可选项,否则我们无法对正在进行的输入做修改。而对于line mode,所有的输入字符都被保存在缓冲区中直到一个NEWLINE字符被输入,通常我们在输入的过程中可以使用特殊字符(CTRL+字符)来修改输入。在Tornado的shell下的输入就是一个很好的line mode例子。 2. Pipe Devices 管道是利用VxWorks的I/O系统进行任务间通讯的虚拟设备。任务写消息到管道上,这些消息可以由其它任务读出。 我们可以使用pipeDevCreate()函数来创建管道,并给定最大消息数,及每个消息的最大长度。VxWorks的管道被设计成与任务级代码一样的方式允许ISRs写管道,许多VxWorks的代码,包括除了管道外的其他I/O设备都不允许ISRs写 。ISRs通过调用write()函数来写管道,但是一旦管道满了,由于ISRs无法阻塞,消息将被丢弃。管道的ioctl的控制命令有: Table 3-10: I/O Control Functions Supported by pipeDrv Function Description FIOFLUSH Discard all messages in the pipe. FIOGETNAME Get the pipe name of the fd. FIONMSGS Get the number of messages remaining in the pipe. FIONREAD Get the size in bytes of the first message in the pipe. 3. Pseudo Memory Devices 我们说的内存设备其实并不是一个真正的设备,所以我们通常称其为伪内存设备。在VxWorks中通常写为memDev,它允许I/O系统把内存当作一个伪I/O来存取。在设备被创建时内存的位置和大小将被确定,这使VxWorks可以在启动时或CPU之间共享数据时保护数据。MemDrv使用高层的方法通过I/O调用在绝对位置读写数据。 首先使用memDrv()初始化mem设备,再用memDevCreate()创建mem设备。MemDrv的控制命令为: Table 3-11: I/O Control Functions Supported by memDrv Function Description FIOSEEK Set the current byte offset in the file. FIOWHERE Return the current byte position in the file. 4. Network File System (NFS) Devices 网络文件系统设备允许使用NFS协议来存取远程网络文件。NFS协议指明了客户端读远程机器,服务器端输出文件的方法。VxWorks下的NFS driver称为nfsDrv,它作为一个NFS客户端来存取网络上的NFS服务器上的文件。VxWorks也允许你运行一个NFS服务器来输出文件到其他远程机器上。使用NFS设备,你可以创建、打开和存取远程的文件就象你存取本地硬盘上的文件系统一样。它屏蔽了底层的网络系统。存取远程文件系统的方法是使用nfsMount()函数来安装那个文件系统,并为其创建一个I/O设备。NfsMount带三个参数,分别为:NFS server的名字,host file system的名字,file system 的local name. 在远程文件系统安装之后,我们可以象存取本地文件一样存取远程文件。要使用NFS文件系统必须要在BSP内INCLUDE_NFS。NFS client的ioctl的控制命令有: Table 3-12: I/O Control Functions Supported by nfsDrv Function Description FIOFSTATGET Get file status information (directory entry data). FIOGETNAME Get the file name of the fd. FIONREAD Get the number of unread bytes in the file. FIOREADDIR Read the next directory entry. FIOSEEK Set the current byte offset in the file. FIOSYNC Flush data to a remote NFS file. FIOWHERE Return the current byte position in the file. 5。on-NFS Network Devices VxWorks对于无NFS的网络设备提供RSH(Remote Shell Protocol)和FTP(File Transfer Protocol)。它们都使用nfsDrv来实现,当一个远程文件通过RSH或FTP被打开时,整个文件会被拷贝到内存中,所以在使用RSH和FTP打开一个远程文件时要注意文件是否超大而无法被拷贝到本地内存内。一旦文件被拷贝到内存,则read和write只是对本地内存内的文件进行操作。当关闭文件的时候,如果它被改变的话,它会被拷贝回远程机器。 要使用RSH和FTP存取远程主机,必须先使用netDevCreate( )函数创建一个网络设备,并选择是RSH还是FTP。网络设备上的文件可以被创建,打开,处理,就像本地的主机文件一样,但是在该主机内要有足够的存取权限。 由于RSH和FTP的出现使得我们存取网络文件是如此的方便,我们的iPAS等多项目里都使用了FTP的方式来存取远程主机的文件,这再一次证明了屏蔽底层细节在开发较大系统中的优越性。 6. RAM Disk Driver VxWorks的RAM disk是将内存模拟为磁盘,将所有的数据保存在内存中,内存的位置和“磁盘”的大小依赖于用ramDevCreate( )函数所得到的结果,我们可以通过多次运行这个函数来创建多个RAM disk. RAM disk的内存可以预分配并将地址作为参数传给ramDevCreate( )函数,也可由该函数自动分配,该设备被创建后必须使用文件系统初始化或make函数将文件系统和一个名字与该设备相联。例如如果我们要创建一个自动分配200KB内存的RAM disk,512字节的扇区大小,一条磁道,没有扇区偏移。设备的名字命名为”DEV1:”,使用的文件系统是dosFs.则要做的方法是: BLK_DEV *pBlkDev; DOS_VOL_DESC *pVolDesc; pBlkDev = ramDevCreate (0, 512, 400, 400, 0); pVolDesc = dosFsMkfs ("DEV1:", pBlkDev); 如果要使用预分配的内存,则需要: pBlkDev = ramDevCreate (0xc0000, 512, 400, 400, 0); pVolDesc = dosFsDevInit ("DEV1:", pBlkDev, NULL); 7. SCSI Drivers SCSI是一个标准外设接口,它一般被应用在硬盘、光驱、软驱、磁带设备上,SCSI块设备driver与dosFs, rt11Fs库兼容,提供很多target 配置。由于SCSI技术本身比其他设备要复杂,而且在我们的项目中基本上应用不到它,所以我们在这里对它不做详细的分析。



关键词: VxWorks     Device     Driver     机制         

菜鸟
2002-06-28 21:30:00     打赏
2楼
这是这片文章的原稿, 有些图, 格式好看些[upload=zip]uploadImages/200262813304338446.zip[/upload]

共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]