[Return to Library] [Contents] [Previous Chapter] [Next Section] [Next Chapter] [Index] [Help]


7    EISA Bus Device Driver Example

This chapter provides you with an opportunity to study an EISA bus device driver called /dev/envram. You can use the /dev/envram device driver as the basis for writing your own working EISA bus device drivers.

Note

The /dev/envram device driver does not operate on the ISA bus.

The /dev/envram device driver operates on an EISA bus and implements many of the device driver interfaces discussed in Chapter 3. It also implements other sections that the EISA bus nonvolatile random-access memory (NVRAM) expansion board needs. The chapter begins with an overview of the tasks performed by the /dev/envram device driver. Following this overview are sections that describe each piece of the /dev/envram device driver. Table 7-1 lists the parts of the /dev/envram device driver and the sections of the chapter where each is described.

Table 7-1: Parts of the /dev/envram Device Driver

Part Section
The envram_reg.h Header File Section 7.2
The envram_data.c File Section 7.3
Include Files Section Section 7.4
Declarations Section Section 7.5
Autoconfiguration Support Section Section 7.6
Status Section Section 7.7
Battery Status Section Section 7.8
Read and Write Device Section Section 7.9
Zero NVRAM Section Section 7.10

The source code uses the following convention:

#define ENVRAM_MAPPED 1 [1]

  1. Numbers appear after some line or lines of code in the /dev/envram device driver example. Following the example, a corresponding number appears that contains an explanation for the associated line or lines. The source code does not contain any inline comments. If you prefer to read the /dev/envram driver source code in its entirety with the inline comments, see Appendix C. [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Next Section] [Next Chapter] [Index] [Help]


7.1    Overview of the /dev/envram Device Driver

The /dev/envram device driver is a character device driver that provides read and write services to the /dev/presto device driver. The /dev/presto device driver is a disk driver that uses nonvolatile memory as a cache. It works as a layer between other drivers and the rest of the Digital UNIX kernel.

The /dev/presto device driver's interfaces appear as the entry points in the cdevsw and bdevsw switch tables, instead of the interfaces of the other drivers (including the /dev/envram driver) it works with. Whenever /dev/presto needs to perform actual I/O operations (for example, when the cache needs filling or draining), it calls the layered driver's entry points (strategy, close, read, and write).

Figure 7-1 shows the relationship between the /dev/envram and /dev/presto device drivers. The figure shows the following flow of data between the different layers:

  1. The file system makes a read or write request.

  2. The /dev/presto device driver interprets the request as an actual I/O operation. It calls the /dev/envram device driver.

  3. The /dev/envram device driver performs the actual work of reading data from and writing data to the EISA bus NVRAM expansion board. In addition to providing services to the /dev/presto driver, the /dev/envram device driver also:

Figure 7-1: Relationship of the /dev/envram and /dev/presto Device Drivers


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


7.2    The envram_reg.h Header File

The following envram_reg.h file is the device register header file for the /dev/envram device driver. It contains public declarations and the definitions that map to the device registers for the EISA bus NVRAM expansion board.

#define ENVRAM_CSR 0xc00 [1] #define ENVRAM_BAT 0xc04 #define ENVRAM_HIBASE 0xc08 #define ENVRAM_CONFIG 0xc0c #define ENVRAM_ID 0xc80 #define ENVRAM_CTRL 0xc84 #define ENVRAM_DMA0 0xc88 #define ENVRAM_DMA1 0xc8c
 
#define ENVRAM_DIAG_REGISTER 0x3f8 [2] #define BOARD_FAILED 0x00000008 #define ENVRAM_DIAG_RESVED 0x400 #define ENVRAM_CACHE_OFFSET 0x400
 
#define SET_LED 0x0100 [3] #define BAT_FAIL 0x0800 #define WRMEM 0x2000 #define SET_DREQ 0x4000 #define DMA_CHAN_7 0X80 #define DMA_CHAN_5 0x40
 
#define BAT_DISCON_BIT 0x0080 [4]
 
#define EISA_ENABLE_BOARD 0x1 [5]
 
#define ENVRAM_ID_MASK 0x0025a310 [6]
 
#define ENVRAM_MAPPED 1 [7] #define ENVRAM_NOTMAPPED 0 #define ENVRAM_CACHED 1 #define ENVRAM_NOTCACHED 0
 
#define ENVRAM_XFER_SIZE 1024 [8] #define ENVRAM_ALLIGN 8192 [9]

  1. This #define, and the seven that follow, map to the device registers of the EISA bus NVRAM expansion board. The following list describes each device register definition:

    [Return to example]

  2. This #define, and the three that follow, map to the EISA NVRAM software diagnostic registers. The following list describes each EISA NVRAM software diagnostic register definition:

    [Return to example]

  3. This #define, and those that follow, are bit masks for the EISA bus NVRAM expansion board's CSR (the ENVRAM_CSR device register offset). The following list describes each bit mask:

    [Return to example]

  4. Defines a bit mask called BAT_DISCON_BIT for the EISA bus NVRAM expansion board's battery disconnect device register (the ENVRAM_BAT device register offset). Section 7.8.2 and Section 7.8.3 show how the eisa_nvram_battery_enable and eisa_nvram_battery_disable interfaces use the BAT_DISCON_BIT bit mask. [Return to example]

  5. Defines a bit mask called EISA_ENABLE_BOARD for the EISA bus NVRAM expansion board's controller device register (the ENVRAM_CTRL device register offset). This bit mask makes memory on the EISA bus NVRAM expansion board available. Section 7.6.1 shows how the envram_probe interface uses this bit mask. [Return to example]

  6. Defines a bit mask called ENVRAM_ID_MASK for the EISA bus NVRAM expansion board's ID device register (the ENVRAM_ID device register offset). Section 7.6.1 shows that the envram_probe interface uses the ENVRAM_ID_MASK bit mask to check the hardware ID in the EISA bus NVRAM expansion board's ID device register. [Return to example]

  7. This #define, and those that follow, communicate with the /dev/presto device driver. The following list describes each definition:

    [Return to example]

  8. Defines a constant called ENVRAM_XFER_SIZE to indicate the maximum DMA transfer size to the NVRAM module. Section 7.6.2 and Section 7.9.2 show how the envram_attach and envram_write interfaces use ENVRAM_XFER_SIZE. [Return to example]

  9. Defines a constant called ENVRAM_ALLIGN to indicate the DMA alignment requirement. Section 7.9.2 shows how the envram_write interface uses ENVRAM_ALLIGN. [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


7.3    The envram_data.c File

The following /usr/sys/data/envram_data.c file is the name_data.c file for the /dev/envram device driver. It contains the softc structure, which is used to share data between the different /dev/envram device driver interfaces.

struct	envram_softc {
 io_handle_t regbase;
 io_handle_t cache_phys_start;
 io_handle_t cache_base;
 vm_offset_t cache_kseg_start;
 u_long saved_mem_sysmap;
 u_int cache_size;
 u_int cache_offset;
 io_handle_t diag_status;
 dma_handle_t sglp;
 struct controller *ctlr;
}; [1]

 
struct envram_softc *envram_softc; [2] struct controller *envram_info[NENVRAM]; [3]

  1. Defines the data structure for the /dev/envram device driver and calls it envram_softc. Most of the sections of the /dev/envram device driver declare a pointer to the envram_softc structure.

    The following list describes the members contained in this structure:

    [Return to example]

  2. Declares a pointer to the envram_softc data structure. [Return to example]

  3. Declares a pointer to an array of controller structures. The compile time variable is used as an index into the array. If the compile time variable NENVRAM is greater than zero (0), declares pointers to arrays of controller structures. Thus, there is one controller structure for each EISA bus NVRAM expansion board. The /dev/envram driver does not currently support this. [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


7.4    Include Files Section

The following code shows the Include Files Section for the /dev/envram device driver:

#include "envram.h" [1]

#include <vm/vm_kern.h> #include <sys/presto.h> [2] #include <io/common/devdriver.h> #include <io/dec/eisa/eisa.h> [3] #include <data/envram_data.c> [4] #include <machine/rpb.h> #include <io/dec/eisa/envram_reg.h> [5]

  1. Includes the envram.h file, which is generated by the config program and contains #define statements for the number of EISA bus devices on the system. This file is also included in /usr/sys/io/common/conf.c, which is where you define the entry points for the driver. However, the entry points for the /dev/envram driver are not defined in /usr/sys/io/common/conf.c because its entry points are called by the /dev/presto device driver. It is the /dev/presto device driver's entry points that are defined in /usr/sys/io/common/conf.c.

    Section 7.6.2 shows how the /dev/envram driver initializes a data structure with the names of its entry points so that the /dev/presto driver can call them.

    [Return to example]

  2. Includes the <sys/presto.h> file, which contains the definitions and structure definitions for the /dev/presto device driver. Section 7.6.2 shows how the /dev/envram driver initializes the presto_interface0 data structure with its entry points. [Return to example]

  3. Includes the /usr/sys/include/io/dec/eisa/eisa.h file, which contains data structures that EISA bus device drivers and the bus configuration code reference. For a summary description of this header file, see Section A.1.

    Writing Device Drivers: Reference provides reference page descriptions of the header files that Digital UNIX device drivers most commonly use. [Return to example]

  4. Includes the name_data.c file for the /dev/envram device driver. The envram_data.c file contains the softc structure that the /dev/envram device driver uses. Section 7.3 describes the members of the softc structure. [Return to example]

  5. Includes the device register header file for the /dev/envram driver. It contains public declarations and #define statements that the /dev/envram device driver uses. The following lists some of the categories of information contained in this file:

    Section 7.2 describes the contents of the envram_reg.h device register header file. [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


7.5    Declarations Section

The following code shows the Declarations Section for the /dev/envram device driver:


 
#define ENVRAM_READIO_D8(a) \ read_io_port((io_handle_t)sc->regbase | a, 1, 0)) [1] #define ENVRAM_READIO_D16(a) \ read_io_port((io_handle_t)sc->regbase | a, 2, 0)) #define ENVRAM_READIO_D32(a) \ read_io_port((io_handle_t)sc->regbase | a, 4, 0))
 
#define ENVRAM_WRITEIO_D8(a,d) \ write_io_port((io_handle_t)sc->regbase | a, 1, 0, d)) [2] #define ENVRAM_WRITEIO_D16(a,d) \ write_io_port((io_handle_t)sc->regbase | a, 2, 0, d)) #define ENVRAM_WRITEIO_D32(a,d) \ write_io_port((io_handle_t)sc->regbase | a, 4, 0, d))
 
int envram_probe(), envram_attach(), eisa_nvram_status(); int eisa_nvram_battery_enable(), eisa_nvram_battery_disable(); void envram_read(), envram_write(), envram_zero(); [3]

struct driver envramdriver = { envram_probe, 0, envram_attach, 0, 0, 0, 0, 0, "envram", envram_info, 0, 0, 0, 0, 0, 0, 0 }; [4]
 

  1. Constructs the ENVRAM_READIO_D8, ENVRAM_READIO_D16, and ENVRAM_READIO_D32 interfaces from the read_io_port interface. These are convenience interfaces that call read_io_port, which is a generic interface that maps to a bus- and machine-specific interface that actually performs the task of reading the byte, word, longword, or quadword from a device register. Use of these interfaces to read data from a device register makes the device driver more portable across different buses, different CPU architectures, and different CPU types within the same architecture.

    The read_io_port interface takes three arguments:

    [Return to example]

  2. Constructs the ENVRAM_WRITEIO_D8, ENVRAM_WRITEIO_D16, and ENVRAM_WRITEIO_D32 interfaces from the write_io_port interface. These are convenience interfaces that call write_io_port, which is a generic interface that maps to a bus- and machine-specific interface that actually performs the task of writing the byte, word, longword, or quadword to a device register. Use of these interfaces to write data to a device register makes the device driver more portable across different bus architectures, different CPU architectures, and different CPU types within the same CPU architecture.

    The write_io_port interface takes four arguments:

    [Return to example]

  3. Are the forward declarations of the entry points for the /dev/envram device driver. [Return to example]

  4. The driver structure for the /dev/envram driver is called envramdriver. The value zero (0) indicates that the /dev/envram driver does not make use of a specific member of the driver structure. The following list describes those members initialized to a nonzero value:

    [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


7.6    Autoconfiguration Support Section

Table 7-2 lists the three interfaces implemented as part of the Autoconfiguration Support Section for the /dev/envram device driver along with the sections in the book where each is described.

Table 7-2: Autoconfiguration Support Section

Interface Section
Implementing the envram_probe Interface Section 7.6.1
Implementing the envram_attach Interface Section 7.6.2
Implementing the envram_ssn Interface Section 7.6.3


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


7.6.1    Implementing the envram_probe Interface

The envram_probe interface is called by the EISA bus configuration code at system boot time and performs the following tasks:

The envram_probe interface has the following implicit input:


.
.
.

ctlr->physaddr

.
.
.

The physaddr member stores the controller's base register physical address.

The following code implements envram_probe:

envram_probe(bus_io_handle, ctlr)
 io_handle_t bus_io_handle; [1]
 struct controller *ctlr; [2]

 
{ register struct envram_softc *sc; [3] u_int hw_id = 0; [4] struct bus_mem mem; [5] struct dma dma_p; [6] u_long eisa_addr_mask = 0xffffffff; [7]
 
if (ctlr->ctlr_num > 0) return(0); [8]
 
sc = (struct envram_softc *)kalloc(sizeof(struct envram_softc)); [9]
 
if (!sc) [10] return(0); bzero((char *)sc, sizeof(struct envram_softc)); [11] envram_softc = sc; [12]
 
sc->ctlr = ctlr; [13]
 
sc->regbase = bus_io_handle; [14]
 
hw_id = ENVRAM_READIO_D32(ENVRAM_ID); [15]
 
if (hw_id != ENVRAM_ID_MASK) [16] { printf("envram_probe: Failed to read ID register\n");
 
kfree(sc, sizeof(struct envram_softc)); return(0); } else printf("envram_probe: EISA NVRAM present\n");
 
sc->cache_offset = ENVRAM_CACHE_OFFSET; [17]
 
if (get_config(ctlr, RES_MEM, , &mem, 0)) { [18] printf("envram probe error\n"); return(0); } sc->cache_size = mem.size; [19] sc->cache_base = (u_long)mem.start_addr; sc->cache_phys_start = (u_long)(sc->cache_base + sc->cache_offset); sc->cache_kseg_start = (vm_offset_t) (PHYS_TO_KSEG(sc->cache_phys_start&eisa_addr_mask)); sc->saved_mem_sysmap = sc->cache_phys_start & ~eisa_addr_mask;
 
sc->cache_size = sc->cache_size - EISA_DIAG_RESVED; [20]
 
if (get_config(ctlr, EISA_DMA, , &dma_p, 0)) { [21] printf("envram probe error dma channel\n"); return(0); }
 
if (dma_p.channel != 7 && dma_p.channel != 5) { [22] printf("envram: invalid dma channel %d\n",dma_p.channel); return(0); }
 
ENVRAM_WRITEIO_D8(ENVRAM_CTRL, EISA_ENABLE_BOARD); [23] mb(); [24]
 
ENVRAM_WRITEIO_D16(ENVRAM_CSR,WRMEM); [25] mb(); [26]
 
envram_read(sc->cache_phys_start-8, &sc->diag_status, 4); [27]
 
if (sc->diag_status & BOARD_FAILED) { [28] printf("Envram diag reg 0x%x\n",sc->diag_status); sc->diag_status = 0; } else { sc->diag_status = 1; } return(1); [29] }

  1. Specifies an I/O handle that you can use to reference a device register located in the EISA/ISA bus address space. This I/O handle is for the base of the device's slot-specific I/O address space. The EISA bus configuration code passes this I/O handle to the driver's xxprobe interface during device autoconfiguration. You can perform standard C mathematical operations on the I/O handle. For example, you can add an offset to or subtract an offset from the I/O handle. [Return to example]

  2. Is a pointer to the controller structure associated with the controller for this EISA bus NVRAM expansion board. The EISA bus configuration code makes the values stored in several members of the ctlr pointer available to the /dev/envram device driver. These members include addr, physaddr, and conn_priv. [Return to example]

  3. Declares a pointer to an envram_softc data structure and calls it sc. The envram_softc data structure allows the /dev/envram device driver's associated interfaces to share data. This data structure is defined in the /usr/sys/data/envram_data.c file. Section 7.3 describes the contents of this file, including the members of envram_softc. [Return to example]

  4. Initializes hw_id to the value zero (0) and later stores it in the EISA bus NVRAM expansion board's ID device register. This ID device register is defined in Section 7.2 as ENVRAM_ID. [Return to example]

  5. Declares a bus_mem data structure and calls it mem. The bus_mem structure describes memory characteristics for an EISA bus expansion board. The bus configuration code initializes the members of the bus_mem structure during device autoconfiguration. Device drivers call the get_config interface to obtain information stored in the members of the bus_mem data structure. [Return to example]

  6. Declares a dma data structure and calls it dma_p. The DMA channel information is encapsulated in the dma structure. Each member of this structure describes information related to the DMA channel. The envram_probe interface passes the address of this structure to the get_config interface. Section A.3 describes the members of the dma structure. [Return to example]

  7. Declares and initializes a variable to store the EISA bus address mask. It performs bit operations by using this address mask bit to determine the values stored in the cache_kseg_start and saved_mem_sysmap members. [Return to example]

  8. Determines if the controller number for the controller associated with this EISA bus NVRAM expansion board is greater than zero (0). If so, envram_probe returns the value zero (0) to the bus configuration code. This indicates that envram_probe could not complete the probe operation because there is support for only one EISA bus NVRAM expansion board. Changes must be made to the /dev/presto device driver interface before multiple units (memory boards) can be supported. [Return to example]

  9. Allocates memory for the envram_softc data structure by calling the kalloc interface.

    If kalloc successfully allocates the memory for the envram_softc structure, it returns the address of the allocated memory. The sc pointer now points to this memory. Otherwise, kalloc returns the value zero (0). [Return to example]

  10. If the memory test fails, the kernel did not allocate the memory and the probe operation exits. [Return to example]

  11. Calls the bzero interface to zero the number of bytes associated with the previously allocated envram_softc structure.

    The bzero interface takes two arguments:

    [Return to example]

  12. Sets the envram_softc structure for this EISA bus NVRAM expansion board to the pointer to the allocated memory. [Return to example]

  13. Sets the ctlr member of the sc pointer to the ctlr pointer associated with this EISA bus NVRAM expansion board. This assignment allows the /dev/envram driver to access the members of this controller structure through the softc structure associated with this EISA bus NVRAM expansion board. [Return to example]

  14. Stores the I/O handle passed in by the bus configuration code in the regbase member of the sc pointer. Section 7.3 shows how the /dev/envram driver uses regbase to construct the read and write interfaces used to read data from and write data to the device registers. [Return to example]

  15. Calls the ENVRAM_READIO_D32 interface to read the ID device register for the EISA bus NVRAM expansion board. In this call, envram_probe passes ENVRAM_ID, which represents the offset to the ID device register. The ENVRAM_READIO_D32 interface returns the requested data, which in this call is a 32-bit value that identifies a valid ID device register.

    Section 7.3 shows how the /dev/envram driver uses read_io_port to construct ENVRAM_READIO_D32. [Return to example]

  16. Checks the value returned by ENVRAM_READIO_D32 to determine if there is a valid ID device register for this EISA bus NVRAM expansion board. If the ID device register is not valid, envram_probe calls printf to display an appropriate error message on the console terminal. It deallocates the EISA bus NVRAM expansion board's envram_softc structure by calling kfree.

    The envram_probe interface returns the value zero (0) to the bus configuration code to indicate an error and that the probe operation failed.

    If the ID device register is valid, envram_probe calls printf to display a message on the console terminal. [Return to example]

  17. Initializes the cache_offset member of the envram_softc structure associated with this EISA bus NVRAM expansion board. Section 7.2 shows that the ENVRAM_CACHE_OFFSET device register is defined in the envram_reg.h file. [Return to example]

  18. Calls get_config to obtain memory-related configuration data associated with the EISA bus NVRAM expansion board. If get_config cannot obtain the requested memory-related information, it prints an appropriate error message on the console terminal and returns the value zero (0) to the bus configuration code that indicates the driver's probe failed. Otherwise, it initializes the cache_size, cache_base, cache_phys_start, cache_kseg_start, and saved_mem_sysmap members of the envram_softc structure associated with this EISA bus NVRAM expansion board.

    The get_config interface takes five arguments:

    [Return to example]

  19. Initializes the bus memory-related members of the sc pointer to the values returned by get_config to the bus_mem structure. It also initializes several other members.

    The following list describes the initialized members:

    [Return to example]

  20. Stores the amount of space the software diagnostics require and assures 2K-bytes of alignment for DMA operations. [Return to example]

  21. Calls get_config to obtain DMA channel-related configuration data associated with the EISA bus NVRAM expansion board. If get_config cannot obtain the requested DMA channel-related information, it prints an appropriate error message on the console terminal and returns the value zero (0) to the bus configuration code that indicates the driver's probe failed. Otherwise, it performs checks on the channel member of the dma structure.

    The envram_probe interface passes the same values to the first, third, and fifth arguments as it passed in the previous call to get_config. To request DMA channel-related information, envram_probe passes the constant RES_DMA to the second argument. The envram_probe interface passes the address of the dma data structure called dma_p0 to the fourth argument so that get_config can store in it the DMA channel-related information. [Return to example]

  22. Specifies the DMA channel number or numbers that this EISA/ISA bus device can use. The EISA/ISA bus configuration code sets the channel number to a number in the range of 0-7. In this case, if channel is any value except for 5 and 7, then envram_probe displays an appropriate error message on the console terminal and returns the value zero (0) to the bus configuration code to indicate the probe failed. [Return to example]

  23. Enables the EISA bus NVRAM expansion board by calling ENVRAM_WRITEIO_D8. The ENVRAM_WRITEIO_D8 interface writes a byte (8 bits) to a device register located in the bus adddress space. Section 7.5 shows how the /dev/envram driver constructs ENVRAM_WRITEIO_D8 by using the write_io_port interface.

    The ENVRAM_WRITEIO_D8 interface takes two arguments:

    [Return to example]

  24. Calls mb after the write to perform a memory barrier. [Return to example]

  25. Enables the EISA bus NVRAM expansion board for writing by calling ENVRAM_WRITEIO_D16. The ENVRAM_WRITEIO_D16 interface writes a word (16 bits) to a device register located in the bus adddress space. Section 7.5 shows how the /dev/envram driver constructs ENVRAM_WRITEIO_D16 by using the write_io_port interface.

    The ENVRAM_WRITEIO_D16 interface takes two arguments:

    [Return to example]

  26. Calls mb after the write to perform a memory barrier. [Return to example]

  27. To check the console diagnostic results, calls the envram_read interface. Section 7.9.1 describes envram_read. [Return to example]

  28. If the BOARD_FAILED bit is set, then the software diagnostic tests failed and envram_probe prints an appropriate error message on the console terminal. It also sets the diag_status member of the sc pointer to the value zero (0) to indicate that the EISA bus NVRAM expansion board did not pass the software diagnostic tests. Otherwise, envram_probe sets the diag_status member to the value 1 to indicate that the EISA bus NVRAM expansion board passed the software diagnostic tests. [Return to example]

  29. Returns the value 1 to the bus configuration code to indicate that the driver's probe operation is successful. [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


7.6.2    Implementing the envram_attach Interface

The envram_attach interface is called by the EISA bus configuration code at system boot time and performs the following tasks:

The envram_attach interface has the following implicit input:


.
.
.

ctlr->physaddr

.
.
.

The physaddr member stores the controller's base register physical address.

The following code implements envram_attach:


 
envram_attach(ctlr) struct controller *ctlr; [1] {
 
register struct envram_softc *sc = envram_softc; [2]
 
if (dma_map_alloc(ENVRAM_XFER_SIZE, sc->ctlr, &sc->sglp, 0) == 0) [3] panic("envram: dma_map_alloc error\n");
 
presto_interface0.nvram_status = eisa_nvram_status; [4] presto_interface0.nvram_battery_status= eisa_nvram_battery_status; presto_interface0.nvram_battery_disable= eisa_nvram_battery_disable; presto_interface0.nvram_battery_enable= eisa_nvram_battery_enable;


 
presto_interface0.nvram_ioreg_read = envram_read; [5] presto_interface0.nvram_ioreg_write = envram_write; presto_interface0.nvram_block_read = envram_read; presto_interface0.nvram_block_write = envram_write; presto_interface0.nvram_ioreg_zero = envram_zero; presto_interface0.nvram_block_zero = envram_zero;
 
presto_interface0.nvram_min_ioreg = sizeof(int); [6] presto_interface0.nvram_ioreg_align = sizeof(int); presto_interface0.nvram_min_block = PRFSIZE; presto_interface0.nvram_block_align = PRFSIZE;
 
presto_init(sc->cache_kseg_start, sc->cache_size, ENVRAM_NOTMAPPED, ENVRAM_CACHED, envram_ssn()); [7] }

  1. Is a pointer to the controller structure associated with the controller for this EISA bus NVRAM expansion board. The EISA bus configuration code makes the values stored in several members of the ctlr pointer available to the /dev/envram device driver. These members include addr, physaddr, and conn_priv. [Return to example]

  2. Declares a pointer to an envram_softc data structure and calls it sc. The envram_softc data structure allows the /dev/envram device driver's associated interfaces to share data. This data structure is defined in the /usr/sys/data/envram_data.c file. Section 7.3 describes the contents of this file, including the members of envram_softc. [Return to example]

  3. Attempts to allocate resources for DMA data transfers by calling dma_map_alloc. The dma_map_alloc interface is a generic interface that maps to a bus- and machine-specific interface that actually performs the allocation of system resources associated with DMA data transfers. Using this interface in DMA read and write operations makes the device driver more portable across different bus and CPU architectures. If dma_map_alloc cannot allocate the resources, envram_attach calls panic to cause a system crash.

    The dma_map_alloc interface takes four arguments:

    [Return to example]

  4. Initializes the members of the presto_interface0 structure to the device driver interfaces that allow the /dev/presto device access to the NVRAM data cache. As the code shows, these interfaces are eisa_nvram_status, eisa_nvram_battery_status, eisa_nvram_battery_disable, and eisa_nvram_battery_enable. Section 7.7, Section 7.8.1, Section 7.8.2, and Section 7.8.3 discuss these interfaces.

    The /usr/sys/include/sys/presto.h file defines a data structure called presto_interface. It also declares an instance of this structure called presto_interface0. This file provides additional information on the members of the presto_interface structure. [Return to example]

  5. Initializes the members of the presto_interface0 structure to the device driver interfaces that allow the /dev/presto device access to the EISA bus NVRAM expansion board. As the code shows, these interfaces are envram_read, envram_write, and envram_zero. Section 7.9.1, Section 7.9.2, and Section 7.10 discuss these interfaces. See the /usr/sys/include/sys/presto.h file for more information on these members of the presto_interface structure. [Return to example]

  6. In the next four lines, sets the minimum size of a small and large I/O device register data block. It also sets the byte alignment restriction for an I/O device register block. The PRFSIZE constant is defined in /usr/sys/include/sys/presto.h as the largest buffer size (in bytes) that the /dev/presto driver handles. See the /usr/sys/include/sys/presto.h file for more information on these members of the presto_interface structure. [Return to example]

  7. Calls presto_init to perform initialization tasks for the /dev/presto driver.

    The presto_init interface takes five arguments:

    [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


7.6.3    Implementing the envram_ssn Interface

The envram_attach interface passes envram_ssn as an argument to presto_init. The presto_init interface calls envram_ssn to obtain the machine (CPU) ID.

The envram_ssn interface performs the following tasks:

The envram_ssn interface returns the machine (CPU) ID located in the HWRPB.

The following code implements envram_ssn:

envram_ssn()
{
  extern struct rpb *rpb; [1]

 
u_int ssn = 0; [2] int i; char *cp;

cp = rpb->rpb_ssn + 9; [3]

if (*cp == '\0') { [4] cp = "NO System Serial Number"+8; printf("envram_ssn: %s\n",cp-8); } for (i = 0 ; i < 8 ; i++, cp--){ [5] if (*cp < '9') ssn += (*cp - '0' ) << (i*4); else if (*cp < 'G') ssn += (*cp - 'A' + 0xa ) << (i*4); else if (*cp < 'a') ssn += ( *cp % 0xf ) << (i*4); else if (*cp < 'g') ssn += (*cp - 'a' + 0xa ) << (i*4); else ssn += ( *cp % 0xf ) << (i*4); } return(ssn); [6] }

  1. Declares a pointer to an rpb (restart parameter block) data structure. This data structure is defined in /usr/sys/include/arch/alpha/rpb.h. The rpb_ssn member stores the system serial number (ssn) for this CPU. The ssn consists of 10 ASCII characters. [Return to example]

  2. Declares a variable to store the system serial number and initializes it to the value zero (0). [Return to example]

  3. Stores the system serial number in the cp variable. [Return to example]

  4. Prints an appropriate message on the console terminal if the system serial number stored in rpb_ssn is the null character. [Return to example]

  5. Uses a for loop to parse the ASCII serial number and convert it to hexadecimal. [Return to example]

  6. Returns the system serial number to the presto_init interface. The presto_init interface was called by the envram_attach interface. [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


7.7    Status Section

The eisa_nvram_status interface provides the /dev/presto device driver with the status of diagnostics run on the NVRAM. Section 7.6.1 shows that the envram_probe interface sets the diag_status member to indicate whether the EISA bus NVRAM expansion board passed software diagnostic tests. Section 7.6.2 shows that the envram_attach interface sets the nvram_status member of the presto_interface0 structure to eisa_nvram_status. This is the mechanism the /dev/presto device driver uses to call the interface that returns the diagnostic status of the NVRAM.

The following code implements eisa_nvram_status:


 
int eisa_nvram_status() {
 
register struct envram_softc *sc = envram_softc; [1]
 
if (sc->diag_status) [2] return(NVRAM_RDONLY); else return(NVRAM_BAD); }

  1. Declares a pointer to an envram_softc data structure and calls it sc. The envram_softc data structure allows the /dev/envram device driver's associated interfaces to share data. This data structure is defined in the /usr/sys/data/envram_data.c file. Section 7.3 describes the contents of this file, including the members of envram_softc. [Return to example]

  2. Checks the diag_status member of the sc pointer to determine whether this EISA bus NVRAM expansion board passed the software diagnostic tests. If the board passed these tests, eisa_nvram_status returns the constant NVRAM_RDONLY to the /dev/presto device driver. If the board fails these tests, eisa_nvram_status returns the constant NVRAM_BAD to the /dev/presto device driver. [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


7.8    Battery Status Section

Table 7-3 lists the three interfaces implemented as part of the Battery Status Section for the /dev/envram device driver along with the sections in the book where each is described.

Table 7-3: Interfaces Implemented as Part of the Battery Status Section

Part Section
Implementing the eisa_nvram_battery_status Interface Section 7.8.1
Implementing the eisa_nvram_battery_enable Interface Section 7.8.2
Implementing the eisa_nvram_battery_disable Interface Section 7.8.3


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


7.8.1    Implementing the eisa_nvram_battery_status Interface

The eisa_nvram_battery_status interface provides the /dev/presto device driver with the status of the battery on the NVRAM. Specifically, eisa_nvram_battery_status performs the following tasks:

Section 7.6.2 shows that the envram_attach interface sets the nvram_battery_status member of the presto_interface0 data structure to eisa_nvram_battery_status. This is the mechanism the /dev/presto device driver uses to call the interface that returns the status of the battery for the NVRAM.

The following code implements eisa_nvram_battery_status:

int eisa_nvram_battery_status()
{
  register struct envram_softc *sc = envram_softc; [1]

 
nvram_batteries0.nv_nbatteries = 1; [2] nvram_batteries0.nv_minimum_ok = 1; nvram_batteries0.nv_primary_mandatory = 1; nvram_batteries0.nv_test_retries = 1;
 
if ((ENVRAM_READIO_D16(ENVRAM_CSR) & BAT_FAIL)) [3] { nvram_batteries0.nv_status[0] = BATT_OK; return(0); } else {
 
return(1); [4] } }

  1. Declares a pointer to an envram_softc data structure and calls it sc. The envram_softc data structure allows the /dev/envram device driver's associated interfaces to share data. This data structure is defined in the /usr/sys/data/envram_data.c file. Section 7.3 describes the contents of this file, including the members of envram_softc. [Return to example]

  2. The /usr/sys/include/sys/presto.h file defines a data structure called nvram_battery_info. It also declares an instance of this structure called nvram_batteries0. The eisa_nvram_battery_status interface fills in the members of the nvram_batteries0 data structure on this and the next three lines. The following list briefly describes these members:

    [Return to example]

  3. Determines if the EISA bus NVRAM expansion board's battery is operational. If the battery is operational, eisa_nvram_battery_status sets the nv_status member to BATT_OK. The nv_status member is defined in /usr/sys/include/sys/presto.h as an array of size BATTCNT.

    Note the use of the ENVRAM_READIO_D16 interface to read the CSR. In this call, eisa_nvram_battery_status passes ENVRAM_CSR, which represents the CSR. The ENVRAM_READIO_D16 interface returns the requested data. Section 7.5 shows how the /dev/envram driver uses read_io_port to construct ENVRAM_READIO_D16. [Return to example]

  4. Returns the value 1 to the /dev/presto device driver if the battery is not operational. [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


7.8.2    Implementing the eisa_nvram_battery_enable Interface

The eisa_nvram_battery_enable interface is called by the /dev/presto device driver and performs the following tasks:

Section 7.6.2 shows that the envram_attach interface sets the nvram_battery_enable member of the presto_interface0 data structure to eisa_nvram_battery_enable. This is the mechanism the /dev/presto device driver uses to call the interface that enables the battery on the EISA bus NVRAM expansion board.

The following code implements eisa_nvram_battery_enable:

int eisa_nvram_battery_enable()
{

 
register struct envram_softc *sc = envram_softc; [1]
 
ENVRAM_WRITEIO_D16(ENVRAM_CSR, WRMEM|SET_LED); [2] ENVRAM_WRITEIO_D8(ENVRAM_BAT,!BAT_DISCON_BIT); [3] mb(); [4]
 
return(0); [5] }

  1. Declares a pointer to an envram_softc data structure and calls it sc. The envram_softc data structure allows the /dev/envram device driver's associated interfaces to share data. This data structure is defined in the /usr/sys/data/envram_data.c file. Section 7.3 describes the contents of this file, including the members of envram_softc. [Return to example]

  2. Enables writes to NVRAM and turns on the light-emitting diode (LED) by calling ENVRAM_WRITEIO_D16. The ENVRAM_WRITEIO_D16 interface writes a word (the WRMEM and SET_LED CSR bit masks) to the CSR device register (represented by the ENVRAM_CSR offset) located in the bus address space. Section 7.5 shows how the /dev/envram driver uses the write_io_port interface to construct ENVRAM_WRITEIO_D16.

    The ENVRAM_WRITEIO_D16 interface takes two arguments:

    [Return to example]

  3. Disables the battery disconnect control bit by calling ENVRAM_WRITEIO_D8. The ENVRAM_WRITEIO_D8 interface writes a byte (the BAT_DISCON_BIT battery disconnect bit mask) to the battery disconnect device register (represented by the ENVRAM_BAT offset) located in the bus address space. Section 7.5 shows how the /dev/envram driver uses the write_io_port interface to construct ENVRAM_WRITEIO_D8.

    The ENVRAM_WRITEIO_D8 interface takes two arguments:

    [Return to example]

  4. Calls mb after the writes to perform a memory barrier. [Return to example]

  5. Returns to the /dev/presto driver the value zero (0) to indicate that it successfully enabled the battery for the EISA bus NVRAM expansion board. [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


7.8.3    Implementing the eisa_nvram_battery_disable Interface

The eisa_nvram_battery_disable interface performs the following tasks:

The eisa_nvram_battery_disable interface is called by the /dev/presto device driver when it needs to disable the battery on the EISA bus NVRAM expansion board. Section 7.6.2 shows that the envram_attach interface sets the nvram_battery_disable member of the presto_interface0 data structure to eisa_nvram_battery_disable. This is the mechanism the /dev/presto device driver uses to call the interface that enables the battery on the EISA bus NVRAM expansion board.

The following code implements eisa_nvram_battery_disable:

int eisa_nvram_battery_disable()
{

 
register struct envram_softc *sc = envram_softc; [1]
 
ENVRAM_WRITEIO_D16(ENVRAM_CSR,WRMEM); [2] ENVRAM_WRITEIO_D8(ENVRAM_BAT,BAT_DISCON_BIT); [3] mb(); ENVRAM_WRITEIO_D8(ENVRAM_BAT,BAT_DISCON_BIT); mb(); ENVRAM_WRITEIO_D8(ENVRAM_BAT,!BAT_DISCON_BIT); mb(); ENVRAM_WRITEIO_D8(ENVRAM_BAT,!BAT_DISCON_BIT); mb(); ENVRAM_WRITEIO_D8(ENVRAM_BAT,BAT_DISCON_BIT); mb();
 
return(0); [4] }

  1. Declares a pointer to an envram_softc data structure and calls it sc. The envram_softc data structure allows the /dev/envram device driver's associated interfaces to share data. This data structure is defined in the /usr/sys/data/envram_data.c file. Section 7.3 describes the contents of this file, including the members of envram_softc. [Return to example]

  2. Enables writes to NVRAM by calling ENVRAM_WRITEIO_D16. The ENVRAM_WRITEIO_D16 interface writes a word (the WRMEM CSR bit mask) to the CSR device register (represented by the ENVRAM_CSR offset) located in the bus address space. Section 7.5 shows how the /dev/envram driver uses the write_io_port interface to construct ENVRAM_WRITEIO_D16.

    The ENVRAM_WRITEIO_D16 interface takes two arguments:

    [Return to example]

  3. Sends a sequence of 11001 to the battery disconnect device register by making five calls to ENVRAM_WRITEIO_D8. Note that eisa_nvram_battery_disable also performs a memory barrier after each write by calling mb.

    The ENVRAM_WRITEIO_D8 interface writes a byte (the BAT_DISCON_BIT battery disconnect bit mask) to the battery disconnect device register (represented by the ENVRAM_BAT offset) located in the bus I/O space. Section 7.5 shows how the /dev/envram driver uses the write_io_port interface to construct ENVRAM_WRITEIO_D8.

    The ENVRAM_WRITEIO_D8 interface takes two arguments:

    [Return to example]

  4. Returns to the /dev/presto driver the value zero (0) to indicate that it successfully disabled the battery for the EISA bus NVRAM expansion board. [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


7.9    Read and Write Device Section

Table 7-4 lists the two interfaces implemented as part of the Read and Write Device Section for the /dev/envram device driver along with the sections in the book where each is described.

Table 7-4: Interfaces Implemented as Part of the Read and Write Device Section

Part Section
Implementing the envram_read Interface Section 7.9.1
Implementing the envram_write Interface Section 7.9.2


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


7.9.1    Implementing the envram_read Interface

The envram_read interface is called by the envram_probe interface and the /dev/presto device driver and performs the following tasks:

Section 7.6.2 shows that the envram_attach interface sets the nvram_ioreg_read (read small pieces of NVRAM) and nvram_block_read (read large pieces of NVRAM) members of the presto_interface0 data structure to envram_read. These members both point to the same interface, which means envram_read handles both small and large reads from the EISA bus NVRAM expansion board.

Note

An xxread interface implemented on Digital UNIX typically has three arguments: dev, uio, and flag. The reason that envram_read has different arguments is that it is not called directly from the I/O system as the result of a read system call. The read request from the I/O system is made to the /dev/presto driver's read entry point, which then calls envram_read to perform the actual read operation.

The following code implements envram_read:

void envram_read(source, dest, len)
  caddr_t source;   [1]
  caddr_t dest;     [2]
  u_int   len;      [3]
{

 
register struct envram_softc *sc = envram_softc; [4]
 
io_copyin((io_handle_t) KSEG_TO_PHYS((u_long)source|sc->saved_mem_sysmap), (vm_offset_t)dest,len); [5] }

  1. Specifies the source address of the data to be written. Because this source address is passed in to envram_read by envram_probe and the /dev/presto device driver, the address format is a kernel segment (kseg) logical physical address. [Return to example]

  2. Specifies the destination address of where to write the data. Because this destination address is passed in by envram_probe and the /dev/presto device driver, the format is a kernel segment (kseg) logical physical address. [Return to example]

  3. Specifies the length of the block of data to be written. This length is passed in by envram_probe and the /dev/presto device driver. [Return to example]

  4. Declares a pointer to an envram_softc data structure and calls it sc. The envram_softc data structure allows the /dev/envram device driver's associated interfaces to share data. This data structure is defined in the /usr/sys/data/envram_data.c file. Section 7.3 describes the contents of this file, including the members of envram_softc. [Return to example]

  5. Calls io_copyin to copy data from bus address space to system memory. The io_copyin interface is a generic interface that maps to a bus- and machine-specific interface that actually performs the copy from bus address space to system memory. Using io_copyin to perform the copy operation makes the device driver more portable across different CPU architectures and different CPU types within the same architecture.

    The io_copyin interface takes three arguments:

    [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


7.9.2    Implementing the envram_write Interface

The envram_write interface is called by the /dev/presto device driver and performs the following tasks:

Section 7.6.2 shows that the envram_attach interface sets the nvram_ioreg_write (write small pieces of NVRAM) and nvram_block_write (write large pieces of NVRAM) members of the presto_interface0 data structure to envram_write. These members both point to the same interface. This means envram_write handles both small and large reads from the EISA bus NVRAM expansion board.

Note

An xxwrite interface implemented on Digital UNIX typically has three arguments: dev, uio, and flag. The reason that envram_write has different arguments is that it is not called directly from the I/O system as the result of a write system call. The read request from the I/O system is made to the /dev/presto driver's write entry point, which then calls envram_write to perform the actual write operation.

The following code implements envram_write:

void envram_write(source, dest, len)
  caddr_t source;    [1]
  caddr_t dest;      [2]
  u_int   len;       [3]
{

 
register struct envram_softc *sc = envram_softc; [4] vm_offset_t destptr; [5] register int xfer; [6] int retry; [7] char *ddest = dest; [8]
 
if (len > 32) { [9]
 
destptr = KSEG_TO_PHYS(dest) - sc->cache_base; [10] ddest = (char *)destptr; [11]
 
if (!(xfer = ENVRAM_XFER_SIZE - ((int)ddest & (ENVRAM_XFER_SIZE-1)))) [12] xfer = ENVRAM_XFER_SIZE;
 
if (xfer > len) xfer = len;
 
if ((u_int)source/ENVRAM_ALLIGN != ((u_int)source+xfer)/ENVRAM_ALLIGN) [13] xfer = xfer - (((u_int)source+xfer) & (ENVRAM_ALLIGN-1));
 
while (1) {
 
if (!(dma_map_load(xfer, source, (struct proc *)0, [14] sc->ctlr, &sc->sglp, 0, DMA_OUT))) panic("envram: dma_map_load failure\n");
 
ENVRAM_WRITEIO_D16(ENVRAM_DMA0,((u_int)(ddest-4) << 6)); [15] ENVRAM_WRITEIO_D16(ENVRAM_DMA1,((u_int)ddest >> 5));
 
ENVRAM_WRITEIO_D16(ENVRAM_CSR,SET_DREQ|WRMEM|SET_LED); [16] mb(); [17] len -= xfer; [18] source += xfer; ddest += xfer;
 
if (!(xfer = ENVRAM_XFER_SIZE - (((int)ddest [19] & (ENVRAM_XFER_SIZE-1))))) xfer = ENVRAM_XFER_SIZE;
 
if (xfer > len) xfer = len; if ((u_int)source/ENVRAM_ALLIGN != [20] ((u_int)source+xfer)/ENVRAM_ALLIGN) xfer = xfer - (((u_int)source+xfer) & (ENVRAM_ALLIGN-1));
 
retry = 10; [21] while (--retry) if (!(ENVRAM_READIO_D16(ENVRAM_CSR) & SET_DREQ)) break;
 
if (!length) break;
 
if (!retry) [22] panic("envram: DMA retry expired\n"); } return; }
 
io_copyout((vm_offset_t)source, (io_handle_t) (KSEG_TO_PHYS((u_long)dest)|sc->saved_mem_sysmap), len); [23] }

  1. Specifies the source address of the data to be written. Because this source address is passed in to envram_write by the /dev/presto device driver, the address format is a kernel segment (kseg) logical physical address. [Return to example]

  2. Specifies the destination address of where to write the data. Because this destination address is passed in by the /dev/presto device driver, the format is a kernel segment (kseg) logical physical address. [Return to example]

  3. Specifies the length of the block of data to be written. This length is passed in by the /dev/presto device driver. [Return to example]

  4. Declares a pointer to an envram_softc data structure and calls it sc. The envram_softc data structure allows the /dev/envram device driver's associated interfaces to share data. This data structure is defined in the /usr/sys/data/envram_data.c file. Section 7.3 describes the contents of this file, including the members of envram_softc. [Return to example]

  5. Stores the physical address returned by KSEG_TO_PHYS. [Return to example]

  6. Stores the size of each partial data transfer. [Return to example]

  7. Stores the retry counter. [Return to example]

  8. Stores the destination pointer. [Return to example]

  9. Performs a DMA operation if the length of the data passed in by the /dev/presto device driver is greater than 32 bytes. [Return to example]

  10. Calls KSEG_TO_PHYS to convert a kernel unmapped virtual address to a physical address.

    The KSEG_TO_PHYS interface takes one argument: the buffer virtual address to convert to a physical address. In this call, the buffer virtual address is the result of subtracting the physical starting address where the memory block was mapped to from the location of the write. The /dev/presto driver passes this location to envram_write. [Return to example]

  11. Stores the destination address in an internal variable. [Return to example]

  12. Aligns the destination to 1K. [Return to example]

  13. Aligns the source to 8K. [Return to example]

  14. Loads and sets the allocated system resources for DMA data transfers by calling dma_map_load. If dma_map_load cannot load and set the allocated system resources, envram_write calls panic to cause a system crash. Section 7.6.2 shows that these resources were previously allocated by calling dma_map_alloc.

    The dma_map_load interface takes seven arguments:

    [Return to example]

  15. Calls ENVRAM_WRITEIO_D16 to set up the NVRAM address. [Return to example]

  16. Calls ENVRAM_WRITEIO_D16 to start the transfer of data to the NVRAM. [Return to example]

  17. Calls mb after the write to perform a memory barrier. [Return to example]

  18. Performs several mathematical operations on the transfer size and the length, source, and destination pointer. [Return to example]

  19. Sets up for the next DMA operation by aligning the destination to 1K. The NVRAM handles DMA operations only inside of a 1K aligned address range. [Return to example]

  20. Aligns the source to 8K. The source is the system memory; thus there are 8K for Digital UNIX pages. [Return to example]

  21. Sets up a while loop that causes the driver to spin on the SET_DREQ bit. If the hardware works, this bit should never be set. [Return to example]

  22. If the retry expires, the hardware is broken and envram_write calls panic to cause a system crash. [Return to example]

  23. Calls io_copyout to copy data from system memory to bus address space. The io_copyout interface is a generic interface that maps to a bus- and machine-specific interface that actually performs the copy to bus address space. Using io_copyout to perform the copy operation makes the device driver more portable across different CPU architectures and different CPU types within the same architecture.

    The io_copyout interface takes three arguments:

    [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Chapter] [Index] [Help]


7.10    Zero NVRAM Section

The envram_zero interface is called by the /dev/presto device driver to zero (clear) a specified length of NVRAM starting at a specified address. Section 7.6.2 shows that the envram_attach interface sets the nvram_ioreg_zero (zero small pieces of NVRAM) and nvram_block_zero (zero large pieces of NVRAM) members of the presto_interface0 data structure to envram_zero. These members both point to the same interface. This means envram_zero zeros (clears) both small and large lengths from the EISA bus NVRAM expansion board.

The following code implements envram_zero:

void envram_zero(addr, len)
  caddr_t addr;   [1]
  u_int   len; [2]
{

 
register struct envram_softc *sc = envram_softc; [3]
 
io_zero((io_handle_t) KSEG_TO_PHYS((u_long)addr|sc->saved_mem_sysmap), len); [4] }

  1. Specifies the starting address of the NVRAM for this EISA bus NVRAM expansion board to zero. Because this address is passed in by the /dev/presto device driver, the format is a kernel segment (kseg) logical physical address. [Return to example]

  2. Specifies the length of the block of data to be zeroed. This length is passed in by the /dev/presto device driver. [Return to example]

  3. Declares a pointer to an envram_softc data structure and calls it sc. The envram_softc data structure allows the /dev/envram device driver's associated interfaces to share data. This data structure is defined in the /usr/sys/data/envram_data.c file. Section 7.3 describes the contents of this file, including the members of envram_softc. [Return to example]

  4. Calls io_zero to zero a block of memory in bus address space. The io_zero interface is a generic interface that maps to a machine-specific interface that actually writes zeros to some location in bus address space. Using io_zero to perform the zero operation makes the device driver more portable across different CPU architectures and different CPU types within the same architecture.

    The io_zero interface takes two arguments:

    [Return to example]