adc linux kernel driver
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


This is a port of the old PCI-AI12-16 data acquision driver for Linux to
a more recent kernel version (2.6.34 as of right now.)

Note, the license does not seem to work well with the GPL, so it can not
be distributed with the rest of the Linux kernel source tree.  I have
only forward ported the driver, fixing the obvious build warnings and
errors.  I do not know if it works at all, or even what to do with this

Please address any questions to the original author, not me.

The original README is below and the original source code, with
userspace testing code, is in the original/ subdirectory.

Greg Kroah-Hartman <>
March 16, 2010


       PCI-AI12-16 Data acquisition board driver documentation.

       Sun Mar  2 21:03:43 EDST 2003      Richard B. Johnson

       Many D/A Converter input boards and their software tend
       to take over your computer. This driver does not. The
       normal mode of operation has it quietly acquiring data
       on all of its input channels all of the time. The data
       from each of the channels is also filtered, using an
       IIR filter, to help remove noise. When a user program
       wants to read the data, it just reads a structure 
       (buffer) containing the data from all 16 channels.
       It can do this at any time without upsetting the
       on-going conversion cycles.

       The other mode of operation is to acquire data on any
       single channel as fast as is possible. All of the
       parameters are settable. Using this mode, you can
       convert data up to about a 2.0 microsecond rate even
       without a FIFO on the board.

       In all cases, the data is presented to the API (you)
       as an ordinary `int`, having been properly sign-extended,
       etc. Since it has only 12 effective bits, it produces
       data from -2048 to +2048 counts. You scale this to
       whatever you want.

       I downloaded the stuff that was supposed to be a Linux
       driver for this board. It expected me to have some kind
       of special environment installed. I gave up. Instead of
       using that Linux stuff, I wrote a new driver. The driver
       implements the Unix/Linux way of accessing hardware by
       using device files. Using simple system calls like open(),
       close(), read(), and ioctl(), you can access all the
       functions of this board. Further, you don't need to be
       concerned with the specifics of the hardware. The driver
       does that. You can set up the board how you want it using
       ioctl() function calls. This is all documented in the
       header file, adcboard.h.

       The present code uses a device major number of 177 for
       access to the driver. You can change that to any unused
       major number and re-compile the driver. The driver is
       designed as a module for Linux versions 2.4.n on up. It
       would have to be modified to work with version 2.5 because
       the Linux developers keep changing the driver interface.

       The program, tester, tests all the functions of the
       board. It also shows how to use the driver because it
       tests everything. Read the comments in tester.c, in
       particular how to set up a filter. The driver provides
       a built-in IIR filter that reduces real-world noise quite
       well. It is not good to average data values in user-
       mode code because the time at which the averaging occurs
       is more-or-less random. The user, therefore, creates a
       filter with a random pole which produces random results.
       Not good. This driver provides a filter with distinct
       characteristics, synchronized to the data-acquisition
       interval. The filter uses fixed-point mathematics and
       never accumulates a round-off error. The usual averaging 
       methods use division which has a round-off error that
       eventually accumulates to the value of 1 less than the
       divisor. The method used here accumulates no round-
       off error so you end up filtering the data without
       accumulating a bias. Although the instantaneous error
       could be as large at 1 less than the divisor, the average
       error is zero. I should have patented this 30 years
       ago when I invented it in the days of 8-bit processors. 

       To make the driver and its test-code, execute `make clean'.
       Then execute `make'. This should compile without warnings
       if you have the Linux source-code installed in the correct
       place. If not, you need to install the source-code for
       the Linux version you are using in the correct place.
       If your Linux version is 2.4.1, the correct place to install
       the Linux source-code is in /usr/src/linux-2.4.1. As long
       as the kernel you are using supports modules, you do not
       need to actually build the kernel from its source but you
       do need to configure the source so that the links to the
       header files are correctly set. The source-code for this
       driver needs only to interface with the header files in
       the source-code tree.

       To install the driver, you execute `ismod adcboard.o`.
       If you want a GPL license within the code to prevent unrelated
       panics from saying "tainted", execute `insmod ioadc.o` instead.
       This second object file contains the GPL signature as well
       as the driver code. Read the source, license.c, to find out
       what it's about. It's about politics and a certain jerk who
       wants to take credit for the work of thousands of individuals,

       When you install the driver, it automatically determines
       what resources are required and sets them up accordingly.
       If you execute `dmesg` or read one of the log files in
       /var/log, you will see:

       ACCES I/O PRODUCTS PCI-AI12-16 A: Version    = V1.1
       ACCES I/O PRODUCTS PCI-AI12-16 A: I/O port   = DFA0
       ACCES I/O PRODUCTS PCI-AI12-16 A: I/O length = 16
       ACCES I/O PRODUCTS PCI-AI12-16 A: Interrupt  = 10
       ACCES I/O PRODUCTS PCI-AI12-16 A: Dev. major = 177
       ACCES I/O PRODUCTS PCI-AI12-16 A: Patches to
       ACCES I/O PRODUCTS PCI-AI12-16 A: Initialization complete

       The actual I/O space may be different on your machine, that's
       what PnP is all about. This driver is designed to be able to
       share an interrupt and it can also operate in a machine with
       two or more CPUs.

       If the board with a FIFO has been detected, the product
       identification will look as shown. If there is no FIFO
       on your board, the "A" at the end will be missing.

       After the device driver module is installed, you can execute
       `tester` to watch it work. Review the source-code, tester.c
       to see how to integrate the new driver and its interface into
       your application. Good luck. Notice from the source code,
       tester.c, you can make a special device "file" anywhere.
       they do not have to be in "/dev". In the test program, I
       just create one if I found that one doesn't exist. A device-
       file is just a "trick" to associate a file-descriptor with
       a "major-number". Your code never actually accesses this
       "file" so it's not a bottleneck. Also note that the first
       invocation of `tester` must be by root to create the required
       device file in the test directory.

       In the "real world", you would probably create the correct
       device-file in /dev so everybody could access it. You would,
       after becoming root, execute:

                  mknod /dev/ADC c 177 0
                  chown root.sys /dev/ADC
                  chmod 666 /dev/ADC

       You can execute in the source-code directory
       to perform this same feat if your fingers are cold. If you
       change the major-number, remember to update this file.

       Then, change the file-name in tester.c so you can use the
       new device file you created.

       Once you are satisfied with the driver, you can modify one
       of the system start-up files to load the module automatically
       each time you boot. Probably the easiest thing to do is to
       add two lines to /etc/modules.conf. First, add, near its
       beginning: "path[ioadc]=/complete/path/to/driver" (no quotes).
       Second, anywhere, add: "alias char-major-177 ioadc" (no quotes).
       Then execute `depmod ioadc`. The driver will be loaded as
       soon as you need it, and will be unloaded after a few hours
       of inactivity. It will continue to be reloaded anytime you
       need it.

       If you add any additional functionality or find some bugs, please
       send me a patch.

       Richard B. Johnson