The sections that make up a Digital UNIX device driver differ, depending on whether the driver is a block, character, or network driver. Figure 3-1 shows the sections that a character device driver can contain and the possible sections that a block device driver can contain. Device drivers do not have to use all of the sections shown in the figure, and more complex drivers can use additional sections. Both character and block device drivers can contain:
The block device driver can also contain a strategy section, a psize section, and a dump section.
The character device driver contains the following sections not contained in a block device driver:
Writing Device Drivers: Tutorial discusses each of the driver sections. The remainder of this chapter describes the differences in the following driver sections as they relate to VMEbus device drivers: include file and autoconfiguration support (specifically, the xxprobe and xxslave interfaces).
Data structures and constant values are defined in header files that you include in the Include Files Section of the driver source code. The number and types of header files you specify in the Include Files Section vary, depending on such things as what structures, constants, and kernel interfaces your device driver references. You need to be familiar with:
Writing Device Drivers: Tutorial describes these files. VMEbus device drivers use the following header file exclusively:
#include <io/dec/vme/vbareg.h>
When Digital UNIX boots, the kernel determines what devices are connected to the computer. After finding a device, the kernel initializes it so that the device can be used at a later time. The probe interface determines if a particular device is present and the attach interface initializes the device. If the device is a disk controller, the slave interface determines if the device is present.
The Autoconfiguration Support Section of a VMEbus device driver contains the code that implements these interfaces and the section applies to both character and block device drivers. The section can contain:
Writing Device Drivers: Tutorial discusses each of these interfaces.
The remainder of this chapter describes the differences in the xxprobe and xxslave interfaces as they apply to VMEbus device drivers.
Note
The following discussion of the xxprobe interface includes information on loadable drivers. Loadable device drivers are not currently supported on the VMEbus. However, you may want to study the loadable driver example code that appears in Writing Device Drivers: Tutorial in anticipation of possible future support.
For convenience in referring to the names of the driver interfaces, the chapter uses the prefix xx. For example, xxprobe refers to a probe interface for some XX device.
A device driver's xxprobe interface performs tasks necessary to determine if the device exists and is functional on a given system. At boot time, the kernel performs checks to determine if the device is present before calling the xxprobe interface for statically configured drivers. The kernel calls the xxprobe interface for each device that is defined in the system configuration file or config.file file fragment for static drivers. In addition, the kernel calls the xxprobe interface for each stanza entry that is defined in the stanza.loadable file fragment for loadable drivers.
For dynamically configured drivers, the xxprobe interface is called indirectly during the driver loading process.
The driver's configure interface calls the configure_driver interface to merge the driver's connectivity information into the system (hardware) configuration tree, which consists of bus, controller, and device structures. The call to configure_driver results in the system calling xxprobe for each instance of the controller present on the VMEbus.
Some tasks performed by the xxprobe interface vary, depending on whether the device driver is configured as static or loadable:
The xxprobe interface typically checks some device control status register (CSR) to determine whether the physical device is present. If the device is not present, the device is not initialized and not available for use.
In previous versions of the operating system, you defined the device interrupt handlers for static device drivers in the system configuration file or the stanza.static file fragment. At system configuration time, the config program registered the defined device interrupt handlers. For this version of Digital UNIX, Digital requires that you register the device interrupt handlers for static device drivers in the same way that you register them for loadable device drivers: by calling the handler_add and handler_enable interfaces.
When device drivers are dynamically loaded, the bus configuration code checks for the existence of the device before calling xxprobe.
The xxprobe interface returns a nonzero value if the probe operation is successful. It returns the value zero (0) to indicate that the driver did not complete the probe operation.
The arguments you pass to the probe interface differ according to the bus on which the driver operates. The following code fragment shows you how to set up a probe interface for a driver that operates on a VMEbus:
xxprobe(addr1, ctlr) iohandle_t addr1; [1] struct controller *ctlr; [2] { /* Variable and structure declarations */
.
.
.
/* Code to perform necessary checks */
.
.
.
/* Code to obtain the second I/O handle */ [3]
.
.
.
This I/O handle corresponds to the first CSR address that you specified in the system configuration file. You precede the control status register (CSR) address for the VMEbus device in the system configuration file with the csr keyword, as follows:
csr 0x8020
The bus configuration code converts this address into an appropriate I/O handle and passes it to the driver's xxprobe interface.
Device drivers pass the I/O handle to the following categories of interfaces, which are discussed in Writing Device Drivers: Tutorial. These interfaces can process the I/O handle to access the desired bus address space.
The CSR I/O access interfaces are read_io_port and write_io_port. These are generic interfaces that allow device drivers to read from and write to device registers. Using these interfaces to read data from and 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 I/O copy interfaces are io_copyin, io_copyio, io_copyout, and io_zero. These are generic interfaces that allow device drivers to perform I/O copy operations. Using these interfaces to perform the copy operation makes the device driver more portable across different CPU architectures and different CPU types within the same architecture.
This member specifies an I/O handle that you can use to reference a device register located in the VMEbus onboard memory. The VMEbus configuration code passes this I/O handle to the driver's xxprobe interface through the controller structure pointer during device autoconfiguration. You can perform standard C mathematical operations (addition and subtraction only) on the I/O handle. For example, you can add an offset to or subtract an offset from the I/O handle.
This I/O handle corresponds to the second CSR address, if present, that you specified in the system configuration file or the stanza.static file fragment. If you did not specify a second CSR address, the value of this argument is zero (0). You precede the second CSR address for the VMEbus device in the system configuration file with the csr2 keyword, as follows:
csr2 0x8040
The bus configuration code converts this address into an appropriate I/O handle and passes it to the driver's xxprobe interface. [Return to example]
Section 6.4 provides more details on how to write a probe interface for a driver that operates on the VMEbus.
In previous versions of the operating system, the xxprobe interface returned the size of the control/status register address space. For this version of Digital UNIX, the xxprobe interface returns a nonzero value on success and the value zero (0) on failure.
A device driver's xxslave interface is called only for a controller that has slave devices connected to it. This interface is called once for each slave attached to the controller. You (or the system manager) specify the attachments of these slave devices for static device drivers in the system configuration file or stanza.static file fragment. The following code fragment shows you how to set up a slave interface for a driver that operates on a VMEbus:
xxslave(device, addr1) struct device *device; [1] iohandle_t addr1; [2] { /* Variable and structure declarations */
.
.
.
/* Code to check that the device is valid */
.
.
.
/* Code to obtain the second I/O handle */ [3]
.
.
.
This I/O handle corresponds to the first CSR address that you specified in the system configuration file. You precede the control status register (CSR) address for the VMEbus device in the system configuration file with the csr keyword, as follows:
csr 0x8020
The bus configuration code converts this address into an appropriate I/O handle and passes it to the driver's xxslave interface.
Device drivers pass the I/O handle to the following categories of interfaces, which are discussed in Writing Device Drivers: Tutorial. These interfaces can process the I/O handle to access the desired bus address space.
The CSR I/O access interfaces are read_io_port and write_io_port. These are generic interfaces that allow device drivers to read from and write to device registers. Using these interfaces to read data from and 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 I/O copy interfaces are io_copyin, io_copyio, io_copyout, and io_zero. These are generic interfaces that allow device drivers to perform I/O copy operations. Using these interfaces to perform the copy operation makes the device driver more portable across different CPU architectures and different CPU types within the same architecture.
This member specifies an I/O handle that you can use to reference a device register located in the VMEbus onboard memory. The VMEbus configuration code passes this I/O handle to the driver's xxprobe interface through the controller structure pointer during device autoconfiguration. You can perform standard C mathematical operations (addition and subtraction only) on the I/O handle. For example, you can add an offset to or subtract an offset from the I/O handle.
This I/O handle corresponds to the second CSR address, if present, that you specified in the system configuration file or the stanza.static file fragment. If you did not specify a second CSR address, the value of this argument is zero (0). You precede the second CSR address for the VMEbus device in the system configuration file with the csr2 keyword, as follows:
csr2 0x8040
The bus configuration code converts this address into an appropriate I/O handle and passes it to the driver's xxslave interface. [Return to example]