linux/drivers/staging/comedi/drivers/das6402.c
<<
>>
Prefs
   1/*
   2   Some comments on the code..
   3
   4   - it shouldn't be necessary to use outb_p().
   5
   6   - ignoreirq creates a race condition.  It needs to be fixed.
   7
   8 */
   9
  10/*
  11   comedi/drivers/das6402.c
  12   An experimental driver for Computerboards' DAS6402 I/O card
  13
  14   Copyright (C) 1999 Oystein Svendsen <svendsen@pvv.org>
  15
  16   This program is free software; you can redistribute it and/or modify
  17   it under the terms of the GNU General Public License as published by
  18   the Free Software Foundation; either version 2 of the License, or
  19   (at your option) any later version.
  20
  21   This program is distributed in the hope that it will be useful,
  22   but WITHOUT ANY WARRANTY; without even the implied warranty of
  23   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  24   GNU General Public License for more details.
  25
  26   You should have received a copy of the GNU General Public License
  27   along with this program; if not, write to the Free Software
  28   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  29
  30 */
  31/*
  32Driver: das6402
  33Description: Keithley Metrabyte DAS6402 (& compatibles)
  34Author: Oystein Svendsen <svendsen@pvv.org>
  35Status: bitrotten
  36Devices: [Keithley Metrabyte] DAS6402 (das6402)
  37
  38This driver has suffered bitrot.
  39*/
  40
  41#include <linux/interrupt.h>
  42#include "../comedidev.h"
  43
  44#include <linux/ioport.h>
  45
  46#define DAS6402_SIZE 16
  47
  48#define N_WORDS (3000*64)
  49
  50#define STOP    0
  51#define START   1
  52
  53#define SCANL 0x3f00
  54#define BYTE unsigned char
  55#define WORD unsigned short
  56
  57/*----- register 8 ----*/
  58#define CLRINT 0x01
  59#define CLRXTR 0x02
  60#define CLRXIN 0x04
  61#define EXTEND 0x10
  62#define ARMED 0x20              /* enable conting of post sample conv */
  63#define POSTMODE 0x40
  64#define MHZ 0x80                /* 10 MHz clock */
  65/*---------------------*/
  66
  67/*----- register 9 ----*/
  68#define IRQ (0x04 << 4)         /* these two are                         */
  69#define IRQV 10                 /*               dependent on each other */
  70
  71#define CONVSRC 0x03            /* trig src is Intarnal pacer */
  72#define BURSTEN 0x04            /* enable burst */
  73#define XINTE 0x08              /* use external int. trig */
  74#define INTE 0x80               /* enable analog interrupts */
  75/*---------------------*/
  76
  77/*----- register 10 ---*/
  78#define TGEN 0x01               /* Use pin DI1 for externl trigging? */
  79#define TGSEL 0x02              /* Use edge triggering */
  80#define TGPOL 0x04              /* active edge is falling */
  81#define PRETRIG 0x08            /* pretrig */
  82/*---------------------*/
  83
  84/*----- register 11 ---*/
  85#define EOB 0x0c
  86#define FIFOHFULL 0x08
  87#define GAIN 0x01
  88#define FIFONEPTY 0x04
  89#define MODE 0x10
  90#define SEM 0x20
  91#define BIP 0x40
  92/*---------------------*/
  93
  94#define M0 0x00
  95#define M2 0x04
  96
  97#define C0 0x00
  98#define C1 0x40
  99#define C2 0x80
 100#define RWLH 0x30
 101
 102struct das6402_private {
 103        int ai_bytes_to_read;
 104
 105        int das6402_ignoreirq;
 106};
 107
 108static void das6402_ai_fifo_dregs(struct comedi_device *dev,
 109                                  struct comedi_subdevice *s)
 110{
 111        while (1) {
 112                if (!(inb(dev->iobase + 8) & 0x01))
 113                        return;
 114                comedi_buf_put(s->async, inw(dev->iobase));
 115        }
 116}
 117
 118static void das6402_setcounter(struct comedi_device *dev)
 119{
 120        BYTE p;
 121        unsigned short ctrlwrd;
 122
 123        /* set up counter0 first, mode 0 */
 124        p = M0 | C0 | RWLH;
 125        outb_p(p, dev->iobase + 15);
 126        ctrlwrd = 2000;
 127        p = (BYTE) (0xff & ctrlwrd);
 128        outb_p(p, dev->iobase + 12);
 129        p = (BYTE) (0xff & (ctrlwrd >> 8));
 130        outb_p(p, dev->iobase + 12);
 131
 132        /* set up counter1, mode 2 */
 133        p = M2 | C1 | RWLH;
 134        outb_p(p, dev->iobase + 15);
 135        ctrlwrd = 10;
 136        p = (BYTE) (0xff & ctrlwrd);
 137        outb_p(p, dev->iobase + 13);
 138        p = (BYTE) (0xff & (ctrlwrd >> 8));
 139        outb_p(p, dev->iobase + 13);
 140
 141        /* set up counter1, mode 2 */
 142        p = M2 | C2 | RWLH;
 143        outb_p(p, dev->iobase + 15);
 144        ctrlwrd = 1000;
 145        p = (BYTE) (0xff & ctrlwrd);
 146        outb_p(p, dev->iobase + 14);
 147        p = (BYTE) (0xff & (ctrlwrd >> 8));
 148        outb_p(p, dev->iobase + 14);
 149}
 150
 151static irqreturn_t intr_handler(int irq, void *d)
 152{
 153        struct comedi_device *dev = d;
 154        struct das6402_private *devpriv = dev->private;
 155        struct comedi_subdevice *s = &dev->subdevices[0];
 156
 157        if (!dev->attached || devpriv->das6402_ignoreirq) {
 158                dev_warn(dev->class_dev, "BUG: spurious interrupt\n");
 159                return IRQ_HANDLED;
 160        }
 161#ifdef DEBUG
 162        printk("das6402: interrupt! das6402_irqcount=%i\n",
 163               devpriv->das6402_irqcount);
 164        printk("das6402: iobase+2=%i\n", inw_p(dev->iobase + 2));
 165#endif
 166
 167        das6402_ai_fifo_dregs(dev, s);
 168
 169        if (s->async->buf_write_count >= devpriv->ai_bytes_to_read) {
 170                outw_p(SCANL, dev->iobase + 2); /* clears the fifo */
 171                outb(0x07, dev->iobase + 8);    /* clears all flip-flops */
 172#ifdef DEBUG
 173                printk("das6402: Got %i samples\n\n",
 174                       devpriv->das6402_wordsread - diff);
 175#endif
 176                s->async->events |= COMEDI_CB_EOA;
 177                comedi_event(dev, s);
 178        }
 179
 180        outb(0x01, dev->iobase + 8);    /* clear only the interrupt flip-flop */
 181
 182        comedi_event(dev, s);
 183        return IRQ_HANDLED;
 184}
 185
 186#if 0
 187static void das6402_ai_fifo_read(struct comedi_device *dev, short *data, int n)
 188{
 189        int i;
 190
 191        for (i = 0; i < n; i++)
 192                data[i] = inw(dev->iobase);
 193}
 194#endif
 195
 196static int das6402_ai_cancel(struct comedi_device *dev,
 197                             struct comedi_subdevice *s)
 198{
 199        struct das6402_private *devpriv = dev->private;
 200
 201        /*
 202         *  This function should reset the board from whatever condition it
 203         *  is in (i.e., acquiring data), to a non-active state.
 204         */
 205
 206        devpriv->das6402_ignoreirq = 1;
 207        dev_dbg(dev->class_dev, "Stopping acquisition\n");
 208        devpriv->das6402_ignoreirq = 1;
 209        outb_p(0x02, dev->iobase + 10); /* disable external trigging */
 210        outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */
 211        outb_p(0, dev->iobase + 9);     /* disables interrupts */
 212
 213        outw_p(SCANL, dev->iobase + 2);
 214
 215        return 0;
 216}
 217
 218#ifdef unused
 219static int das6402_ai_mode2(struct comedi_device *dev,
 220                            struct comedi_subdevice *s, comedi_trig * it)
 221{
 222        struct das6402_private *devpriv = dev->private;
 223
 224        devpriv->das6402_ignoreirq = 1;
 225        dev_dbg(dev->class_dev, "Starting acquisition\n");
 226        outb_p(0x03, dev->iobase + 10); /* enable external trigging */
 227        outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */
 228        outb_p(IRQ | CONVSRC | BURSTEN | INTE, dev->iobase + 9);
 229
 230        devpriv->ai_bytes_to_read = it->n * sizeof(short);
 231
 232        /* um... ignoreirq is a nasty race condition */
 233        devpriv->das6402_ignoreirq = 0;
 234
 235        outw_p(SCANL, dev->iobase + 2);
 236
 237        return 0;
 238}
 239#endif
 240
 241static int board_init(struct comedi_device *dev)
 242{
 243        struct das6402_private *devpriv = dev->private;
 244        BYTE b;
 245
 246        devpriv->das6402_ignoreirq = 1;
 247
 248        outb(0x07, dev->iobase + 8);
 249
 250        /* register 11  */
 251        outb_p(MODE, dev->iobase + 11);
 252        b = BIP | SEM | MODE | GAIN | FIFOHFULL;
 253        outb_p(b, dev->iobase + 11);
 254
 255        /* register 8   */
 256        outb_p(EXTEND, dev->iobase + 8);
 257        b = EXTEND | MHZ;
 258        outb_p(b, dev->iobase + 8);
 259        b = MHZ | CLRINT | CLRXTR | CLRXIN;
 260        outb_p(b, dev->iobase + 8);
 261
 262        /* register 9    */
 263        b = IRQ | CONVSRC | BURSTEN | INTE;
 264        outb_p(b, dev->iobase + 9);
 265
 266        /* register 10   */
 267        b = TGSEL | TGEN;
 268        outb_p(b, dev->iobase + 10);
 269
 270        b = 0x07;
 271        outb_p(b, dev->iobase + 8);
 272
 273        das6402_setcounter(dev);
 274
 275        outw_p(SCANL, dev->iobase + 2); /* reset card fifo */
 276
 277        devpriv->das6402_ignoreirq = 0;
 278
 279        return 0;
 280}
 281
 282static int das6402_attach(struct comedi_device *dev,
 283                          struct comedi_devconfig *it)
 284{
 285        struct das6402_private *devpriv;
 286        unsigned int irq;
 287        int ret;
 288        struct comedi_subdevice *s;
 289
 290        ret = comedi_request_region(dev, it->options[0], DAS6402_SIZE);
 291        if (ret)
 292                return ret;
 293
 294        irq = it->options[0];
 295        dev_dbg(dev->class_dev, "( irq = %u )\n", irq);
 296        ret = request_irq(irq, intr_handler, 0, "das6402", dev);
 297        if (ret < 0)
 298                return ret;
 299
 300        dev->irq = irq;
 301
 302        devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
 303        if (!devpriv)
 304                return -ENOMEM;
 305        dev->private = devpriv;
 306
 307        ret = comedi_alloc_subdevices(dev, 1);
 308        if (ret)
 309                return ret;
 310
 311        /* ai subdevice */
 312        s = &dev->subdevices[0];
 313        s->type = COMEDI_SUBD_AI;
 314        s->subdev_flags = SDF_READABLE | SDF_GROUND;
 315        s->n_chan = 8;
 316        /* s->trig[2]=das6402_ai_mode2; */
 317        s->cancel = das6402_ai_cancel;
 318        s->maxdata = (1 << 12) - 1;
 319        s->len_chanlist = 16;   /* ? */
 320        s->range_table = &range_unknown;
 321
 322        board_init(dev);
 323
 324        return 0;
 325}
 326
 327static struct comedi_driver das6402_driver = {
 328        .driver_name    = "das6402",
 329        .module         = THIS_MODULE,
 330        .attach         = das6402_attach,
 331        .detach         = comedi_legacy_detach,
 332};
 333module_comedi_driver(das6402_driver)
 334
 335MODULE_AUTHOR("Comedi http://www.comedi.org");
 336MODULE_DESCRIPTION("Comedi low-level driver");
 337MODULE_LICENSE("GPL");
 338