Writing Device Drivers

Chapter 15 Loading and Unloading Drivers

This chapter describes the procedure for installing a device driver in the system, and for dynamically loading and unloading a device driver during testing and development.

Preparing for Installation

Before the driver is actually installed, all necessary files must be prepared. The driver's module name must either match the name of the device nodes, or the system must be informed that this driver should manage other names. The driver must then be properly compiled, and a configuration file must be created if necessary.

Module Naming

The system maintains a one-to-one association between the name of the driver module and the name of the dev_info node. For example, a dev_info node for a device named wombat is handled by a driver module called wombat in a subdirectory called drv (resulting in drv/wombat) found in the module path.

If the driver should manage dev_info nodes with different names, the add_drv(1M) utility can create aliases. The -i flag specifies the names of other dev_info nodes that the driver handles.

Compiling and Linking the Driver

Compile each driver source file and link the resulting object files into a driver module. For a driver called xx that has two C-language source files the following commands are appropriate:

test% cc -D_KERNEL -c xx1.ctest% cc -D_KERNEL -c xx2.ctest% ld -r -o xx xx1.o xx2.o

The _KERNEL symbol must be defined while compiling kernel (driver) code. No other symbols (such as sun4c or sun4m) should be defined, aside from driver private symbols. DEBUG may also be defined to enable any calls to ASSERT(9F). There is also no need to use the -I flag for the standard headers.

Once the driver is stable, optimization flags can be used. For the Sun WorkShop Compiler C, the normal -O flag, or its equivalent -xO2, may be used. Note that -xO2 is the highest level of optimization device drivers should use (see cc(1)).


Note -

Running ld -r is necessary even if there is only one object module.


Writing a Hardware Configuration File

If the device is non-self-identifying, the kernel requires a hardware configuration file for it. If the driver is called xx, the hardware configuration file for it should be called xx.conf. See driver.conf(4), pseudo(4), sbus(4), scsi(4), and vme(4) for more information on hardware configuration files. On the Intel platform, device information is now supplied by the booting system. Hardware configuration files should no longer be needed to provide probe(9E) arguments, even for non-self-identifying devices.

Arbitrary properties can be defined in hardware configuration files by adding entries of the form property=value, where property is the property name, and value is its initial value. This allows devices to be configured by changing the property values.

Installing and Removing Drivers

Before a driver can be used, the system must be informed that it exists. The add_drv(1M) utility must be used to correctly install the device driver. Once the driver is installed, it can be loaded and unloaded from memory without using add_drv(1M) again.

Copying the Driver to a Module Directory

Device drivers reside in different directories depending on the platform they run on and whether they are needed at boot time. Platform-dependent device drivers reside in the following locations:

To install a driver, the driver and its configuration file must be copied to a drv directory in the module path. For example, to copy a driver to /usr/kernel/drv, type:

$ su# cp xx /usr/kernel/drv# cp xx.conf /usr/kernel/drv

Optionally Editing /etc/devlink.tab

If the driver creates minor nodes that do not represent disks, tapes, or ports (terminal devices), /etc/devlink.tab can be modified to cause devlinks(1M) to create logical device names in /dev. See devlink.tab(4) for a description of the syntax of this file.

Alternatively, logical names can be created by a program run at driver installation time.

Running add_drvadd_drv(1M)

Run add_drv(1M) to install the driver in the system. If the driver installs successfully, add_drv(1M) will run disks(1M), tapes(1M), ports(1M), and devlinks(1M) to create the logical names in /dev.

# add_drv xx

This is a simple case in which the device identifies itself as xx and the device special files will have default ownership and permissions (0600 root sys). add_drv(1M) also allows additional names for the device (aliases) to be specified. See add_drv(1M) to determine how to add aliases and set file permissions explicitly.


Note -

add_drv(1M) should not be run when installing a STREAMS module. See the STREAMS Programming Guide for details.


Removing the Driver

To remove a driver from the system, use rem_drv(1M), then delete the driver module and configuration file from the module path. The driver cannot be used again until it is reinstalled with add_drv(1M).

Loading Drivers

Opening a special file associated with the device driver causes the driver to be loaded. modload(1M) can also be used to load the driver into memory, but it does not call any routines in the module. Opening the device is the preferred method.

Getting the Driver Module's ID

Individual drivers can be unloaded by module id. To determine the module ID assigned to a driver, use modinfo(1M). Find the driver's name in the output. The first column of that entry is the driver's module ID.

# modinfoId	Loadaddr			Size		Info		Rev		Module Name

...

124	ff211000			1df4		101		1		xx (xx driver v1.0)

The number in the Info field is the major number chosen for the driver.

Unloading Drivers

Normally, the system automatically unloads device drivers when they are no longer in use. During development, it may be necessary to use modunload(1M) to unload the driver before installing a new version. In order for modunload(1M) to be successful, the device driver must not be active; there must be no outstanding references to the device, such as through open(2) or mmap(2).

Use modunload(1M) to unload a driver from the system:

# modunload -i module_id

In addition to being inactive, the driver must have working detach(9E) and _fini(9E) routines for modunload(1M) to succeed.

To unload all currently unloadable modules, specify module ID zero:

# modunload -i 0

Driver Packaging

The normal delivery vehicle for unbundled software is to create a package with all the components of the software bundled together. A package provides a controlled mechanism for installation and removal of all the components of a software product, including applications, configuration tools, drivers, man pages and other documentation.

Package Postinstall

Packages that include a driver must run add_drv(1M) to complete the installation of the driver, after installing the driver binary and other components, onto a system. Here is an example package postinstall script to run add_drv(1M) to complete the driver installation.

#!/bin/sh
#
#       @(#)postinstall 1.1

PATH="/usr/bin:/usr/sbin:${PATH}"
export PATH

#
# Driver info
#
DRV=<driver-name>
DRVALIAS="<company-name>,<driver-name>"
DRVPERM='* 0666 root sys'

ADD_DRV=/usr/sbin/add_drv

#
# Select the correct add_drv options to execute.
# add_drv touches /reconfigure to cause the
# next boot to be a reconfigure boot.
#
if [ "${BASEDIR}" = "/" ]; then
        #
        # On a running system, modify the
        # system files and attach the driver
        #
        ADD_DRV_FLAGS=""
else     
        #
        # On a client, modify the system files
        # relative to BASEDIR
        #
        ADD_DRV_FLAGS="-b ${BASEDIR}"
fi       
 
#
# Make sure add_drv has not been previously executed
# before attempting to add the driver.
#
grep "^${DRV} " $BASEDIR/etc/name_to_major > /dev/null 2>&1
if [ $? -ne 0 ]; then
        ${ADD_DRV} ${ADD_DRV_FLAGS} -m "${DRVPERM}" -i "${DRVALIAS}" ${DRV}
        if [ $? -ne 0 ]; then
                echo "postinstall: add_drv $DRV failed\n" >&2
                exit 1
        fi
fi
exit 0

Package Postremove

When removing a package, a package that includes a driver must run rem_drv(1M) to complete the removal of the driver, after removing the driver binary and other components from a system. Here is an example package postremove script to run rem_drv(1M) to complete the driver removal.

#!/bin/sh
#
#       @(#)postremove  1.1
 
PATH="/usr/bin:/usr/sbin:${PATH}"
export PATH
 
#
# Driver info
#
DRV=<driver-name>
REM_DRV=/usr/sbin/rem_drv
 
#
# Select the correct rem_drv options to execute.
# rem_drv touches /reconfigure to cause the
# next boot to be a reconfigure boot.
#
if [ "${BASEDIR}" = "/" ]; then
        #
        # On a running system, modify the
        # system files and remove the driver
        #
        REM_DRV_FLAGS=""
else     
        #
        # On a client, modify the system files
        # relative to BASEDIR
        #
        REM_DRV_FLAGS="-b ${BASEDIR}"
fi
 
${REM_DRV} ${REM_DRV_FLAGS} ${DRV}
 
exit 0