</title>
<para>
-This Section explains the most important implementations aspects of
+This section explains the most important implementations aspects of
the &comedi; device drivers. It tries to give the interested device
driver writer an overview of the different steps required to write a
new device driver.
</para>
<para>
-This Section does <emphasis>not</emphasis> explain all implementation
+This section does <emphasis>not</emphasis> explain all implementation
details of the &comedi; software itself: &comedi; has once and for
all solved lots of boring but indispensable infrastructural things,
such as: timers, management of which drivers
<listitem>
<para>
How does the
-<link linkend="userkernelhow">communication</link> between user space
-and kernel space work?
+<link linkend="userkernelhow">communication</link> between user-space
+and kernel-space work?
</para>
</listitem>
<section id="userkernelhow">
<title>
-Communication user space-kernel space
+Communication user-space — kernel-space
</title>
<para>
-In user space, you interact with the functions implemented in the
-<filename role="directory">/usr/src/comedilib</filename> directory. Most
-of the device driver core of the Comedilib library is found in
+In user-space, you interact with the functions implemented in the
+Comedilib library.
+Most of the device driver core of the Comedilib library is found in
<filename role="directory">lib</filename> subdirectory.
</para>
<para>
<link linkend="commandsstreaming">commands</link>
are transmitted to kernel space through a traditional
<function>ioctl</function> system call.
-(See <filename>/usr/src/comedilib/lib/ioctl.c</filename>.)
-The user space information command is <emphasis>encoded</emphasis> as
+(See <filename>lib/ioctl.c</filename> in Comedilib.)
+The user-space information command is <emphasis>encoded</emphasis> as
a number in the <function>ioctl</function> call, and decoded in the
-kernel space library. There, they are executed by their kernel-space
+kernel-space library. There, they are executed by their kernel-space
counterparts. This is done in the
-<filename>/usr/src/comedi/comedi/comedi_fops.c</filename> file: the
-<function>comedi_ioctl()</function> function processes the results of
+<filename>comedi_fops.c</filename> file in the Comedi sources: the
+<function>comedi_unlocked_ioctl</function> function processes the results of
the <function>ioctl</function> system call, interprets its contents,
-and then calls the corresponding kernel space
+and then calls the corresponding kernel-space
<function>do_…_ioctl</function> function(s).
For example, a &comedi;
<link linkend="instructions">instruction</link> is further processed
-by the <function>do_insn_ioctl()</function>function. (Which, in turn,
-uses <function>parse_insn()</function> for further detailed processing.)
+by the <function>do_insn_ioctl</function> function. (Which, in turn,
+uses <function>parse_insn</function> for further detailed processing.)
</para>
<para>
The data corresponding to instructions and commands is transmitted
-with the <function>copy_from_user()</function> system call;
-acquisition data captured by the interface card passes the kernel-user
-space boundary with the help of a <function>copy_to_user()</function>
-system call.
+with the <function>copy_from_user</function> function;
+acquisition data captured by the interface card passes the
+kernel/user-space boundary with the help of a <function>copy_to_user</function>
+function.
</para>
</section>
<listitem>
<para>
<filename>include/linux/comedilib.h</filename>: the header file for
-the kernel library of &comedi;.
+the kernel library of &comedi; (<systemitem>kcomedilib</systemitem> module).
</para>
</listitem>
</para>
<para>
From all the relevant &comedi; device driver code that is found in the
-<filename role="directory">/usr/src/comedi/comedi</filename> directory
-(<emphasis>if</emphasis> the &comedi; source has been installed in its
-normal <filename role="directory">/usr/src/comedi</filename> location),
+<filename role="directory">comedi</filename> kernel module source directory,
the <emphasis role="strong">generic</emphasis> functionality is
contained in two parts:
<itemizedlist>
</para>
<para>
There are some differences in what is possible and/or needed
-in kernel space and in user space, so the functionalities offered in
+in kernel-space and in user-space, so the functionalities offered in
<filename role="directory">kcomedilib</filename> are not an exact copy
of the user-space library. For example, locking, interrupt handling,
real-time execution, callback handling, etc., are only available in
-kernel space.
+kernel-space.
</para>
<para>
Most drivers don't make use (yet) of these real-time functionalities.
typedef struct comedi_driver_struct <link linkend="comedidriver">comedi_driver</link>;
</programlisting>
They can be found in
-<filename>/usr/src/comedi/include/linux/comedidev.h</filename>.
+<filename>include/linux/comedidev.h</filename>.
Most of the fields are filled in by the &comedi; infrastructure, but
there are still quite a handful that your driver must provide or use.
As for the user-level &comedi;, each of the hierarchical layers has
-its own data structures: channel (<function>comedi_lrange</function>),
+its own data structures: range (<type>comedi_lrange</type>),
subdevice, and device.
</para>
<para>
<emphasis>hardware</emphasis>, not with the <emphasis>user</emphasis>.
</para>
<para>
-However, the <link linkend="ref-type-comedi-insn">comedi_insn</link>
-and <link linkend="ref-type-comedi-cmd">comedi_cmd</link>
-data structures are shared between user space and kernel space: this
+However, the <type><link linkend="ref-type-comedi-insn">comedi_insn</link></type>
+and <type><link linkend="ref-type-comedi-cmd">comedi_cmd</link></type>
+data structures are shared between user-space and kernel-space: this
should come as no surprise, since these data structures contain all
information that the user-space program must transfer to the
kernel-space driver for each acquisition.
level (device, sub-device, channel), the device driver level provides
two more data structures which the application programmer doesn't get
in touch with: the data structure
-<link linkend="comedidriver">comedi_driver</link>
+<type><link linkend="comedidriver">comedi_driver</link></type>
that stores the device driver information that is relevant at the
operating system level, and the data structure
-<link linkend="comediasync">comedi_async</link> that stores the
+<type><link linkend="comediasync">comedi_async</link></type> that stores the
information about all <emphasis>asynchronous</emphasis> activities
(interrupts, callbacks and events).
</para>
<section id="comedilrange">
<title>
-<function>comedi_lrange</function>
+<type>comedi_lrange</type>
</title>
<para>
The channel information is simple, since it contains only the signal
<section id="comedisubdevice">
<title>
-<function>comedi_subdevice</function>
+<type>comedi_subdevice</type>
</title>
<para>
The subdevice is the smallest &comedi; entity that can be used for
unsigned int state;
};
</programlisting>
-The function pointers <function>(*insn_read)</function> …
-<function>(*cancel)</function> .
+The function pointers <structfield>insn_read</structfield> …
+<structfield>cancel</structfield> .
offer (pointers to) the standardized
<link linkend="functionreference">user-visible API</link>
that every subdevice should offer; every device driver has to fill
definition, not show up in the device driver data structures.)
</para>
<para>
-The <function>buf_change()</function> and <function>munge()</function>
-functions offer functionality that is not visible to the user and for
+The <structfield>buf_change</structfield> and <structfield>munge</structfield>
+function pointers offer functionality that is not visible to the user and for
which the device driver writer must provide a board-specific
implementation:
-<function>buf_change()</function> is called when a change in the
-data buffer requires handling; <function>munge()</function> transforms
+<function>buf_change</function> is called when a change in the
+data buffer requires handling; <function>munge</function> transforms
different bit-representations of DAQ values, for example from
<emphasis>unsigned</emphasis> to <emphasis>2's complement</emphasis>.
</para>
<section id="comedidevice">
<title>
-<function>comedi_device</function>
+<type>comedi_device</type>
</title>
<para>
<section id="comediasync">
<title>
-<function>comedi_async</function>
+<type>comedi_async</type>
</title>
<para>
<section id="comedidriver">
<title>
-<function>comedi_driver</function>
+<type>comedi_driver</type>
</title>
<para>
</title>
<para>
-The <filename role="directory">/usr/src/comedi/comedi/drivers</filename>
+The <filename role="directory">comedi/drivers</filename>
subdirectory contains
the <emphasis role="strong">board-specific</emphasis> device driver
code. Each new card must get an entry in this directory.
in in the generic &comedi; data structures. As part of this, pointers
to the low level instructions being supported by the subdevice have to
be set, which define the basic functionality. In somewhat more detail,
-the <function>mydriver_attach()</function> function must:
+the <function>mydriver_attach</function> function must:
<itemizedlist>
<listitem>
<listitem>
<para>
-return 1, indicating success. If there were any errors along the way,
-you should return the appropriate error number. If an error is
-returned, the <function>mydriver_detach()</function> function is
-called. The <function>mydriver_detach()</function> function should
+return <literal>1</literal>, indicating success. If there were any errors along the way,
+you should return the appropriate (negative) error number. If an error is
+returned, the <function>mydriver_detach</function> function is
+called. The <function>mydriver_detach</function> function should
check any resources that may have been allocated and release them as
necessary. The &comedi; core frees
-<function>dev->subdevices</function> and
-<function>dev->private</function>, so this does not need to be done in
-<function>detach</function>.
+<structfield>dev->subdevices</structfield> and
+<structfield>dev->private</structfield>, so this does not need to be done in
+<function>mydriver_detach</function>.
</para>
</listitem>
Typically, you will be able to implement most of
the above-mentioned functionality by
<emphasis>cut-and-paste</emphasis> from already existing drivers. The
-<function>mydriver_attach()</function> function needs most of your
+<function>mydriver_attach</function> function needs most of your
attention, because it must correctly define and allocate the (private
and generic) data structures that are needed for this device. That is,
each sub-device and each channel must get appropriate data fields, and
well with almost all DAQ functionalities found on interface cards.
These can be found in the
<link linkend="comedikernelgeneric">header files</link> of the
-<filename role="directory">/usr/src/comedi/include/linux/</filename>
+<filename role="directory">include/linux/</filename>
directory.
</para>
<para>
-Drivers for digital IOs should implement the following functions:
+Drivers with digital I/O subdevices should implement the following functions,
+setting the function pointers in the <type>comedi_subdevice</type>:
<itemizedlist>
<listitem>
<para>
-<function>insn_bits()</function>: drivers set this if they have a
+<function>insn_bits</function>: drivers set this if they have a
function that supports reading and writing multiple bits in a digital
I/O subdevice at the same time. Most (if not all) of the drivers use
this interface instead of insn_read and insn_write for DIO subdevices.
<listitem>
<para>
-<function>insn_config()</function>: implements INSN_CONFIG
+<function>insn_config</function>: implements <constant>INSN_CONFIG</constant>
instructions. Currently used for configuring the direction of digital
I/O lines, although will eventually be used for generic configuration
of drivers that is outside the scope of the currently defined &comedi;
</itemizedlist>
Finally, the device driver writer must implement the
-<function>read</function> and <function>write</function> functions for
+<function>insn_read</function> and <function>insn_write</function> functions for
the analog channels on the card:
<itemizedlist>
<listitem>
<para>
-<function>insn_read()</function>: acquire the inputs on the board and
+<function>insn_read</function>: acquire the inputs on the board and
transfer them to the software buffer of the driver.
</para>
</listitem>
<listitem>
<para>
-<function>insn_write()</function>: transfer data from the software
+<function>insn_write</function>: transfer data from the software
buffer to the card, and execute the appropriate output conversions.
</para>
</listitem>
</itemizedlist>
In some drivers, you want to catch interrupts, and/or want to use the
-<link linkend="insn-inttrig">INSN_INTTRIG</link> instruction. In this
+<constant><link linkend="insn-inttrig">INSN_INTTRIG</link></constant>
+instruction. In this
case, you must provide and register these
<link linkend="drivercallbacks">callback</link> functions.
</para>
<listitem>
<para>
Another driver-supplied callback function is executed when the user
-program launches an <link linkend="insn-inttrig">INSN_INTTRIG</link>
+program launches an <constant><link linkend="insn-inttrig">INSN_INTTRIG</link></constant>
instruction. This event handling is executed
<emphasis>synchronously</emphasis> with the execution of the
triggering instruction.
s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR
</programlisting>
It fills in the bits corresponding to particular events in the
-<link linkend="comediasync">comedi_async</link> data structure.
+<type><link linkend="comediasync">comedi_async</link></type> data structure.
The possible event bits are:
<itemizedlist>
<listitem>
<para>
<anchor id="comedi-cb-eoa"/>
-<parameter>COMEDI_CB_EOA</parameter>: execute the callback at the
+<constant>COMEDI_CB_EOA</constant>: execute the callback at the
<quote>End-Of-Acquisition</quote> (or <quote>End-Of-Output</quote>).
</para>
</listitem>
<listitem>
<para>
<anchor id="comedi-cb-eos"/>
-<parameter>COMEDI_CB_EOS</parameter>: execute the callback at the
+<constant>COMEDI_CB_EOS</constant>: execute the callback at the
<quote>End-Of-Scan</quote>.
</para>
</listitem>
<listitem>
<para>
<anchor id="comedi-cb-overflow"/>
-<parameter>COMEDI_CB_OVERFLOW</parameter>: execute the callback when a
+<constant>COMEDI_CB_OVERFLOW</constant>: execute the callback when a
buffer overflow or underflow has occurred.
</para>
</listitem>
<listitem>
<para>
<anchor id="comedi-cb-error"/>
-<parameter>COMEDI_CB_ERROR</parameter>: execute the callback at the
+<constant>COMEDI_CB_ERROR</constant>: execute the callback at the
occurrence of an (undetermined) error.
</para>
</listitem>
<listitem>
<para>
Drivers are to have absolutely <emphasis role="strong">no</emphasis>
-global variables, mainly because the existence of global variables
+global variables (apart from read-only, constant data, or data structures
+shared by all devices), mainly because the existence of global variables
immediately negates any possibility of using the driver for two
-devices. The pointer <function>dev->private</function> should be used
+devices. The pointer <structfield>dev->private</structfield> should be used
to point to a structure containing any additional variables needed by
a driver/device combination.
</para>
<listitem>
<para>
Drivers should report errors and warnings via the
-<function>comedi_error()</function> function.
+<function>comedi_error</function> function.
(This is <emphasis>not</emphasis> the same function as the user-space
-<link linkend="func-ref-comedi-perror">comedi_perror()</link> function.)
+<function><link linkend="func-ref-comedi-perror">comedi_perror</link></function> function.)
</para>
</listitem>
<listitem>
<para>
-Put your new driver into <quote>comedi/drivers/mydriver.c</quote>.
+Put your new driver into <filename>comedi/drivers/mydriver.c</filename>.
</para>
</listitem>
<listitem>
<para>
-Edit <quote>comedi/drivers/Makefile.am</quote> and add <quote>mydriver.ko</quote>
-to the <quote>module_PROGRAMS</quote> list. Also add a line
+Edit <filename>comedi/drivers/Makefile.am</filename> and add <literal>mydriver.ko</literal>
+to the <literal>module_PROGRAMS</literal> list. Also add a line
<programlisting>
mydriver_ko_SOURCES = mydriver.c
</programlisting>
<listitem>
<para>
-Run ./autogen.sh in the top-level comedi directory. You will
+Run <command>./autogen.sh</command> in the top-level comedi directory. You will
need to have (a recent version of) autoconf and automake
-installed to successfully run autogen.sh. Afterwards, your driver will
-be built along with the rest of the drivers when you 'make'.
+installed to successfully run <command>autogen.sh</command>. Afterwards, your driver will
+be built along with the rest of the drivers when you run <command>make</command>.
</para>
</listitem>
<para>
If you want to have your driver included in the &comedi; distribution
(you <emphasis>definitely</emphasis> want to :-) ) send it to
-David Schleef <address><email>ds@schleef.org</email></address> or
-Frank Hess <address><email>fmhess@users.sourceforge.net</email></address>
-for review and integration. Note your work must be licensed under terms
-compatible with the GNU GPL to be distributed as a part of Comedi.
+the &comedi; mailing list
+for review and integration. See the top-level <filename>README</filename>
+for details of the &comedi; mailing list.)
+Note your work must be licensed under terms
+compatible with the GNU GPL to be distributed as a part of &comedi;.
</para>
</listitem>
</itemizedlist>