Data Structures Required for Drivers
To support autoconfiguration, drivers are required to statically initialize the following data structures:
The data structures in Figure 5-1 are relied on by the
driver. These structures must be provided and be initialized correctly. Without these data structures,
the driver might not load properly. As a result, the necessary routines might
not be loaded. If an operation is not supported by the
driver, the address of the nodev(9F) routine can be used as a placeholder. In
some instances, the driver supports the entry point and only needs to return
success or failure. In such cases, the address of the routine nulldev(9F) can be
used.
Note - These structures should be initialized at compile-time. The driver should not access or
change the structures at any other time.
modlinkage Structure
static struct modlinkage xxmodlinkage = {
MODREV_1, /* ml_rev */
&xxmodldrv, /* ml_linkage[] */
NULL /* NULL termination */
};
The first field is the version number of the module that loads
the subsystem. This field should be MODREV_1. The second field points to driver's modldrv
structure defined next. The last element of the structure should always be NULL.
modldrv Structure
static struct modldrv xxmodldrv = {
&mod_driverops, /* drv_modops */
"generic driver v1.1", /* drv_linkinfo */
&xx_dev_ops /* drv_dev_ops */
};
This structure describes the module in more detail. The first field provides information
regarding installation of the module. This field should be set to &mod_driverops for
driver modules. The second field is a string to be displayed by modinfo(1M).
The second field should contain sufficient information for identifying the version of source
code that generated the driver binary. The last field points to the driver's
dev_ops structure defined in the following section.
dev_ops Structure
static struct dev_ops xx_dev_ops = {
DEVO_REV, /* devo_rev, */
0, /* devo_refcnt */
xxgetinfo, /* getinfo(9E) */
nulldev, /* identify(9E) */
xxprobe, /* probe(9E) */
xxattach, /* attach(9E) */
xxdetach, /* detach(9E) */
nodev, /* devo_reset */
&xx_cb_ops, /* devo_cb_ops */
NULL, /* devo_bus_ops */
&xxpower /* power(9E) */
};
The dev_ops(9S) structure enables the kernel to find the autoconfiguration entry points of
the device driver. The devo_rev field identifies the revision number of the structure. This
field must be set to DEVO_REV. The devo_refcnt field must be initialized to
zero. The function address fields should be filled in with the address of
the appropriate driver entry point, except in the following cases:
Set the devo_probe field to nulldev(9F) if a probe(9E) routine is not needed.
Set the identify() field to nulldev(9F). The identify() entry point is obsolete.
Set the devo_reset field to nodev(9F).
Set the power(9E) field to NULL if a power() routine is not needed. Drivers for devices that provide Power Management functionality must have a power() entry point.
The devo_cb_ops member should include the address of the cb_ops(9S) structure. The devo_bus_ops field
must be set to NULL.
cb_ops Structure
static struct cb_ops xx_cb_ops = {
xxopen, /* open(9E) */
xxclose, /* close(9E) */
xxstrategy, /* strategy(9E) */
xxprint, /* print(9E) */
xxdump, /* dump(9E) */
xxread, /* read(9E) */
xxwrite, /* write(9E) */
xxioctl, /* ioctl(9E) */
xxdevmap, /* devmap(9E) */
nodev, /* mmap(9E) */
xxsegmap, /* segmap(9E) */
xxchpoll, /* chpoll(9E) */
xxprop_op, /* prop_op(9E) */
NULL, /* streamtab(9S) */
D_MP | D_64BIT, /* cb_flag */
CB_REV, /* cb_rev */
xxaread, /* aread(9E) */
xxawrite /* awrite(9E) */
};
The cb_ops(9S) structure contains the entry points for the character operations and block
operations of the device driver. Any entry points that the driver does not
support should be initialized to nodev(9F). For example, character device drivers should set
all the block-only fields, such as cb_stategy, to nodev(9F). Note that the
mmap(9E) entry point is maintained for compatibility with previous releases. Drivers should use the
devmap(9E) entry point for device memory mapping. If devmap(9E) is supported,
set mmap(9E) to nodev(9F).
The streamtab field indicates whether the driver is STREAMS-based. Only the network device
drivers that are discussed in Chapter 19, Drivers for Network Devices are STREAMS-based. All non-STREAMS-based drivers must
set the streamtab field to NULL.
The cb_flag member contains the following flags:
The D_MP flag indicates that the driver is safe for multithreading. The Solaris OS supports only thread-safe drivers so D_MP must be set.
The D_64BIT flag causes the driver to use the uio_loffset field of the uio(9S) structure. The driver should set the D_64BIT flag in the cb_flag field to handle 64-bit offsets properly.
The D_DEVMAP flag supports the devmap(9E) entry point. For information on devmap(9E), see Chapter 10, Mapping Device and Kernel Memory.
cb_rev is the cb_ops structure revision number. This field must be set to
CB_REV.