Merge branch 'for-3.11' of git://linux-nfs.org/~bfields/linux
[linux-2.6.git] / drivers / staging / comedi / drivers / das6402.c
blobf0530778bb3b376dd5b985c134eaf21fc1856854
1 /*
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.
8 */
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.
27 Driver: das6402
28 Description: Keithley Metrabyte DAS6402 (& compatibles)
29 Author: Oystein Svendsen <svendsen@pvv.org>
30 Status: bitrotten
31 Devices: [Keithley Metrabyte] DAS6402 (das6402)
33 This driver has suffered bitrot.
36 #include <linux/interrupt.h>
37 #include "../comedidev.h"
39 #include <linux/ioport.h>
41 #define DAS6402_SIZE 16
43 #define N_WORDS (3000*64)
45 #define STOP 0
46 #define START 1
48 #define SCANL 0x3f00
49 #define BYTE unsigned char
50 #define WORD unsigned short
52 /*----- register 8 ----*/
53 #define CLRINT 0x01
54 #define CLRXTR 0x02
55 #define CLRXIN 0x04
56 #define EXTEND 0x10
57 #define ARMED 0x20 /* enable conting of post sample conv */
58 #define POSTMODE 0x40
59 #define MHZ 0x80 /* 10 MHz clock */
60 /*---------------------*/
62 /*----- register 9 ----*/
63 #define IRQ (0x04 << 4) /* these two are */
64 #define IRQV 10 /* dependent on each other */
66 #define CONVSRC 0x03 /* trig src is Intarnal pacer */
67 #define BURSTEN 0x04 /* enable burst */
68 #define XINTE 0x08 /* use external int. trig */
69 #define INTE 0x80 /* enable analog interrupts */
70 /*---------------------*/
72 /*----- register 10 ---*/
73 #define TGEN 0x01 /* Use pin DI1 for externl trigging? */
74 #define TGSEL 0x02 /* Use edge triggering */
75 #define TGPOL 0x04 /* active edge is falling */
76 #define PRETRIG 0x08 /* pretrig */
77 /*---------------------*/
79 /*----- register 11 ---*/
80 #define EOB 0x0c
81 #define FIFOHFULL 0x08
82 #define GAIN 0x01
83 #define FIFONEPTY 0x04
84 #define MODE 0x10
85 #define SEM 0x20
86 #define BIP 0x40
87 /*---------------------*/
89 #define M0 0x00
90 #define M2 0x04
92 #define C0 0x00
93 #define C1 0x40
94 #define C2 0x80
95 #define RWLH 0x30
97 struct das6402_private {
98 int ai_bytes_to_read;
100 int das6402_ignoreirq;
103 static void das6402_ai_fifo_dregs(struct comedi_device *dev,
104 struct comedi_subdevice *s)
106 while (1) {
107 if (!(inb(dev->iobase + 8) & 0x01))
108 return;
109 comedi_buf_put(s->async, inw(dev->iobase));
113 static void das6402_setcounter(struct comedi_device *dev)
115 BYTE p;
116 unsigned short ctrlwrd;
118 /* set up counter0 first, mode 0 */
119 p = M0 | C0 | RWLH;
120 outb_p(p, dev->iobase + 15);
121 ctrlwrd = 2000;
122 p = (BYTE) (0xff & ctrlwrd);
123 outb_p(p, dev->iobase + 12);
124 p = (BYTE) (0xff & (ctrlwrd >> 8));
125 outb_p(p, dev->iobase + 12);
127 /* set up counter1, mode 2 */
128 p = M2 | C1 | RWLH;
129 outb_p(p, dev->iobase + 15);
130 ctrlwrd = 10;
131 p = (BYTE) (0xff & ctrlwrd);
132 outb_p(p, dev->iobase + 13);
133 p = (BYTE) (0xff & (ctrlwrd >> 8));
134 outb_p(p, dev->iobase + 13);
136 /* set up counter1, mode 2 */
137 p = M2 | C2 | RWLH;
138 outb_p(p, dev->iobase + 15);
139 ctrlwrd = 1000;
140 p = (BYTE) (0xff & ctrlwrd);
141 outb_p(p, dev->iobase + 14);
142 p = (BYTE) (0xff & (ctrlwrd >> 8));
143 outb_p(p, dev->iobase + 14);
146 static irqreturn_t intr_handler(int irq, void *d)
148 struct comedi_device *dev = d;
149 struct das6402_private *devpriv = dev->private;
150 struct comedi_subdevice *s = &dev->subdevices[0];
152 if (!dev->attached || devpriv->das6402_ignoreirq) {
153 dev_warn(dev->class_dev, "BUG: spurious interrupt\n");
154 return IRQ_HANDLED;
156 #ifdef DEBUG
157 printk("das6402: interrupt! das6402_irqcount=%i\n",
158 devpriv->das6402_irqcount);
159 printk("das6402: iobase+2=%i\n", inw_p(dev->iobase + 2));
160 #endif
162 das6402_ai_fifo_dregs(dev, s);
164 if (s->async->buf_write_count >= devpriv->ai_bytes_to_read) {
165 outw_p(SCANL, dev->iobase + 2); /* clears the fifo */
166 outb(0x07, dev->iobase + 8); /* clears all flip-flops */
167 #ifdef DEBUG
168 printk("das6402: Got %i samples\n\n",
169 devpriv->das6402_wordsread - diff);
170 #endif
171 s->async->events |= COMEDI_CB_EOA;
172 comedi_event(dev, s);
175 outb(0x01, dev->iobase + 8); /* clear only the interrupt flip-flop */
177 comedi_event(dev, s);
178 return IRQ_HANDLED;
181 #if 0
182 static void das6402_ai_fifo_read(struct comedi_device *dev, short *data, int n)
184 int i;
186 for (i = 0; i < n; i++)
187 data[i] = inw(dev->iobase);
189 #endif
191 static int das6402_ai_cancel(struct comedi_device *dev,
192 struct comedi_subdevice *s)
194 struct das6402_private *devpriv = dev->private;
197 * This function should reset the board from whatever condition it
198 * is in (i.e., acquiring data), to a non-active state.
201 devpriv->das6402_ignoreirq = 1;
202 dev_dbg(dev->class_dev, "Stopping acquisition\n");
203 devpriv->das6402_ignoreirq = 1;
204 outb_p(0x02, dev->iobase + 10); /* disable external trigging */
205 outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */
206 outb_p(0, dev->iobase + 9); /* disables interrupts */
208 outw_p(SCANL, dev->iobase + 2);
210 return 0;
213 #ifdef unused
214 static int das6402_ai_mode2(struct comedi_device *dev,
215 struct comedi_subdevice *s, comedi_trig * it)
217 struct das6402_private *devpriv = dev->private;
219 devpriv->das6402_ignoreirq = 1;
220 dev_dbg(dev->class_dev, "Starting acquisition\n");
221 outb_p(0x03, dev->iobase + 10); /* enable external trigging */
222 outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */
223 outb_p(IRQ | CONVSRC | BURSTEN | INTE, dev->iobase + 9);
225 devpriv->ai_bytes_to_read = it->n * sizeof(short);
227 /* um... ignoreirq is a nasty race condition */
228 devpriv->das6402_ignoreirq = 0;
230 outw_p(SCANL, dev->iobase + 2);
232 return 0;
234 #endif
236 static int board_init(struct comedi_device *dev)
238 struct das6402_private *devpriv = dev->private;
239 BYTE b;
241 devpriv->das6402_ignoreirq = 1;
243 outb(0x07, dev->iobase + 8);
245 /* register 11 */
246 outb_p(MODE, dev->iobase + 11);
247 b = BIP | SEM | MODE | GAIN | FIFOHFULL;
248 outb_p(b, dev->iobase + 11);
250 /* register 8 */
251 outb_p(EXTEND, dev->iobase + 8);
252 b = EXTEND | MHZ;
253 outb_p(b, dev->iobase + 8);
254 b = MHZ | CLRINT | CLRXTR | CLRXIN;
255 outb_p(b, dev->iobase + 8);
257 /* register 9 */
258 b = IRQ | CONVSRC | BURSTEN | INTE;
259 outb_p(b, dev->iobase + 9);
261 /* register 10 */
262 b = TGSEL | TGEN;
263 outb_p(b, dev->iobase + 10);
265 b = 0x07;
266 outb_p(b, dev->iobase + 8);
268 das6402_setcounter(dev);
270 outw_p(SCANL, dev->iobase + 2); /* reset card fifo */
272 devpriv->das6402_ignoreirq = 0;
274 return 0;
277 static int das6402_attach(struct comedi_device *dev,
278 struct comedi_devconfig *it)
280 struct das6402_private *devpriv;
281 unsigned int irq;
282 int ret;
283 struct comedi_subdevice *s;
285 ret = comedi_request_region(dev, it->options[0], DAS6402_SIZE);
286 if (ret)
287 return ret;
289 irq = it->options[0];
290 dev_dbg(dev->class_dev, "( irq = %u )\n", irq);
291 ret = request_irq(irq, intr_handler, 0, "das6402", dev);
292 if (ret < 0)
293 return ret;
295 dev->irq = irq;
297 devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
298 if (!devpriv)
299 return -ENOMEM;
300 dev->private = devpriv;
302 ret = comedi_alloc_subdevices(dev, 1);
303 if (ret)
304 return ret;
306 /* ai subdevice */
307 s = &dev->subdevices[0];
308 s->type = COMEDI_SUBD_AI;
309 s->subdev_flags = SDF_READABLE | SDF_GROUND;
310 s->n_chan = 8;
311 /* s->trig[2]=das6402_ai_mode2; */
312 s->cancel = das6402_ai_cancel;
313 s->maxdata = (1 << 12) - 1;
314 s->len_chanlist = 16; /* ? */
315 s->range_table = &range_unknown;
317 board_init(dev);
319 return 0;
322 static struct comedi_driver das6402_driver = {
323 .driver_name = "das6402",
324 .module = THIS_MODULE,
325 .attach = das6402_attach,
326 .detach = comedi_legacy_detach,
328 module_comedi_driver(das6402_driver)
330 MODULE_AUTHOR("Comedi http://www.comedi.org");
331 MODULE_DESCRIPTION("Comedi low-level driver");
332 MODULE_LICENSE("GPL");