linux/drivers/staging/comedi/drivers/ni_daq_700.c
<<
>>
Prefs
   1/*
   2 *     comedi/drivers/ni_daq_700.c
   3 *     Driver for DAQCard-700 DIO/AI
   4 *     copied from 8255
   5 *
   6 *     COMEDI - Linux Control and Measurement Device Interface
   7 *     Copyright (C) 1998 David A. Schleef <ds@schleef.org>
   8 *
   9 *     This program is free software; you can redistribute it and/or modify
  10 *     it under the terms of the GNU General Public License as published by
  11 *     the Free Software Foundation; either version 2 of the License, or
  12 *     (at your option) any later version.
  13 *
  14 *     This program is distributed in the hope that it will be useful,
  15 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17 *     GNU General Public License for more details.
  18 *
  19 *     You should have received a copy of the GNU General Public License
  20 *     along with this program; if not, write to the Free Software
  21 *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22 *
  23 */
  24
  25/*
  26Driver: ni_daq_700
  27Description: National Instruments PCMCIA DAQCard-700 DIO only
  28Author: Fred Brooks <nsaspook@nsaspook.com>,
  29  based on ni_daq_dio24 by Daniel Vecino Castel <dvecino@able.es>
  30Devices: [National Instruments] PCMCIA DAQ-Card-700 (ni_daq_700)
  31Status: works
  32Updated: Wed, 19 Sep 2012 12:07:20 +0000
  33
  34The daqcard-700 appears in Comedi as a  digital I/O subdevice (0) with
  3516 channels and a analog input subdevice (1) with 16 single-ended channels.
  36
  37Digital:  The channel 0 corresponds to the daqcard-700's output
  38port, bit 0; channel 8 corresponds to the input port, bit 0.
  39
  40Digital direction configuration: channels 0-7 output, 8-15 input (8225 device
  41emu as port A output, port B input, port C N/A).
  42
  43Analog: The input  range is 0 to 4095 for -10 to +10 volts 
  44IRQ is assigned but not used.
  45
  46Version 0.1     Original DIO only driver
  47Version 0.2     DIO and basic AI analog input support on 16 se channels
  48
  49Manuals:        Register level: http://www.ni.com/pdf/manuals/340698.pdf
  50                User Manual:    http://www.ni.com/pdf/manuals/320676d.pdf
  51*/
  52
  53#include <linux/ioport.h>
  54#include <linux/interrupt.h>
  55#include <linux/slab.h>
  56
  57#include "../comedidev.h"
  58
  59#include <pcmcia/cistpl.h>
  60#include <pcmcia/ds.h>
  61
  62/* daqcard700 registers */
  63#define DIO_W           0x04    /* WO 8bit */
  64#define DIO_R           0x05    /* RO 8bit */
  65#define CMD_R1          0x00    /* WO 8bit */
  66#define CMD_R2          0x07    /* RW 8bit */
  67#define CMD_R3          0x05    /* W0 8bit */
  68#define STA_R1          0x00    /* RO 8bit */
  69#define STA_R2          0x01    /* RO 8bit */
  70#define ADFIFO_R        0x02    /* RO 16bit */
  71#define ADCLEAR_R       0x01    /* WO 8bit */
  72#define CDA_R0          0x08    /* RW 8bit */
  73#define CDA_R1          0x09    /* RW 8bit */
  74#define CDA_R2          0x0A    /* RW 8bit */
  75#define CMO_R           0x0B    /* RO 8bit */
  76#define TIC_R           0x06    /* WO 8bit */
  77
  78static int daq700_dio_insn_bits(struct comedi_device *dev,
  79                                struct comedi_subdevice *s,
  80                                struct comedi_insn *insn, unsigned int *data)
  81{
  82        if (data[0]) {
  83                s->state &= ~data[0];
  84                s->state |= (data[0] & data[1]);
  85
  86                if (data[0] & 0xff)
  87                        outb(s->state & 0xff, dev->iobase + DIO_W);
  88        }
  89
  90        data[1] = s->state & 0xff;
  91        data[1] |= inb(dev->iobase + DIO_R) << 8;
  92
  93        return insn->n;
  94}
  95
  96static int daq700_dio_insn_config(struct comedi_device *dev,
  97                                  struct comedi_subdevice *s,
  98                                  struct comedi_insn *insn, unsigned int *data)
  99{
 100        unsigned int chan = 1 << CR_CHAN(insn->chanspec);
 101
 102        switch (data[0]) {
 103        case INSN_CONFIG_DIO_INPUT:
 104                break;
 105        case INSN_CONFIG_DIO_OUTPUT:
 106                break;
 107        case INSN_CONFIG_DIO_QUERY:
 108                data[1] = (s->io_bits & chan) ? COMEDI_OUTPUT : COMEDI_INPUT;
 109                break;
 110        default:
 111                return -EINVAL;
 112        }
 113
 114        return insn->n;
 115}
 116
 117static int daq700_ai_rinsn(struct comedi_device *dev,
 118                           struct comedi_subdevice *s,
 119                           struct comedi_insn *insn, unsigned int *data)
 120{
 121        int n, i, chan;
 122        int d;
 123        unsigned int status;
 124        enum { TIMEOUT = 100 };
 125
 126        chan = CR_CHAN(insn->chanspec);
 127        /* write channel to multiplexer */
 128        /* set mask scan bit high to disable scanning */
 129        outb(chan | 0x80, dev->iobase + CMD_R1);
 130
 131        /* convert n samples */
 132        for (n = 0; n < insn->n; n++) {
 133                /* trigger conversion with out0 L to H */
 134                outb(0x00, dev->iobase + CMD_R2); /* enable ADC conversions */
 135                outb(0x30, dev->iobase + CMO_R); /* mode 0 out0 L, from H */
 136                /* mode 1 out0 H, L to H, start conversion */
 137                outb(0x32, dev->iobase + CMO_R);
 138                /* wait for conversion to end */
 139                for (i = 0; i < TIMEOUT; i++) {
 140                        status = inb(dev->iobase + STA_R2);
 141                        if ((status & 0x03) != 0) {
 142                                dev_info(dev->class_dev,
 143                                         "Overflow/run Error\n");
 144                                return -EOVERFLOW;
 145                        }
 146                        status = inb(dev->iobase + STA_R1);
 147                        if ((status & 0x02) != 0) {
 148                                dev_info(dev->class_dev, "Data Error\n");
 149                                return -ENODATA;
 150                        }
 151                        if ((status & 0x11) == 0x01) {
 152                                /* ADC conversion complete */
 153                                break;
 154                        }
 155                        udelay(1);
 156                }
 157                if (i == TIMEOUT) {
 158                        dev_info(dev->class_dev,
 159                                 "timeout during ADC conversion\n");
 160                        return -ETIMEDOUT;
 161                }
 162                /* read data */
 163                d = inw(dev->iobase + ADFIFO_R);
 164                /* mangle the data as necessary */
 165                /* Bipolar Offset Binary: 0 to 4095 for -10 to +10 */
 166                d &= 0x0fff;
 167                d ^= 0x0800;
 168                data[n] = d;
 169        }
 170        return n;
 171}
 172
 173/*
 174 * Data acquisition is enabled.
 175 * The counter 0 output is high.
 176 * The I/O connector pin CLK1 drives counter 1 source.
 177 * Multiple-channel scanning is disabled.
 178 * All interrupts are disabled.
 179 * The analog input range is set to +-10 V
 180 * The analog input mode is single-ended.
 181 * The analog input circuitry is initialized to channel 0.
 182 * The A/D FIFO is cleared.
 183 */
 184static void daq700_ai_config(struct comedi_device *dev,
 185                             struct comedi_subdevice *s)
 186{                       
 187        unsigned long iobase = dev->iobase;
 188
 189        outb(0x80, iobase + CMD_R1);    /* disable scanning, ADC to chan 0 */
 190        outb(0x00, iobase + CMD_R2);    /* clear all bits */
 191        outb(0x00, iobase + CMD_R3);    /* set +-10 range */
 192        outb(0x32, iobase + CMO_R);     /* config counter mode1, out0 to H */
 193        outb(0x00, iobase + TIC_R);     /* clear counter interrupt */
 194        outb(0x00, iobase + ADCLEAR_R); /* clear the ADC FIFO */
 195        inw(iobase + ADFIFO_R);         /* read 16bit junk from FIFO to clear */
 196}
 197
 198static int daq700_auto_attach(struct comedi_device *dev,
 199                              unsigned long context)
 200{
 201        struct pcmcia_device *link = comedi_to_pcmcia_dev(dev);
 202        struct comedi_subdevice *s;
 203        int ret;
 204
 205        dev->board_name = dev->driver->driver_name;
 206
 207        link->config_flags |= CONF_AUTO_SET_IO;
 208        ret = comedi_pcmcia_enable(dev, NULL);
 209        if (ret)
 210                return ret;
 211        dev->iobase = link->resource[0]->start;
 212
 213        ret = comedi_alloc_subdevices(dev, 2);
 214        if (ret)
 215                return ret;
 216
 217        /* DAQCard-700 dio */
 218        s = &dev->subdevices[0];
 219        s->type         = COMEDI_SUBD_DIO;
 220        s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 221        s->n_chan       = 16;
 222        s->range_table  = &range_digital;
 223        s->maxdata      = 1;
 224        s->insn_bits    = daq700_dio_insn_bits;
 225        s->insn_config  = daq700_dio_insn_config;
 226        s->state        = 0;
 227        s->io_bits      = 0x00ff;
 228
 229        /* DAQCard-700 ai */
 230        s = &dev->subdevices[1];
 231        s->type = COMEDI_SUBD_AI;
 232        /* we support single-ended (ground)  */
 233        s->subdev_flags = SDF_READABLE | SDF_GROUND;
 234        s->n_chan = 16;
 235        s->maxdata = (1 << 12) - 1;
 236        s->range_table = &range_bipolar10;
 237        s->insn_read = daq700_ai_rinsn;
 238        daq700_ai_config(dev, s);
 239
 240        dev_info(dev->class_dev, "%s: %s, io 0x%lx\n",
 241                dev->driver->driver_name,
 242                dev->board_name,
 243                dev->iobase);
 244
 245        return 0;
 246}
 247
 248static struct comedi_driver daq700_driver = {
 249        .driver_name    = "ni_daq_700",
 250        .module         = THIS_MODULE,
 251        .auto_attach    = daq700_auto_attach,
 252        .detach         = comedi_pcmcia_disable,
 253};
 254
 255static int daq700_cs_attach(struct pcmcia_device *link)
 256{
 257        return comedi_pcmcia_auto_config(link, &daq700_driver);
 258}
 259
 260static const struct pcmcia_device_id daq700_cs_ids[] = {
 261        PCMCIA_DEVICE_MANF_CARD(0x010b, 0x4743),
 262        PCMCIA_DEVICE_NULL
 263};
 264MODULE_DEVICE_TABLE(pcmcia, daq700_cs_ids);
 265
 266static struct pcmcia_driver daq700_cs_driver = {
 267        .name           = "ni_daq_700",
 268        .owner          = THIS_MODULE,
 269        .id_table       = daq700_cs_ids,
 270        .probe          = daq700_cs_attach,
 271        .remove         = comedi_pcmcia_auto_unconfig,
 272};
 273module_comedi_pcmcia_driver(daq700_driver, daq700_cs_driver);
 274
 275MODULE_AUTHOR("Fred Brooks <nsaspook@nsaspook.com>");
 276MODULE_DESCRIPTION(
 277        "Comedi driver for National Instruments PCMCIA DAQCard-700 DIO/AI");
 278MODULE_VERSION("0.2.00");
 279MODULE_LICENSE("GPL");
 280
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.