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.
This section does not 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
are active, memory management for drivers and buffers, wrapping
of RTOS-specific interfaces, interrupt handler management, general
error handling, the /proc
interface, etc. So,
the device driver writers can concentrate on the interesting stuff:
implementing their specific interface card's DAQ functionalities.
In order to make a decent Comedi device driver, you must know the answers to the following questions:
How does the communication between user-space and kernel-space work?
What functionality is provided by the generic kernel-space Comedi functions, and what must be provided for each specific new driver?
How to use DMA and interrupts?
What are the addresses and meanings of all the card's registers?
This information is to be found in the so-called “register level manual” of the card. Without it, coding a device driver is close to hopeless. It is also something that Comedi (and hence also this handbook) cannot give any support or information for: board manufacturers all use their own design and nomenclature.
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
lib
subdirectory.
All user-space Comedi
instructions and
commands
are transmitted to kernel space through a traditional
ioctl
system call.
(See lib/ioctl.c
in Comedilib.)
The user-space information command is encoded as
a number in the ioctl
call, and decoded in the
kernel-space library. There, they are executed by their kernel-space
counterparts. This is done in the
comedi_fops.c
file in the Comedi sources: the
comedi_unlocked_ioctl
function processes the results of
the ioctl
system call, interprets its contents,
and then calls the corresponding kernel-space
do_…_ioctl
function(s).
For example, a Comedi
instruction is further processed
by the do_insn_ioctl
function. (Which, in turn,
uses parse_insn
for further detailed processing.)
The data corresponding to instructions and commands is transmitted
with the copy_from_user
function;
acquisition data captured by the interface card passes the
kernel/user-space boundary with the help of a copy_to_user
function.