2 Some comments on the code..
4 - it shouldn't be necessary to use outb_p().
6 - ignoreirq creates a race condition. It needs to be fixed.
11 comedi/drivers/das6402.c
12 An experimental driver for Computerboards' DAS6402 I/O card
14 Copyright (C) 1999 Oystein Svendsen <svendsen@pvv.org>
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.
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.
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.
33 Description: Keithley Metrabyte DAS6402 (& compatibles)
34 Author: Oystein Svendsen <svendsen@pvv.org>
36 Devices: [Keithley Metrabyte] DAS6402 (das6402)
38 This driver has suffered bitrot.
41 #include <linux/interrupt.h>
42 #include "../comedidev.h"
44 #include <linux/ioport.h>
46 #define DAS6402_SIZE 16
48 #define N_WORDS 3000*64
54 #define BYTE unsigned char
55 #define WORD unsigned short
57 /*----- register 8 ----*/
62 #define ARMED 0x20 /* enable conting of post sample conv */
64 #define MHZ 0x80 /* 10 MHz clock */
65 /*---------------------*/
67 /*----- register 9 ----*/
68 #define IRQ (0x04 << 4) /* these two are */
69 #define IRQV 10 /* dependent on each other */
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 /*---------------------*/
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 /*---------------------*/
84 /*----- register 11 ---*/
86 #define FIFOHFULL 0x08
88 #define FIFONEPTY 0x04
92 /*---------------------*/
102 static int das6402_attach(struct comedi_device *dev, struct comedi_devconfig *it);
103 static int das6402_detach(struct comedi_device *dev);
104 static struct comedi_driver driver_das6402 = {
105 .driver_name = "das6402",
106 .module = THIS_MODULE,
107 .attach = das6402_attach,
108 .detach = das6402_detach,
111 COMEDI_INITCLEANUP(driver_das6402);
113 struct das6402_private {
114 int ai_bytes_to_read;
116 int das6402_ignoreirq;
118 #define devpriv ((struct das6402_private *)dev->private)
120 static void das6402_ai_fifo_dregs(struct comedi_device *dev, struct comedi_subdevice *s);
122 static void das6402_setcounter(struct comedi_device *dev)
125 unsigned short ctrlwrd;
127 /* set up counter0 first, mode 0 */
129 outb_p(p, dev->iobase + 15);
131 p = (BYTE) (0xff & ctrlwrd);
132 outb_p(p, dev->iobase + 12);
133 p = (BYTE) (0xff & (ctrlwrd >> 8));
134 outb_p(p, dev->iobase + 12);
136 /* set up counter1, mode 2 */
138 outb_p(p, dev->iobase + 15);
140 p = (BYTE) (0xff & ctrlwrd);
141 outb_p(p, dev->iobase + 13);
142 p = (BYTE) (0xff & (ctrlwrd >> 8));
143 outb_p(p, dev->iobase + 13);
145 /* set up counter1, mode 2 */
147 outb_p(p, dev->iobase + 15);
149 p = (BYTE) (0xff & ctrlwrd);
150 outb_p(p, dev->iobase + 14);
151 p = (BYTE) (0xff & (ctrlwrd >> 8));
152 outb_p(p, dev->iobase + 14);
155 static irqreturn_t intr_handler(int irq, void *d)
157 struct comedi_device *dev = d;
158 struct comedi_subdevice *s = dev->subdevices;
160 if (!dev->attached || devpriv->das6402_ignoreirq) {
161 printk("das6402: BUG: spurious interrupt\n");
165 printk("das6402: interrupt! das6402_irqcount=%i\n",
166 devpriv->das6402_irqcount);
167 printk("das6402: iobase+2=%i\n", inw_p(dev->iobase + 2));
170 das6402_ai_fifo_dregs(dev, s);
172 if (s->async->buf_write_count >= devpriv->ai_bytes_to_read) {
173 outw_p(SCANL, dev->iobase + 2); /* clears the fifo */
174 outb(0x07, dev->iobase + 8); /* clears all flip-flops */
176 printk("das6402: Got %i samples\n\n",
177 devpriv->das6402_wordsread - diff);
179 s->async->events |= COMEDI_CB_EOA;
180 comedi_event(dev, s);
183 outb(0x01, dev->iobase + 8); /* clear only the interrupt flip-flop */
185 comedi_event(dev, s);
190 static void das6402_ai_fifo_read(struct comedi_device *dev, short *data, int n)
194 for (i = 0; i < n; i++)
195 data[i] = inw(dev->iobase);
199 static void das6402_ai_fifo_dregs(struct comedi_device *dev, struct comedi_subdevice *s)
202 if (!(inb(dev->iobase + 8) & 0x01))
204 comedi_buf_put(s->async, inw(dev->iobase));
208 static int das6402_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
211 * This function should reset the board from whatever condition it
212 * is in (i.e., acquiring data), to a non-active state.
215 devpriv->das6402_ignoreirq = 1;
217 printk("das6402: Stopping acquisition\n");
219 devpriv->das6402_ignoreirq = 1;
220 outb_p(0x02, dev->iobase + 10); /* disable external trigging */
221 outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */
222 outb_p(0, dev->iobase + 9); /* disables interrupts */
224 outw_p(SCANL, dev->iobase + 2);
230 static int das6402_ai_mode2(struct comedi_device *dev, struct comedi_subdevice *s,
233 devpriv->das6402_ignoreirq = 1;
236 printk("das6402: Starting acquisition\n");
238 outb_p(0x03, dev->iobase + 10); /* enable external trigging */
239 outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */
240 outb_p(IRQ | CONVSRC | BURSTEN | INTE, dev->iobase + 9);
242 devpriv->ai_bytes_to_read = it->n * sizeof(short);
244 /* um... ignoreirq is a nasty race condition */
245 devpriv->das6402_ignoreirq = 0;
247 outw_p(SCANL, dev->iobase + 2);
253 static int board_init(struct comedi_device *dev)
257 devpriv->das6402_ignoreirq = 1;
259 outb(0x07, dev->iobase + 8);
262 outb_p(MODE, dev->iobase + 11);
263 b = BIP | SEM | MODE | GAIN | FIFOHFULL;
264 outb_p(b, dev->iobase + 11);
267 outb_p(EXTEND, dev->iobase + 8);
269 outb_p(b, dev->iobase + 8);
270 b = MHZ | CLRINT | CLRXTR | CLRXIN;
271 outb_p(b, dev->iobase + 8);
274 b = IRQ | CONVSRC | BURSTEN | INTE;
275 outb_p(b, dev->iobase + 9);
279 outb_p(b, dev->iobase + 10);
282 outb_p(b, dev->iobase + 8);
284 das6402_setcounter(dev);
286 outw_p(SCANL, dev->iobase + 2); /* reset card fifo */
288 devpriv->das6402_ignoreirq = 0;
293 static int das6402_detach(struct comedi_device *dev)
296 free_irq(dev->irq, dev);
298 release_region(dev->iobase, DAS6402_SIZE);
303 static int das6402_attach(struct comedi_device *dev, struct comedi_devconfig *it)
306 unsigned long iobase;
308 struct comedi_subdevice *s;
310 dev->board_name = "das6402";
312 iobase = it->options[0];
316 printk("comedi%d: das6402: 0x%04lx", dev->minor, iobase);
318 if (!request_region(iobase, DAS6402_SIZE, "das6402")) {
319 printk(" I/O port conflict\n");
322 dev->iobase = iobase;
324 /* should do a probe here */
326 irq = it->options[0];
327 printk(" ( irq = %u )", irq);
328 ret = request_irq(irq, intr_handler, 0, "das6402", dev);
330 printk("irq conflict\n");
335 ret = alloc_private(dev, sizeof(struct das6402_private));
339 ret = alloc_subdevices(dev, 1);
344 s = dev->subdevices + 0;
345 s->type = COMEDI_SUBD_AI;
346 s->subdev_flags = SDF_READABLE | SDF_GROUND;
348 /* s->trig[2]=das6402_ai_mode2; */
349 s->cancel = das6402_ai_cancel;
350 s->maxdata = (1 << 12) - 1;
351 s->len_chanlist = 16; /* ? */
352 s->range_table = &range_unknown;