Device Driver Tutorial

Displaying Data Stored in Kernel Memory

The pseudo device driver presented in this section writes a constant string to a system log when the driver is loaded.

This first version of the Quote Of The Day driver (qotd_1) is even more simple than the dummy driver from the previous chapter. The dummy driver includes all functions that are required to drive hardware. This qotd_1 driver includes only the bare minimum functions it needs to make a string available to a user command. For example, this qotd_1 driver has no cb_ops(9S) structure. Therefore, this driver defines no open(9E), close(9E), read(9E), or write(9E) function. If you examine the dev_ops(9S) structure for this qotd_1 driver, you see that no getinfo(9E), attach(9E), or detach(9E) function is defined. This driver contains no function declarations because all the functions that are defined in this driver are declared in the modctl.h header file. You must include the modctl.h header file in your qotd_1.c file.

This qotd_1 driver defines a global variable to hold its text data. The _init(9E) entry point for this driver uses the cmn_err(9F) function to write the string to a system log. The dummy driver also uses the cmn_err(9F) function to display messages. The qotd_1 driver is different from the dummy driver because the qotd_1 driver stores its string in kernel memory.

Writing Quote Of The Day Version 1

Enter the source code shown in the following example into a text file named qotd_1.c.


Example 3–1 Quote Of The Day Version 1 Source File

#include <sys/modctl.h>
#include <sys/conf.h>
#include <sys/devops.h>
#include <sys/cmn_err.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>

#define QOTD_MAXLEN     128

static const char qotd[QOTD_MAXLEN]
        = "Be careful about reading health books. \
You may die of a misprint. - Mark Twain\n";

static struct dev_ops qotd_dev_ops = {
        DEVO_REV,               /* devo_rev */
        0,                      /* devo_refcnt */
        ddi_no_info,            /* devo_getinfo */
        nulldev,                /* devo_identify */
        nulldev,                /* devo_probe */
        nulldev,                /* devo_attach */
        nulldev,                /* devo_detach */
        nodev,                  /* devo_reset */
        (struct cb_ops *)NULL,  /* devo_cb_ops */
        (struct bus_ops *)NULL, /* devo_bus_ops */
        nulldev,                /* devo_power */
        ddi_quiesce_not_needed, /* devo_quiesce */
};

static struct modldrv modldrv = {
        &mod_driverops,
        "Quote of the Day 1.0",
        &qotd_dev_ops};

static struct modlinkage modlinkage = {
        MODREV_1,
        (void *)&modldrv,
        NULL
};

int
_init(void)
{
        cmn_err(CE_CONT, "QOTD: %s\n", qotd);
        return (mod_install(&modlinkage));
}

int
_info(struct modinfo *modinfop)
{
        return (mod_info(&modlinkage, modinfop));
}
int
_fini(void)
{
        return (mod_remove(&modlinkage));
}

Enter the configuration information shown in the following example into a text file named qotd_1.conf.


Example 3–2 Quote Of The Day Version 1 Configuration File

name="qotd_1" parent="pseudo" instance=0;

Building, Installing, and Using Quote Of The Day Version 1

Compile and link the driver. Use the -D_KERNEL option to indicate that this code defines a kernel module. The following example shows compiling and linking for a 32-bit architecture using the Oracle Solaris Studio C compiler:


% cc -D_KERNEL -c qotd_1.c
% ld -r -o qotd_1 qotd_1.o

Note that the name of the driver, qotd_1, must match the name property in the configuration file.

Make sure you are user root when you install the driver.

Copy the driver binary to the /tmp directory as discussed in Device Driver Testing Tips.


# cp qotd_1 /tmp
# ln -s /tmp/qotd_1 /usr/kernel/drv/qotd_1

Copy the configuration file to the kernel driver area of the system.


# cp qotd_1.conf /usr/kernel/drv

This qotd_1 driver writes a message to a system log each time the driver is loaded. The cmn_err(9F) function writes low priority messages such as the message defined in this qotd_1 driver to /dev/log. The syslogd(1M) daemon reads messages from /dev/log and writes low priority messages to /var/adm/messages.

To test this driver, watch for the message in /var/adm/messages. In a separate window, enter the following command:


% tail -f /var/adm/messages

Make sure you are user root when you load the driver. Use the add_drv(1M) command to load the driver:


# add_drv qotd_1

You should see the following messages in the window where you are viewing /var/adm/messages:


date time machine pseudo: [ID 129642 kern.info] pseudo-device: devinfo0
date time machine genunix: [ID 936769 kern.info] devinfo0 is /pseudo/devinfo@0
date time machine qotd: [ID 197678 kern.notice] QOTD_1: Be careful about
reading health books. You may die of a misprint. - Mark Twain

This last line is the content of the variable output by the cmn_err(9F) function in the _init(9E) entry point. The _init(9E) entry point is called when the driver is loaded.