Hardware driver interface
=========================

[ this is a little outdated -ds ]
[ this is a lot outdated -fmh ]
[ this is a little bit less outdated, hopefully -rs ]
[ the 'adding new drivers' section has been updated -ija ]


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 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

- Linux Device Drivers, 2nd Edition
  http://www.xml.com/ldd/chapter/book/index.html

- The Linux source




2. The source tree

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. 




3. Adding new 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/drivers/Makefile.am' and update 'module_PROGRAMS',
  'pcmcia_modules', or 'usb_modules', depending on the type of driver.
  Add a 'mydriver_KO_sources' macro set to your 'mydriver.c' file (look
  at the other examples).  If your driver has its own include files, add
  them to the EXTRA_DIST macro.
- Edit 'comedi/drivers/Kbuild' and add a 'obj-m += mydriver.o',
  'obj-$(COMEDI_CONFIG_PCMCIA_MODULES) += mydriver.o', or
  'obj-$(COMEDI_CONFIG_USB_MODULES) += mydriver.o' line, depending on the
  type of driver.

Now run 'autoreconf' to update the configure script, re-run './configure'
with any necessary command-line options to update the makefiles, and run
'make' to rebuild comedi 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.




4. Driver basics

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:

- 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 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

A few things to strive for:

   o  Your hardware driver should be functional appropriate to
      the resources allocated.  I.e., if the driver is fully
      functional when configured with an IRQ and DMA, it should
      still function moderately well with just an IRQ, or still
      do minor tasks without IRQ or DMA.  Does your driver really
      require an IRQ to do digital I/O?  Maybe someone will want
      to use your driver *just* to do digital I/O and has no
      interrupts available.

   o  Drivers are to have absolutely *NO* global variables, mainly
      because the existence of global variables immediately negates
      any possibility of using the driver for two devices.  The
      pointer dev->private should be used to point to a structure
      containing any additional variables needed by a driver/device
      combination.

   o  Drivers should report errors and warnings via a printk line
      that starts with "comedi%d: driver_name:" where %d is the
      minor number of the device.



