JavaScript is required to for searching.
Skip Navigation Links
Exit Print View
Device Driver Tutorial     Oracle Solaris 11 Express 11/10
search filter icon
search icon

Document Information

Preface

1.  Introduction to Device Drivers

2.  Template Driver Example

Overview of the Template Driver Example

Writing the Template Driver

Writing the Loadable Module Configuration Entry Points

Declaring the Loadable Module Configuration Entry Points

Defining the Module Initialization Entry Point

Defining the Module Information Entry Point

Defining the Module Unload Entry Point

Including Loadable Module Configuration Header Files

Writing the Autoconfiguration Entry Points

Declaring the Autoconfiguration Entry Points

Defining the Device Attach Entry Point

Defining the Device Detach Entry Point

Defining the Get Driver Information Entry Point

Defining the Report Driver Property Information Entry Point

Including Autoconfiguration Header Files

Writing the User Context Entry Points

Declaring the User Context Entry Points

Defining the Open Device Entry Point

Defining the Close Device Entry Point

Defining the Read Device Entry Point

Defining the Write Device Entry Point

Including User Context Header Files

Writing the Driver Data Structures

Defining the Character and Block Operations Structure

Defining the Device Operations Structure

Defining the Module Linkage Structures

Including Data Structures Header Files

Writing the Device Configuration File

Building and Installing the Template Driver

Testing the Template Driver

Adding the Template Driver

Reading and Writing the Device

Removing the Template Driver

Complete Template Driver Source

3.  Reading and Writing Data in Kernel Memory

4.  Tips for Developing Device Drivers

Index

Complete Template Driver Source

The following code is the complete source for the dummy driver described in this chapter:

/*
 * Minimalist pseudo-device.
 * Writes a message whenever a routine is entered.
 *
 * Build the driver:
 *      cc -D_KERNEL -c dummy.c
 *      ld -r -o dummy dummy.o
 * Copy the driver and the configuration file to /usr/kernel/drv:
 *      cp dummy.conf /usr/kernel/drv
 *      cp dummy /tmp
 *      ln -s /tmp/dummy /usr/kernel/drv/dummy
 * Add the driver:
 *      add_drv dummy
 * Test (1) read from driver (2) write to driver:
 *      cat /devices/pseudo/dummy@*
 *      echo hello > `ls /devices/pseudo/dummy@*`
 * Verify the tests in another window:
 *      tail -f /var/adm/messages
 * Remove the driver:
 *      rem_drv dummy
 */

#include <sys/devops.h>  /* used by dev_ops */
#include <sys/conf.h>    /* used by dev_ops and cb_ops */
#include <sys/modctl.h>  /* used by modlinkage, modldrv, _init, _info, */
                         /* and _fini */
#include <sys/types.h>   /* used by open, close, read, write, prop_op, */
                         /* and ddi_prop_op */
#include <sys/file.h>    /* used by open, close */
#include <sys/errno.h>   /* used by open, close, read, write */
#include <sys/open.h>    /* used by open, close, read, write */
#include <sys/cred.h>    /* used by open, close, read */
#include <sys/uio.h>     /* used by read */
#include <sys/stat.h>    /* defines S_IFCHR used by ddi_create_minor_node */
#include <sys/cmn_err.h> /* used by all entry points for this driver */
#include <sys/ddi.h>     /* used by all entry points for this driver */
                         /* also used by cb_ops, ddi_get_instance, and */
                         /* ddi_prop_op */
#include <sys/sunddi.h>  /* used by all entry points for this driver */
                         /* also used by cb_ops, ddi_create_minor_node, */
                         /* ddi_get_instance, and ddi_prop_op */

static int dummy_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
static int dummy_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
static int dummy_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
    void **resultp);
static int dummy_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
    int flags, char *name, caddr_t valuep, int *lengthp);
static int dummy_open(dev_t *devp, int flag, int otyp, cred_t *cred);
static int dummy_close(dev_t dev, int flag, int otyp, cred_t *cred);
static int dummy_read(dev_t dev, struct uio *uiop, cred_t *credp);
static int dummy_write(dev_t dev, struct uio *uiop, cred_t *credp);

/* cb_ops structure */
static struct cb_ops dummy_cb_ops = {
    dummy_open,
    dummy_close,
    nodev,              /* no strategy - nodev returns ENXIO */
    nodev,              /* no print */
    nodev,              /* no dump */
    dummy_read,
    dummy_write,
    nodev,              /* no ioctl */
    nodev,              /* no devmap */
    nodev,              /* no mmap */
    nodev,              /* no segmap */
    nochpoll,           /* returns ENXIO for non-pollable devices */
    dummy_prop_op,
    NULL,               /* streamtab struct; if not NULL, all above */
                        /* fields are ignored */
    D_NEW | D_MP,       /* compatibility flags: see conf.h */
    CB_REV,             /* cb_ops revision number */
    nodev,              /* no aread */
    nodev               /* no awrite */
};

/* dev_ops structure */
static struct dev_ops dummy_dev_ops = {
    DEVO_REV,
    0,                         /* reference count */
    dummy_getinfo,             /* no getinfo(9E) */
    nulldev,                   /* no identify(9E) - nulldev returns 0 */
    nulldev,                   /* no probe(9E) */
    dummy_attach,
    dummy_detach,
    nodev,                     /* no reset - nodev returns ENXIO */
    &dummy_cb_ops,
    (struct bus_ops *)NULL,
    nodev,                     /* no power(9E) */
    ddi_quiesce_not_needed,    /* no quiesce(9E) */
};

/* modldrv structure */
static struct modldrv md = {
    &mod_driverops,     /* Type of module. This is a driver. */
    "dummy driver",     /* Name of the module. */
    &dummy_dev_ops
};

/* modlinkage structure */
static struct modlinkage ml = {
    MODREV_1,
    &md,
    NULL
};

/* dev_info structure */
dev_info_t *dummy_dip;  /* keep track of one instance */


/* Loadable module configuration entry points */
int
_init(void)
{
    cmn_err(CE_NOTE, "Inside _init");
    return(mod_install(&ml));
}

int
_info(struct modinfo *modinfop)
{
    cmn_err(CE_NOTE, "Inside _info");
    return(mod_info(&ml, modinfop));
}

int
_fini(void)
{
    cmn_err(CE_NOTE, "Inside _fini");
    return(mod_remove(&ml));
}

/* Device configuration entry points */
static int
dummy_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
    cmn_err(CE_NOTE, "Inside dummy_attach");
    switch(cmd) {
    case DDI_ATTACH:
        dummy_dip = dip;
        if (ddi_create_minor_node(dip, "0", S_IFCHR,
            ddi_get_instance(dip), DDI_PSEUDO,0)
            != DDI_SUCCESS) {
            cmn_err(CE_NOTE,
                "%s%d: attach: could not add character node.",
                "dummy", 0);
            return(DDI_FAILURE);
        } else
            return DDI_SUCCESS;
    default:
        return DDI_FAILURE;
    }
}

static int
dummy_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
{
    cmn_err(CE_NOTE, "Inside dummy_detach");
    switch(cmd) {
    case DDI_DETACH:
        dummy_dip = 0;
        ddi_remove_minor_node(dip, NULL);
        return DDI_SUCCESS;
    default:
        return DDI_FAILURE;
    }
}

static int
dummy_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, 
    void **resultp)
{
    cmn_err(CE_NOTE, "Inside dummy_getinfo");
    switch(cmd) {
    case DDI_INFO_DEVT2DEVINFO:
        *resultp = dummy_dip;
        return DDI_SUCCESS;
    case DDI_INFO_DEVT2INSTANCE:
        *resultp = 0;
        return DDI_SUCCESS;
    default:
        return DDI_FAILURE;
    }
}

/* Main entry points */
static int
dummy_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
    int flags, char *name, caddr_t valuep, int *lengthp)
{
    cmn_err(CE_NOTE, "Inside dummy_prop_op");
    return(ddi_prop_op(dev,dip,prop_op,flags,name,valuep,lengthp));
}

static int
dummy_open(dev_t *devp, int flag, int otyp, cred_t *cred)
{
    cmn_err(CE_NOTE, "Inside dummy_open");
    return DDI_SUCCESS;
}

static int
dummy_close(dev_t dev, int flag, int otyp, cred_t *cred)
{
    cmn_err(CE_NOTE, "Inside dummy_close");
    return DDI_SUCCESS;
}

static int
dummy_read(dev_t dev, struct uio *uiop, cred_t *credp)
{
    cmn_err(CE_NOTE, "Inside dummy_read");
    return DDI_SUCCESS;
}

static int
dummy_write(dev_t dev, struct uio *uiop, cred_t *credp)
{
    cmn_err(CE_NOTE, "Inside dummy_write");
    return DDI_SUCCESS;
}