RTXI 1.3
comedi/comedi/drivers/pcmad.c
Go to the documentation of this file.
00001 /*
00002     comedi/drivers/pcmad.c
00003     Hardware driver for Winsystems PCM-A/D12 and PCM-A/D16
00004 
00005     COMEDI - Linux Control and Measurement Device Interface
00006     Copyright (C) 2000,2001 David A. Schleef <ds@schleef.org>
00007 
00008     This program is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012 
00013     This program is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016     GNU General Public License for more details.
00017 
00018     You should have received a copy of the GNU General Public License
00019     along with this program; if not, write to the Free Software
00020     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00021 
00022 */
00023 /*
00024 Driver: pcmad
00025 Description: Winsystems PCM-A/D12, PCM-A/D16
00026 Author: ds
00027 Devices: [Winsystems] PCM-A/D12 (pcmad12), PCM-A/D16 (pcmad16)
00028 Status: untested
00029 
00030 This driver was written on a bet that I couldn't write a driver
00031 in less than 2 hours.  I won the bet, but never got paid.  =(
00032 
00033 Configuration options:
00034   [0] - I/O port base
00035   [1] - unused
00036   [2] - Analog input reference
00037           0 = single ended
00038           1 = differential
00039   [3] - Analog input encoding (must match jumpers)
00040           0 = straight binary
00041           1 = two's complement
00042 */
00043 
00044 #include <linux/comedidev.h>
00045 
00046 #include <linux/ioport.h>
00047 
00048 #define PCMAD_SIZE              4
00049 
00050 #define PCMAD_STATUS            0
00051 #define PCMAD_LSB               1
00052 #define PCMAD_MSB               2
00053 #define PCMAD_CONVERT           1
00054 
00055 struct pcmad_board_struct {
00056         const char *name;
00057         int n_ai_bits;
00058 };
00059 static const struct pcmad_board_struct pcmad_boards[] = {
00060         {
00061               name:     "pcmad12",
00062               n_ai_bits:12,
00063                 },
00064         {
00065               name:     "pcmad16",
00066               n_ai_bits:16,
00067                 },
00068 };
00069 
00070 #define this_board ((const struct pcmad_board_struct *)(dev->board_ptr))
00071 #define n_pcmad_boards (sizeof(pcmad_boards)/sizeof(pcmad_boards[0]))
00072 
00073 struct pcmad_priv_struct {
00074         int differential;
00075         int twos_comp;
00076 };
00077 #define devpriv ((struct pcmad_priv_struct *)dev->private)
00078 
00079 static int pcmad_attach(comedi_device * dev, comedi_devconfig * it);
00080 static int pcmad_detach(comedi_device * dev);
00081 static comedi_driver driver_pcmad = {
00082       driver_name:"pcmad",
00083       module:THIS_MODULE,
00084       attach:pcmad_attach,
00085       detach:pcmad_detach,
00086       board_name:&pcmad_boards[0].name,
00087       num_names:n_pcmad_boards,
00088       offset:sizeof(pcmad_boards[0]),
00089 };
00090 
00091 COMEDI_INITCLEANUP(driver_pcmad);
00092 
00093 #define TIMEOUT 100
00094 
00095 static int pcmad_ai_insn_read(comedi_device * dev, comedi_subdevice * s,
00096         comedi_insn * insn, lsampl_t * data)
00097 {
00098         int i;
00099         int chan;
00100         int n;
00101 
00102         chan = CR_CHAN(insn->chanspec);
00103 
00104         for (n = 0; n < insn->n; n++) {
00105                 outb(chan, dev->iobase + PCMAD_CONVERT);
00106 
00107                 for (i = 0; i < TIMEOUT; i++) {
00108                         if ((inb(dev->iobase + PCMAD_STATUS) & 0x3) == 0x3)
00109                                 break;
00110                 }
00111                 data[n] = inb(dev->iobase + PCMAD_LSB);
00112                 data[n] |= (inb(dev->iobase + PCMAD_MSB) << 8);
00113 
00114                 if (devpriv->twos_comp) {
00115                         data[n] ^= (1 << (this_board->n_ai_bits - 1));
00116                 }
00117         }
00118 
00119         return n;
00120 }
00121 
00122 /*
00123  * options:
00124  * 0    i/o base
00125  * 1    unused
00126  * 2    0=single ended 1=differential
00127  * 3    0=straight binary 1=two's comp
00128  */
00129 static int pcmad_attach(comedi_device * dev, comedi_devconfig * it)
00130 {
00131         int ret;
00132         comedi_subdevice *s;
00133         unsigned long iobase;
00134 
00135         iobase = it->options[0];
00136         printk("comedi%d: pcmad: 0x%04lx ", dev->minor, iobase);
00137         if (!request_region(iobase, PCMAD_SIZE, "pcmad")) {
00138                 printk("I/O port conflict\n");
00139                 return -EIO;
00140         }
00141         dev->iobase = iobase;
00142 
00143         if ((ret = alloc_subdevices(dev, 1)) < 0)
00144                 return ret;
00145         if ((ret = alloc_private(dev, sizeof(struct pcmad_priv_struct))) < 0)
00146                 return ret;
00147 
00148         dev->board_name = this_board->name;
00149 
00150         s = dev->subdevices + 0;
00151         s->type = COMEDI_SUBD_AI;
00152         s->subdev_flags = SDF_READABLE | AREF_GROUND;
00153         s->n_chan = 16;         /* XXX */
00154         s->len_chanlist = 1;
00155         s->insn_read = pcmad_ai_insn_read;
00156         s->maxdata = (1 << this_board->n_ai_bits) - 1;
00157         s->range_table = &range_unknown;
00158 
00159         return 0;
00160 }
00161 
00162 static int pcmad_detach(comedi_device * dev)
00163 {
00164         printk("comedi%d: pcmad: remove\n", dev->minor);
00165 
00166         if (dev->irq) {
00167                 free_irq(dev->irq, dev);
00168         }
00169         if (dev->iobase)
00170                 release_region(dev->iobase, PCMAD_SIZE);
00171 
00172         return 0;
00173 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines