Device Driver Tutorial

Writing the Loadable Module Configuration Entry Points

Every kernel module of any type must define at least the following three loadable module configuration entry points:

The mod_install(9F), mod_info(9F), and mod_remove(9F) functions are used in exactly the same way in every driver, regardless of the functionality of the driver. You do not need to investigate what the values of the arguments of these functions should be. You can copy these function calls from this example and paste them into every driver you write.

In this section, the following code is added to the dummy.c source file:

/* 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));
}

Declaring the Loadable Module Configuration Entry Points

The _init(9E), _info(9E), and _fini(9E) routine names are not unique to any particular kernel module. You customize the behavior of these routines when you define them in your module, but the names of these routines are not unique. These three routines are declared in the modctl.h header file. You need to include the modctl.h header file in your dummy.c file. Do not declare these three routines in dummy.c.

Defining the Module Initialization Entry Point

The _init(9E) routine returns type int and takes no arguments. The _init(9E) routine must call the mod_install(9F) function and return the success or failure value that is returned by mod_install(9F).

The mod_install(9F) function takes an argument that is a modlinkage(9S) structure. See Defining the Module Linkage Structures for information about the modlinkage(9S) structure.

This driver is supposed to write a message each time an entry point is entered. Use the cmn_err(9F) function to write a message to a system log. The cmn_err(9F) function usually is used to report an error condition. The cmn_err(9F) function also is useful for debugging in the same way that you might use print statements in a user program. Be sure to remove cmn_err() calls that are used for development or debugging before you compile your production version driver. You might want to use cmn_err() calls in a production driver to write error messages that would be useful to a system administrator.

The cmn_err(9F) function requires you to include the cmn_err.h header file, the ddi.h header file, and the sunddi.h header file. The cmn_err(9F) function takes two arguments. The first argument is a constant that indicates the severity of the error message. The message written by this driver is not an error message but is simply a test message. Use CE_NOTE for the value of this severity constant. The second argument the cmn_err(9F) function takes is a string message.

The following code is the _init(9E) routine that you should enter into your dummy.c file. The ml structure is the modlinkage(9S) structure that is discussed in Defining the Module Linkage Structures.

int
_init(void)
{
    cmn_err(CE_NOTE, "Inside _init");
    return(mod_install(&ml));
}

Defining the Module Information Entry Point

The _info(9E) routine returns type int and takes an argument that is a pointer to an opaque modinfo structure. The _info(9E) routine must return the value that is returned by the mod_info(9F) function.

The mod_info(9F) function takes two arguments. The first argument to mod_info(9F) is a modlinkage(9S) structure. See Defining the Module Linkage Structures for information about the modlinkage(9S) structure. The second argument to mod_info(9F) is the same modinfo structure pointer that is the argument to the _info(9E) routine. The mod_info(9F) function returns the module information or returns zero if an error occurs.

Use the cmn_err(9F) function to write a message to the system log in the same way that you used the cmn_err(9F) function in your _init(9E) entry point.

The following code is the _info(9E) routine that you should enter into your dummy.c file. The ml structure is discussed in Defining the Module Linkage Structures. The modinfop argument is a pointer to an opaque structure that the system uses to pass module information.

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

Defining the Module Unload Entry Point

The _fini(9E) routine returns type int and takes no arguments. The _fini(9E) routine must call the mod_remove(9F) function and return the success or failure value that is returned by mod_remove(9F).

When mod_remove(9F) is successful, the _fini(9E) routine must undo everything that the _init(9E) routine did. The _fini(9E) routine must call mod_remove(9F) because the _init(9E) routine called mod_install(9F). The _fini(9E) routine must deallocate anything that was allocated, close anything that was opened, and destroy anything that was created in the _init(9E) routine.

The _fini(9E) routine can be called at any time when a module is loaded. In normal operation, the _fini(9E) routine often fails. This behavior is normal because the kernel allows the module to determine whether the module can be unloaded. If mod_remove(9F) is successful, the module determines that devices were detached, and the module can be unloaded. If mod_remove(9F) fails, the module determines that devices were not detached, and the module cannot be unloaded.

The following actions take place when mod_remove(9F) is called:

The mod_remove(9F) function takes an argument that is a modlinkage(9S) structure. See Defining the Module Linkage Structures for information about the modlinkage(9S) structure.

Use the cmn_err(9F) function to write a message to the system log in the same way that you used the cmn_err(9F) function in your _init(9E) entry point.

The following code is the _fini(9E) routine that you should enter into your dummy.c file. The ml structure is discussed in Defining the Module Linkage Structures.

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

Including Loadable Module Configuration Header Files

The _init(9E), _info(9E), _fini(9E), and mod_install(9F) functions require you to include the modctl.h header file. The cmn_err(9F) function requires you to include the cmn_err.h header file, the ddi.h header file, and the sunddi.h header file.

The following header files are required by the three loadable module configuration routines that you have written in this section. Include this code near the top of your dummy.c file.

#include <sys/modctl.h>  /* used by _init, _info, _fini */
#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 */
#include <sys/sunddi.h>  /* used by all entry points for this driver */