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.
28 Description: Keithley Metrabyte DAS6402 (& compatibles)
29 Author: Oystein Svendsen <svendsen@pvv.org>
31 Devices: [Keithley Metrabyte] DAS6402 (das6402)
33 This driver has suffered bitrot.
36 #include <linux/module.h>
37 #include <linux/interrupt.h>
38 #include "../comedidev.h"
40 #define DAS6402_SIZE 16
42 #define N_WORDS (3000*64)
48 #define BYTE unsigned char
49 #define WORD unsigned short
51 /*----- register 8 ----*/
56 #define ARMED 0x20 /* enable conting of post sample conv */
58 #define MHZ 0x80 /* 10 MHz clock */
59 /*---------------------*/
61 /*----- register 9 ----*/
62 #define IRQ (0x04 << 4) /* these two are */
63 #define IRQV 10 /* dependent on each other */
65 #define CONVSRC 0x03 /* trig src is Intarnal pacer */
66 #define BURSTEN 0x04 /* enable burst */
67 #define XINTE 0x08 /* use external int. trig */
68 #define INTE 0x80 /* enable analog interrupts */
69 /*---------------------*/
71 /*----- register 10 ---*/
72 #define TGEN 0x01 /* Use pin DI1 for externl trigging? */
73 #define TGSEL 0x02 /* Use edge triggering */
74 #define TGPOL 0x04 /* active edge is falling */
75 #define PRETRIG 0x08 /* pretrig */
76 /*---------------------*/
78 /*----- register 11 ---*/
80 #define FIFOHFULL 0x08
82 #define FIFONEPTY 0x04
86 /*---------------------*/
96 struct das6402_private {
99 int das6402_ignoreirq;
102 static void das6402_ai_fifo_dregs(struct comedi_device *dev,
103 struct comedi_subdevice *s)
106 if (!(inb(dev->iobase + 8) & 0x01))
108 comedi_buf_put(s->async, inw(dev->iobase));
112 static void das6402_setcounter(struct comedi_device *dev)
115 unsigned short ctrlwrd;
117 /* set up counter0 first, mode 0 */
119 outb_p(p, dev->iobase + 15);
121 p = (BYTE) (0xff & ctrlwrd);
122 outb_p(p, dev->iobase + 12);
123 p = (BYTE) (0xff & (ctrlwrd >> 8));
124 outb_p(p, dev->iobase + 12);
126 /* set up counter1, mode 2 */
128 outb_p(p, dev->iobase + 15);
130 p = (BYTE) (0xff & ctrlwrd);
131 outb_p(p, dev->iobase + 13);
132 p = (BYTE) (0xff & (ctrlwrd >> 8));
133 outb_p(p, dev->iobase + 13);
135 /* set up counter1, mode 2 */
137 outb_p(p, dev->iobase + 15);
139 p = (BYTE) (0xff & ctrlwrd);
140 outb_p(p, dev->iobase + 14);
141 p = (BYTE) (0xff & (ctrlwrd >> 8));
142 outb_p(p, dev->iobase + 14);
145 static irqreturn_t intr_handler(int irq, void *d)
147 struct comedi_device *dev = d;
148 struct das6402_private *devpriv = dev->private;
149 struct comedi_subdevice *s = &dev->subdevices[0];
151 if (!dev->attached || devpriv->das6402_ignoreirq) {
152 dev_warn(dev->class_dev, "BUG: spurious interrupt\n");
156 printk("das6402: interrupt! das6402_irqcount=%i\n",
157 devpriv->das6402_irqcount);
158 printk("das6402: iobase+2=%i\n", inw_p(dev->iobase + 2));
161 das6402_ai_fifo_dregs(dev, s);
163 if (s->async->buf_write_count >= devpriv->ai_bytes_to_read) {
164 outw_p(SCANL, dev->iobase + 2); /* clears the fifo */
165 outb(0x07, dev->iobase + 8); /* clears all flip-flops */
167 printk("das6402: Got %i samples\n\n",
168 devpriv->das6402_wordsread - diff);
170 s->async->events |= COMEDI_CB_EOA;
171 comedi_event(dev, s);
174 outb(0x01, dev->iobase + 8); /* clear only the interrupt flip-flop */
176 comedi_event(dev, s);
181 static void das6402_ai_fifo_read(struct comedi_device *dev, short *data, int n)
185 for (i = 0; i < n; i++)
186 data[i] = inw(dev->iobase);
190 static int das6402_ai_cancel(struct comedi_device *dev,
191 struct comedi_subdevice *s)
193 struct das6402_private *devpriv = dev->private;
196 * This function should reset the board from whatever condition it
197 * is in (i.e., acquiring data), to a non-active state.
200 devpriv->das6402_ignoreirq = 1;
201 dev_dbg(dev->class_dev, "Stopping acquisition\n");
202 devpriv->das6402_ignoreirq = 1;
203 outb_p(0x02, dev->iobase + 10); /* disable external trigging */
204 outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */
205 outb_p(0, dev->iobase + 9); /* disables interrupts */
207 outw_p(SCANL, dev->iobase + 2);
213 static int das6402_ai_mode2(struct comedi_device *dev,
214 struct comedi_subdevice *s, comedi_trig * it)
216 struct das6402_private *devpriv = dev->private;
218 devpriv->das6402_ignoreirq = 1;
219 dev_dbg(dev->class_dev, "Starting acquisition\n");
220 outb_p(0x03, dev->iobase + 10); /* enable external trigging */
221 outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */
222 outb_p(IRQ | CONVSRC | BURSTEN | INTE, dev->iobase + 9);
224 devpriv->ai_bytes_to_read = it->n * sizeof(short);
226 /* um... ignoreirq is a nasty race condition */
227 devpriv->das6402_ignoreirq = 0;
229 outw_p(SCANL, dev->iobase + 2);
235 static int board_init(struct comedi_device *dev)
237 struct das6402_private *devpriv = dev->private;
240 devpriv->das6402_ignoreirq = 1;
242 outb(0x07, dev->iobase + 8);
245 outb_p(MODE, dev->iobase + 11);
246 b = BIP | SEM | MODE | GAIN | FIFOHFULL;
247 outb_p(b, dev->iobase + 11);
250 outb_p(EXTEND, dev->iobase + 8);
252 outb_p(b, dev->iobase + 8);
253 b = MHZ | CLRINT | CLRXTR | CLRXIN;
254 outb_p(b, dev->iobase + 8);
257 b = IRQ | CONVSRC | BURSTEN | INTE;
258 outb_p(b, dev->iobase + 9);
262 outb_p(b, dev->iobase + 10);
265 outb_p(b, dev->iobase + 8);
267 das6402_setcounter(dev);
269 outw_p(SCANL, dev->iobase + 2); /* reset card fifo */
271 devpriv->das6402_ignoreirq = 0;
276 static int das6402_attach(struct comedi_device *dev,
277 struct comedi_devconfig *it)
279 struct das6402_private *devpriv;
282 struct comedi_subdevice *s;
284 ret = comedi_request_region(dev, it->options[0], DAS6402_SIZE);
288 irq = it->options[0];
289 dev_dbg(dev->class_dev, "( irq = %u )\n", irq);
290 ret = request_irq(irq, intr_handler, 0, "das6402", dev);
296 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
300 ret = comedi_alloc_subdevices(dev, 1);
305 s = &dev->subdevices[0];
306 s->type = COMEDI_SUBD_AI;
307 s->subdev_flags = SDF_READABLE | SDF_GROUND;
309 /* s->trig[2]=das6402_ai_mode2; */
310 s->cancel = das6402_ai_cancel;
311 s->maxdata = (1 << 12) - 1;
312 s->len_chanlist = 16; /* ? */
313 s->range_table = &range_unknown;
320 static struct comedi_driver das6402_driver = {
321 .driver_name = "das6402",
322 .module = THIS_MODULE,
323 .attach = das6402_attach,
324 .detach = comedi_legacy_detach,
326 module_comedi_driver(das6402_driver)
328 MODULE_AUTHOR("Comedi http://www.comedi.org");
329 MODULE_DESCRIPTION("Comedi low-level driver");
330 MODULE_LICENSE("GPL");