linux/drivers/staging/comedi/drivers/poc.c
<<
>>
Prefs
   1/*
   2    comedi/drivers/poc.c
   3    Mini-drivers for POC (Piece of Crap) boards
   4    Copyright (C) 2000 Frank Mori Hess <fmhess@users.sourceforge.net>
   5    Copyright (C) 2001 David A. Schleef <ds@schleef.org>
   6
   7    This program is free software; you can redistribute it and/or modify
   8    it under the terms of the GNU General Public License as published by
   9    the Free Software Foundation; either version 2 of the License, or
  10    (at your option) any later version.
  11
  12    This program is distributed in the hope that it will be useful,
  13    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15    GNU General Public License for more details.
  16
  17    You should have received a copy of the GNU General Public License
  18    along with this program; if not, write to the Free Software
  19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20*/
  21/*
  22Driver: poc
  23Description: Generic driver for very simple devices
  24Author: ds
  25Devices: [Keithley Metrabyte] DAC-02 (dac02), [Advantech] PCL-733 (pcl733),
  26  PCL-734 (pcl734)
  27Updated: Sat, 16 Mar 2002 17:34:48 -0800
  28Status: unknown
  29
  30This driver is indended to support very simple ISA-based devices,
  31including:
  32  dac02 - Keithley DAC-02 analog output board
  33  pcl733 - Advantech PCL-733
  34  pcl734 - Advantech PCL-734
  35
  36Configuration options:
  37  [0] - I/O port base
  38*/
  39
  40#include "../comedidev.h"
  41
  42#include <linux/ioport.h>
  43
  44static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it);
  45static int poc_detach(struct comedi_device *dev);
  46static int readback_insn(struct comedi_device *dev, struct comedi_subdevice *s,
  47                         struct comedi_insn *insn, unsigned int *data);
  48
  49static int dac02_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
  50                          struct comedi_insn *insn, unsigned int *data);
  51static int pcl733_insn_bits(struct comedi_device *dev,
  52                            struct comedi_subdevice *s,
  53                            struct comedi_insn *insn, unsigned int *data);
  54static int pcl734_insn_bits(struct comedi_device *dev,
  55                            struct comedi_subdevice *s,
  56                            struct comedi_insn *insn, unsigned int *data);
  57
  58struct boarddef_struct {
  59        const char *name;
  60        unsigned int iosize;
  61        int (*setup) (struct comedi_device *);
  62        int type;
  63        int n_chan;
  64        int n_bits;
  65        int (*winsn) (struct comedi_device *, struct comedi_subdevice *,
  66                      struct comedi_insn *, unsigned int *);
  67        int (*rinsn) (struct comedi_device *, struct comedi_subdevice *,
  68                      struct comedi_insn *, unsigned int *);
  69        int (*insnbits) (struct comedi_device *, struct comedi_subdevice *,
  70                         struct comedi_insn *, unsigned int *);
  71        const struct comedi_lrange *range;
  72};
  73static const struct boarddef_struct boards[] = {
  74        {
  75         .name = "dac02",
  76         .iosize = 8,
  77         /*      .setup = dac02_setup, */
  78         .type = COMEDI_SUBD_AO,
  79         .n_chan = 2,
  80         .n_bits = 12,
  81         .winsn = dac02_ao_winsn,
  82         .rinsn = readback_insn,
  83         .range = &range_unknown,
  84         },
  85        {
  86         .name = "pcl733",
  87         .iosize = 4,
  88         .type = COMEDI_SUBD_DI,
  89         .n_chan = 32,
  90         .n_bits = 1,
  91         .insnbits = pcl733_insn_bits,
  92         .range = &range_digital,
  93         },
  94        {
  95         .name = "pcl734",
  96         .iosize = 4,
  97         .type = COMEDI_SUBD_DO,
  98         .n_chan = 32,
  99         .n_bits = 1,
 100         .insnbits = pcl734_insn_bits,
 101         .range = &range_digital,
 102         },
 103};
 104
 105#define n_boards ARRAY_SIZE(boards)
 106#define this_board ((const struct boarddef_struct *)dev->board_ptr)
 107
 108static struct comedi_driver driver_poc = {
 109        .driver_name = "poc",
 110        .module = THIS_MODULE,
 111        .attach = poc_attach,
 112        .detach = poc_detach,
 113        .board_name = &boards[0].name,
 114        .num_names = n_boards,
 115        .offset = sizeof(boards[0]),
 116};
 117
 118static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 119{
 120        struct comedi_subdevice *s;
 121        unsigned long iobase;
 122        unsigned int iosize;
 123
 124        iobase = it->options[0];
 125        printk("comedi%d: poc: using %s iobase 0x%lx\n", dev->minor,
 126               this_board->name, iobase);
 127
 128        dev->board_name = this_board->name;
 129
 130        if (iobase == 0) {
 131                printk("io base address required\n");
 132                return -EINVAL;
 133        }
 134
 135        iosize = this_board->iosize;
 136        /* check if io addresses are available */
 137        if (!request_region(iobase, iosize, "dac02")) {
 138                printk
 139                    ("I/O port conflict: failed to allocate ports 0x%lx to 0x%lx\n",
 140                     iobase, iobase + iosize - 1);
 141                return -EIO;
 142        }
 143        dev->iobase = iobase;
 144
 145        if (alloc_subdevices(dev, 1) < 0)
 146                return -ENOMEM;
 147        if (alloc_private(dev, sizeof(unsigned int) * this_board->n_chan) < 0)
 148                return -ENOMEM;
 149
 150        /* analog output subdevice */
 151        s = dev->subdevices + 0;
 152        s->type = this_board->type;
 153        s->n_chan = this_board->n_chan;
 154        s->maxdata = (1 << this_board->n_bits) - 1;
 155        s->range_table = this_board->range;
 156        s->insn_write = this_board->winsn;
 157        s->insn_read = this_board->rinsn;
 158        s->insn_bits = this_board->insnbits;
 159        if (s->type == COMEDI_SUBD_AO || s->type == COMEDI_SUBD_DO) {
 160                s->subdev_flags = SDF_WRITABLE;
 161        }
 162
 163        return 0;
 164}
 165
 166static int poc_detach(struct comedi_device *dev)
 167{
 168        /* only free stuff if it has been allocated by _attach */
 169        if (dev->iobase)
 170                release_region(dev->iobase, this_board->iosize);
 171
 172        printk("comedi%d: dac02: remove\n", dev->minor);
 173
 174        return 0;
 175}
 176
 177static int readback_insn(struct comedi_device *dev, struct comedi_subdevice *s,
 178                         struct comedi_insn *insn, unsigned int *data)
 179{
 180        int chan;
 181
 182        chan = CR_CHAN(insn->chanspec);
 183        data[0] = ((unsigned int *)dev->private)[chan];
 184
 185        return 1;
 186}
 187
 188/* DAC-02 registers */
 189#define DAC02_LSB(a)    (2 * a)
 190#define DAC02_MSB(a)    (2 * a + 1)
 191
 192static int dac02_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
 193                          struct comedi_insn *insn, unsigned int *data)
 194{
 195        int temp;
 196        int chan;
 197        int output;
 198
 199        chan = CR_CHAN(insn->chanspec);
 200        ((unsigned int *)dev->private)[chan] = data[0];
 201        output = data[0];
 202#ifdef wrong
 203        /*  convert to complementary binary if range is bipolar */
 204        if ((CR_RANGE(insn->chanspec) & 0x2) == 0)
 205                output = ~output;
 206#endif
 207        temp = (output << 4) & 0xf0;
 208        outb(temp, dev->iobase + DAC02_LSB(chan));
 209        temp = (output >> 4) & 0xff;
 210        outb(temp, dev->iobase + DAC02_MSB(chan));
 211
 212        return 1;
 213}
 214
 215static int pcl733_insn_bits(struct comedi_device *dev,
 216                            struct comedi_subdevice *s,
 217                            struct comedi_insn *insn, unsigned int *data)
 218{
 219        if (insn->n != 2)
 220                return -EINVAL;
 221
 222        data[1] = inb(dev->iobase + 0);
 223        data[1] |= (inb(dev->iobase + 1) << 8);
 224        data[1] |= (inb(dev->iobase + 2) << 16);
 225        data[1] |= (inb(dev->iobase + 3) << 24);
 226
 227        return 2;
 228}
 229
 230static int pcl734_insn_bits(struct comedi_device *dev,
 231                            struct comedi_subdevice *s,
 232                            struct comedi_insn *insn, unsigned int *data)
 233{
 234        if (insn->n != 2)
 235                return -EINVAL;
 236        if (data[0]) {
 237                s->state &= ~data[0];
 238                s->state |= (data[0] & data[1]);
 239                if ((data[0] >> 0) & 0xff)
 240                        outb((s->state >> 0) & 0xff, dev->iobase + 0);
 241                if ((data[0] >> 8) & 0xff)
 242                        outb((s->state >> 8) & 0xff, dev->iobase + 1);
 243                if ((data[0] >> 16) & 0xff)
 244                        outb((s->state >> 16) & 0xff, dev->iobase + 2);
 245                if ((data[0] >> 24) & 0xff)
 246                        outb((s->state >> 24) & 0xff, dev->iobase + 3);
 247        }
 248        data[1] = s->state;
 249
 250        return 2;
 251}
 252
 253COMEDI_INITCLEANUP(driver_poc);
 254