The comedi/drivers
subdirectory contains
the board-specific device driver
code. Each new card must get an entry in this directory.
Or
extend the functionality of an already existing driver file if the new
card is quite similar to that implemented in an already existing
driver. For example, many of the National Instruments DAQ cards use
the same driver files.
To help device driver writers,
Comedi provides the “skeleton” of a new device driver,
in the comedi/drivers/skel.c
file. Before
starting to write a new driver, make sure you understand this file,
and compare it to what you find in the other already available
board-specific files in the same directory.
The first thing you notice in skel.c
is the
documentation section: the Comedi documentation is partially
generated automatically, from the information that is given in this
section. So, please comply with the structure and the keywords
provided as Comedi standards.
The second part of the device driver contains board-specific static data structure and defines: addresses of hardware registers; defines and function prototypes for functionality that is only used inside of the device driver for this board; the encoding of the types and number of available channels; PCI information; etc.
Each driver has to register two functions which are called when you load and unload your board's device driver (typically via a kernel module):
mydriver_attach(); mydriver_detach();
In the “attach” function, memory is allocated for the
necessary data structures,
all properties of a device and its subdevices are defined, and filled
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 mydriver_attach
function must:
check and request the I/O port region, IRQ, DMA, and other hardware resources. It is convenient here if you verify the existence of the hardware and the correctness of the other information given. Sometimes, unfortunately, this cannot be done.
allocate memory for the private data structures.
initialize the board registers and possible subdevices (timer, DMA, PCI, hardware FIFO, etc.).
return 1
, indicating success. If there were any errors along the way,
you should return the appropriate (negative) error number. If an error is
returned, the mydriver_detach
function is
called. The mydriver_detach
function should
check any resources that may have been allocated and release them as
necessary. The Comedi core frees
dev->subdevices
and
dev->private
, so this does not need to be done in
mydriver_detach
.
If the driver has the possibility to offer asynchronous data acquisition, you have to code an interrupt service routine, event handling routines, and/or callback routines.
Typically, you will be able to implement most of
the above-mentioned functionality by
cut-and-paste from already existing drivers. The
mydriver_attach
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
an appropriate initialization. The good news, of course, is that
Comedi provides the data structures and the defines that fit very
well with almost all DAQ functionalities found on interface cards.
These can be found in the
header files of the
include/linux/
directory.
Drivers with digital I/O subdevices should implement the following functions, setting the function pointers in the comedi_subdevice:
insn_bits
: 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.
insn_config
: implements INSN_CONFIG
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
interface.
Finally, the device driver writer must implement the
insn_read
and insn_write
functions for
the analog channels on the card:
insn_read
: acquire the inputs on the board and
transfer them to the software buffer of the driver.
insn_write
: transfer data from the software
buffer to the card, and execute the appropriate output conversions.
In some drivers, you want to catch interrupts, and/or want to use the
INSN_INTTRIG
instruction. In this
case, you must provide and register these
callback functions.
Implementation of all of the above-mentioned functions requires perfect knowledge about the hardware registers and addresses of the interface card. In general, you can find some inspiration in the already available device drivers, but don't trust that blind cut-and-paste will bring you far…