Both types of drivers contain:
This section implements the probe, slave, attach, and unattach interfaces.
This section implements the device driver's interrupt handler.
The block device driver can also contain a strategy section, a psize section, and a dump section.
Although the strategy interface applies to reading and writing of block data by block device drivers, character drivers can also contain a strategy interface that the character driver's read and write interfaces call. VMEbus device drivers are typically character drivers and their read and write interfaces use the physio interface. The physio interface performs the appropriate read or write operation (programmed I/O, VMEbus adapter hardware DMA, or device DMA). One of the parameters passed to the physio interface is the driver's strategy interface. Note
The character device driver contains the following sections not contained in a block device driver:
This section implements the mmap interface.
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:
Writing Device Drivers: Tutorial describes
these files. VMEbus device drivers use the following header file for VMEbus
definitions:
For VMEbus device drivers, you must specify vba as
the definition for the bus name constant. For example, for the
dmaex example driver:
Specifying vba provides the means for the VMEbus
autoconfiguration code to determine that a controller
structure is associated with the VMEbus.
The Autoconfiguration Support Section of a VMEbus device driver
contains the code that implements these interfaces for both character and
block device drivers. For drivers that are dynamically configured into the
kernel, the Autoconfiguration Support Section also contains a controller
unattach or a device unattach
interface, which is called when the driver is unloaded. You define the
entry point for each of these interfaces in the driver structure.
Writing Device Drivers: Tutorial describes each
of these interfaces. In addition, the remainder of this chapter discusses
each interface from a VMEbus device driver prespective:
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 a VMEbus device XX.
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 a 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.
It is assumed that the device is physically present and
addressable.
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:
This I/O handle corresponds to the first CSR address that you
specified in a VBA_Option entry in the
/etc/sysconfigtab file or a sysconfigtab
file fragment.
(Section 4.3 describes the
VBA_Option entry.)
You use the Csr1 field of the
VBA_Option entry to specify the CSR address for the
VMEbus device, as follows:
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.
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 any, that you
specified in a VBA_Option entry in the
/etc/sysconfigtab file or a
sysconfigtab file fragment.
(Section 4.3 describes the
VBA_Option entry.)
You can use the
Csr2 field of the VBA_Option entry to
specify an optional VMEbus device register or memory address to map into CPU
I/O space, as follows:
Section 6.5 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.
This member specifies an I/O handle that you can use to reference a
device register located in the VMEbus onboard memory. This I/O handle is
created, stored, and can be used in the same manner as the second I/O handle
described for xxprobe; see
Section 3.3.1.
The following code shows the general form for setting up a controller
attach interface:
The example driver used in this manual has a very brief controller
attach interface and no device attach
interface; see Section 6.5.2 for the
/dev/dmaex driver's implementation of the
attach interface.
The following code shows the general form for setting up a controller
unattach interface:
A device unattach is set up similarly, except it receives a
pointer to a device structure instead of a
bus structure, and performs device-specific cleanup.
The example driver used in this manual has a controller
unattach interface and no device unattach
interface; see Section 6.5.3 for the
/dev/dmaex driver's implementation of the
unattach interface.
Figure 3-1: Sections of a Character Device Driver and a Block Device Driver

3.1 Include Files Section
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:
#include <io/dec/vme/vbareg.h>
3.2 Configure Section
The Configure Section of a device driver must define a bus-specific
name constant. This constant represents the name of the bus on which your
driver operates, and is passed to the configure_driver
and unconfigure_driver interfaces.
#define DMAEX_BUSNAME1 "vba"
You must also specify vba for the
bus_name member of the
controller_config data structure (described in
Writing Device Drivers: Tutorial), which Configure Section
register_configuration code sets up in preparation for a
call to the create_controller_structure interface. In
the created controller structure, the
bus_name field is set to vba.
3.3 Autoconfiguration Support Section
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. The
slave interface, if one is implemented, checks that a
device is valid for a specific controller.
3.3.1 Setting Up a probe Interface
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. For dynamically configured drivers, the
xxprobe interface is called
indirectly during the driver loading process.
int xxprobe(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]
.
.
.
VBA_Option = ..., Csr1 - 0x8020, ...
The bus configuration code converts the Csr1 address,
combined with information in driver structure members
addr1_size and
addr1_atype,
into an appropriate I/O
handle and passes it to the driver's
xxprobe interface.
VBA_Option = ..., Csr2 - 0x8040, ...
The bus configuration code converts the Csr2 address,
combined with information in driver structure members
addr2_size and
addr2_atype, into an
appropriate I/O handle. It is not passed to the driver's
xxprobe interface, but is
available in the driver's controller structure.
3.3.2 Setting Up the slave Interface
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.
The following code fragment shows you how to set up a slave
interface for a driver that operates on a VMEbus:
int xxslave(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]
.
.
.
3.3.3 Setting Up a Controller attach Interface
A device driver's attach interface establishes
communication with the device. There are two attach
interfaces: a controller attach for controller-specific initialization
(called once for each controller) and a device attach
interface for device-specific initialization (called once for each slave
device attached to a controller).
int xxcattach (struct controller *ctlr)
{
...
/* Interface calls to establish communication with the device */
...
}
A device attach is set up similarly, except it receives a
pointer to a device structure instead of a
controller structure, and performs device-specific initialization.
3.3.4 Setting Up a Controller unattach Interface
A device driver's unattach interface removes the
specified controller or device
structure from the list of controllers or devices it handles, unmaps any
controller or device CSRs that were mapped, frees any controller or device
resources that were allocated, and removes any handlers that were added per
controller or device.
There are two unattach
interfaces: a controller unattach for controller structure removal
and a device unattach for device structure removal.
int xx_ctlr_unattach (struct bus *bus,
struct controller *ctlr)
{
...
/* Interface calls to remove structures, handlers, free resources */
...
}
In the case of VMEbus device drivers, actions might include
calling the
vba_unmap_csr interface to unmap CSRs mapped with
vba_map_csr and issuing handler_disable
and handler_delete calls for every handler associated
with the controller.