Device Driver Tutorial

Writing the User Context Entry Points

User context entry points correspond closely to system calls. When a system call opens a device file, then the open(9E) routine in the driver for that device is called.

All character and block drivers must define the open(9E) user context entry point. However, the open(9E) routine can be nulldev(9F). The close(9E), read(9E), and write(9E) user context routines are optional.

In this section, the following code is added:

/* Use context entry points */
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;
}

Declaring the User Context Entry Points

The user context entry point routines need to be uniquely named for this driver. Use the same prefix for each of the user context entry points that you used for each of the autoconfiguration entry point routines. The following declarations are the entry point declarations you should have in your dummy.c file:

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);

Defining the Open Device Entry Point

The open(9E) routine returns type int. The open(9E) routine should return either DDI_SUCCESS or the appropriate error number.

The open(9E) routine takes four arguments. This dummy driver is so simple that this dummy_open() routine does not use any of the open(9E) arguments. The examples in Chapter 3, Reading and Writing Data in Kernel Memory show the open(9E) routine in more detail.

The following code is the dummy_open() routine that you should enter into your dummy.c file. You can copy the name portion of this function definition directly from the declaration you entered in Declaring the User Context Entry Points. Write a message to the system log and return success.

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

Defining the Close Device Entry Point

The close(9E) routine returns type int. The close(9E) routine should return either DDI_SUCCESS or the appropriate error number.

The close(9E) routine takes four arguments. This dummy driver is so simple that this dummy_close() routine does not use any of the close(9E) arguments. The examples in Chapter 3, Reading and Writing Data in Kernel Memory show the close(9E) routine in more detail.

The close(9E) routine must undo everything that the open(9E) routine did. The close(9E) routine must deallocate anything that was allocated, close anything that was opened, and destroy anything that was created in the open(9E) routine. In this dummy driver, the open(9E) routine is so simple that nothing needs to be reclaimed or undone in the close(9E) routine.

The following code is the dummy_close() routine that you should enter into your dummy.c file. You can copy the name portion of this function definition directly from the declaration you entered in Declaring the User Context Entry Points. Write a message to the system log and return 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;
}

Defining the Read Device Entry Point

The read(9E) routine returns type int. The read(9E) routine should return either DDI_SUCCESS or the appropriate error number.

The read(9E) routine takes three arguments. This dummy driver is so simple that this dummy_read() routine does not use any of the read(9E) arguments. The examples in Chapter 3, Reading and Writing Data in Kernel Memory show the read(9E) routine in more detail.

The following code is the dummy_read() routine that you should enter into your dummy.c file. You can copy the name portion of this function definition directly from the declaration you entered in Declaring the User Context Entry Points. Write a message to the system log and return success.

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

Defining the Write Device Entry Point

The write(9E) routine returns type int. The write(9E) routine should return either DDI_SUCCESS or the appropriate error number.

The write(9E) routine takes three arguments. This dummy driver is so simple that this dummy_write() routine does not use any of the write(9E) arguments. The examples in Chapter 3, Reading and Writing Data in Kernel Memory show the write(9E) routine in more detail.

The following code is the dummy_write() routine that you should enter into your dummy.c file. You can copy the name portion of this function definition directly from the declaration you entered in Declaring the User Context Entry Points. Write a message to the system log and return success.

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

Including User Context Header Files

The four user context entry point routines require your module to include several header files. You already have included the types.h header file, the ddi.h header file, and the sunddi.h header file. You need to include the file.h, errno.h, open.h, cred.h, and uio.h header files.

The following code is the list of header files that you now should have included in your dummy.c file for all the entry points you have written in this section and the previous two sections:

#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 ddi_get_instance and */
                         /* ddi_prop_op */
#include <sys/sunddi.h>  /* used by all entry points for this driver */
                         /* also used by ddi_create_minor_node, */
                         /* ddi_get_instance, and ddi_prop_op */