linux/drivers/staging/comedi/drivers/dt2817.c
<<
>>
Prefs
   1/*
   2    comedi/drivers/dt2817.c
   3    Hardware driver for Data Translation DT2817
   4
   5    COMEDI - Linux Control and Measurement Device Interface
   6    Copyright (C) 1998 David A. Schleef <ds@schleef.org>
   7
   8    This program is free software; you can redistribute it and/or modify
   9    it under the terms of the GNU General Public License as published by
  10    the Free Software Foundation; either version 2 of the License, or
  11    (at your option) any later version.
  12
  13    This program is distributed in the hope that it will be useful,
  14    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16    GNU General Public License for more details.
  17
  18    You should have received a copy of the GNU General Public License
  19    along with this program; if not, write to the Free Software
  20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21
  22*/
  23/*
  24Driver: dt2817
  25Description: Data Translation DT2817
  26Author: ds
  27Status: complete
  28Devices: [Data Translation] DT2817 (dt2817)
  29
  30A very simple digital I/O card.  Four banks of 8 lines, each bank
  31is configurable for input or output.  One wonders why it takes a
  3250 page manual to describe this thing.
  33
  34The driver (which, btw, is much less than 50 pages) has 1 subdevice
  35with 32 channels, configurable in groups of 8.
  36
  37Configuration options:
  38  [0] - I/O port base base address
  39*/
  40
  41#include "../comedidev.h"
  42
  43#include <linux/ioport.h>
  44
  45#define DT2817_SIZE 5
  46
  47#define DT2817_CR 0
  48#define DT2817_DATA 1
  49
  50static int dt2817_dio_insn_config(struct comedi_device *dev,
  51                                  struct comedi_subdevice *s,
  52                                  struct comedi_insn *insn, unsigned int *data)
  53{
  54        int mask;
  55        int chan;
  56        int oe = 0;
  57
  58        if (insn->n != 1)
  59                return -EINVAL;
  60
  61        chan = CR_CHAN(insn->chanspec);
  62        if (chan < 8)
  63                mask = 0xff;
  64        else if (chan < 16)
  65                mask = 0xff00;
  66        else if (chan < 24)
  67                mask = 0xff0000;
  68        else
  69                mask = 0xff000000;
  70        if (data[0])
  71                s->io_bits |= mask;
  72        else
  73                s->io_bits &= ~mask;
  74
  75        if (s->io_bits & 0x000000ff)
  76                oe |= 0x1;
  77        if (s->io_bits & 0x0000ff00)
  78                oe |= 0x2;
  79        if (s->io_bits & 0x00ff0000)
  80                oe |= 0x4;
  81        if (s->io_bits & 0xff000000)
  82                oe |= 0x8;
  83
  84        outb(oe, dev->iobase + DT2817_CR);
  85
  86        return 1;
  87}
  88
  89static int dt2817_dio_insn_bits(struct comedi_device *dev,
  90                                struct comedi_subdevice *s,
  91                                struct comedi_insn *insn, unsigned int *data)
  92{
  93        unsigned int changed;
  94
  95        /* It's questionable whether it is more important in
  96         * a driver like this to be deterministic or fast.
  97         * We choose fast. */
  98
  99        if (data[0]) {
 100                changed = s->state;
 101                s->state &= ~data[0];
 102                s->state |= (data[0] & data[1]);
 103                changed ^= s->state;
 104                changed &= s->io_bits;
 105                if (changed & 0x000000ff)
 106                        outb(s->state & 0xff, dev->iobase + DT2817_DATA + 0);
 107                if (changed & 0x0000ff00)
 108                        outb((s->state >> 8) & 0xff,
 109                             dev->iobase + DT2817_DATA + 1);
 110                if (changed & 0x00ff0000)
 111                        outb((s->state >> 16) & 0xff,
 112                             dev->iobase + DT2817_DATA + 2);
 113                if (changed & 0xff000000)
 114                        outb((s->state >> 24) & 0xff,
 115                             dev->iobase + DT2817_DATA + 3);
 116        }
 117        data[1] = inb(dev->iobase + DT2817_DATA + 0);
 118        data[1] |= (inb(dev->iobase + DT2817_DATA + 1) << 8);
 119        data[1] |= (inb(dev->iobase + DT2817_DATA + 2) << 16);
 120        data[1] |= (inb(dev->iobase + DT2817_DATA + 3) << 24);
 121
 122        return insn->n;
 123}
 124
 125static int dt2817_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 126{
 127        int ret;
 128        struct comedi_subdevice *s;
 129        unsigned long iobase;
 130
 131        iobase = it->options[0];
 132        printk(KERN_INFO "comedi%d: dt2817: 0x%04lx ", dev->minor, iobase);
 133        if (!request_region(iobase, DT2817_SIZE, "dt2817")) {
 134                printk("I/O port conflict\n");
 135                return -EIO;
 136        }
 137        dev->iobase = iobase;
 138        dev->board_name = "dt2817";
 139
 140        ret = comedi_alloc_subdevices(dev, 1);
 141        if (ret)
 142                return ret;
 143
 144        s = dev->subdevices + 0;
 145
 146        s->n_chan = 32;
 147        s->type = COMEDI_SUBD_DIO;
 148        s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 149        s->range_table = &range_digital;
 150        s->maxdata = 1;
 151        s->insn_bits = dt2817_dio_insn_bits;
 152        s->insn_config = dt2817_dio_insn_config;
 153
 154        s->state = 0;
 155        outb(0, dev->iobase + DT2817_CR);
 156
 157        printk(KERN_INFO "\n");
 158
 159        return 0;
 160}
 161
 162static void dt2817_detach(struct comedi_device *dev)
 163{
 164        if (dev->iobase)
 165                release_region(dev->iobase, DT2817_SIZE);
 166}
 167
 168static struct comedi_driver dt2817_driver = {
 169        .driver_name    = "dt2817",
 170        .module         = THIS_MODULE,
 171        .attach         = dt2817_attach,
 172        .detach         = dt2817_detach,
 173};
 174module_comedi_driver(dt2817_driver);
 175
 176MODULE_AUTHOR("Comedi http://www.comedi.org");
 177MODULE_DESCRIPTION("Comedi low-level driver");
 178MODULE_LICENSE("GPL");
 179