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
 102static int das6402_attach(struct comedi_device *dev,
 103                          struct comedi_devconfig *it);
 104static int das6402_detach(struct comedi_device *dev);
 105static struct comedi_driver driver_das6402 = {
 106        .driver_name = "das6402",
 107        .module = THIS_MODULE,
 108        .attach = das6402_attach,
 109        .detach = das6402_detach,
 110};
 111
 112COMEDI_INITCLEANUP(driver_das6402);
 113
 114struct das6402_private {
 115        int ai_bytes_to_read;
 116
 117        int das6402_ignoreirq;
 118};
 119#define devpriv ((struct das6402_private *)dev->private)
 120
 121static void das6402_ai_fifo_dregs(struct comedi_device *dev,
 122                                  struct comedi_subdevice *s);
 123
 124static void das6402_setcounter(struct comedi_device *dev)
 125{
 126        BYTE p;
 127        unsigned short ctrlwrd;
 128
 129        /* set up counter0 first, mode 0 */
 130        p = M0 | C0 | RWLH;
 131        outb_p(p, dev->iobase + 15);
 132        ctrlwrd = 2000;
 133        p = (BYTE) (0xff & ctrlwrd);
 134        outb_p(p, dev->iobase + 12);
 135        p = (BYTE) (0xff & (ctrlwrd >> 8));
 136        outb_p(p, dev->iobase + 12);
 137
 138        /* set up counter1, mode 2 */
 139        p = M2 | C1 | RWLH;
 140        outb_p(p, dev->iobase + 15);
 141        ctrlwrd = 10;
 142        p = (BYTE) (0xff & ctrlwrd);
 143        outb_p(p, dev->iobase + 13);
 144        p = (BYTE) (0xff & (ctrlwrd >> 8));
 145        outb_p(p, dev->iobase + 13);
 146
 147        /* set up counter1, mode 2 */
 148        p = M2 | C2 | RWLH;
 149        outb_p(p, dev->iobase + 15);
 150        ctrlwrd = 1000;
 151        p = (BYTE) (0xff & ctrlwrd);
 152        outb_p(p, dev->iobase + 14);
 153        p = (BYTE) (0xff & (ctrlwrd >> 8));
 154        outb_p(p, dev->iobase + 14);
 155}
 156
 157static irqreturn_t intr_handler(int irq, void *d)
 158{
 159        struct comedi_device *dev = d;
 160        struct comedi_subdevice *s = dev->subdevices;
 161
 162        if (!dev->attached || devpriv->das6402_ignoreirq) {
 163                printk("das6402: BUG: spurious interrupt\n");
 164                return IRQ_HANDLED;
 165        }
 166#ifdef DEBUG
 167        printk("das6402: interrupt! das6402_irqcount=%i\n",
 168               devpriv->das6402_irqcount);
 169        printk("das6402: iobase+2=%i\n", inw_p(dev->iobase + 2));
 170#endif
 171
 172        das6402_ai_fifo_dregs(dev, s);
 173
 174        if (s->async->buf_write_count >= devpriv->ai_bytes_to_read) {
 175                outw_p(SCANL, dev->iobase + 2); /* clears the fifo */
 176                outb(0x07, dev->iobase + 8);    /* clears all flip-flops */
 177#ifdef DEBUG
 178                printk("das6402: Got %i samples\n\n",
 179                       devpriv->das6402_wordsread - diff);
 180#endif
 181                s->async->events |= COMEDI_CB_EOA;
 182                comedi_event(dev, s);
 183        }
 184
 185        outb(0x01, dev->iobase + 8);    /* clear only the interrupt flip-flop */
 186
 187        comedi_event(dev, s);
 188        return IRQ_HANDLED;
 189}
 190
 191#if 0
 192static void das6402_ai_fifo_read(struct comedi_device *dev, short *data, int n)
 193{
 194        int i;
 195
 196        for (i = 0; i < n; i++)
 197                data[i] = inw(dev->iobase);
 198}
 199#endif
 200
 201static void das6402_ai_fifo_dregs(struct comedi_device *dev,
 202                                  struct comedi_subdevice *s)
 203{
 204        while (1) {
 205                if (!(inb(dev->iobase + 8) & 0x01))
 206                        return;
 207                comedi_buf_put(s->async, inw(dev->iobase));
 208        }
 209}
 210
 211static int das6402_ai_cancel(struct comedi_device *dev,
 212                             struct comedi_subdevice *s)
 213{
 214        /*
 215         *  This function should reset the board from whatever condition it
 216         *  is in (i.e., acquiring data), to a non-active state.
 217         */
 218
 219        devpriv->das6402_ignoreirq = 1;
 220#ifdef DEBUG
 221        printk("das6402: Stopping acquisition\n");
 222#endif
 223        devpriv->das6402_ignoreirq = 1;
 224        outb_p(0x02, dev->iobase + 10); /* disable external trigging */
 225        outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */
 226        outb_p(0, dev->iobase + 9);     /* disables interrupts */
 227
 228        outw_p(SCANL, dev->iobase + 2);
 229
 230        return 0;
 231}
 232
 233#ifdef unused
 234static int das6402_ai_mode2(struct comedi_device *dev,
 235                            struct comedi_subdevice *s, comedi_trig * it)
 236{
 237        devpriv->das6402_ignoreirq = 1;
 238
 239#ifdef DEBUG
 240        printk("das6402: Starting acquisition\n");
 241#endif
 242        outb_p(0x03, dev->iobase + 10); /* enable external trigging */
 243        outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */
 244        outb_p(IRQ | CONVSRC | BURSTEN | INTE, dev->iobase + 9);
 245
 246        devpriv->ai_bytes_to_read = it->n * sizeof(short);
 247
 248        /* um... ignoreirq is a nasty race condition */
 249        devpriv->das6402_ignoreirq = 0;
 250
 251        outw_p(SCANL, dev->iobase + 2);
 252
 253        return 0;
 254}
 255#endif
 256
 257static int board_init(struct comedi_device *dev)
 258{
 259        BYTE b;
 260
 261        devpriv->das6402_ignoreirq = 1;
 262
 263        outb(0x07, dev->iobase + 8);
 264
 265        /* register 11  */
 266        outb_p(MODE, dev->iobase + 11);
 267        b = BIP | SEM | MODE | GAIN | FIFOHFULL;
 268        outb_p(b, dev->iobase + 11);
 269
 270        /* register 8   */
 271        outb_p(EXTEND, dev->iobase + 8);
 272        b = EXTEND | MHZ;
 273        outb_p(b, dev->iobase + 8);
 274        b = MHZ | CLRINT | CLRXTR | CLRXIN;
 275        outb_p(b, dev->iobase + 8);
 276
 277        /* register 9    */
 278        b = IRQ | CONVSRC | BURSTEN | INTE;
 279        outb_p(b, dev->iobase + 9);
 280
 281        /* register 10   */
 282        b = TGSEL | TGEN;
 283        outb_p(b, dev->iobase + 10);
 284
 285        b = 0x07;
 286        outb_p(b, dev->iobase + 8);
 287
 288        das6402_setcounter(dev);
 289
 290        outw_p(SCANL, dev->iobase + 2); /* reset card fifo */
 291
 292        devpriv->das6402_ignoreirq = 0;
 293
 294        return 0;
 295}
 296
 297static int das6402_detach(struct comedi_device *dev)
 298{
 299        if (dev->irq)
 300                free_irq(dev->irq, dev);
 301        if (dev->iobase)
 302                release_region(dev->iobase, DAS6402_SIZE);
 303
 304        return 0;
 305}
 306
 307static int das6402_attach(struct comedi_device *dev,
 308                          struct comedi_devconfig *it)
 309{
 310        unsigned int irq;
 311        unsigned long iobase;
 312        int ret;
 313        struct comedi_subdevice *s;
 314
 315        dev->board_name = "das6402";
 316
 317        iobase = it->options[0];
 318        if (iobase == 0)
 319                iobase = 0x300;
 320
 321        printk("comedi%d: das6402: 0x%04lx", dev->minor, iobase);
 322
 323        if (!request_region(iobase, DAS6402_SIZE, "das6402")) {
 324                printk(" I/O port conflict\n");
 325                return -EIO;
 326        }
 327        dev->iobase = iobase;
 328
 329        /* should do a probe here */
 330
 331        irq = it->options[0];
 332        printk(" ( irq = %u )", irq);
 333        ret = request_irq(irq, intr_handler, 0, "das6402", dev);
 334        if (ret < 0) {
 335                printk("irq conflict\n");
 336                return ret;
 337        }
 338        dev->irq = irq;
 339
 340        ret = alloc_private(dev, sizeof(struct das6402_private));
 341        if (ret < 0)
 342                return ret;
 343
 344        ret = alloc_subdevices(dev, 1);
 345        if (ret < 0)
 346                return ret;
 347
 348        /* ai subdevice */
 349        s = dev->subdevices + 0;
 350        s->type = COMEDI_SUBD_AI;
 351        s->subdev_flags = SDF_READABLE | SDF_GROUND;
 352        s->n_chan = 8;
 353        /* s->trig[2]=das6402_ai_mode2; */
 354        s->cancel = das6402_ai_cancel;
 355        s->maxdata = (1 << 12) - 1;
 356        s->len_chanlist = 16;   /* ? */
 357        s->range_table = &range_unknown;
 358
 359        board_init(dev);
 360
 361        return 0;
 362}
 363