Staging: comedi: add das6402 driver
authorOystein Svendsen <svendsen@pvv.org>
Thu, 19 Feb 2009 17:52:05 +0000 (09:52 -0800)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 3 Apr 2009 21:53:49 +0000 (14:53 -0700)
Driver for Computerboards' DAS6402 I/O card

From: Oystein Svendsen <svendsen@pvv.org>
Cc: David Schleef <ds@schleef.org>
Cc: Ian Abbott <abbotti@mev.co.uk>
Cc: Frank Mori Hess <fmhess@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/staging/comedi/drivers/das6402.c [new file with mode: 0644]

diff --git a/drivers/staging/comedi/drivers/das6402.c b/drivers/staging/comedi/drivers/das6402.c
new file mode 100644 (file)
index 0000000..e87a16e
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+   Some comments on the code..
+
+   - it shouldn't be necessary to use outb_p().
+
+   - ignoreirq creates a race condition.  It needs to be fixed.
+
+ */
+
+/*
+   comedi/drivers/das6402.c
+   An experimental driver for Computerboards' DAS6402 I/O card
+
+   Copyright (C) 1999 Oystein Svendsen <svendsen@pvv.org>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+/*
+Driver: das6402
+Description: Keithley Metrabyte DAS6402 (& compatibles)
+Author: Oystein Svendsen <svendsen@pvv.org>
+Status: bitrotten
+Devices: [Keithley Metrabyte] DAS6402 (das6402)
+
+This driver has suffered bitrot.
+*/
+
+#include "../comedidev.h"
+
+#include <linux/ioport.h>
+
+#define DAS6402_SIZE 16
+
+#define N_WORDS 3000*64
+
+#define STOP    0
+#define START   1
+
+#define SCANL 0x3f00
+#define BYTE unsigned char
+#define WORD unsigned short
+
+/*----- register 8 ----*/
+#define CLRINT 0x01
+#define CLRXTR 0x02
+#define CLRXIN 0x04
+#define EXTEND 0x10
+#define ARMED 0x20             /* enable conting of post sample conv */
+#define POSTMODE 0x40
+#define MHZ 0x80               /* 10 MHz clock */
+/*---------------------*/
+
+/*----- register 9 ----*/
+#define IRQ (0x04 << 4)                /* these two are                         */
+#define IRQV 10                        /*               dependent on each other */
+
+#define CONVSRC 0x03           /* trig src is Intarnal pacer */
+#define BURSTEN 0x04           /* enable burst */
+#define XINTE 0x08             /* use external int. trig */
+#define INTE 0x80              /* enable analog interrupts */
+/*---------------------*/
+
+/*----- register 10 ---*/
+#define TGEN 0x01              /* Use pin DI1 for externl trigging? */
+#define TGSEL 0x02             /* Use edge triggering */
+#define TGPOL 0x04             /* active edge is falling */
+#define PRETRIG 0x08           /* pretrig */
+/*---------------------*/
+
+/*----- register 11 ---*/
+#define EOB 0x0c
+#define FIFOHFULL 0x08
+#define GAIN 0x01
+#define FIFONEPTY 0x04
+#define MODE 0x10
+#define SEM 0x20
+#define BIP 0x40
+/*---------------------*/
+
+#define M0 0x00
+#define M2 0x04
+
+#define        C0 0x00
+#define        C1 0x40
+#define        C2 0x80
+#define        RWLH 0x30
+
+static int das6402_attach(comedi_device * dev, comedi_devconfig * it);
+static int das6402_detach(comedi_device * dev);
+static comedi_driver driver_das6402 = {
+      driver_name:"das6402",
+      module:THIS_MODULE,
+      attach:das6402_attach,
+      detach:das6402_detach,
+};
+
+COMEDI_INITCLEANUP(driver_das6402);
+
+typedef struct {
+       int ai_bytes_to_read;
+
+       int das6402_ignoreirq;
+} das6402_private;
+#define devpriv ((das6402_private *)dev->private)
+
+static void das6402_ai_fifo_dregs(comedi_device * dev, comedi_subdevice * s);
+
+static void das6402_setcounter(comedi_device * dev)
+{
+       BYTE p;
+       unsigned short ctrlwrd;
+
+       /* set up counter0 first, mode 0 */
+       p = M0 | C0 | RWLH;
+       outb_p(p, dev->iobase + 15);
+       ctrlwrd = 2000;
+       p = (BYTE) (0xff & ctrlwrd);
+       outb_p(p, dev->iobase + 12);
+       p = (BYTE) (0xff & (ctrlwrd >> 8));
+       outb_p(p, dev->iobase + 12);
+
+       /* set up counter1, mode 2 */
+       p = M2 | C1 | RWLH;
+       outb_p(p, dev->iobase + 15);
+       ctrlwrd = 10;
+       p = (BYTE) (0xff & ctrlwrd);
+       outb_p(p, dev->iobase + 13);
+       p = (BYTE) (0xff & (ctrlwrd >> 8));
+       outb_p(p, dev->iobase + 13);
+
+       /* set up counter1, mode 2 */
+       p = M2 | C2 | RWLH;
+       outb_p(p, dev->iobase + 15);
+       ctrlwrd = 1000;
+       p = (BYTE) (0xff & ctrlwrd);
+       outb_p(p, dev->iobase + 14);
+       p = (BYTE) (0xff & (ctrlwrd >> 8));
+       outb_p(p, dev->iobase + 14);
+}
+
+static irqreturn_t intr_handler(int irq, void *d PT_REGS_ARG)
+{
+       comedi_device *dev = d;
+       comedi_subdevice *s = dev->subdevices;
+
+       if (!dev->attached || devpriv->das6402_ignoreirq) {
+               printk("das6402: BUG: spurious interrupt\n");
+               return IRQ_HANDLED;
+       }
+#ifdef DEBUG
+       printk("das6402: interrupt! das6402_irqcount=%i\n",
+               devpriv->das6402_irqcount);
+       printk("das6402: iobase+2=%i\n", inw_p(dev->iobase + 2));
+#endif
+
+       das6402_ai_fifo_dregs(dev, s);
+
+       if (s->async->buf_write_count >= devpriv->ai_bytes_to_read) {
+               outw_p(SCANL, dev->iobase + 2); /* clears the fifo */
+               outb(0x07, dev->iobase + 8);    /* clears all flip-flops */
+#ifdef DEBUG
+               printk("das6402: Got %i samples\n\n",
+                       devpriv->das6402_wordsread - diff);
+#endif
+               s->async->events |= COMEDI_CB_EOA;
+               comedi_event(dev, s);
+       }
+
+       outb(0x01, dev->iobase + 8);    /* clear only the interrupt flip-flop */
+
+       comedi_event(dev, s);
+       return IRQ_HANDLED;
+}
+
+#if 0
+static void das6402_ai_fifo_read(comedi_device * dev, sampl_t * data, int n)
+{
+       int i;
+
+       for (i = 0; i < n; i++)
+               data[i] = inw(dev->iobase);
+}
+#endif
+
+static void das6402_ai_fifo_dregs(comedi_device * dev, comedi_subdevice * s)
+{
+       while (1) {
+               if (!(inb(dev->iobase + 8) & 0x01))
+                       return;
+               comedi_buf_put(s->async, inw(dev->iobase));
+       }
+}
+
+static int das6402_ai_cancel(comedi_device * dev, comedi_subdevice * s)
+{
+       /*
+        *  This function should reset the board from whatever condition it
+        *  is in (i.e., acquiring data), to a non-active state.
+        */
+
+       devpriv->das6402_ignoreirq = 1;
+#ifdef DEBUG
+       printk("das6402: Stopping acquisition\n");
+#endif
+       devpriv->das6402_ignoreirq = 1;
+       outb_p(0x02, dev->iobase + 10); /* disable external trigging */
+       outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */
+       outb_p(0, dev->iobase + 9);     /* disables interrupts */
+
+       outw_p(SCANL, dev->iobase + 2);
+
+       return 0;
+}
+
+#ifdef unused
+static int das6402_ai_mode2(comedi_device * dev, comedi_subdevice * s,
+       comedi_trig * it)
+{
+       devpriv->das6402_ignoreirq = 1;
+
+#ifdef DEBUG
+       printk("das6402: Starting acquisition\n");
+#endif
+       outb_p(0x03, dev->iobase + 10); /* enable external trigging */
+       outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */
+       outb_p(IRQ | CONVSRC | BURSTEN | INTE, dev->iobase + 9);
+
+       devpriv->ai_bytes_to_read = it->n * sizeof(sampl_t);
+
+       /* um... ignoreirq is a nasty race condition */
+       devpriv->das6402_ignoreirq = 0;
+
+       outw_p(SCANL, dev->iobase + 2);
+
+       return 0;
+}
+#endif
+
+static int board_init(comedi_device * dev)
+{
+       BYTE b;
+
+       devpriv->das6402_ignoreirq = 1;
+
+       outb(0x07, dev->iobase + 8);
+
+       /* register 11  */
+       outb_p(MODE, dev->iobase + 11);
+       b = BIP | SEM | MODE | GAIN | FIFOHFULL;
+       outb_p(b, dev->iobase + 11);
+
+       /* register 8   */
+       outb_p(EXTEND, dev->iobase + 8);
+       b = EXTEND | MHZ;
+       outb_p(b, dev->iobase + 8);
+       b = MHZ | CLRINT | CLRXTR | CLRXIN;
+       outb_p(b, dev->iobase + 8);
+
+       /* register 9    */
+       b = IRQ | CONVSRC | BURSTEN | INTE;
+       outb_p(b, dev->iobase + 9);
+
+       /* register 10   */
+       b = TGSEL | TGEN;
+       outb_p(b, dev->iobase + 10);
+
+       b = 0x07;
+       outb_p(b, dev->iobase + 8);
+
+       das6402_setcounter(dev);
+
+       outw_p(SCANL, dev->iobase + 2); /* reset card fifo */
+
+       devpriv->das6402_ignoreirq = 0;
+
+       return 0;
+}
+
+static int das6402_detach(comedi_device * dev)
+{
+       if (dev->irq)
+               comedi_free_irq(dev->irq, dev);
+       if (dev->iobase)
+               release_region(dev->iobase, DAS6402_SIZE);
+
+       return 0;
+}
+
+static int das6402_attach(comedi_device * dev, comedi_devconfig * it)
+{
+       unsigned int irq;
+       unsigned long iobase;
+       int ret;
+       comedi_subdevice *s;
+
+       dev->board_name = "das6402";
+
+       iobase = it->options[0];
+       if (iobase == 0)
+               iobase = 0x300;
+
+       printk("comedi%d: das6402: 0x%04lx", dev->minor, iobase);
+
+       if (!request_region(iobase, DAS6402_SIZE, "das6402")) {
+               printk(" I/O port conflict\n");
+               return -EIO;
+       }
+       dev->iobase = iobase;
+
+       /* should do a probe here */
+
+       irq = it->options[0];
+       printk(" ( irq = %u )", irq);
+       ret = comedi_request_irq(irq, intr_handler, 0, "das6402", dev);
+       if (ret < 0) {
+               printk("irq conflict\n");
+               return ret;
+       }
+       dev->irq = irq;
+
+       if ((ret = alloc_private(dev, sizeof(das6402_private))) < 0)
+               return ret;
+
+       if ((ret = alloc_subdevices(dev, 1)) < 0)
+               return ret;
+
+       /* ai subdevice */
+       s = dev->subdevices + 0;
+       s->type = COMEDI_SUBD_AI;
+       s->subdev_flags = SDF_READABLE | SDF_GROUND;
+       s->n_chan = 8;
+       //s->trig[2]=das6402_ai_mode2;
+       s->cancel = das6402_ai_cancel;
+       s->maxdata = (1 << 12) - 1;
+       s->len_chanlist = 16;   /* ? */
+       s->range_table = &range_unknown;
+
+       board_init(dev);
+
+       return 0;
+}