JavaScript is required to for searching.
Skip Navigation Links
Exit Print View
Writing Device Drivers
search filter icon
search icon

Document Information


Part I Designing Device Drivers for the Solaris Platform

1.  Overview of Solaris Device Drivers

2.  Solaris Kernel and Device Tree

3.  Multithreading

4.  Properties

5.  Managing Events and Queueing Tasks

6.  Driver Autoconfiguration

Driver Loading and Unloading

Data Structures Required for Drivers

modlinkage Structure

modldrv Structure

dev_ops Structure

cb_ops Structure

Loadable Driver Interfaces

_init() Example

_fini() Example

_info() Example

Device Configuration Concepts

Device Instances and Instance Numbers

Minor Nodes and Minor Numbers

probe() Entry Point

attach() Entry Point

Driver Soft-State Management

Lock Variable and Conditional Variable Initialization

Creating Minor Device Nodes

Deferred Attach

detach() Entry Point

getinfo() Entry Point

Using Device IDs

Registering Device IDs

Registering a Device-Supplied ID

Registering a Fabricated ID

Unregistering Device IDs

7.  Device Access: Programmed I/O

8.  Interrupt Handlers

9.  Direct Memory Access (DMA)

10.  Mapping Device and Kernel Memory

11.  Device Context Management

12.  Power Management

13.  Hardening Solaris Drivers

14.  Layered Driver Interface (LDI)

Part II Designing Specific Kinds of Device Drivers

15.  Drivers for Character Devices

16.  Drivers for Block Devices

17.  SCSI Target Drivers

18.  SCSI Host Bus Adapter Drivers

19.  Drivers for Network Devices

20.  USB Drivers

Part III Building a Device Driver

21.  Compiling, Loading, Packaging, and Testing Drivers

22.  Debugging, Testing, and Tuning Device Drivers

23.  Recommended Coding Practices

Part IV Appendixes

A.  Hardware Overview

B.  Summary of Solaris DDI/DKI Services

C.  Making a Device Driver 64-Bit Ready

D.  Console Frame Buffer Drivers


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,      /* devo_getinfo: getinfo(9E) */
    nulldev,        /* devo_identify: identify(9E) */
    xxprobe,        /* devo_probe: probe(9E) */
    xxattach,       /* devo_attach: attach(9E) */
    xxdetach,       /* devo_detach: detach(9E) */
    nodev,          /* devo_reset */
    &xx_cb_ops,     /* devo_cb_ops */
    NULL,           /* devo_bus_ops */
    &xxpower        /* devo_power: 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:

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:

cb_rev is the cb_ops structure revision number. This field must be set to CB_REV.