📄 c-iosys9.html
字号:
int xferDirection ) { if (xferDirection == 1) { myDevToBuf (pExampleBuf); cacheInvalidate (DATA_CACHE, pExampleBuf, exampleBufLen); }</a></b><dd> <b><a name="97987"> else { cacheFlush (DATA_CACHE, pExampleBuf, exampleBufLen); myBufToDev (pExampleBuf); } }</a></b></pre></dl><dl class="margin"><dd><p class="Body"><a name="85882"> </a>It is possible to make a driver more efficient by combining cache-safe buffer allocation and cache-entry flushing or invalidation. The idea is to flush or invalidate a cache entry only when absolutely necessary. To address issues of cache coherency for static buffers, use <b class="routine"><i class="routine">cacheDmaMalloc</i></b><b>(</b> <b>)</b>. This routine initializes a <b class="symbol_UC">CACHE_FUNCS </b>structure (defined in <b class="file">cacheLib.h</b>) to point to flush and invalidate routines that can be used to keep the cache coherent. The macros <b class="symbol_UC">CACHE_DMA_FLUSH</b> and <b class="symbol_UC">CACHE_DMA_INVALIDATE</b> use this structure to optimize the calling of the flush and invalidate routines. If the corresponding function pointer in the <b class="symbol_UC">CACHE_FUNCS</b> structure is <b class="symbol_UC">NULL</b>, no unnecessary flush/invalidate routines are called because it is assumed that the buffer is cache coherent (hence it is not necessary to flush/invalidate the cache entry manually). </p><dd><p class="Body"><a name="85886"> </a>Some architectures allow the virtual address to be different from the physical address seen by the device; see <a href="c-vm3.html#84391"><i class="title">7.3 Virtual Memory Configuration</i></a> in this manual. In this situation, the driver code uses a virtual address and the device uses a physical address. Whenever a device is given an address, it must be a physical address. Whenever the driver accesses the memory, it uses the virtual address. The driver translates the address using the following macros: <b class="symbol_UC">CACHE_DMA_PHYS_TO_VIRT</b> (to translate a physical address to a virtual one) and <b class="symbol_UC">CACHE_DMA_VIRT_TO_PHYS</b> (to translate a virtual address to a physical one). </p></dl></dl><h4 class="EntityTitle"><a name="85893"><font face="Helvetica, sans-serif" size="-1" class="sans">Example 3-12: Address-Translation Driver</font></a></h4><dl class="margin"><dl class="margin"><dd><pre class="Code"><b><a name="85894">/* The following code is an example of a driver that performs address * translations. It attempts to allocate a cache-safe buffer, fill it, and * then write it out to the device. It uses CACHE_DMA_FLUSH to make sure * the data is current. The driver then reads in new data and uses * CACHE_DMA_INVALIDATE to guarantee cache coherency. */</a></b><dd> <b><a name="85896">#include "vxWorks.h" #include "cacheLib.h" #include "myExample.h" STATUS myDmaExample (void) { void * pMyBuf; void * pPhysAddr;</a></b><dd> <b><a name="85904"> /* allocate cache safe buffers if possible */</a></b><dd> <b><a name="85905"> if ((pMyBuf = cacheDmaMalloc (MY_BUF_SIZE)) == NULL) return (ERROR); </a></b><dd> <b><a name="85908"> <i class="i"> fill buffer with useful information </i></a></b><dd> <b><a name="85910"> /* flush cache entry before data is written to device */</a></b><dd> <b><a name="85911"> CACHE_DMA_FLUSH (pMyBuf, MY_BUF_SIZE);</a></b><dd> <b><a name="85913"> /* convert virtual address to physical */</a></b><dd> <b><a name="93953"> pPhysAddr = CACHE_DMA_VIRT_TO_PHYS (pMyBuf);</a></b><dd> <b><a name="85916"> /* program device to read data from RAM */</a></b><dd> <b><a name="85917"> myBufToDev (pPhysAddr); <i class="i"> wait for DMA to complete </i> <i class="i"> ready to read new data </i></a></b><dd> <b><a name="85923"> /* program device to write data to RAM */</a></b><dd> <b><a name="85924"> myDevToBuf (pPhysAddr); <i class="i"> wait for transfer to complete </i></a></b><dd> <b><a name="85928"> /* convert physical to virtual address */</a></b><dd> <b><a name="85929"> pMyBuf = CACHE_DMA_PHYS_TO_VIRT (pPhysAddr);</a></b><dd> <b><a name="85931"> /* invalidate buffer */</a></b><dd> <b><a name="85932"> CACHE_DMA_INVALIDATE (pMyBuf, MY_BUF_SIZE); <i class="i"> use data </i></a></b><dd> <b><a name="85936"> /* when done free memory */</a></b><dd> <b><a name="85937"> if (cacheDmaFree (pMyBuf) == ERROR) return (ERROR);</a></b><dd> <b><a name="85940"> return (OK); }</a></b></pre></dl></dl><font face="Helvetica, sans-serif" class="sans"><h4 class="H3"><i><a name="85946">3.9.4 Block Devices</a></i></h4></font><font face="Helvetica, sans-serif" class="sans"><h4 class="H4"><i><a name="85948">General Implementation</a></i></h4></font><dl class="margin"><dl class="margin"><dd><p class="Body"><a name="88292"> </a>In VxWorks, block devices have a slightly different interface than other I/O devices. Rather than interacting directly with the I/O system, block device drivers interact with a file system. The file system, in turn, interacts with the I/O system. Direct access block devices have been supported since SCSI-1 and are used compatibly with dosFs, rt11Fs, and rawFs. In addition, VxWorks supports SCSI-2 sequential devices, which are organized so individual blocks of data are read and written sequentially. When data blocks are written, they are added sequentially at the end of the written medium; that is, data blocks cannot be replaced in the middle of the medium. However, data blocks can be accessed individually for reading throughout the medium. This process of accessing data on a sequential medium differs from that of other block devices. <div class="frame"><h4 class="EntityTitle"><a name="93984"><font face="Helvetica, sans-serif" size="-1" class="sans">Figure 3-8: Non-Block Devices vs. Block Devices</font></a></h4><dl class="margin"><div class="Anchor"><a name="94027"> </a><img class="figure" border="0" src="images/c-iosysa1.gif"></div></dl></div></p><dd><p class="Body"><a name="85950"> </a><a href="c-iosys9.html#93984">Figure 3-8</a> shows a layered model of I/O for both block and non-block (character) devices. This layered arrangement allows the same block device driver to be used with different file systems, and reduces the number of I/O functions that must be supported in the driver. </p><dd><p class="Body"><a name="86003"> </a>A device driver for a block device must provide a means for creating a logical block device structure, a <b class="symbol_UC">BLK_DEV</b> for direct access block devices or a <b class="symbol_UC">SEQ_DEV</b> for sequential block devices. The <b class="symbol_UC">BLK_DEV</b>/<b class="symbol_UC">SEQ_DEV</b> structure describes the device in a generic fashion, specifying only those common characteristics that must be known to a file system being used with the device. Fields within the structures specify various physical configuration variables for the device--for example, block size, or total number of blocks. Other fields in the structures specify routines within the device driver that are to be used for manipulating the device (reading blocks, writing blocks, doing I/O control functions, resetting the device, and checking device status). The <b class="symbol_UC">BLK_DEV</b>/<b class="symbol_UC">SEQ_DEV</b> structures also contain fields used by the driver to indicate certain conditions (for example, a disk change) to the file system.</p><dd><p class="Body"><a name="86005"> </a>When the driver creates the block device, the device has no name or file system associated with it. These are assigned during the device initialization routine for the chosen file system (for example, <b class="routine"><i class="routine">dosFsDevInit</i></b><b>(</b> <b>)</b>, <b class="routine"><i class="routine">rt11FsDevInit</i></b><b>(</b> <b>) </b>or <b class="routine"><i class="routine">tapeFsDevInit</i></b><b>(</b> <b>)</b>).</p><dd><p class="Body"><a name="86006"> </a>The low-level device driver for a block device is not installed in the I/O system driver table, unlike non-block device drivers. Instead, each file system in the VxWorks system is installed in the driver table as a "driver." Each file system has only one entry in the table, even though several different low-level device drivers can have devices served by that file system.</p><dd><p class="Body"><a name="89201"> </a>After a device is initialized for use with a particular file system, all I/O operations for the device are routed through that file system. To perform specific device operations, the file system in turn calls the routines in the specified <b class="symbol_UC">BLK_DEV</b> or <b class="symbol_UC">SEQ_DEV</b> structure.</p><dd><p class="Body"><a name="86008"> </a>A driver for a block device must provide the interface between the device and VxWorks. There is a specific set of functions required by VxWorks; individual devices vary based on what additional functions must be provided. The user manual for the device being used, as well as any other drivers for the device, is invaluable in creating the VxWorks driver. The following sections describe the components necessary to build low-level block device drivers that adhere to the standard interface for VxWorks file systems.</p></dl></dl><font face="Helvetica, sans-serif" class="sans"><h4 class="H4"><i><a name="86009">Low-Level Driver Initialization Routine</a></i></h4></font><dl class="margin"><dl class="margin"><dd><p class="Body"><a name="86010"> </a>The driver normally requires a general initialization routine. This routine performs all operations that are done one time only, as opposed to operations that must be performed for each device served by the driver. As a general guideline, the operations in the initialization routine affect the whole device controller, while later operations affect only specific devices.</p><dd><p class="Body"><a name="86011"> </a>Common operations in block device driver initialization routines include:</p></dl><dl class="margin"><ul class="DashSingle" type="circle"><li><a name="86012"> </a>initializing hardware </li></ul><ul class="DashSingle" type="circle"><li><a name="86013"> </a>allocating and initializing data structures</li></ul><ul class="DashSingle" type="circle"><li><a name="86014"> </a>creating semaphores </li></ul><ul class="DashSingle" type="circle"><li><a name="86015"> </a>initializing interrupt vectors </li></ul><ul class="DashSingle" type="circle"><li><a name="86016"> </a>enabling interrupts </li></ul></dl><dl class="margin"><dd><p class="Body"><a name="86017"> </a>The operations performed in the initialization routine are entirely specific to the device (controller) being used; VxWorks has no requirements for a driver initialization routine.</p><dd><p class="Body"><a name="86018"> </a>Unlike non-block device drivers, the driver initialization routine does not call <b class="routine"><i class="routine">iosDrvInstall</i></b><b>(</b> <b>)</b> to install the driver in the I/O system driver table. Instead, the file system installs itself as a "driver" and routes calls to the actual driver using the routine addresses placed in the block device structure, <b class="symbol_UC">BLK_DEV</b> or <b class="symbol_UC">SEQ_DEV</b> (see <a href="c-iosys9.html#86023"><i class="title">Device Creation Routine</i></a>).</p></dl></dl><font face="Helvetica, sans-serif" class="sans"><h4 class="H4"><i><a name="86023">Device Creation Routine</a></i></h4></font><dl class="margin"><dl class="margin"><dd><p class="Body"><a name="86024"> </a>The driver must provide a routine to create (define) a logical disk or sequential device. A logical disk device may be only a portion of a larger physical device. If this is the case, the device driver must keep track of any block offset values or other means of identifying the physical area corresponding to the logical device. VxWorks file systems always use block numbers beginning with zero for the start of a device. A sequential access device can be either of variable block size or fixed block size. Most applications use devices of fixed block size.</p><dd><p class="Body"><a name="86025"> </a>The device creation routine generally allocates a device descriptor structure that the driver uses to manage the device. The first item in this device descriptor must be a VxWorks block device structure (<b class="symbol_UC">BLK_DEV </b>or<b class="symbol_UC"> SEQ_DEV</b>). It must appear first because its address is passed by the file system during calls to the driver; having the <b class="symbol_UC">BLK_DEV</b> or <b class="symbol_UC">SEQ_DEV</b> as the first item permits also using this address to identify the device descriptor.</p><dd><p class="Body"><a name="88416"> </a>The device creation routine must initialize the fields within the <b class="symbol_UC">BLK_DEV </b>or<b class="symbol_UC"> SEQ_DEV </b>structure. The <b class="symbol_UC">BLK_DEV</b> fields and their initialization values are shown in <a href="c-iosys9.html#88424">Table 3-14</a>. The <b class="symbol_UC">SEQ_DEV</b> fields and their initialization values are shown in <a href="c-iosys9.html#88495">Table 3-15</a>. <p class="table"><h4 class="EntityTitle"><a name="88424"><font face="Helvetica, sans-serif" size="-1" class="sans">Table 3-14: Fields in the BLK_DEV Structure</font></a></h4><table border="0" cellpadding="0" cellspacing="0"><tr><td colspan="20"><hr class="tablerule"></td></tr><tr valign="middle"><th rowspan="1" colspan="1"><div class="CellHeading"><b><a name="88428"> </a><font face="Helvetica, sans-serif" size="-1" class="sans">Field</font></b></div></th><th rowspan="1" colspan="1"><div class="CellHeading"><b><a name="88430"> </a><font face="Helvetica, sans-serif" size="-1" class="sans">Value</font></b></div></th></tr><tr><td colspan="20"><hr class="tablerule2"></td></tr><tr valign="top"><td colspan=1 rowspan=1><div class="CellBody"><a name="88432"> </a><b class="symbol_lc">bd_blkRd</b> </div></td><td colspan=1 rowspan=1><div class="CellBody"><a name="88434"> </a>Address of the driver routine that reads blocks from the device. </div></td></tr><tr valign="top"><td colspan=1 rowspan=1><div class="CellBody"><a name="88436"> </a><b class="symbol_lc">bd_blkWrt</b> </div></td><td colspan=1 rowspan=1><div class="CellBody"><a name="88438"> </a>Address of the driver routine that writes blocks to the device. </div></td></tr>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -