Merge branch 'next/drivers' into HEAD
[deliverable/linux.git] / drivers / staging / comedi / drivers / das6402.c
CommitLineData
48f16b6a
OS
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
25436dc9 41#include <linux/interrupt.h>
48f16b6a
OS
42#include "../comedidev.h"
43
44#include <linux/ioport.h>
45
46#define DAS6402_SIZE 16
47
ecd89ddc 48#define N_WORDS (3000*64)
48f16b6a
OS
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
c7b8bb98 102struct das6402_private {
48f16b6a
OS
103 int ai_bytes_to_read;
104
105 int das6402_ignoreirq;
c7b8bb98
BP
106};
107#define devpriv ((struct das6402_private *)dev->private)
48f16b6a 108
0a85b6f0 109static void das6402_ai_fifo_dregs(struct comedi_device *dev,
71e7271b
HS
110 struct comedi_subdevice *s)
111{
112 while (1) {
113 if (!(inb(dev->iobase + 8) & 0x01))
114 return;
115 comedi_buf_put(s->async, inw(dev->iobase));
116 }
117}
48f16b6a 118
da91b269 119static void das6402_setcounter(struct comedi_device *dev)
48f16b6a
OS
120{
121 BYTE p;
122 unsigned short ctrlwrd;
123
124 /* set up counter0 first, mode 0 */
125 p = M0 | C0 | RWLH;
126 outb_p(p, dev->iobase + 15);
127 ctrlwrd = 2000;
128 p = (BYTE) (0xff & ctrlwrd);
129 outb_p(p, dev->iobase + 12);
130 p = (BYTE) (0xff & (ctrlwrd >> 8));
131 outb_p(p, dev->iobase + 12);
132
133 /* set up counter1, mode 2 */
134 p = M2 | C1 | RWLH;
135 outb_p(p, dev->iobase + 15);
136 ctrlwrd = 10;
137 p = (BYTE) (0xff & ctrlwrd);
138 outb_p(p, dev->iobase + 13);
139 p = (BYTE) (0xff & (ctrlwrd >> 8));
140 outb_p(p, dev->iobase + 13);
141
142 /* set up counter1, mode 2 */
143 p = M2 | C2 | RWLH;
144 outb_p(p, dev->iobase + 15);
145 ctrlwrd = 1000;
146 p = (BYTE) (0xff & ctrlwrd);
147 outb_p(p, dev->iobase + 14);
148 p = (BYTE) (0xff & (ctrlwrd >> 8));
149 outb_p(p, dev->iobase + 14);
150}
151
70265d24 152static irqreturn_t intr_handler(int irq, void *d)
48f16b6a 153{
71b5f4f1 154 struct comedi_device *dev = d;
92cfef5d 155 struct comedi_subdevice *s = &dev->subdevices[0];
48f16b6a
OS
156
157 if (!dev->attached || devpriv->das6402_ignoreirq) {
f41ad667 158 dev_warn(dev->class_dev, "BUG: spurious interrupt\n");
48f16b6a
OS
159 return IRQ_HANDLED;
160 }
161#ifdef DEBUG
162 printk("das6402: interrupt! das6402_irqcount=%i\n",
0a85b6f0 163 devpriv->das6402_irqcount);
48f16b6a
OS
164 printk("das6402: iobase+2=%i\n", inw_p(dev->iobase + 2));
165#endif
166
167 das6402_ai_fifo_dregs(dev, s);
168
169 if (s->async->buf_write_count >= devpriv->ai_bytes_to_read) {
170 outw_p(SCANL, dev->iobase + 2); /* clears the fifo */
171 outb(0x07, dev->iobase + 8); /* clears all flip-flops */
172#ifdef DEBUG
173 printk("das6402: Got %i samples\n\n",
0a85b6f0 174 devpriv->das6402_wordsread - diff);
48f16b6a
OS
175#endif
176 s->async->events |= COMEDI_CB_EOA;
177 comedi_event(dev, s);
178 }
179
180 outb(0x01, dev->iobase + 8); /* clear only the interrupt flip-flop */
181
182 comedi_event(dev, s);
183 return IRQ_HANDLED;
184}
185
186#if 0
da91b269 187static void das6402_ai_fifo_read(struct comedi_device *dev, short *data, int n)
48f16b6a
OS
188{
189 int i;
190
191 for (i = 0; i < n; i++)
192 data[i] = inw(dev->iobase);
193}
194#endif
195
0a85b6f0
MT
196static int das6402_ai_cancel(struct comedi_device *dev,
197 struct comedi_subdevice *s)
48f16b6a
OS
198{
199 /*
200 * This function should reset the board from whatever condition it
201 * is in (i.e., acquiring data), to a non-active state.
202 */
203
204 devpriv->das6402_ignoreirq = 1;
f41ad667 205 dev_dbg(dev->class_dev, "Stopping acquisition\n");
48f16b6a
OS
206 devpriv->das6402_ignoreirq = 1;
207 outb_p(0x02, dev->iobase + 10); /* disable external trigging */
208 outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */
209 outb_p(0, dev->iobase + 9); /* disables interrupts */
210
211 outw_p(SCANL, dev->iobase + 2);
212
213 return 0;
214}
215
216#ifdef unused
0a85b6f0
MT
217static int das6402_ai_mode2(struct comedi_device *dev,
218 struct comedi_subdevice *s, comedi_trig * it)
48f16b6a
OS
219{
220 devpriv->das6402_ignoreirq = 1;
f41ad667 221 dev_dbg(dev->class_dev, "Starting acquisition\n");
48f16b6a
OS
222 outb_p(0x03, dev->iobase + 10); /* enable external trigging */
223 outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */
224 outb_p(IRQ | CONVSRC | BURSTEN | INTE, dev->iobase + 9);
225
790c5541 226 devpriv->ai_bytes_to_read = it->n * sizeof(short);
48f16b6a
OS
227
228 /* um... ignoreirq is a nasty race condition */
229 devpriv->das6402_ignoreirq = 0;
230
231 outw_p(SCANL, dev->iobase + 2);
232
233 return 0;
234}
235#endif
236
da91b269 237static int board_init(struct comedi_device *dev)
48f16b6a
OS
238{
239 BYTE b;
240
241 devpriv->das6402_ignoreirq = 1;
242
243 outb(0x07, dev->iobase + 8);
244
245 /* register 11 */
246 outb_p(MODE, dev->iobase + 11);
247 b = BIP | SEM | MODE | GAIN | FIFOHFULL;
248 outb_p(b, dev->iobase + 11);
249
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);
256
257 /* register 9 */
258 b = IRQ | CONVSRC | BURSTEN | INTE;
259 outb_p(b, dev->iobase + 9);
260
261 /* register 10 */
262 b = TGSEL | TGEN;
263 outb_p(b, dev->iobase + 10);
264
265 b = 0x07;
266 outb_p(b, dev->iobase + 8);
267
268 das6402_setcounter(dev);
269
270 outw_p(SCANL, dev->iobase + 2); /* reset card fifo */
271
272 devpriv->das6402_ignoreirq = 0;
273
274 return 0;
275}
276
0a85b6f0
MT
277static int das6402_attach(struct comedi_device *dev,
278 struct comedi_devconfig *it)
48f16b6a
OS
279{
280 unsigned int irq;
281 unsigned long iobase;
282 int ret;
34c43922 283 struct comedi_subdevice *s;
48f16b6a
OS
284
285 dev->board_name = "das6402";
286
287 iobase = it->options[0];
288 if (iobase == 0)
289 iobase = 0x300;
290
48f16b6a 291 if (!request_region(iobase, DAS6402_SIZE, "das6402")) {
f41ad667 292 dev_err(dev->class_dev, "I/O port conflict\n");
48f16b6a
OS
293 return -EIO;
294 }
295 dev->iobase = iobase;
296
297 /* should do a probe here */
298
299 irq = it->options[0];
f41ad667 300 dev_dbg(dev->class_dev, "( irq = %u )\n", irq);
5f74ea14 301 ret = request_irq(irq, intr_handler, 0, "das6402", dev);
7e4198f4 302 if (ret < 0)
48f16b6a 303 return ret;
48f16b6a 304
7e4198f4 305 dev->irq = irq;
c3744138
BP
306 ret = alloc_private(dev, sizeof(struct das6402_private));
307 if (ret < 0)
48f16b6a
OS
308 return ret;
309
2f0b9d08 310 ret = comedi_alloc_subdevices(dev, 1);
8b6c5694 311 if (ret)
48f16b6a
OS
312 return ret;
313
314 /* ai subdevice */
92cfef5d 315 s = &dev->subdevices[0];
48f16b6a
OS
316 s->type = COMEDI_SUBD_AI;
317 s->subdev_flags = SDF_READABLE | SDF_GROUND;
318 s->n_chan = 8;
2696fb57 319 /* s->trig[2]=das6402_ai_mode2; */
48f16b6a
OS
320 s->cancel = das6402_ai_cancel;
321 s->maxdata = (1 << 12) - 1;
322 s->len_chanlist = 16; /* ? */
323 s->range_table = &range_unknown;
324
325 board_init(dev);
326
327 return 0;
328}
90f703d3 329
484ecc95 330static void das6402_detach(struct comedi_device *dev)
71e7271b
HS
331{
332 if (dev->irq)
333 free_irq(dev->irq, dev);
334 if (dev->iobase)
335 release_region(dev->iobase, DAS6402_SIZE);
71e7271b
HS
336}
337
338static struct comedi_driver das6402_driver = {
339 .driver_name = "das6402",
340 .module = THIS_MODULE,
341 .attach = das6402_attach,
342 .detach = das6402_detach,
343};
344module_comedi_driver(das6402_driver)
345
90f703d3
AT
346MODULE_AUTHOR("Comedi http://www.comedi.org");
347MODULE_DESCRIPTION("Comedi low-level driver");
348MODULE_LICENSE("GPL");
This page took 0.353538 seconds and 5 git commands to generate.