<?Pub UDT _bookmark _target?><?Pub EntList amp nbsp gt lt ndash hyphen?><?Pub CX solbook(book(title()bookinfo()chapter()?><chapter id="eoqrt"><?Pub Tag atict:info tracking="off" ref="0"?><?Pub Tag
atict:user user="ae149097" fullname="Alta Elstad"?><title>Template Driver Example</title><highlights><para>This chapter shows you how to develop a very simple, working driver.
This chapter explains how to write the driver and configuration file, compile
the driver, load the driver, and test the driver.</para><para><indexterm><primary>devices</primary><secondary>pseudo</secondary></indexterm>The driver that is shown in this chapter is a pseudo device driver
that merely writes a message to a system log every time an entry point is
entered. This driver demonstrates the minimum functionality that any character
driver must implement. You can use this driver as a template for building
a complex driver.</para><itemizedlist><para>This chapter discusses the following driver development steps:</para><listitem><para><olink targetptr="ffzpv" remap="internal">Overview of the Template Driver Example</olink></para>
</listitem><listitem><para><olink targetptr="writedriver" remap="internal">Writing the Template Driver</olink></para>
</listitem><listitem><para><olink targetptr="eoxzw" remap="internal">Writing the Device Configuration
File</olink></para>
</listitem><listitem><para><olink targetptr="eoxzr" remap="internal">Building and Installing the Template
Driver</olink></para>
</listitem><listitem><para><olink targetptr="eoxzu" remap="internal">Testing the Template Driver</olink></para>
</listitem><listitem><para><olink targetptr="eqbof" remap="internal">Complete Template Driver Source</olink></para>
</listitem>
</itemizedlist>
</highlights><sect1 id="ffzpv"><title>Overview of the Template Driver Example</title><orderedlist><para>This example guides you through the following steps:</para><listitem><para>Create a directory where you can develop your driver and open
a new text file named <filename>dummy.c</filename>.</para>
</listitem><listitem><para>Write the entry points for loadable module configuration: <olink targetdoc="group-refman" targetptr="u-init-9e" remap="external"><citerefentry><refentrytitle>_init</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink>, <olink targetdoc="group-refman" targetptr="u-info-9e" remap="external"><citerefentry><refentrytitle>_info</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink>, and <olink targetdoc="group-refman" targetptr="u-fini-9e" remap="external"><citerefentry><refentrytitle>_fini</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink>.</para>
</listitem><listitem><para>Write the entry points for autoconfiguration: <olink targetdoc="group-refman" targetptr="attach-9e" remap="external"><citerefentry><refentrytitle>attach</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink>, <olink targetdoc="group-refman" targetptr="detach-9e" remap="external"><citerefentry><refentrytitle>detach</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink>, <olink targetdoc="group-refman" targetptr="getinfo-9e" remap="external"><citerefentry><refentrytitle>getinfo</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink>, and <olink targetdoc="group-refman" targetptr="prop-op-9e" remap="external"><citerefentry><refentrytitle>prop_op</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink>.</para>
</listitem><listitem><para>Write the entry points for user context: <olink targetdoc="group-refman" targetptr="open-9e" remap="external"><citerefentry><refentrytitle>open</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink>, <olink targetdoc="group-refman" targetptr="close-9e" remap="external"><citerefentry><refentrytitle>close</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink>, <olink targetdoc="group-refman" targetptr="read-9e" remap="external"><citerefentry><refentrytitle>read</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink>, and <olink targetdoc="group-refman" targetptr="write-9e" remap="external"><citerefentry><refentrytitle>write</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink>.</para>
</listitem><listitem><para>Define the data structures: the character and block operations
structure <olink targetdoc="group-refman" targetptr="cb-ops-9s" remap="external"><citerefentry><refentrytitle>cb_ops</refentrytitle><manvolnum>9S</manvolnum></citerefentry></olink>,
the device operations structure <olink targetdoc="group-refman" targetptr="dev-ops-9s" remap="external"><citerefentry><refentrytitle>dev_ops</refentrytitle><manvolnum>9S</manvolnum></citerefentry></olink>, and the module linkage structures <olink targetdoc="group-refman" targetptr="modldrv-9s" remap="external"><citerefentry><refentrytitle>modldrv</refentrytitle><manvolnum>9S</manvolnum></citerefentry></olink> and <olink targetdoc="group-refman" targetptr="modlinkage-9s" remap="external"><citerefentry><refentrytitle>modlinkage</refentrytitle><manvolnum>9S</manvolnum></citerefentry></olink>.</para>
</listitem><listitem><para>Create the driver configuration file <filename>dummy.conf</filename>.</para>
</listitem><listitem><para>Build and install the driver.</para>
</listitem><listitem><para>Test the driver by loading the driver, reading from and writing
to the device node, and unloading the driver.</para>
</listitem>
</orderedlist><para><indexterm><primary>device drivers</primary><secondary>entry points</secondary></indexterm>The entry points that are to be created in this example are shown
in the following diagram.</para><figure id="fgotp"><title>Entry Points for the <literal>dummy</literal> Example</title><mediaobject><imageobject><imagedata entityref="epoints.dummy"/>
</imageobject><textobject><simpara>Diagram shows the entry points that are to be created
in the dummy examples.</simpara>
</textobject>
</mediaobject>
</figure>
</sect1><sect1 id="writedriver"><title>Writing the Template Driver</title><indexterm><primary>devices</primary><secondary>character</secondary>
</indexterm><para>This section describes the entry points and data structures that are
included in this driver and shows you how to define them. All of these data
structures and almost all of these entry points are required for any character
device driver.</para><itemizedlist><para>This section describes the following entry points and data structures:</para><listitem><para>Loadable module configuration entry points</para>
</listitem><listitem><para>Autoconfiguration entry points</para>
</listitem><listitem><para>User context entry points</para>
</listitem><listitem><para>Character and block operations structure</para>
</listitem><listitem><para>Device operations structure</para>
</listitem><listitem><para>Module linkage structures</para>
</listitem>
</itemizedlist><para>First, create a directory where you can develop your driver. This driver
is named  <literal>dummy</literal> because this driver does not do any real
work. Next, open a new text file named <filename>dummy.c</filename>.</para><sect2 id="eoxzy"><title>Writing the Loadable Module Configuration Entry Points</title><indexterm><primary>entry points</primary><secondary>loadable module configuration</secondary>
</indexterm><indexterm><primary>entry points</primary><secondary><function>_init</function></secondary>
</indexterm><indexterm><primary><function>_init</function> entry point</primary>
</indexterm><indexterm><primary>entry points</primary><secondary><function>_info</function></secondary>
</indexterm><indexterm><primary><function>_info</function> entry point</primary>
</indexterm><indexterm><primary>entry points</primary><secondary><function>_fini</function></secondary>
</indexterm><indexterm><primary><function>_fini</function> entry point</primary>
</indexterm><indexterm><primary><function>mod_install</function> kernel function</primary>
</indexterm><indexterm><primary>kernel functions</primary><secondary><function>mod_install</function></secondary>
</indexterm><indexterm><primary><function>mod_info</function> kernel function</primary>
</indexterm><indexterm><primary>kernel functions</primary><secondary><function>mod_info</function></secondary>
</indexterm><indexterm><primary><function>mod_remove</function> kernel function</primary>
</indexterm><indexterm><primary>kernel functions</primary><secondary><function>mod_remove</function></secondary>
</indexterm><itemizedlist><para>Every kernel module of any type must define at least the following three
loadable module configuration entry points:</para><listitem><para>The <olink targetdoc="group-refman" targetptr="u-init-9e" remap="external"><citerefentry><refentrytitle>_init</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink> routine
initializes a loadable module. The <citerefentry><refentrytitle>_init</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine must at least call the <olink targetdoc="group-refman" targetptr="mod-install-9f" remap="external"><citerefentry><refentrytitle>mod_install</refentrytitle><manvolnum>9F</manvolnum></citerefentry></olink> function and return the success or failure value that
is returned by <citerefentry><refentrytitle>mod_install</refentrytitle><manvolnum>9F</manvolnum></citerefentry>.</para>
</listitem><listitem><para>The <olink targetdoc="group-refman" targetptr="u-info-9e" remap="external"><citerefentry><refentrytitle>_info</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink> routine
returns information about a loadable module. The <citerefentry><refentrytitle>_info</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine must at least
call the <olink targetdoc="group-refman" targetptr="mod-info-9f" remap="external"><citerefentry><refentrytitle>mod_info</refentrytitle><manvolnum>9F</manvolnum></citerefentry></olink> function
and return the value that is returned by <citerefentry><refentrytitle>mod_info</refentrytitle><manvolnum>9F</manvolnum></citerefentry>.</para>
</listitem><listitem><para>The <olink targetdoc="group-refman" targetptr="u-fini-9e" remap="external"><citerefentry><refentrytitle>_fini</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink> routine
prepares a loadable module for unloading. The <citerefentry><refentrytitle>_fini</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine must at least call the <olink targetdoc="group-refman" targetptr="mod-remove-9f" remap="external"><citerefentry><refentrytitle>mod_remove</refentrytitle><manvolnum>9F</manvolnum></citerefentry></olink> function
and return the success or failure value that is returned by <citerefentry><refentrytitle>mod_remove</refentrytitle><manvolnum>9F</manvolnum></citerefentry>. When <citerefentry><refentrytitle>mod_remove</refentrytitle><manvolnum>9F</manvolnum></citerefentry> is successful, the <citerefentry><refentrytitle>_fini</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine
must undo everything that the <citerefentry><refentrytitle>_init</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine did.</para>
</listitem>
</itemizedlist><para>The <citerefentry><refentrytitle>mod_install</refentrytitle><manvolnum>9F</manvolnum></citerefentry>, <citerefentry><refentrytitle>mod_info</refentrytitle><manvolnum>9F</manvolnum></citerefentry>, and <citerefentry><refentrytitle>mod_remove</refentrytitle><manvolnum>9F</manvolnum></citerefentry> 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.</para><para>In this section, the following code is added to the <filename>dummy.c</filename> source
file:</para><programlisting>/* Loadable module configuration entry points */
int
_init(void)
{
    cmn_err(CE_NOTE, "Inside _init");
    return(mod_install(&amp;ml));
}

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

int
_fini(void)
{
    cmn_err(CE_NOTE, "Inside _fini");
    return(mod_remove(&amp;ml));
}</programlisting><sect3 id="epmnj"><title>Declaring the Loadable Module Configuration Entry
Points</title><para>The <citerefentry><refentrytitle>_init</refentrytitle><manvolnum>9E</manvolnum></citerefentry>, <citerefentry><refentrytitle>_info</refentrytitle><manvolnum>9E</manvolnum></citerefentry>, and <citerefentry><refentrytitle>_fini</refentrytitle><manvolnum>9E</manvolnum></citerefentry> 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 <filename>modctl.h</filename> header
file. You need to include the <filename>modctl.h</filename> header file in
your <filename>dummy.c</filename> file. Do not declare these three routines
in <filename>dummy.c</filename>.</para>
</sect3><sect3 id="epmnk"><title>Defining the Module Initialization Entry Point</title><indexterm><primary>entry points</primary><secondary><function>_init</function></secondary>
</indexterm><indexterm><primary><function>_init</function> entry point</primary>
</indexterm><indexterm><primary><function>mod_install</function> kernel function</primary>
</indexterm><indexterm><primary>kernel functions</primary><secondary><function>mod_install</function></secondary>
</indexterm><indexterm><primary><literal>modlinkage</literal> driver structure</primary>
</indexterm><indexterm><primary>driver structures</primary><secondary><literal>modlinkage</literal></secondary>
</indexterm><indexterm><primary><function>cmn_err</function> kernel function</primary>
</indexterm><indexterm><primary>kernel functions</primary><secondary><function>cmn_err</function></secondary>
</indexterm><para>The <olink targetdoc="group-refman" targetptr="u-init-9e" remap="external"><citerefentry><refentrytitle>_init</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink> routine
returns type <literal>int</literal> and takes no arguments. The <citerefentry><refentrytitle>_init</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine
must call the <olink targetdoc="group-refman" targetptr="mod-install-9f" remap="external"><citerefentry><refentrytitle>mod_install</refentrytitle><manvolnum>9F</manvolnum></citerefentry></olink> function and return the success or failure value that
is returned by <citerefentry><refentrytitle>mod_install</refentrytitle><manvolnum>9F</manvolnum></citerefentry>.</para><para>The <citerefentry><refentrytitle>mod_install</refentrytitle><manvolnum>9F</manvolnum></citerefentry> function takes an argument that is a <citerefentry><refentrytitle>modlinkage</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure. See <olink targetptr="epffy" remap="internal">Defining the Module
Linkage Structures</olink> for information about the <citerefentry><refentrytitle>modlinkage</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure.</para><para>This driver is supposed to write a message each time an entry point
is entered. Use the <olink targetdoc="group-refman" targetptr="cmn-err-9f" remap="external"><citerefentry><refentrytitle>cmn_err</refentrytitle><manvolnum>9F</manvolnum></citerefentry></olink> function
to write a message to a system log. The <citerefentry><refentrytitle>cmn_err</refentrytitle><manvolnum>9F</manvolnum></citerefentry> function usually is used to report
an error condition. The <citerefentry><refentrytitle>cmn_err</refentrytitle><manvolnum>9F</manvolnum></citerefentry> function also is useful for debugging
in the same way that you might use print statements in a user program. Be
sure to remove <function>cmn_err</function> calls that are used for development
or debugging before you compile your production version driver. You might
want to use <function>cmn_err</function> calls in a production driver to write
error messages that would be useful to a system administrator.</para><para>The <citerefentry><refentrytitle>cmn_err</refentrytitle><manvolnum>9F</manvolnum></citerefentry> function requires you to include the <filename>cmn_err.h</filename> header
file, the <filename>ddi.h</filename> header file, and the <filename>sunddi.h</filename> header
file. The <citerefentry><refentrytitle>cmn_err</refentrytitle><manvolnum>9F</manvolnum></citerefentry> 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 <literal>CE_NOTE</literal> for the value of this severity constant. The second argument the <citerefentry><refentrytitle>cmn_err</refentrytitle><manvolnum>9F</manvolnum></citerefentry> function
takes is a string message.</para><para>The following code is the <citerefentry><refentrytitle>_init</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine that you should enter into
your <filename>dummy.c</filename> file. The <literal>ml</literal> structure
is the <citerefentry><refentrytitle>modlinkage</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure that is discussed in <olink targetptr="epffy" remap="internal">Defining
the Module Linkage Structures</olink>.</para><programlisting>int
_init(void)
{
    cmn_err(CE_NOTE, "Inside _init");
    return(mod_install(&amp;ml));
}</programlisting>
</sect3><sect3 id="epmnm"><title>Defining the Module Information Entry Point</title><indexterm><primary>entry points</primary><secondary><function>_info</function></secondary>
</indexterm><indexterm><primary><function>_info</function> entry point</primary>
</indexterm><indexterm><primary><function>mod_info</function> kernel function</primary>
</indexterm><indexterm><primary>kernel functions</primary><secondary><function>mod_info</function></secondary>
</indexterm><indexterm><primary><literal>modinfo</literal> driver structure</primary>
</indexterm><indexterm><primary>driver structures</primary><secondary><literal>modinfo</literal></secondary>
</indexterm><para>The <olink targetdoc="group-refman" targetptr="u-info-9e" remap="external"><citerefentry><refentrytitle>_info</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink> routine
returns type <literal>int</literal> and takes an argument that is a pointer
to an opaque <literal>modinfo</literal> structure. The <citerefentry><refentrytitle>_info</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine
must return the value that is returned by the <olink targetdoc="group-refman" targetptr="mod-info-9f" remap="external"><citerefentry><refentrytitle>mod_info</refentrytitle><manvolnum>9F</manvolnum></citerefentry></olink> function.</para><para>The <citerefentry><refentrytitle>mod_info</refentrytitle><manvolnum>9F</manvolnum></citerefentry> function takes two arguments. The first argument to <citerefentry><refentrytitle>mod_info</refentrytitle><manvolnum>9F</manvolnum></citerefentry> is
a <citerefentry><refentrytitle>modlinkage</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure. See <olink targetptr="epffy" remap="internal">Defining the Module
Linkage Structures</olink> for information about the <citerefentry><refentrytitle>modlinkage</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure. The second argument to <citerefentry><refentrytitle>mod_info</refentrytitle><manvolnum>9F</manvolnum></citerefentry> is the same <literal>modinfo</literal> structure pointer that is the argument to the <citerefentry><refentrytitle>_info</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine.
The <citerefentry><refentrytitle>mod_info</refentrytitle><manvolnum>9F</manvolnum></citerefentry> function returns the module information or returns zero if
an error occurs.</para><para>Use the <olink targetdoc="group-refman" targetptr="cmn-err-9f" remap="external"><citerefentry><refentrytitle>cmn_err</refentrytitle><manvolnum>9F</manvolnum></citerefentry></olink> function
to write a message to the system log in the same way that you used the <citerefentry><refentrytitle>cmn_err</refentrytitle><manvolnum>9F</manvolnum></citerefentry> function
in your <citerefentry><refentrytitle>_init</refentrytitle><manvolnum>9E</manvolnum></citerefentry> entry point.</para><para>The following code is the <citerefentry><refentrytitle>_info</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine that you should enter into
your <filename>dummy.c</filename> file. The <literal>ml</literal> structure
is discussed in <olink targetptr="epffy" remap="internal">Defining the Module Linkage Structures</olink>.
The <literal>modinfop</literal> argument is a pointer to an opaque structure
that the system uses to pass module information.</para><programlisting>int
_info(struct modinfo *modinfop)
{
    cmn_err(CE_NOTE, "Inside _info");
    return(mod_info(&amp;ml, modinfop));
}</programlisting>
</sect3><sect3 id="epmnn"><title>Defining the Module Unload Entry Point</title><indexterm><primary>entry points</primary><secondary><function>_fini</function></secondary>
</indexterm><indexterm><primary><function>_fini</function> entry point</primary>
</indexterm><indexterm><primary><function>mod_remove</function> kernel function</primary>
</indexterm><indexterm><primary>kernel functions</primary><secondary><function>mod_remove</function></secondary>
</indexterm><para>The <olink targetdoc="group-refman" targetptr="u-fini-9e" remap="external"><citerefentry><refentrytitle>_fini</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink> routine
returns type <literal>int</literal> and takes no arguments. The <citerefentry><refentrytitle>_fini</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine
must  call the <olink targetdoc="group-refman" targetptr="mod-remove-9f" remap="external"><citerefentry><refentrytitle>mod_remove</refentrytitle><manvolnum>9F</manvolnum></citerefentry></olink> function and return the success or failure value that
is returned by <citerefentry><refentrytitle>mod_remove</refentrytitle><manvolnum>9F</manvolnum></citerefentry>.</para><para>When <citerefentry><refentrytitle>mod_remove</refentrytitle><manvolnum>9F</manvolnum></citerefentry> is successful, the <citerefentry><refentrytitle>_fini</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine must undo everything that
the <citerefentry><refentrytitle>_init</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine did. The <citerefentry><refentrytitle>_fini</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine must call <citerefentry><refentrytitle>mod_remove</refentrytitle><manvolnum>9F</manvolnum></citerefentry> because the <citerefentry><refentrytitle>_init</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine called <citerefentry><refentrytitle>mod_install</refentrytitle><manvolnum>9F</manvolnum></citerefentry>. The <citerefentry><refentrytitle>_fini</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine must deallocate anything
that was allocated, close anything that was opened, and destroy anything that
was created in the <citerefentry><refentrytitle>_init</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine.</para><para>The <citerefentry><refentrytitle>_fini</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine can be called at any time when a module is loaded.
In normal operation, the <citerefentry><refentrytitle>_fini</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine often fails. This behavior
is normal because the kernel allows the module to determine whether the module
can be unloaded. If <citerefentry><refentrytitle>mod_remove</refentrytitle><manvolnum>9F</manvolnum></citerefentry> is successful, the module determines
that devices were detached, and the module can be unloaded. If <citerefentry><refentrytitle>mod_remove</refentrytitle><manvolnum>9F</manvolnum></citerefentry> fails, the module determines that devices were not detached,
and the module cannot be unloaded.</para><itemizedlist><para>The following actions take place when <citerefentry><refentrytitle>mod_remove</refentrytitle><manvolnum>9F</manvolnum></citerefentry> is called:</para><listitem><itemizedlist><para>The kernel checks whether this driver is busy. This driver is busy if
one of the following conditions is true:</para><listitem><para>A device node that is managed by this driver is open.</para>
</listitem><listitem><para><indexterm><primary>linking</primary></indexterm><indexterm><primary>commands</primary><secondary><command>ld</command></secondary></indexterm><indexterm><primary><command>ld</command> command</primary></indexterm>Another module that depends on this driver is open. A module depends
on this driver if the module was linked using the <option>N</option> option
with this driver named as the argument to that <option>N</option> option.
See the <olink targetdoc="group-refman" targetptr="ld-1" remap="external"><citerefentry><refentrytitle>ld</refentrytitle><manvolnum>1</manvolnum></citerefentry></olink> man
page for more information.</para>
</listitem>
</itemizedlist>
</listitem><listitem><para>If the driver is busy, then <citerefentry><refentrytitle>mod_remove</refentrytitle><manvolnum>9F</manvolnum></citerefentry> fails and <citerefentry><refentrytitle>_fini</refentrytitle><manvolnum>9E</manvolnum></citerefentry> fails.</para>
</listitem><listitem><para><indexterm><primary>entry points</primary><secondary><function>detach</function></secondary></indexterm><indexterm><primary><function>detach</function> entry point</primary></indexterm>If the driver is not busy, then the kernel calls
the <olink targetdoc="group-refman" targetptr="detach-9e" remap="external"><citerefentry><refentrytitle>detach</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink> entry
point of the driver.</para><itemizedlist><listitem><para>If <citerefentry><refentrytitle>detach</refentrytitle><manvolnum>9E</manvolnum></citerefentry> fails, then <citerefentry><refentrytitle>mod_remove</refentrytitle><manvolnum>9F</manvolnum></citerefentry> fails and <citerefentry><refentrytitle>_fini</refentrytitle><manvolnum>9E</manvolnum></citerefentry> fails.</para>
</listitem><listitem><para>If <citerefentry><refentrytitle>detach</refentrytitle><manvolnum>9E</manvolnum></citerefentry> succeeds, then <citerefentry><refentrytitle>mod_remove</refentrytitle><manvolnum>9F</manvolnum></citerefentry> succeeds, and <citerefentry><refentrytitle>_fini</refentrytitle><manvolnum>9E</manvolnum></citerefentry> continues its cleanup work.</para>
</listitem>
</itemizedlist>
</listitem>
</itemizedlist><para>The <citerefentry><refentrytitle>mod_remove</refentrytitle><manvolnum>9F</manvolnum></citerefentry> function takes an argument that is a <citerefentry><refentrytitle>modlinkage</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure. See <olink targetptr="epffy" remap="internal">Defining the Module
Linkage Structures</olink> for information about the <citerefentry><refentrytitle>modlinkage</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure.</para><para>Use the <olink targetdoc="group-refman" targetptr="cmn-err-9f" remap="external"><citerefentry><refentrytitle>cmn_err</refentrytitle><manvolnum>9F</manvolnum></citerefentry></olink> function
to write a message to the system log in the same way that you used the <citerefentry><refentrytitle>cmn_err</refentrytitle><manvolnum>9F</manvolnum></citerefentry> function
in your <citerefentry><refentrytitle>_init</refentrytitle><manvolnum>9E</manvolnum></citerefentry> entry point.</para><para>The following code is the <citerefentry><refentrytitle>_fini</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine that you should enter into
your <filename>dummy.c</filename> file. The <literal>ml</literal> structure
is discussed in <olink targetptr="epffy" remap="internal">Defining the Module Linkage Structures</olink>.</para><programlisting>int
_fini(void)
{
    cmn_err(CE_NOTE, "Inside _fini");
    return(mod_remove(&amp;ml));
}</programlisting>
</sect3><sect3 id="epmnl"><title>Including Loadable Module Configuration Header Files</title><para>The <olink targetdoc="group-refman" targetptr="u-init-9e" remap="external"><citerefentry><refentrytitle>_init</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink>, <citerefentry><refentrytitle>_info</refentrytitle><manvolnum>9E</manvolnum></citerefentry>, <citerefentry><refentrytitle>_fini</refentrytitle><manvolnum>9E</manvolnum></citerefentry>,
and <olink targetdoc="group-refman" targetptr="mod-install-9f" remap="external"><citerefentry><refentrytitle>mod_install</refentrytitle><manvolnum>9F</manvolnum></citerefentry></olink> functions require you to include the <literal>modctl.h</literal> header
file. The <olink targetdoc="group-refman" targetptr="cmn-err-9f" remap="external"><citerefentry><refentrytitle>cmn_err</refentrytitle><manvolnum>9F</manvolnum></citerefentry></olink> function
requires you to include the <literal>cmn_err.h</literal> header file, the <literal>ddi.h</literal> header file, and the <literal>sunddi.h</literal> header file.</para><para>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 <filename>dummy.c</filename> file.</para><programlisting>#include &lt;sys/modctl.h&gt;  /* used by _init, _info, _fini */
#include &lt;sys/cmn_err.h&gt; /* used by all entry points for this driver */
#include &lt;sys/ddi.h&gt;     /* used by all entry points for this driver */
#include &lt;sys/sunddi.h&gt;  /* used by all entry points for this driver */</programlisting>
</sect3>
</sect2><sect2 id="epmnh"><title>Writing the Autoconfiguration Entry Points</title><indexterm><primary>entry points</primary><secondary>autoconfiguration</secondary>
</indexterm><indexterm><primary>entry points</primary><secondary><function>attach</function></secondary>
</indexterm><indexterm><primary><function>attach</function> entry point</primary>
</indexterm><indexterm><primary><function>ddi_create_minor_node</function> kernel function</primary>
</indexterm><indexterm><primary>kernel functions</primary><secondary><function>ddi_create_minor_node</function></secondary>
</indexterm><indexterm><primary>entry points</primary><secondary><function>detach</function></secondary>
</indexterm><indexterm><primary><function>detach</function> entry point</primary>
</indexterm><indexterm><primary><function>ddi_remove_minor_node</function> kernel function</primary>
</indexterm><indexterm><primary>kernel functions</primary><secondary><function>ddi_remove_minor_node</function></secondary>
</indexterm><indexterm><primary>entry points</primary><secondary><function>getinfo</function></secondary>
</indexterm><indexterm><primary><function>getinfo</function> entry point</primary>
</indexterm><indexterm><primary>entry points</primary><secondary><function>prop_op</function></secondary>
</indexterm><indexterm><primary><function>prop_op</function> entry point</primary>
</indexterm><indexterm><primary><function>ddi_prop_op</function> kernel function</primary>
</indexterm><indexterm><primary>kernel functions</primary><secondary><function>ddi_prop_op</function></secondary>
</indexterm><itemizedlist><para>Every character driver must define at least the following autoconfiguration
entry points. The kernel calls these routines when the device driver is loaded.</para><listitem><para>The <olink targetdoc="group-refman" targetptr="attach-9e" remap="external"><citerefentry><refentrytitle>attach</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink> routine
must call <olink targetdoc="group-refman" targetptr="ddi-create-minor-node-9f" remap="external"><citerefentry><refentrytitle>ddi_create_minor_node</refentrytitle><manvolnum>9F</manvolnum></citerefentry></olink>. The <citerefentry><refentrytitle>ddi_create_minor_node</refentrytitle><manvolnum>9F</manvolnum></citerefentry> function provides the information
the system needs to create the device files.</para>
</listitem><listitem><para>The <olink targetdoc="group-refman" targetptr="detach-9e" remap="external"><citerefentry><refentrytitle>detach</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink> routine
must call <olink targetdoc="group-refman" targetptr="ddi-remove-minor-node-9f" remap="external"><citerefentry><refentrytitle>ddi_remove_minor_node</refentrytitle><manvolnum>9F</manvolnum></citerefentry></olink> to deallocate everything that was allocated by <citerefentry><refentrytitle>ddi_create_minor_node</refentrytitle><manvolnum>9F</manvolnum></citerefentry>. The <citerefentry><refentrytitle>detach</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine must undo everything that
the <citerefentry><refentrytitle>attach</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine did.</para>
</listitem><listitem><para>The <olink targetdoc="group-refman" targetptr="getinfo-9e" remap="external"><citerefentry><refentrytitle>getinfo</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink> routine
returns requested device driver information through one of its arguments.</para>
</listitem><listitem><para>The <olink targetdoc="group-refman" targetptr="prop-op-9e" remap="external"><citerefentry><refentrytitle>prop_op</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink> routine
returns requested device driver property information through a pointer. You
can call the <olink targetdoc="group-refman" targetptr="ddi-prop-op-9f" remap="external"><citerefentry><refentrytitle>ddi_prop_op</refentrytitle><manvolnum>9F</manvolnum></citerefentry></olink> function instead of writing your own <citerefentry><refentrytitle>prop_op</refentrytitle><manvolnum>9E</manvolnum></citerefentry> entry
point. Use the <citerefentry><refentrytitle>prop_op</refentrytitle><manvolnum>9E</manvolnum></citerefentry> entry point to customize the behavior of the <citerefentry><refentrytitle>ddi_prop_op</refentrytitle><manvolnum>9F</manvolnum></citerefentry> function.</para>
</listitem>
</itemizedlist><para>In this section, the following code is added:</para><programlisting><?Pub _bookmark Command="[Quick Mark]"?>/* Device autoconfiguration 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;
    }
}

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));
}</programlisting><sect3 id="epmqa"><title>Declaring the Autoconfiguration Entry Points</title><para>The <citerefentry><refentrytitle>attach</refentrytitle><manvolnum>9E</manvolnum></citerefentry>, <citerefentry><refentrytitle>detach</refentrytitle><manvolnum>9E</manvolnum></citerefentry>, <citerefentry><refentrytitle>getinfo</refentrytitle><manvolnum>9E</manvolnum></citerefentry>, and <citerefentry><refentrytitle>prop_op</refentrytitle><manvolnum>9E</manvolnum></citerefentry> entry point routines
need to be uniquely named for this driver. Choose a prefix to use with each
entry point routine.</para><note><para><indexterm><primary>prefixes</primary></indexterm><indexterm><primary>devices</primary><secondary>prefixes</secondary></indexterm>By convention,
the prefix used for function and data names that are unique to this driver
is either the name of this driver or an abbreviation of the name of this driver.
Use the same prefix throughout the driver. This practice makes debugging much
easier.</para>
</note><para>In the example shown in this chapter, <literal>dummy_</literal> is used
for the prefix to each function and data name that is unique to this example.</para><para>The following declarations are the autoconfiguration entry point declarations
you should have in your <filename>dummy.c</filename> file. Note that each
of these functions is declared <literal>static</literal>.</para><programlisting>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);</programlisting>
</sect3><sect3 id="epmqc"><title>Defining the Device Attach Entry Point</title><indexterm><primary>entry points</primary><secondary><function>attach</function></secondary>
</indexterm><indexterm><primary><function>attach</function> entry point</primary>
</indexterm><indexterm><primary><function>ddi_soft_state</function> kernel function</primary>
</indexterm><indexterm><primary>kernel functions</primary><secondary><function>ddi_soft_state</function></secondary>
</indexterm><para>The <olink targetdoc="group-refman" targetptr="attach-9e" remap="external"><citerefentry><refentrytitle>attach</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink> routine
returns type <literal>int</literal>. The <citerefentry><refentrytitle>attach</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine must return either <literal>DDI_SUCCESS</literal> or <literal>DDI_FAILURE</literal>. These two constants are defined
in <filename>sunddi.h</filename>. All of the autoconfiguration entry point
routines except for <citerefentry><refentrytitle>prop_op</refentrytitle><manvolnum>9E</manvolnum></citerefentry> return either <literal>DDI_SUCCESS</literal> or <literal>DDI_FAILURE</literal>.</para><para>The <citerefentry><refentrytitle>attach</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine takes two arguments. The first argument is a pointer
to the <literal>dev_info</literal> structure for this driver. All of the autoconfiguration
entry point routines take a <literal>dev_info</literal> argument. The second
argument is a constant that specifies the attach type. The value that is passed
through this second argument is either <literal>DDI_ATTACH</literal> or <literal>DDI_RESUME</literal>. Every <citerefentry><refentrytitle>attach</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine must define behavior for
at least <literal>DDI_ATTACH</literal>.</para><para>The <literal>DDI_ATTACH</literal> code must initialize a device instance.
In a realistic driver, you define and manage multiple instances of the driver
by using a state structure and the <olink targetdoc="group-refman" targetptr="ddi-soft-state-9f" remap="external"><citerefentry><refentrytitle>ddi_soft_state</refentrytitle><manvolnum>9F</manvolnum></citerefentry></olink> functions. Each instance
of the driver has its own copy of the state structure that holds data specific
to that instance. One of the pieces of data that is specific to each instance
is the device instance pointer. Each instance of the device driver is represented
by a separate device file in <filename>/devices</filename>. Each device instance
file is pointed to by a separate device instance pointer. See <olink targetptr="fcowf" remap="internal">Managing Device State</olink> for information about state
structures and <citerefentry><refentrytitle>ddi_soft_state</refentrytitle><manvolnum>9F</manvolnum></citerefentry> functions. See <olink targetptr="fgomr" remap="internal">Devices as Files</olink> for information about device files and instances.</para><para>This <literal>dummy</literal> driver allows only one instance. Because
this driver allows only one instance, this driver does not use a state structure.
This driver still must declare a device instance pointer and initialize the
pointer value in the <citerefentry><refentrytitle>attach</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine. Enter the following code
near the beginning of <filename>dummy.c</filename> to declare a device instance
pointer for this driver:</para><programlisting>dev_info_t *dummy_dip;  /* keep track of one instance */</programlisting><para>The following code is the <function>dummy_attach</function> routine
that you should enter into your <filename>dummy.c</filename> file. You can
copy the name portion of this function definition directly from the declaration
you entered in <olink targetptr="epmqa" remap="internal">Declaring the Autoconfiguration Entry
Points</olink>.</para><programlisting>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;
    }
}</programlisting><para><indexterm><primary><function>ddi_get_instance</function> kernel function</primary></indexterm><indexterm><primary>kernel functions</primary><secondary><function>ddi_get_instance</function></secondary></indexterm><indexterm><primary><function>ddi_create_minor_node</function> kernel function</primary></indexterm><indexterm><primary>kernel functions</primary><secondary><function>ddi_create_minor_node</function></secondary></indexterm><indexterm><primary>device instance pointer (dip)</primary></indexterm><indexterm><primary><literal>dev_info</literal> device structure</primary></indexterm><indexterm><primary>device structures</primary><secondary><literal>dev_info</literal></secondary></indexterm><indexterm><primary>devices</primary><secondary>numbers</secondary></indexterm><indexterm><primary>minor number</primary></indexterm><indexterm><primary>instance number</primary></indexterm><indexterm><primary>devices</primary><secondary>instances</secondary></indexterm>First,
use <citerefentry><refentrytitle>cmn_err</refentrytitle><manvolnum>9F</manvolnum></citerefentry> to write a message to the system log, as you did in your <citerefentry><refentrytitle>_init</refentrytitle><manvolnum>9E</manvolnum></citerefentry> entry
point. Then provide <literal>DDI_ATTACH</literal> behavior. Within the <literal>DDI_ATTACH</literal> code, first assign the device instance pointer from the <function>dummy_attach</function> argument to the <literal>dummy_dip</literal> variable that you
declared above. You need to save this pointer value in the global variable
so that you can use this pointer to get information about this instance from <function>dummy_getinfo</function> and detach this instance in <function>dummy_detach</function>.
In this <function>dummy_attach</function> routine, the device instance pointer
is used by the <olink targetdoc="group-refman" targetptr="ddi-get-instance-9f" remap="external"><citerefentry><refentrytitle>ddi_get_instance</refentrytitle><manvolnum>9F</manvolnum></citerefentry></olink> function to return the instance number. The device
instance pointer and the instance number both are used by <olink targetdoc="group-refman" targetptr="ddi-create-minor-node-9f" remap="external"><citerefentry><refentrytitle>ddi_create_minor_node</refentrytitle><manvolnum>9F</manvolnum></citerefentry></olink> to create a new device node.</para><para>A realistic driver probably would use the <citerefentry><refentrytitle>ddi_soft_state</refentrytitle><manvolnum>9F</manvolnum></citerefentry> functions to create
and manage a device node. This <literal>dummy</literal> driver uses the <citerefentry><refentrytitle>ddi_create_minor_node</refentrytitle><manvolnum>9F</manvolnum></citerefentry> function to create a device node. The <citerefentry><refentrytitle>ddi_create_minor_node</refentrytitle><manvolnum>9F</manvolnum></citerefentry> function takes six arguments. The first argument to the <citerefentry><refentrytitle>ddi_create_minor_node</refentrytitle><manvolnum>9F</manvolnum></citerefentry> function is the device instance pointer that points to the <literal>dev_info</literal> structure of this device. The second argument is the name
of this minor node. The third argument is <literal>S_IFCHR</literal> if this
device is a character minor device or is <literal>S_IFBLK</literal> if this
device is a block minor device. This <literal>dummy</literal> driver is a
character driver.</para><para>The fourth argument to the <citerefentry><refentrytitle>ddi_create_minor_node</refentrytitle><manvolnum>9F</manvolnum></citerefentry> function is the minor
number of this minor device. This number is also called the instance number.
The <citerefentry><refentrytitle>ddi_get_instance</refentrytitle><manvolnum>9F</manvolnum></citerefentry> function returns this instance number. The fifth argument
to the <citerefentry><refentrytitle>ddi_create_minor_node</refentrytitle><manvolnum>9F</manvolnum></citerefentry> function is the node type. The <citerefentry><refentrytitle>ddi_create_minor_node</refentrytitle><manvolnum>9F</manvolnum></citerefentry> man page lists the possible node types. The <literal>DDI_PSEUDO</literal> node
type is for pseudo devices. The sixth argument to the <citerefentry><refentrytitle>ddi_create_minor_node</refentrytitle><manvolnum>9F</manvolnum></citerefentry> function specifies whether this is a clone device. This is
not a clone device, so set this argument value to 0.</para><para>If the <citerefentry><refentrytitle>ddi_create_minor_node</refentrytitle><manvolnum>9F</manvolnum></citerefentry> call is not successful, write a message
to the system log and return <literal>DDI_FAILURE</literal>. If the <citerefentry><refentrytitle>ddi_create_minor_node</refentrytitle><manvolnum>9F</manvolnum></citerefentry> call is successful, return <literal>DDI_SUCCESS</literal>.
If this <function>dummy_attach</function> routine receives any <literal>cmd</literal> other
than <literal>DDI_ATTACH</literal>, return <literal>DDI_FAILURE</literal>.</para>
</sect3><sect3 id="epmqi"><title>Defining the Device Detach Entry Point</title><indexterm><primary>entry points</primary><secondary><function>detach</function></secondary>
</indexterm><indexterm><primary><function>detach</function> entry point</primary>
</indexterm><indexterm><primary><function>ddi_remove_minor_node</function> kernel function</primary>
</indexterm><indexterm><primary>kernel functions</primary><secondary><function>ddi_remove_minor_node</function></secondary>
</indexterm><indexterm><primary>device instance pointer (dip)</primary>
</indexterm><indexterm><primary><literal>dev_info</literal> device structure</primary>
</indexterm><indexterm><primary>device structures</primary><secondary><literal>dev_info</literal></secondary>
</indexterm><indexterm><primary>instance number</primary>
</indexterm><indexterm><primary>devices</primary><secondary>instances</secondary>
</indexterm><para>The <olink targetdoc="group-refman" targetptr="detach-9e" remap="external"><citerefentry><refentrytitle>detach</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink> routine
takes two arguments. The first argument is a pointer to the <literal>dev_info</literal> structure
for this driver. The second argument is a constant that specifies the detach
type. The value that is passed through this second argument is either <literal>DDI_DETACH</literal> or <literal>DDI_SUSPEND</literal>. Every <citerefentry><refentrytitle>detach</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine
must define behavior for at least <literal>DDI_DETACH</literal>.</para><para>The <literal>DDI_DETACH</literal> code must undo everything that the <literal>DDI_ATTACH</literal> code did. In the <literal>DDI_ATTACH</literal> code in
your <citerefentry><refentrytitle>attach</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine, you saved the address of a new <literal>dev_info</literal> structure
and you called the <citerefentry><refentrytitle>ddi_create_minor_node</refentrytitle><manvolnum>9F</manvolnum></citerefentry> function to create a new node. In
the <literal>DDI_DETACH</literal> code in this <citerefentry><refentrytitle>detach</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine, you need
to reset the variable that pointed to the <literal>dev_info</literal> structure
for this node. You also need to call the <olink targetdoc="group-refman" targetptr="ddi-remove-minor-node-9f" remap="external"><citerefentry><refentrytitle>ddi_remove_minor_node</refentrytitle><manvolnum>9F</manvolnum></citerefentry></olink> function
to remove this node. The <citerefentry><refentrytitle>detach</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine must deallocate anything
that was allocated, close anything that was opened, and destroy anything that
was created in the <citerefentry><refentrytitle>attach</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine.</para><para>The following code is the <function>dummy_detach</function> routine
that you should enter into your <filename>dummy.c</filename> file. You can
copy the name portion of this function definition directly from the declaration
you entered in <olink targetptr="epmqa" remap="internal">Declaring the Autoconfiguration Entry
Points</olink>.</para><programlisting>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;
    }
}</programlisting><para>First, use <citerefentry><refentrytitle>cmn_err</refentrytitle><manvolnum>9F</manvolnum></citerefentry> to write a message to the system log, as you did
in your <citerefentry><refentrytitle>_init</refentrytitle><manvolnum>9E</manvolnum></citerefentry> entry point. Then provide <literal>DDI_DETACH</literal> behavior.
Within the <literal>DDI_DETACH</literal> code, first reset the <literal>dummy_dip</literal> variable that you set in <function>dummy_attach</function> above.
You cannot reset this device instance pointer unless you remove all instances
of the device. This <literal>dummy</literal> driver supports only one instance.</para><para>Next, call the <citerefentry><refentrytitle>ddi_remove_minor_node</refentrytitle><manvolnum>9F</manvolnum></citerefentry> function to remove this device node.
The <citerefentry><refentrytitle>ddi_remove_minor_node</refentrytitle><manvolnum>9F</manvolnum></citerefentry> function takes two arguments. The
first argument is the device instance pointer that points to the <literal>dev_info</literal> structure of this device. The second argument is the name of the
minor node you want to remove. If the value of the minor node argument is <literal>NULL</literal>, then <citerefentry><refentrytitle>ddi_remove_minor_node</refentrytitle><manvolnum>9F</manvolnum></citerefentry> removes all instances of this device.
Because the <literal>DDI_DETACH</literal> code of this driver always removes
all instances, this <literal>dummy</literal> driver supports only one instance.</para><para>If the value of the <literal>cmd</literal> argument to this <function>dummy_detach</function> routine is <literal>DDI_DETACH</literal>, remove all instances
of this device and return <literal>DDI_SUCCESS</literal>. If this <function>dummy_detach</function> routine receives any <literal>cmd</literal> other than <literal>DDI_DETACH</literal>, return <literal>DDI_FAILURE</literal>.</para>
</sect3><sect3 id="epmql"><title>Defining the Get Driver Information Entry Point</title><indexterm><primary>entry points</primary><secondary><function>getinfo</function></secondary>
</indexterm><indexterm><primary><function>getinfo</function> entry point</primary>
</indexterm><indexterm><primary>device instance pointer (dip)</primary>
</indexterm><indexterm><primary><literal>dev_info</literal> device structure</primary>
</indexterm><indexterm><primary>device structures</primary><secondary><literal>dev_info</literal></secondary>
</indexterm><indexterm><primary>instance number</primary>
</indexterm><indexterm><primary>devices</primary><secondary>instances</secondary>
</indexterm><para>The <olink targetdoc="group-refman" targetptr="getinfo-9e" remap="external"><citerefentry><refentrytitle>getinfo</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink> routine
takes a pointer to a device number and returns a pointer to a device information
structure or returns a device instance number. The return value of the <citerefentry><refentrytitle>getinfo</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine
is <literal>DDI_SUCCESS</literal> or <literal>DDI_FAILURE</literal>. The pointer
or instance number requested from the <citerefentry><refentrytitle>getinfo</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine is returned through a pointer
argument.</para><para>The <citerefentry><refentrytitle>getinfo</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine takes four arguments. The first argument is a pointer
to the <literal>dev_info</literal> structure for this driver. This <literal>dev_info</literal> structure argument is obsolete and is no longer used by the <citerefentry><refentrytitle>getinfo</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine.</para><para>The second argument to the <citerefentry><refentrytitle>getinfo</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine is a constant that specifies
what information the <citerefentry><refentrytitle>getinfo</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine must return. The value of
this second argument is either <literal>DDI_INFO_DEVT2DEVINFO</literal> or <literal>DDI_INFO_DEVT2INSTANCE</literal>. The third argument to the <citerefentry><refentrytitle>getinfo</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine
is a pointer to a device number. The fourth argument is a pointer to the place
where the <citerefentry><refentrytitle>getinfo</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine must store the requested information. The information
stored at this location depends on the value you passed in the second argument
to the <citerefentry><refentrytitle>getinfo</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine.</para><para>The following table describes the relationship between the second and
fourth arguments to the <citerefentry><refentrytitle>getinfo</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine.</para><table frame="topbot" id="eqbiy"><title>Get Driver Information Entry Point
Arguments</title><tgroup cols="3" colsep="0" rowsep="0"><colspec colwidth="30*"/><colspec colwidth="25*"/><colspec colwidth="45*"/><thead><row rowsep="1"><entry><para><replaceable>cmd</replaceable></para>
</entry><entry><para><replaceable>arg</replaceable></para>
</entry><entry><para><replaceable>resultp</replaceable></para>
</entry>
</row>
</thead><tbody><row><entry><para><literal>DDI_INFO_DEVT2DEVINFO</literal></para>
</entry><entry><para>Device number</para>
</entry><entry><para>Device information structure pointer</para>
</entry>
</row><row><entry><para><literal>DDI_INFO_DEVT2INSTANCE</literal></para>
</entry><entry><para>Device number</para>
</entry><entry><para>Device instance number</para>
</entry>
</row>
</tbody>
</tgroup>
</table><para>The following code is the <function>dummy_getinfo</function> routine
that you should enter into your <filename>dummy.c</filename> file. You can
copy the name portion of this function definition directly from the declaration
you entered in <olink targetptr="epmqa" remap="internal">Declaring the Autoconfiguration Entry
Points</olink>.</para><programlisting>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;
    }
}</programlisting><para>First, use <citerefentry><refentrytitle>cmn_err</refentrytitle><manvolnum>9F</manvolnum></citerefentry> to write a message to the system log, as you did
in your <citerefentry><refentrytitle>_init</refentrytitle><manvolnum>9E</manvolnum></citerefentry> entry point. Then provide <literal>DDI_INFO_DEVT2DEVINFO</literal> behavior.
A realistic driver would use <replaceable>arg</replaceable> to get the instance
number of this device node. A realistic driver would then call the <citerefentry><refentrytitle>ddi_get_soft_state</refentrytitle><manvolnum>9F</manvolnum></citerefentry> function and return the device information structure pointer
from that state structure. This <literal>dummy</literal> driver supports only
one instance and does not use a state structure. In the <literal>DDI_INFO_DEVT2DEVINFO</literal> code of this <function>dummy_getinfo</function> routine, simply
return the one device information structure pointer that the <function>dummy_attach</function> routine saved.</para><para>Next, provide <literal>DDI_INFO_DEVT2INSTANCE</literal> behavior. Within
the <literal>DDI_INFO_DEVT2INSTANCE</literal> code, simply return 0. This <literal>dummy</literal> driver supports only one instance. The instance number of
that one instance is 0.</para>
</sect3><sect3 id="epmqj"><title>Defining the Report Driver Property Information Entry
Point</title><indexterm><primary>devices</primary><secondary>properties</secondary>
</indexterm><indexterm><primary>entry points</primary><secondary><function>prop_op</function></secondary>
</indexterm><indexterm><primary><function>prop_op</function> entry point</primary>
</indexterm><indexterm><primary><function>ddi_prop_op</function> kernel function</primary>
</indexterm><indexterm><primary>kernel functions</primary><secondary><function>ddi_prop_op</function></secondary>
</indexterm><para>The <olink targetdoc="group-refman" targetptr="prop-op-9e" remap="external"><citerefentry><refentrytitle>prop_op</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink> entry
point is required for every driver. If your driver does not need to customize
the behavior of the <citerefentry><refentrytitle>prop_op</refentrytitle><manvolnum>9E</manvolnum></citerefentry> entry point, then your driver can
use the <olink targetdoc="group-refman" targetptr="ddi-prop-op-9f" remap="external"><citerefentry><refentrytitle>ddi_prop_op</refentrytitle><manvolnum>9F</manvolnum></citerefentry></olink> function for the <citerefentry><refentrytitle>prop_op</refentrytitle><manvolnum>9E</manvolnum></citerefentry> entry point. Drivers that create
and manage their own properties need a custom <citerefentry><refentrytitle>prop_op</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine. This <literal>dummy</literal> driver uses a <citerefentry><refentrytitle>prop_op</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine to call <olink targetdoc="group-refman" targetptr="cmn-err-9f" remap="external"><citerefentry><refentrytitle>cmn_err</refentrytitle><manvolnum>9F</manvolnum></citerefentry></olink> before calling
the <citerefentry><refentrytitle>ddi_prop_op</refentrytitle><manvolnum>9F</manvolnum></citerefentry> function.</para><para>The <citerefentry><refentrytitle>prop_op</refentrytitle><manvolnum>9E</manvolnum></citerefentry> entry point and the <citerefentry><refentrytitle>ddi_prop_op</refentrytitle><manvolnum>9F</manvolnum></citerefentry> function both require that you include
the <literal>types.h</literal> header file. The <citerefentry><refentrytitle>prop_op</refentrytitle><manvolnum>9E</manvolnum></citerefentry> entry point and the <citerefentry><refentrytitle>ddi_prop_op</refentrytitle><manvolnum>9F</manvolnum></citerefentry> function both take the same seven arguments. These arguments
are not discussed here because this <literal>dummy</literal> driver does not
create and manage its own properties. See the <citerefentry><refentrytitle>prop_op</refentrytitle><manvolnum>9E</manvolnum></citerefentry> man page to learn
about the <citerefentry><refentrytitle>prop_op</refentrytitle><manvolnum>9E</manvolnum></citerefentry> arguments.</para><para>The following code is the <function>dummy_prop_op</function> routine
that you should enter into your <filename>dummy.c</filename> file. You can
copy the name portion of this function definition directly from the declaration
you entered in <olink targetptr="epmqa" remap="internal">Declaring the Autoconfiguration Entry
Points</olink>.</para><programlisting>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));
}</programlisting><para>First, use <citerefentry><refentrytitle>cmn_err</refentrytitle><manvolnum>9F</manvolnum></citerefentry> to write a message to the system log, as you did
in your <citerefentry><refentrytitle>_init</refentrytitle><manvolnum>9E</manvolnum></citerefentry> entry point. Then call the <citerefentry><refentrytitle>ddi_prop_op</refentrytitle><manvolnum>9F</manvolnum></citerefentry> function with exactly
the same arguments as the <function>dummy_prop_op</function> function.</para>
</sect3><sect3 id="epmqe"><title>Including Autoconfiguration Header Files</title><para>All of the autoconfiguration entry point routines and all of the user
context entry point routines require that you include the <filename>ddi.h</filename> and <filename>sunddi.h</filename> header files. You already included these two header files
for the <citerefentry><refentrytitle>cmn_err</refentrytitle><manvolnum>9F</manvolnum></citerefentry> function.</para><para>The <olink targetdoc="group-refman" targetptr="ddi-create-minor-node-9f" remap="external"><citerefentry><refentrytitle>ddi_create_minor_node</refentrytitle><manvolnum>9F</manvolnum></citerefentry></olink> function requires the <filename>stat.h</filename> header
file. The <function>dummy_attach</function> routine calls the <citerefentry><refentrytitle>ddi_create_minor_node</refentrytitle><manvolnum>9F</manvolnum></citerefentry> function. The <olink targetdoc="group-refman" targetptr="prop-op-9e" remap="external"><citerefentry><refentrytitle>prop_op</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink> and the <olink targetdoc="group-refman" targetptr="ddi-prop-op-9f" remap="external"><citerefentry><refentrytitle>ddi_prop_op</refentrytitle><manvolnum>9F</manvolnum></citerefentry></olink> functions require the <filename>types.h</filename> header
file.</para><para>The following code is the list of header files that you now should have
included in your <filename>dummy.c</filename> file for the four autoconfiguration
routines you have written in this section and the three loadable module configuration
routines you wrote in the previous section.</para><programlisting>#include &lt;sys/modctl.h&gt;  /* used by _init, _info, _fini */
#include &lt;sys/types.h&gt;   /* used by prop_op, ddi_prop_op */
#include &lt;sys/stat.h&gt;    /* defines S_IFCHR used by ddi_create_minor_node */
#include &lt;sys/cmn_err.h&gt; /* used by all entry points for this driver */
#include &lt;sys/ddi.h&gt;     /* used by all entry points for this driver */
                         /* also used by ddi_get_instance, ddi_prop_op */
#include &lt;sys/sunddi.h&gt;  /* used by all entry points for this driver */
                         /* also used by ddi_create_minor_node, */
                         /* ddi_get_instance, and ddi_prop_op */</programlisting>
</sect3>
</sect2><sect2 id="epmni"><title>Writing the User Context Entry Points</title><indexterm><primary>entry points</primary><secondary>user context</secondary>
</indexterm><indexterm><primary>entry points</primary><secondary><function>open</function></secondary>
</indexterm><indexterm><primary><function>open</function> entry point</primary>
</indexterm><indexterm><primary><function>nulldev</function> kernel function</primary>
</indexterm><indexterm><primary>kernel functions</primary><secondary><function>nulldev</function></secondary>
</indexterm><indexterm><primary>entry points</primary><secondary><function>close</function></secondary>
</indexterm><indexterm><primary><function>close</function> entry point</primary>
</indexterm><indexterm><primary>entry points</primary><secondary><function>read</function></secondary>
</indexterm><indexterm><primary><function>read</function> entry point</primary>
</indexterm><indexterm><primary>entry points</primary><secondary><function>write</function></secondary>
</indexterm><indexterm><primary><function>write</function> entry point</primary>
</indexterm><para>User context entry points correspond closely to system calls. When a
system call opens a device file, then the <citerefentry><refentrytitle>open</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine in the driver for that device
is called.</para><para>All character and block drivers must define the <citerefentry><refentrytitle>open</refentrytitle><manvolnum>9E</manvolnum></citerefentry> user
context entry point. However, the <citerefentry><refentrytitle>open</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine can be <olink targetdoc="group-refman" targetptr="nulldev-9f" remap="external"><citerefentry><refentrytitle>nulldev</refentrytitle><manvolnum>9F</manvolnum></citerefentry></olink>. The <citerefentry><refentrytitle>close</refentrytitle><manvolnum>9E</manvolnum></citerefentry>, <citerefentry><refentrytitle>read</refentrytitle><manvolnum>9E</manvolnum></citerefentry>,
and <citerefentry><refentrytitle>write</refentrytitle><manvolnum>9E</manvolnum></citerefentry> user context routines are optional.</para><itemizedlist><listitem><para>The <olink targetdoc="group-refman" targetptr="open-9e" remap="external"><citerefentry><refentrytitle>open</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink> routine
gains access to the device.</para>
</listitem><listitem><para>The <olink targetdoc="group-refman" targetptr="close-9e" remap="external"><citerefentry><refentrytitle>close</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink> routine
relinquishes access to the device. The <citerefentry><refentrytitle>close</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine must undo everything that
the <citerefentry><refentrytitle>open</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine did.</para>
</listitem><listitem><para>The <olink targetdoc="group-refman" targetptr="read-9e" remap="external"><citerefentry><refentrytitle>read</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink> routine
reads data from the device node.</para>
</listitem><listitem><para>The <olink targetdoc="group-refman" targetptr="write-9e" remap="external"><citerefentry><refentrytitle>write</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink> routine
writes data to the device node.</para>
</listitem>
</itemizedlist><para>In this section, the following code is added:</para><programlisting><?Pub _bookmark Command="[Quick Mark]"?>/* 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;
}</programlisting><?Pub _bookmark Command="[Quick Mark]"?><sect3 id="eqbim"><title>Declaring the User Context Entry Points</title><para>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 <filename>dummy.c</filename> file:</para><programlisting>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);</programlisting>
</sect3><sect3 id="eqbii"><title>Defining the Open Device Entry Point</title><indexterm><primary>entry points</primary><secondary><function>open</function></secondary>
</indexterm><indexterm><primary><function>open</function> entry point</primary>
</indexterm><para>The <olink targetdoc="group-refman" targetptr="open-9e" remap="external"><citerefentry><refentrytitle>open</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink> routine
returns type <literal>int</literal>. The <citerefentry><refentrytitle>open</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine should return either <literal>DDI_SUCCESS</literal> or the appropriate error number.</para><para>The <citerefentry><refentrytitle>open</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine takes four arguments. This <literal>dummy</literal> driver
is so simple that this <function>dummy_open</function> routine does not use
any of the <citerefentry><refentrytitle>open</refentrytitle><manvolnum>9E</manvolnum></citerefentry> arguments. The examples in <olink targetptr="faatl" remap="internal">Chapter&nbsp;3,
Reading and Writing Data in Kernel Memory</olink> show the <citerefentry><refentrytitle>open</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine
in more detail.</para><para>The following code is the <function>dummy_open</function> routine that
you should enter into your <filename>dummy.c</filename> file. You can copy
the name portion of this function definition directly from the declaration
you entered in <olink targetptr="eqbim" remap="internal">Declaring the User Context Entry Points</olink>.
Write a message to the system log and return success.</para><programlisting>static int
dummy_open(dev_t *devp, int flag, int otyp, cred_t *cred)
{
    cmn_err(CE_NOTE, "Inside dummy_open");
    return DDI_SUCCESS;
}</programlisting>
</sect3><sect3 id="eqbil"><title>Defining the Close Device Entry Point</title><indexterm><primary>entry points</primary><secondary><function>close</function></secondary>
</indexterm><indexterm><primary><function>close</function> entry point</primary>
</indexterm><para>The <olink targetdoc="group-refman" targetptr="close-9e" remap="external"><citerefentry><refentrytitle>close</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink> routine
returns type <literal>int</literal>. The <citerefentry><refentrytitle>close</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine should return either <literal>DDI_SUCCESS</literal> or the appropriate error number.</para><para>The <citerefentry><refentrytitle>close</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine takes four arguments. This <literal>dummy</literal> driver
is so simple that this <function>dummy_close</function> routine does not use
any of the <citerefentry><refentrytitle>close</refentrytitle><manvolnum>9E</manvolnum></citerefentry> arguments. The examples in <olink targetptr="faatl" remap="internal">Chapter&nbsp;3,
Reading and Writing Data in Kernel Memory</olink> show the <citerefentry><refentrytitle>close</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine
in more detail.</para><para>The <citerefentry><refentrytitle>close</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine must undo everything that the <citerefentry><refentrytitle>open</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine
did. The <citerefentry><refentrytitle>close</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine must deallocate anything that was allocated, close
anything that was opened, and destroy anything that was created in the <citerefentry><refentrytitle>open</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine.
In this <literal>dummy</literal> driver, the <citerefentry><refentrytitle>open</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine is so simple that nothing
needs to be reclaimed or undone in the <citerefentry><refentrytitle>close</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine.</para><para>The following code is the <function>dummy_close</function> routine that
you should enter into your <filename>dummy.c</filename> file. You can copy
the name portion of this function definition directly from the declaration
you entered in <olink targetptr="eqbim" remap="internal">Declaring the User Context Entry Points</olink>.
Write a message to the system log and return success.</para><programlisting>static int
dummy_close(dev_t dev, int flag, int otyp, cred_t *cred)
{
    cmn_err(CE_NOTE, "Inside dummy_close");
    return DDI_SUCCESS;
}</programlisting>
</sect3><sect3 id="eqbjc"><title>Defining the Read Device Entry Point</title><indexterm><primary>entry points</primary><secondary><function>read</function></secondary>
</indexterm><indexterm><primary><function>read</function> entry point</primary>
</indexterm><para>The <olink targetdoc="group-refman" targetptr="read-9e" remap="external"><citerefentry><refentrytitle>read</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink> routine
returns type <literal>int</literal>. The <citerefentry><refentrytitle>read</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine should return either <literal>DDI_SUCCESS</literal> or the appropriate error number.</para><para>The <citerefentry><refentrytitle>read</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine takes three arguments. This <literal>dummy</literal> driver
is so simple that this <function>dummy_read</function> routine does not use
any of the <citerefentry><refentrytitle>read</refentrytitle><manvolnum>9E</manvolnum></citerefentry> arguments. The examples in <olink targetptr="faatl" remap="internal">Chapter&nbsp;3,
Reading and Writing Data in Kernel Memory</olink> show the <citerefentry><refentrytitle>read</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine
in more detail.</para><para>The following code is the <function>dummy_read</function> routine that
you should enter into your <filename>dummy.c</filename> file. You can copy
the name portion of this function definition directly from the declaration
you entered in <olink targetptr="eqbim" remap="internal">Declaring the User Context Entry Points</olink>.
Write a message to the system log and return success.</para><programlisting>static int
dummy_read(dev_t dev, struct uio *uiop, cred_t *credp)
{
    cmn_err(CE_NOTE, "Inside dummy_read");
    return DDI_SUCCESS;
}</programlisting>
</sect3><sect3 id="eqbjb"><title>Defining the Write Device Entry Point</title><indexterm><primary>entry points</primary><secondary><function>write</function></secondary>
</indexterm><indexterm><primary><function>write</function> entry point</primary>
</indexterm><para>The <olink targetdoc="group-refman" targetptr="write-9e" remap="external"><citerefentry><refentrytitle>write</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink> routine
returns type <literal>int</literal>. The <citerefentry><refentrytitle>write</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine should return either <literal>DDI_SUCCESS</literal> or the appropriate error number.</para><para>The <citerefentry><refentrytitle>write</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine takes three arguments. This <literal>dummy</literal> driver
is so simple that this <function>dummy_write</function> routine does not use
any of the <citerefentry><refentrytitle>write</refentrytitle><manvolnum>9E</manvolnum></citerefentry> arguments. The examples in <olink targetptr="faatl" remap="internal">Chapter&nbsp;3,
Reading and Writing Data in Kernel Memory</olink> show the <citerefentry><refentrytitle>write</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine
in more detail.</para><para>The following code is the <function>dummy_write</function> routine that
you should enter into your <filename>dummy.c</filename> file. You can copy
the name portion of this function definition directly from the declaration
you entered in <olink targetptr="eqbim" remap="internal">Declaring the User Context Entry Points</olink>.
Write a message to the system log and return success.</para><programlisting>static int
dummy_write(dev_t dev, struct uio *uiop, cred_t *credp)
{
    cmn_err(CE_NOTE, "Inside dummy_write");
    return DDI_SUCCESS;
}</programlisting>
</sect3><sect3 id="eqbit"><title>Including User Context Header Files</title><para>The four user context entry point routines require your module to include
several header files. You already have included the <filename>types.h</filename> header
file, the <filename>ddi.h</filename> header file, and the <filename>sunddi.h</filename> header
file. You need to include the <filename>file.h</filename>, <filename>errno.h</filename>, <filename>open.h</filename>, <filename>cred.h</filename>, and <filename>uio.h</filename> header
files.</para><para>The following code is the list of header files that you now should have
included in your <filename>dummy.c</filename> file for all the entry points
you have written in this section and the previous two sections:</para><programlisting>#include &lt;sys/modctl.h&gt;  /* used by modlinkage, modldrv, _init, _info, */
                         /* and _fini */
#include &lt;sys/types.h&gt;   /* used by open, close, read, write, prop_op, */
                         /* and ddi_prop_op */
#include &lt;sys/file.h&gt;    /* used by open, close */
#include &lt;sys/errno.h&gt;   /* used by open, close, read, write */
#include &lt;sys/open.h&gt;    /* used by open, close, read, write */
#include &lt;sys/cred.h&gt;    /* used by open, close, read */
#include &lt;sys/uio.h&gt;     /* used by read */
#include &lt;sys/stat.h&gt;    /* defines S_IFCHR used by ddi_create_minor_node */
#include &lt;sys/cmn_err.h&gt; /* used by all entry points for this driver */
#include &lt;sys/ddi.h&gt;     /* used by all entry points for this driver */
                         /* also used by ddi_get_instance and */
                         /* ddi_prop_op */
#include &lt;sys/sunddi.h&gt;  /* used by all entry points for this driver */
                         /* also used by ddi_create_minor_node, */
                         /* ddi_get_instance, and ddi_prop_op */</programlisting>
</sect3>
</sect2><sect2 id="eoxzx"><title>Writing the Driver Data Structures</title><indexterm><primary><literal>dev_ops</literal> driver structure</primary>
</indexterm><indexterm><primary>driver structures</primary><secondary><literal>dev_ops</literal></secondary>
</indexterm><indexterm><primary><literal>cb_ops</literal> driver structure</primary>
</indexterm><indexterm><primary>driver structures</primary><secondary><literal>cb_ops</literal></secondary>
</indexterm><indexterm><primary><literal>modldrv</literal> driver structure</primary>
</indexterm><indexterm><primary>driver structures</primary><secondary><literal>modldrv</literal></secondary>
</indexterm><indexterm><primary><literal>modlinkage</literal> driver structure</primary>
</indexterm><indexterm><primary>driver structures</primary><secondary><literal>modlinkage</literal></secondary>
</indexterm><para>All of the data structures described in this section are required for
every device driver. All drivers must define a <olink targetdoc="group-refman" targetptr="dev-ops-9s" remap="external"><citerefentry><refentrytitle>dev_ops</refentrytitle><manvolnum>9S</manvolnum></citerefentry></olink> device operations structure.
Because the <citerefentry><refentrytitle>dev_ops</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure includes a pointer to the <olink targetdoc="group-refman" targetptr="cb-ops-9s" remap="external"><citerefentry><refentrytitle>cb_ops</refentrytitle><manvolnum>9S</manvolnum></citerefentry></olink> character
and block operations structure, you must define the <citerefentry><refentrytitle>cb_ops</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure
first. The <olink targetdoc="group-refman" targetptr="modldrv-9s" remap="external"><citerefentry><refentrytitle>modldrv</refentrytitle><manvolnum>9S</manvolnum></citerefentry></olink> linkage
structure for loadable drivers includes a pointer to the <citerefentry><refentrytitle>dev_ops</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure.
The <olink targetdoc="group-refman" targetptr="modlinkage-9s" remap="external"><citerefentry><refentrytitle>modlinkage</refentrytitle><manvolnum>9S</manvolnum></citerefentry></olink> module linkage structure includes a pointer to the <citerefentry><refentrytitle>modldrv</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure.</para><para>Except for the loadable module configuration entry points, all of the
required entry points for a driver are initialized in the character and block
operations structure or in the device operations structure. Some optional
entry points and other related data also are initialized in these data structures.
Initializing the entry points in these data structures enables the driver
to be dynamically loaded.</para><para>The loadable module configuration entry points are not initialized in
driver data structures. The <citerefentry><refentrytitle>_init</refentrytitle><manvolnum>9E</manvolnum></citerefentry>, <citerefentry><refentrytitle>_info</refentrytitle><manvolnum>9E</manvolnum></citerefentry>, and <citerefentry><refentrytitle>_fini</refentrytitle><manvolnum>9E</manvolnum></citerefentry> entry points are required for all
kernel modules and are not specific to device driver modules.</para><para>In this section, the following code is added:</para><programlisting>/* 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 */
    &amp;dummy_cb_ops,
    (struct bus_ops *)NULL,
    nodev,                     /* no power(9E) */
    ddi_quiesce_not_needed,    /* no quiesce(9E) */
};

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

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

/* dev_info structure */
dev_info_t *dummy_dip;  /* keep track of one instance */</programlisting><sect3 id="eoyag"><title>Defining the Character and Block Operations Structure</title><indexterm><primary>driver structures</primary><secondary>character and block operations structure</secondary>
</indexterm><indexterm><primary><literal>cb_ops</literal> driver structure</primary>
</indexterm><indexterm><primary>driver structures</primary><secondary><literal>cb_ops</literal></secondary>
</indexterm><para>The <olink targetdoc="group-refman" targetptr="cb-ops-9s" remap="external"><citerefentry><refentrytitle>cb_ops</refentrytitle><manvolnum>9S</manvolnum></citerefentry></olink> structure
initializes standard character and block interfaces. See the <citerefentry><refentrytitle>cb_ops</refentrytitle><manvolnum>9S</manvolnum></citerefentry> man
page to learn what each element is and what the value of each element should
be. This <literal>dummy</literal> driver does not use all of the elements
in the <citerefentry><refentrytitle>cb_ops</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure. See the description that follows the code sample.</para><para>When you name this structure, use the same <literal>dummy_</literal> prefix
that you used for the names of the autoconfiguration routines and the names
of the user context routines. Prepend the <literal>static</literal> type modifier
to the declaration.</para><para>The following code is the <citerefentry><refentrytitle>cb_ops</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure that you should enter into
your <filename>dummy.c</filename> file:</para><programlisting>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 */
};</programlisting><para>Enter the names of the <citerefentry><refentrytitle>open</refentrytitle><manvolnum>9E</manvolnum></citerefentry> and <citerefentry><refentrytitle>close</refentrytitle><manvolnum>9E</manvolnum></citerefentry> entry points for this driver as the
values of the first two elements of this structure. Enter the names of the <citerefentry><refentrytitle>read</refentrytitle><manvolnum>9E</manvolnum></citerefentry> and <citerefentry><refentrytitle>write</refentrytitle><manvolnum>9E</manvolnum></citerefentry> entry
points for this driver as the values of the sixth and seventh elements of
this structure. Enter the name of the <citerefentry><refentrytitle>prop_op</refentrytitle><manvolnum>9E</manvolnum></citerefentry> entry point for this driver as the
value of the thirteenth element in this structure.</para><para><indexterm><primary><function>nodev</function> kernel function</primary></indexterm><indexterm><primary>kernel functions</primary><secondary><function>nodev</function></secondary></indexterm><indexterm><primary><function>nochpoll</function> kernel function</primary></indexterm><indexterm><primary>kernel functions</primary><secondary><function>nochpoll</function></secondary></indexterm>The <citerefentry><refentrytitle>strategy</refentrytitle><manvolnum>9E</manvolnum></citerefentry>, <citerefentry><refentrytitle>print</refentrytitle><manvolnum>9E</manvolnum></citerefentry>,
and <citerefentry><refentrytitle>dump</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routines are for block drivers only. This <literal>dummy</literal> driver
does not define these three routines because this driver is a character driver.
This driver does not define an <citerefentry><refentrytitle>ioctl</refentrytitle><manvolnum>9E</manvolnum></citerefentry> entry point because this driver does
not use I/O control commands. This driver does not define <citerefentry><refentrytitle>devmap</refentrytitle><manvolnum>9E</manvolnum></citerefentry>, <citerefentry><refentrytitle>mmap</refentrytitle><manvolnum>9E</manvolnum></citerefentry>,
or <citerefentry><refentrytitle>segmap</refentrytitle><manvolnum>9E</manvolnum></citerefentry> entry points because this driver does not support memory mapping.
This driver does not does not define <citerefentry><refentrytitle>aread</refentrytitle><manvolnum>9E</manvolnum></citerefentry> or <citerefentry><refentrytitle>awrite</refentrytitle><manvolnum>9E</manvolnum></citerefentry> entry points because this driver
does not perform any asynchronous reads or writes. Initialize all of these
unused function elements to <olink targetdoc="group-refman" targetptr="nodev-9f" remap="external"><citerefentry><refentrytitle>nodev</refentrytitle><manvolnum>9F</manvolnum></citerefentry></olink>.
The <citerefentry><refentrytitle>nodev</refentrytitle><manvolnum>9F</manvolnum></citerefentry> function returns the <literal>ENXIO</literal> error code.</para><para>Specify the <olink targetdoc="group-refman" targetptr="nochpoll-9f" remap="external"><citerefentry><refentrytitle>nochpoll</refentrytitle><manvolnum>9F</manvolnum></citerefentry></olink> function
for the <citerefentry><refentrytitle>chpoll</refentrytitle><manvolnum>9E</manvolnum></citerefentry> element of the <citerefentry><refentrytitle>cb_ops</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure because this driver is
not for a pollable device. Specify <literal>NULL</literal> for the <citerefentry><refentrytitle>streamtab</refentrytitle><manvolnum>9S</manvolnum></citerefentry> STREAMS
entity declaration structure because this driver is not a STREAMS driver.</para><para>The compatibility flags are defined in the <filename>conf.h</filename> header
file. The <literal>D_NEW</literal> flag means this driver is a new-style driver.
The <literal>D_MP</literal> flag means this driver safely allows multiple
threads of execution. All drivers must be multithreaded-safe, and must specify
this <literal>D_MP</literal> flag. The <literal>D_64BIT</literal> flag means
this driver supports 64-bit offsets and block numbers. See the <filename>conf.h</filename> header
file for more compatibility flags.</para><para>The <literal>CB_REV</literal> element of the <citerefentry><refentrytitle>cb_ops</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure is the <citerefentry><refentrytitle>cb_ops</refentrytitle><manvolnum>9S</manvolnum></citerefentry> revision
number. <literal>CB_REV</literal> is defined in the <filename>devops.h</filename> header
file.</para>
</sect3><sect3 id="eoyaf"><title>Defining the Device Operations Structure</title><indexterm><primary>driver structures</primary><secondary>device operations structure</secondary>
</indexterm><indexterm><primary><literal>dev_ops</literal> driver structure</primary>
</indexterm><indexterm><primary>driver structures</primary><secondary><literal>dev_ops</literal></secondary>
</indexterm><para>The <olink targetdoc="group-refman" targetptr="dev-ops-9s" remap="external"><citerefentry><refentrytitle>dev_ops</refentrytitle><manvolnum>9S</manvolnum></citerefentry></olink> structure
initializes interfaces that are used for operations such as attaching and
detaching the driver. See the <citerefentry><refentrytitle>dev_ops</refentrytitle><manvolnum>9S</manvolnum></citerefentry> man page to learn what each element
is and what the value of each element should be. This <literal>dummy</literal> driver
does not use all of the elements in the <citerefentry><refentrytitle>dev_ops</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure. See the description that
follows the code sample.</para><para>When you name this structure, use the same <literal>dummy_</literal> prefix
that you used for the names of the autoconfiguration routines and the names
of the user context routines. Prepend the <literal>static</literal> type modifier
to the declaration.</para><para>The following code is the <citerefentry><refentrytitle>dev_ops</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure that you should enter into
your <filename>dummy.c</filename> file:</para><programlisting>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 */
    &amp;dummy_cb_ops,
    (struct bus_ops *)NULL,
    nodev,                     /* no power(9E) */
    ddi_quiesce_not_needed,    /* no quiesce(9E) */
};</programlisting><para>The <literal>DEVO_REV</literal> element of the <citerefentry><refentrytitle>dev_ops</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure
is the driver build version. <literal>DEVO_REV</literal> is defined in the <literal>devops.h</literal> header file. The second element in this structure is the
driver reference count. Initialize this value to zero. The driver reference
count is the number of instances of this driver that are currently open. The
driver cannot be unloaded if any instances of the driver are still open.</para><para><indexterm><primary><function>nulldev</function> kernel function</primary></indexterm><indexterm><primary>kernel functions</primary><secondary><function>nulldev</function></secondary></indexterm><indexterm><primary><function>nodev</function> kernel function</primary></indexterm><indexterm><primary>kernel functions</primary><secondary><function>nodev</function></secondary></indexterm>The next six
elements of the <citerefentry><refentrytitle>dev_ops</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure are the names of the <citerefentry><refentrytitle>getinfo</refentrytitle><manvolnum>9E</manvolnum></citerefentry>, <citerefentry><refentrytitle>identify</refentrytitle><manvolnum>9E</manvolnum></citerefentry>, <citerefentry><refentrytitle>probe</refentrytitle><manvolnum>9E</manvolnum></citerefentry>, <citerefentry><refentrytitle>attach</refentrytitle><manvolnum>9E</manvolnum></citerefentry>, <citerefentry><refentrytitle>detach</refentrytitle><manvolnum>9E</manvolnum></citerefentry>,
and <function>reset</function> functions for this particular driver. The <citerefentry><refentrytitle>identify</refentrytitle><manvolnum>9E</manvolnum></citerefentry> function
is obsolete. Initialize this structure element to <olink targetdoc="group-refman" targetptr="nulldev-9f" remap="external"><citerefentry><refentrytitle>nulldev</refentrytitle><manvolnum>9F</manvolnum></citerefentry></olink>. The <citerefentry><refentrytitle>probe</refentrytitle><manvolnum>9E</manvolnum></citerefentry> function
determines whether the corresponding device exists and is valid. This <literal>dummy</literal> driver does not define a <citerefentry><refentrytitle>probe</refentrytitle><manvolnum>9E</manvolnum></citerefentry> function. Initialize this structure
element to <literal>nulldev</literal>. The <citerefentry><refentrytitle>nulldev</refentrytitle><manvolnum>9F</manvolnum></citerefentry> function returns success. The <function>reset</function> function is obsolete. Initialize the <function>reset</function> function
to <olink targetdoc="group-refman" targetptr="nodev-9f" remap="external"><citerefentry><refentrytitle>nodev</refentrytitle><manvolnum>9F</manvolnum></citerefentry></olink>.</para><para>The next element of the <citerefentry><refentrytitle>dev_ops</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure is a pointer to the <citerefentry><refentrytitle>cb_ops</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure
for this driver. You initialized the <citerefentry><refentrytitle>cb_ops</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure for this driver in <olink targetptr="eoyag" remap="internal">Defining the Character and Block Operations Structure</olink>.
Enter <literal>&amp;dummy_cb_ops</literal> for the value of the pointer to
the <citerefentry><refentrytitle>cb_ops</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure.</para><para>The next element of the <citerefentry><refentrytitle>dev_ops</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure is a pointer to the bus
operations structure. Only nexus drivers have bus operations structures. This <literal>dummy</literal> driver is not a nexus driver. Set this value to <literal>NULL</literal> because
this driver is a leaf driver.</para><para>The next element of the <citerefentry><refentrytitle>dev_ops</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure is the name of the <citerefentry><refentrytitle>power</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine
for this driver. The <citerefentry><refentrytitle>power</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine operates on a hardware device.
This driver does not drive a hardware device. Set the value of this structure
element to <literal>nodev</literal>.</para><para>The last element of the <citerefentry><refentrytitle>dev_ops</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure is the name of the <olink targetdoc="refman9e" targetptr="quiesce-9e" remap="external"><citerefentry><refentrytitle>quiesce</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink> routine for this driver.
The <citerefentry><refentrytitle>quiesce</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routine operates on a hardware device. This driver does not
drive a hardware device. Set the value of this structure element to <function>ddi_quiesce_not_needed</function>(9F).</para>
</sect3><sect3 id="epffy"><title>Defining the Module Linkage Structures</title><indexterm><primary>driver structures</primary><secondary>module linkage structures</secondary>
</indexterm><indexterm><primary><literal>modldrv</literal> driver structure</primary>
</indexterm><indexterm><primary>driver structures</primary><secondary><literal>modldrv</literal></secondary>
</indexterm><indexterm><primary><literal>modlinkage</literal> driver structure</primary>
</indexterm><indexterm><primary>driver structures</primary><secondary><literal>modlinkage</literal></secondary>
</indexterm><para>Two other module loading structures are required for every driver. The <olink targetdoc="group-refman" targetptr="modlinkage-9s" remap="external"><citerefentry><refentrytitle>modlinkage</refentrytitle><manvolnum>9S</manvolnum></citerefentry></olink> module linkage
structure is used by the <citerefentry><refentrytitle>_init</refentrytitle><manvolnum>9E</manvolnum></citerefentry>, <citerefentry><refentrytitle>_info</refentrytitle><manvolnum>9E</manvolnum></citerefentry>, and <citerefentry><refentrytitle>_fini</refentrytitle><manvolnum>9E</manvolnum></citerefentry> routines to install, remove, and
retrieve information from a module. The <olink targetdoc="group-refman" targetptr="modldrv-9s" remap="external"><citerefentry><refentrytitle>modldrv</refentrytitle><manvolnum>9S</manvolnum></citerefentry></olink> linkage structure for loadable
drivers exports driver-specific information to the kernel. See the man pages
for each structure to learn what each element is and what the value of each
element should be.</para><para>The following code defines the <citerefentry><refentrytitle>modldrv</refentrytitle><manvolnum>9S</manvolnum></citerefentry> and <citerefentry><refentrytitle>modlinkage</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structures for the
driver shown in this chapter:</para><programlisting>static struct modldrv md = {
    &amp;mod_driverops,     /* Type of module. This is a driver. */
    "dummy driver",     /* Name of the module. */
    &amp;dummy_dev_ops
};

static struct modlinkage ml = {
    MODREV_1,
    &amp;md,
    NULL
};</programlisting><para>The first element in the <citerefentry><refentrytitle>modldrv</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure is a pointer to a structure
that tells the kernel what kind of module this is. Set this value to the address
of the <literal>mod_driverops</literal> structure. The <literal>mod_driverops</literal> structure
tells the kernel that the <filename>dummy.c</filename> module is a loadable
driver module. The <literal>mod_driverops</literal> structure is declared
in the <filename>modctl.h</filename> header file. You already included the <filename>modctl.h</filename> header file in your <filename>dummy.c</filename> file,
so do not declare the <literal>mod_driverops</literal> structure in <filename>dummy.c</filename>. The <literal>mod_driverops</literal> structure is defined in
the <filename>modctl.c</filename> source file.</para><para>The second element in the <citerefentry><refentrytitle>modldrv</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure is a string that describes
this module. Usually this string contains the name of this module and the
version number of this module. The last element of the <citerefentry><refentrytitle>modldrv</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure
is a pointer to the <citerefentry><refentrytitle>dev_ops</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure for this driver. You initialized
the <citerefentry><refentrytitle>dev_ops</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure for this driver in <olink targetptr="eoyaf" remap="internal">Defining
the Device Operations Structure</olink>.</para><para>The first element in the <citerefentry><refentrytitle>modlinkage</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure is the revision number
of the loadable modules system. Set this value to <literal>MODREV_1</literal>.
The next element of the <citerefentry><refentrytitle>modlinkage</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure is the address of a null-terminated
array of pointers to linkage structures. Driver modules have only one linkage
structure. Enter the address of the <literal>md</literal> structure for the
value of this element of the <citerefentry><refentrytitle>modlinkage</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure. Enter the value <literal>NULL</literal> to terminate this list of linkage structures.</para>
</sect3><sect3 id="eqbni"><title>Including Data Structures Header Files</title><para>The <olink targetdoc="group-refman" targetptr="cb-ops-9s" remap="external"><citerefentry><refentrytitle>cb_ops</refentrytitle><manvolnum>9S</manvolnum></citerefentry></olink> and <olink targetdoc="group-refman" targetptr="dev-ops-9s" remap="external"><citerefentry><refentrytitle>dev_ops</refentrytitle><manvolnum>9S</manvolnum></citerefentry></olink> structures
require you to include the <filename>conf.h</filename> and <filename>devops.h</filename> header
files. The <olink targetdoc="group-refman" targetptr="modlinkage-9s" remap="external"><citerefentry><refentrytitle>modlinkage</refentrytitle><manvolnum>9S</manvolnum></citerefentry></olink> and <olink targetdoc="group-refman" targetptr="modldrv-9s" remap="external"><citerefentry><refentrytitle>modldrv</refentrytitle><manvolnum>9S</manvolnum></citerefentry></olink> structures require you to
include the <literal>modctl.h</literal> header file. You already included
the <filename>modctl.h</filename> header file for the loadable module configuration
entry points.</para><para>The following code is the complete list of header files that you now
should have included in your <filename>dummy.c</filename> file:</para><programlisting>#include &lt;sys/devops.h&gt;  /* used by dev_ops */
#include &lt;sys/conf.h&gt;    /* used by dev_ops and cb_ops */
#include &lt;sys/modctl.h&gt;  /* used by modlinkage, modldrv, _init, _info, */
                         /* and _fini */
#include &lt;sys/types.h&gt;   /* used by open, close, read, write, prop_op, */
                         /* and ddi_prop_op */
#include &lt;sys/file.h&gt;    /* used by open, close */
#include &lt;sys/errno.h&gt;   /* used by open, close, read, write */
#include &lt;sys/open.h&gt;    /* used by open, close, read, write */
#include &lt;sys/cred.h&gt;    /* used by open, close, read */
#include &lt;sys/uio.h&gt;     /* used by read */
#include &lt;sys/stat.h&gt;    /* defines S_IFCHR used by ddi_create_minor_node */
#include &lt;sys/cmn_err.h&gt; /* used by all entry points for this driver */
#include &lt;sys/ddi.h&gt;     /* used by all entry points for this driver */
                         /* also used by cb_ops, ddi_get_instance, and */
                         /* ddi_prop_op */
#include &lt;sys/sunddi.h&gt;  /* used by all entry points for this driver */
                         /* also used by cb_ops, ddi_create_minor_node, */
                         /* ddi_get_instance, and ddi_prop_op */</programlisting>
</sect3>
</sect2>
</sect1><sect1 id="eoxzw"><title>Writing the Device Configuration File</title><indexterm><primary>configuration files</primary>
</indexterm><indexterm><primary>devices</primary><secondary>configuration files</secondary>
</indexterm><para>This driver requires a configuration file. The minimum information that
a configuration file must contain is the name of the device node and the name
or type of the device's parent. In this simple example, the node name of the
device is the same as the file name of the driver. Create a file named <filename>dummy.conf</filename> in your working directory. Put the following single
line of information into <filename>dummy.conf</filename>:</para><programlisting>name="dummy" parent="pseudo";</programlisting>
</sect1><sect1 id="eoxzr"><title>Building and Installing the Template Driver</title><para>This section shows you how to build and install the driver for a 32-bit
platform. See <olink targetptr="fgouv" remap="internal">Building a Driver</olink> and <olink targetptr="fsfqv" remap="internal">Installing a Driver</olink> for build and install instructions
for SPARC architectures and for 64-bit x86 architectures.</para><para>Compile and link the driver. Use the <option>D_KERNEL</option> option
to indicate that this code defines a kernel module. The following example
shows compiling and linking for a 32-bit architecture using the Sun Studio
C compiler:</para><screen>% <userinput>cc -D_KERNEL -c dummy.c</userinput>
% <userinput>ld -r -o dummy dummy.o</userinput></screen><para>Make sure you are user <literal>root</literal> when you install the
driver.</para><para>Install drivers in the <filename>/tmp</filename> directory until you
are finished modifying and testing the <function>_info</function>, <function>_init</function>, and <function>attach</function> routines. Copy the driver binary
to the <filename>/tmp</filename> directory. Link to the driver from the kernel
driver directory. See <olink targetptr="fdlbq" remap="internal">Device Driver Testing Tips</olink> for
more information.</para><screen># <userinput>cp dummy /tmp</userinput></screen><para>Link to the following directory for a 32-bit architecture:</para><screen># <userinput>ln -s /tmp/dummy /usr/kernel/drv/dummy</userinput></screen><para>Copy the configuration file to the kernel driver area of the system.</para><screen># <userinput>cp dummy.conf /usr/kernel/drv</userinput></screen>
</sect1><sect1 id="eoxzu"><title>Testing the Template Driver</title><indexterm><primary>files</primary><secondary><filename>/var/adm/messages</filename></secondary>
</indexterm><indexterm><primary><filename>/var/adm/messages</filename> file</primary>
</indexterm><indexterm><primary>commands</primary><secondary><command>syslogd</command></secondary>
</indexterm><indexterm><primary><command>syslogd</command> command</primary>
</indexterm><indexterm><primary><function>cmn_err</function> kernel function</primary>
</indexterm><indexterm><primary>kernel functions</primary><secondary><function>cmn_err</function></secondary>
</indexterm><para>This <literal>dummy</literal> driver merely writes a message to a system
log each time an entry point routine is entered. To test this driver, watch
for these messages to confirm that each entry point routine is successfully
entered.</para><para>The <olink targetdoc="group-refman" targetptr="cmn-err-9f" remap="external"><citerefentry><refentrytitle>cmn_err</refentrytitle><manvolnum>9F</manvolnum></citerefentry></olink> function
writes low priority messages such as the messages defined in this <literal>dummy</literal> driver
to <filename>/dev/log</filename>. The <olink targetdoc="group-refman" targetptr="syslogd-1m" remap="external"><citerefentry><refentrytitle>syslogd</refentrytitle><manvolnum>1M</manvolnum></citerefentry></olink> daemon reads messages from <filename>/dev/log</filename> and writes low priority messages to <filename>/var/adm/messages</filename>.</para><para>In a separate window, enter the following command and monitor the output
as you perform the tests described in the remainder of this section:</para><screen>% <userinput>tail -f /var/adm/messages</userinput></screen><sect2 id="eqbqx"><title>Adding the Template Driver</title><indexterm><primary>device drivers</primary><secondary>loading</secondary>
</indexterm><indexterm><primary>commands</primary><secondary><command>add_drv</command></secondary>
</indexterm><indexterm><primary><command>add_drv</command> command</primary>
</indexterm><para>Make sure you are user <literal>root</literal> when you add the driver.
Use the <olink targetdoc="group-refman" targetptr="add-drv-1m" remap="external"><citerefentry><refentrytitle>add_drv</refentrytitle><manvolnum>1M</manvolnum></citerefentry></olink> command
to add the driver:</para><screen># <userinput>add_drv dummy</userinput></screen><para>You should see the following messages in the window where you are viewing <filename>/var/adm/messages</filename>:</para><screen><replaceable>date</replaceable> <replaceable>time</replaceable> <replaceable>machine</replaceable> dummy: [ID 513080 kern.notice] NOTICE: Inside _info
<replaceable>date</replaceable> <replaceable>time</replaceable> <replaceable>machine</replaceable> dummy: [ID 874762 kern.notice] NOTICE: Inside _init
<replaceable>date</replaceable> <replaceable>time</replaceable> <replaceable>machine</replaceable> dummy: [ID 678704 kern.notice] NOTICE: Inside dummy_attach</screen><para>The <citerefentry><refentrytitle>_info</refentrytitle><manvolnum>9E</manvolnum></citerefentry>, <citerefentry><refentrytitle>_init</refentrytitle><manvolnum>9E</manvolnum></citerefentry>, and <citerefentry><refentrytitle>attach</refentrytitle><manvolnum>9E</manvolnum></citerefentry> entry points are called in that order
when you add a driver.</para><para><indexterm><primary><literal>/devices/pseudo</literal> directory</primary></indexterm>The <literal>dummy</literal> driver has been added to the <filename>/devices</filename> directory:</para><screen>% <userinput>ls -l /devices/pseudo | grep dummy</userinput>
drwxr-xr-x   2 root     sys          512 <replaceable>date</replaceable> <replaceable>time</replaceable> dummy@0
crw-------   1 root     sys       92,  0 <replaceable>date</replaceable> <replaceable>time</replaceable> dummy@0:0</screen><para><indexterm><primary>commands</primary><secondary><command>modinfo</command></secondary></indexterm><indexterm><primary><command>modinfo</command> command</primary></indexterm>The <literal>dummy</literal> driver also is the most recent module
listed by <olink targetdoc="group-refman" targetptr="modinfo-1m" remap="external"><citerefentry><refentrytitle>modinfo</refentrytitle><manvolnum>1M</manvolnum></citerefentry></olink>:</para><screen>% <userinput>modinfo</userinput>
 Id Loadaddr   Size Info Rev Module Name
180 ed192b70    544  92   1  dummy (dummy driver)</screen><para><indexterm><primary>files</primary><secondary><filename>/etc/name_to_major</filename></secondary></indexterm><indexterm><primary><filename>/etc/name_to_major</filename> file</primary></indexterm>The module name, <literal>dummy driver</literal>, is the value
you entered for the second member of the <citerefentry><refentrytitle>modldrv</refentrytitle><manvolnum>9S</manvolnum></citerefentry> structure. The value <literal>92</literal> is
the major number of this module.</para><screen>% <userinput>grep dummy /etc/name_to_major</userinput>
dummy 92</screen><para>The <literal>Loadaddr</literal> address of <literal>ed192b70</literal> is
the address of the first instruction in the <literal>dummy</literal> driver.
This address might be useful, for example, in debugging.</para><screen>% <userinput>mdb -k</userinput>
&gt; dummy`_init $m
    BASE    LIMIT     SIZE NAME
ed192b70 ed192ff0      480 dummy
&gt; <userinput>$q</userinput></screen><para><indexterm><primary>commands</primary><secondary><command>prtconf</command></secondary></indexterm><indexterm><primary><command>prtconf</command> command</primary></indexterm>The <literal>dummy</literal> driver also is the most recent module
listed by <olink targetdoc="group-refman" targetptr="prtconf-1m" remap="external"><citerefentry><refentrytitle>prtconf</refentrytitle><manvolnum>1M</manvolnum></citerefentry></olink> in
the pseudo device section:</para><screen>% <userinput>prtconf -P</userinput>
    pseudo, instance #0
        dummy, instance #0 (driver not attached)</screen><para>A driver is automatically loaded when a device that the driver manages
is accessed. A driver might be automatically unloaded when the driver is not
in use.</para><itemizedlist><para>If your driver is in the <filename>/devices</filename> directory but <citerefentry><refentrytitle>modinfo</refentrytitle><manvolnum>1M</manvolnum></citerefentry> does
not list your driver, you can use either of the following methods to load
your driver:</para><listitem><para><indexterm><primary>commands</primary><secondary><command>modload</command></secondary></indexterm><indexterm><primary><command>modload</command> command</primary></indexterm>Use the <olink targetdoc="group-refman" targetptr="modload-1m" remap="external"><citerefentry><refentrytitle>modload</refentrytitle><manvolnum>1M</manvolnum></citerefentry></olink> command.</para>
</listitem><listitem><para>Access the device. The driver is loaded automatically when
a device that the driver manages is accessed. The following section describes
how to access the <literal>dummy</literal> device.</para>
</listitem>
</itemizedlist>
</sect2><sect2 id="eqbqv"><title>Reading and Writing the Device</title><indexterm><primary>devices</primary><secondary>reading</secondary>
</indexterm><para>Make sure you are user <literal>root</literal> when you perform the
tests described in this section. If you are not user <literal>root</literal>,
you will receive &ldquo;Permission denied&rdquo; error messages when you try
to access the <filename>/devices/pseudo/dummy@0:0</filename> special file.
Notice the permissions that are shown for <filename>/devices/pseudo/dummy@0:0</filename> in <olink targetptr="eqbqx" remap="internal">Adding the Template Driver</olink>.</para><para><indexterm><primary>commands</primary><secondary><command>cat</command></secondary></indexterm><indexterm><primary><command>cat</command> command</primary></indexterm>Test reading from the device. Your <literal>dummy</literal> device
probably is named <filename>/devices/pseudo/dummy@0:0</filename>. The following
command reads from your <literal>dummy</literal> device even if it has a slightly
different name:</para><screen># <userinput>cat /devices/pseudo/dummy*</userinput></screen><para>You should see the following messages in the window where you are viewing <filename>/var/adm/messages</filename>:</para><screen><replaceable>date</replaceable> <replaceable>time</replaceable> <replaceable>machine</replaceable> dummy: [ID 136952 kern.notice] NOTICE: Inside dummy_open
<replaceable>date</replaceable> <replaceable>time</replaceable> <replaceable>machine</replaceable> dummy: [ID 623947 kern.notice] NOTICE: Inside dummy_getinfo
<replaceable>date</replaceable> <replaceable>time</replaceable> <replaceable>machine</replaceable> dummy: [ID 891851 kern.notice] NOTICE: Inside dummy_prop_op
<replaceable>date</replaceable> <replaceable>time</replaceable> <replaceable>machine</replaceable> dummy: [ID 623947 kern.notice] NOTICE: Inside dummy_getinfo
<replaceable>date</replaceable> <replaceable>time</replaceable> <replaceable>machine</replaceable> dummy: [ID 891851 kern.notice] NOTICE: Inside dummy_prop_op
<replaceable>date</replaceable> <replaceable>time</replaceable> <replaceable>machine</replaceable> dummy: [ID 623947 kern.notice] NOTICE: Inside dummy_getinfo
<replaceable>date</replaceable> <replaceable>time</replaceable> <replaceable>machine</replaceable> dummy: [ID 709590 kern.notice] NOTICE: Inside dummy_read
<replaceable>date</replaceable> <replaceable>time</replaceable> <replaceable>machine</replaceable> dummy: [ID 550206 kern.notice] NOTICE: Inside dummy_close</screen><para><indexterm><primary>devices</primary><secondary>writing</secondary></indexterm><indexterm><primary>commands</primary><secondary><command>echo</command></secondary></indexterm><indexterm><primary><command>echo</command> command</primary></indexterm>Test writing to the device:</para><screen># <userinput>echo hello &gt; `ls /devices/pseudo/dummy*`</userinput></screen><para>You should see the following messages in the window where you are viewing <filename>/var/adm/messages</filename>:</para><screen><replaceable>date</replaceable> <replaceable>time</replaceable> <replaceable>machine</replaceable> dummy: [ID 136952 kern.notice] NOTICE: Inside dummy_open
<replaceable>date</replaceable> <replaceable>time</replaceable> <replaceable>machine</replaceable> dummy: [ID 623947 kern.notice] NOTICE: Inside dummy_getinfo
<replaceable>date</replaceable> <replaceable>time</replaceable> <replaceable>machine</replaceable> dummy: [ID 891851 kern.notice] NOTICE: Inside dummy_prop_op
<replaceable>date</replaceable> <replaceable>time</replaceable> <replaceable>machine</replaceable> dummy: [ID 623947 kern.notice] NOTICE: Inside dummy_getinfo
<replaceable>date</replaceable> <replaceable>time</replaceable> <replaceable>machine</replaceable> dummy: [ID 891851 kern.notice] NOTICE: Inside dummy_prop_op
<replaceable>date</replaceable> <replaceable>time</replaceable> <replaceable>machine</replaceable> dummy: [ID 623947 kern.notice] NOTICE: Inside dummy_getinfo
<replaceable>date</replaceable> <replaceable>time</replaceable> <replaceable>machine</replaceable> dummy: [ID 672780 kern.notice] NOTICE: Inside dummy_write
<replaceable>date</replaceable> <replaceable>time</replaceable> <replaceable>machine</replaceable> dummy: [ID 550206 kern.notice] NOTICE: Inside dummy_close</screen><para>As you can see, this output from the write test is almost identical
to the output you saw from the read test. The only difference is in the seventh
line of the output. Using the <olink targetdoc="group-refman" targetptr="cat-1" remap="external"><citerefentry><refentrytitle>cat</refentrytitle><manvolnum>1</manvolnum></citerefentry></olink> command
causes the kernel to access the <olink targetdoc="group-refman" targetptr="read-9e" remap="external"><citerefentry><refentrytitle>read</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink> entry point of the driver. Using the <olink targetdoc="group-refman" targetptr="echo-1" remap="external"><citerefentry><refentrytitle>echo</refentrytitle><manvolnum>1</manvolnum></citerefentry></olink> command causes the kernel
to access the <olink targetdoc="group-refman" targetptr="write-9e" remap="external"><citerefentry><refentrytitle>write</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink> entry
point of the driver. The text argument that you give to <olink targetdoc="group-refman" targetptr="echo-1" remap="external"><citerefentry><refentrytitle>echo</refentrytitle><manvolnum>1</manvolnum></citerefentry></olink> is ignored because this driver
does not do anything with that data.</para>
</sect2><sect2 id="eqbqw"><title>Removing the Template Driver</title><indexterm><primary>device drivers</primary><secondary>removing</secondary>
</indexterm><indexterm><primary>commands</primary><secondary><command>rem_drv</command></secondary>
</indexterm><indexterm><primary><command>rem_drv</command> command</primary>
</indexterm><para>Make sure you are user <literal>root</literal> when you unload the driver.
Use the <olink targetdoc="group-refman" targetptr="rem-drv-1m" remap="external"><citerefentry><refentrytitle>rem_drv</refentrytitle><manvolnum>1M</manvolnum></citerefentry></olink> command
to unload the driver and remove the device from the <filename>/devices</filename> directory:</para><screen># <userinput>rem_drv dummy</userinput></screen><para>You should see the following messages in the window where you are viewing <filename>/var/adm/messages</filename>:</para><screen><replaceable>date</replaceable> <replaceable>time</replaceable> <replaceable>machine</replaceable> dummy: [ID 513080 kern.notice] NOTICE: Inside _info
<replaceable>date</replaceable> <replaceable>time</replaceable> <replaceable>machine</replaceable> dummy: [ID 617648 kern.notice] NOTICE: Inside dummy_detach
<replaceable>date</replaceable> <replaceable>time</replaceable> <replaceable>machine</replaceable> dummy: [ID 812373 kern.notice] NOTICE: Inside _fini</screen><para>The <literal>dummy</literal> device is no longer in the <filename>/devices</filename> directory:</para><screen># <userinput>ls /devices/pseudo/dummy*</userinput>
/devices/pseudo/dummy*: No such file or directory</screen><para>The next time you want to read from or write to the <literal>dummy</literal> device,
you must load the driver again using <citerefentry><refentrytitle>add_drv</refentrytitle><manvolnum>1M</manvolnum></citerefentry>.</para><para><indexterm><primary>device drivers</primary><secondary>unloading</secondary></indexterm><indexterm><primary>commands</primary><secondary><command>modunload</command></secondary></indexterm><indexterm><primary><command>modunload</command> command</primary></indexterm>You can use the <olink targetdoc="group-refman" targetptr="modunload-1m" remap="external"><citerefentry><refentrytitle>modunload</refentrytitle><manvolnum>1M</manvolnum></citerefentry></olink> command to unload the driver
but not remove the device from <filename>/devices</filename>. Then the next
time you read from or write to the <literal>dummy</literal> device, the driver
is automatically loaded.</para><para>Press Control-C to stop tailing the <filename>/var/adm/messages</filename> messages.</para>
</sect2>
</sect1><sect1 id="eqbof"><title>Complete Template Driver Source</title><para>The following code is the complete source for the <literal>dummy</literal> driver
described in this chapter:</para><programlisting>/*
 * 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 &gt; `ls /devices/pseudo/dummy@*`
 * Verify the tests in another window:
 *      tail -f /var/adm/messages
 * Remove the driver:
 *      rem_drv dummy
 */

#include &lt;sys/devops.h&gt;  /* used by dev_ops */
#include &lt;sys/conf.h&gt;    /* used by dev_ops and cb_ops */
#include &lt;sys/modctl.h&gt;  /* used by modlinkage, modldrv, _init, _info, */
                         /* and _fini */
#include &lt;sys/types.h&gt;   /* used by open, close, read, write, prop_op, */
                         /* and ddi_prop_op */
#include &lt;sys/file.h&gt;    /* used by open, close */
#include &lt;sys/errno.h&gt;   /* used by open, close, read, write */
#include &lt;sys/open.h&gt;    /* used by open, close, read, write */
#include &lt;sys/cred.h&gt;    /* used by open, close, read */
#include &lt;sys/uio.h&gt;     /* used by read */
#include &lt;sys/stat.h&gt;    /* defines S_IFCHR used by ddi_create_minor_node */
#include &lt;sys/cmn_err.h&gt; /* used by all entry points for this driver */
#include &lt;sys/ddi.h&gt;     /* used by all entry points for this driver */
                         /* also used by cb_ops, ddi_get_instance, and */
                         /* ddi_prop_op */
#include &lt;sys/sunddi.h&gt;  /* 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 */
    &amp;dummy_cb_ops,
    (struct bus_ops *)NULL,
    nodev,                     /* no power(9E) */
    ddi_quiesce_not_needed,    /* no quiesce(9E) */
};

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

/* modlinkage structure */
static struct modlinkage ml = {
    MODREV_1,
    &amp;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(&amp;ml));
}

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

int
_fini(void)
{
    cmn_err(CE_NOTE, "Inside _fini");
    return(mod_remove(&amp;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;
}</programlisting>
</sect1>
</chapter><?Pub *0000129950 0?>