-
Hardware driver interface
-
+=========================
[ this is a little outdated -ds ]
[ this is a lot outdated -fmh ]
+[ this is a little bit less outdated, hopefully -rs ]
+
+
+Table of Contents
+=================
+
+1. Introduction
+2. The source tree
+3. Adding new drivers
+4. Driver basics
+5. Instructions
+
+
1. Introduction
-This comedi hardware driver writing HOWTO is written to help you
-write a driver for your particular choice of hardware. You should
-be familiar with how comedi works from the user's point of view,
-i.e., from a process that is utilizing the comedi driver.
+This comedi hardware driver writing HOWTO is written to help you write a
+driver for your particular choice of hardware. You should be familiar with
+how comedi works from the user's point of view, i.e., from a process that is
+utilizing the comedi driver.
+
+This guide does not explain the details of things like reading and writing
+I/O ports, Linux kernel internals, or interrupt processing. These issues are
+covered in other documents, e.g.
+
+- The IO-Port Programming Mini HOWTO:
+ http://www.linuxdoc.org/HOWTO/mini/IO-Port-Programming.html
+
+- Linux Kernel Module Programming Guide
+ http://www.linuxdoc.org/LDP/lkmpg/mpg.html
+
+- Kernel Hacker's Guide
+ http://www.linuxdoc.org/LDP/khg/HyperNews/get/khg.html
+
+- The Linux source
+
-This guide does not explain the details of things like reading
-and writing I/O ports, Linux kernel internals, or interrupt
-processing. These issues are covered in other documents,
-specifically, the IO-Port-Programming mini-HOWTO, the Kernel
-Hacker's Guide, and the Linux source.
2. The source tree
-As of comedi-0.5.0, hardware drivers need to be part of the
-source tree and be compiled with the rest of the comedi driver
-into the module comedi.o. Later versions will hopefully support
-separate compiling/separate modules, etc.
+Currently hardware drivers need to be part of the source tree and be
+compiled with the rest of the comedi driver into the module comedi.o. Later
+versions will hopefully support separate compiling/separate modules, etc.
+
+The source for the comedi module is located in the 'comedi/' directory,
+including the device independent part. The source files of the hardware
+drivers for the different boards are located in 'comedi/drivers/', the
+kernel space library (which is used for accessing comedi from realtime
+programs) lives in 'comedi/kcomedilib/'.
+
+In the drivers' directory there is a striped-down example ('skel.c') that
+may be a good starting point for new hardware drivers.
+
+
+
-The source for the comedi module is located in module/, including
-the device independent part and each hardware driver. A hardware
-driver, such as the "dt282x" driver, is typically located in the
-C source file of the same name.
+3. Adding new drivers
-The hardware driver "dummy" is a stripped-down example that may be
-a good starting point for new hardware drivers.
+The best way to write a new driver is to take one of the existing ones (e.g.
+the 'skel' driver) and modify it to your own needs. For integrating new
+drivers in the comedi source tree the following things have to be done:
+- Put your new driver into 'comedi/drivers/mydriver.c'.
+- Edit 'comedi/Config.in' and add a new 'dep_tristate' line (look at the
+ other examples). Invent a senseful name for the driver's variable.
+- Add a line to 'comedi/drivers/Makefile', using your freshly defined
+ variable.
-3. comedi_config and *_init()
+Now 'make distclean', reconfigure comedi with a new 'make', rebuild and be
+happy. If you want to have your driver included in the comedi distribution
+(you _definitely_ want to :) ) send it to David Schleef <ds@schleef.org> for
+review and integration.
-The file "module/comeditypes.c" has a list of the initialization
-functions for all the drivers. You should add your init function
-to this list. The top level Makefile and scripts/configure
-take care of all the defines.
-The purpose of comeditypes.c is to keep a list of available
-hardware drivers by keeping a list of available initialization
-functions. Thus, when comedi_config is run, it issues the
-COMEDI_CONFIG ioctl() with the name of the driver and
-configuration parameters (I/O port address, irq, dma, etc.).
-The comedi driver then calls the initialization function of
-each hardware driver on the list.
-Inside the initialization function, you should perform the
-following tasks:
- o Check to see if you are the correct hardware driver
- for the name specified in the comedi_devconfig structure.
- Your hardware driver may consider several names as
- "correct", and even behave differently depending on
- the name given. The idea here is to support different
- cards in a series using different names, but using the
- same hardware driver. If you are not the correct
- hardware driver, return a 0.
+4. Driver basics
- o Announce that the hardware driver has begun initialization
- by a printk("comedi%d: driver: ",minor);
+Implementation details for the following things can be found in the skel
+driver. Each driver has to register two functions which are called when you
+configure and deconfigure your board:
- o 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.
+- mydriver_attach()
+- mydriver_detach()
+
+In the 'attach' function all properties of a device and its subdevices are
+defined. As part of this pointers to the low level instructions being
+supported by the subdevice have to be set (see next section) which define
+the basic functionality.
+
+
+
+5. Instructions
+
+Instructions (insns) are comedi's low level functins for accessing all kinds
+of channels, like analog or digital IOs.
+
+Drivers for digital IOs should implement the following functions:
+
+- 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.
+
+Drivers for analog IOs should implement these function:
+
+- insn_read():
+ Analog inputs have to implement insn_read.
+
+- insn_write():
+ The same with insn_write.
+
+
+[THIS SEEMS TO BE OBSOLETE??? -rs] -------------------------------------------
+
+Inside the initialization function, you should perform the following tasks:
+
+ o Announce that the hardware driver has begun initialization by a
+ printk("comedi%d: driver: ",minor);
+
+ o 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.
o Fill in the comedi_device structure.
- o Allocate your private data structure and space for channel
- configuration.
-
- o Configure each channel. Each channel has three function
- pointers: one for triggering a single conversion (itrig),
- one for triggering general conversions (trig), and one
- for setting channel parameters (sp). Each channel also has
- a parameter linked list.
- Parameters are added to this list via addparam(). All the
- parameter routines are in param.c. They are currently not
- very efficient, so if you know of a better algorithm...
- Look at the header files for parameter types that you may
- wish to include.
-
- o Initialize the read buffer via comedi_initbuf(). The buffering
- routines are in buffer.c, and support multiple processes
- reading the same device. The buffers are also dynamic, so
- you don't have to worry about the hardware driver collecting
- 1M of data before the controlling process reads it. I've been
- using these routines for a while--they appear to be pretty
- stable. Most of the error messages you get from the buffer
- routines indicate memory leaks.
-
- o Set mtrig in the comedi_device structure to the function that
- is called for a channel scan trigger.
-
- o Tell the comedi driver the function to call when your driver
- needs to be removed.
-
- o Return a 1. If there were any errors along the way, you
- should return the appropriate error number, but don't forget
- to release any resources that you allocated. (It will only
- take one time to realize that if you don't release an I/O region,
- you have to reboot to get it back. (Or write a hack, as I did.))
-
-
-4. Set Parameter routines
-
-When the COMEDI_SETPARAM ioctl() is called, the comedi driver
-calls the setparameter routine of the channel involved. Common
-settable parameters are input gain (input range) and setting bits
-on digital I/O lines as input or output. The setparameter
-function should check the validity of the parameter type and
-value, and then call changeparam() to update the parameter
-linked lists. If necessary, calls to update the hardware
-should be made.
-
-
-5. Triggering routines
-
-Like the setparameter routines, each channel has a trigger
-function that is called for a COMEDI_TRIG ioctl(). The trigger
-function is called with the comedi_trig structure, which
-includes the trigger type, number of samples, and one sample value
-(which may be read or written, depending on context).
-
-As of 0.5.0, there are two triggering routines per channel, one
-for TRIGNOW, and one for all the rest. The reason this was done
-is because the TRIGNOW functions are exported to the rest of the
-kernel (i.e., for RTLinux).
-
-Trigger types are accompanied by the trigger variable, which
-is interpreted based on the trigger type. The types of triggers
-(currently) available are:
-
- o COMEDI_TRIGNOW - causes one sample conversion to be
- completed immediately. The trigger variable and number of
- samples are ignored.
-
- o COMEDI_TRIGCLK - causes conversions timed by a clock on
- the hardware. The trigger variable determines the clock
- speed.
-
- o COMEDI_TRIGEXT - causes conversions to be triggered by
- an external trigger provided by the hardware. The trigger
- variable determines the particular choice, if there is
- more than one choice.
-
-Other trigger sources that may be defined in the future are
-analog triggers and comedi triggers. Comedi triggers could include
-the 100 Hz interrupt, the rtc interrupt, general timing triggers,
-signals generated by other boards, etc.
-
-Except for COMEDI_TRIGNOW, your triggering routine should return
-after telling the hardware to perform the requested task. For
-COMEDI_TRIGNOW on input, you should wait for the conversion to
-finish and return it in the ioctl structure, but do *NOT* report
-the sample via report_sample().
-
-Typically, you will poll the hardware or the hardware will
-generate interrupts to tell you when samples are ready. The
-samples should be reported via report_sample().
-
-
-6. The remove function
-
-A driver is removed from service via a call to dev->rem(). The driver
-is expected to halt all conversions, put the hardware in a sane,
-off-line state, delete all channel parameters, free all allocated memory,
-and release any irq's and port addresses held. If these things are
-not all done, there will be memory leaks, and more importantly, the
-driver will not configure properly if reused.
+ o Allocate your private data structure and subdevices.
+
+ o Set up each subdevice.
+
+ o Return 0, indicating sucess. If there were any errors along
+ the way, you should return the appropriate error number. If
+ an error is returned, the _detach function is called. The
+ _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 _detach.
A. Goals
-