]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/comedi/drivers/das6402.c
Merge branch 'master' of git://git.infradead.org/users/dwmw2/solos-2.6
[karo-tx-linux.git] / drivers / staging / comedi / drivers / das6402.c
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 /*
32 Driver: das6402
33 Description: Keithley Metrabyte DAS6402 (& compatibles)
34 Author: Oystein Svendsen <svendsen@pvv.org>
35 Status: bitrotten
36 Devices: [Keithley Metrabyte] DAS6402 (das6402)
37
38 This driver has suffered bitrot.
39 */
40
41 #include <linux/interrupt.h>
42 #include "../comedidev.h"
43
44 #include <linux/ioport.h>
45
46 #define DAS6402_SIZE 16
47
48 #define N_WORDS 3000*64
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
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,
109 };
110
111 COMEDI_INITCLEANUP(driver_das6402);
112
113 struct das6402_private {
114         int ai_bytes_to_read;
115
116         int das6402_ignoreirq;
117 };
118 #define devpriv ((struct das6402_private *)dev->private)
119
120 static void das6402_ai_fifo_dregs(struct comedi_device *dev, struct comedi_subdevice *s);
121
122 static void das6402_setcounter(struct comedi_device *dev)
123 {
124         BYTE p;
125         unsigned short ctrlwrd;
126
127         /* set up counter0 first, mode 0 */
128         p = M0 | C0 | RWLH;
129         outb_p(p, dev->iobase + 15);
130         ctrlwrd = 2000;
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);
135
136         /* set up counter1, mode 2 */
137         p = M2 | C1 | RWLH;
138         outb_p(p, dev->iobase + 15);
139         ctrlwrd = 10;
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);
144
145         /* set up counter1, mode 2 */
146         p = M2 | C2 | RWLH;
147         outb_p(p, dev->iobase + 15);
148         ctrlwrd = 1000;
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);
153 }
154
155 static irqreturn_t intr_handler(int irq, void *d)
156 {
157         struct comedi_device *dev = d;
158         struct comedi_subdevice *s = dev->subdevices;
159
160         if (!dev->attached || devpriv->das6402_ignoreirq) {
161                 printk("das6402: BUG: spurious interrupt\n");
162                 return IRQ_HANDLED;
163         }
164 #ifdef DEBUG
165         printk("das6402: interrupt! das6402_irqcount=%i\n",
166                 devpriv->das6402_irqcount);
167         printk("das6402: iobase+2=%i\n", inw_p(dev->iobase + 2));
168 #endif
169
170         das6402_ai_fifo_dregs(dev, s);
171
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 */
175 #ifdef DEBUG
176                 printk("das6402: Got %i samples\n\n",
177                         devpriv->das6402_wordsread - diff);
178 #endif
179                 s->async->events |= COMEDI_CB_EOA;
180                 comedi_event(dev, s);
181         }
182
183         outb(0x01, dev->iobase + 8);    /* clear only the interrupt flip-flop */
184
185         comedi_event(dev, s);
186         return IRQ_HANDLED;
187 }
188
189 #if 0
190 static void das6402_ai_fifo_read(struct comedi_device *dev, short *data, int n)
191 {
192         int i;
193
194         for (i = 0; i < n; i++)
195                 data[i] = inw(dev->iobase);
196 }
197 #endif
198
199 static void das6402_ai_fifo_dregs(struct comedi_device *dev, struct comedi_subdevice *s)
200 {
201         while (1) {
202                 if (!(inb(dev->iobase + 8) & 0x01))
203                         return;
204                 comedi_buf_put(s->async, inw(dev->iobase));
205         }
206 }
207
208 static int das6402_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
209 {
210         /*
211          *  This function should reset the board from whatever condition it
212          *  is in (i.e., acquiring data), to a non-active state.
213          */
214
215         devpriv->das6402_ignoreirq = 1;
216 #ifdef DEBUG
217         printk("das6402: Stopping acquisition\n");
218 #endif
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 */
223
224         outw_p(SCANL, dev->iobase + 2);
225
226         return 0;
227 }
228
229 #ifdef unused
230 static int das6402_ai_mode2(struct comedi_device *dev, struct comedi_subdevice *s,
231         comedi_trig *it)
232 {
233         devpriv->das6402_ignoreirq = 1;
234
235 #ifdef DEBUG
236         printk("das6402: Starting acquisition\n");
237 #endif
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);
241
242         devpriv->ai_bytes_to_read = it->n * sizeof(short);
243
244         /* um... ignoreirq is a nasty race condition */
245         devpriv->das6402_ignoreirq = 0;
246
247         outw_p(SCANL, dev->iobase + 2);
248
249         return 0;
250 }
251 #endif
252
253 static int board_init(struct comedi_device *dev)
254 {
255         BYTE b;
256
257         devpriv->das6402_ignoreirq = 1;
258
259         outb(0x07, dev->iobase + 8);
260
261         /* register 11  */
262         outb_p(MODE, dev->iobase + 11);
263         b = BIP | SEM | MODE | GAIN | FIFOHFULL;
264         outb_p(b, dev->iobase + 11);
265
266         /* register 8   */
267         outb_p(EXTEND, dev->iobase + 8);
268         b = EXTEND | MHZ;
269         outb_p(b, dev->iobase + 8);
270         b = MHZ | CLRINT | CLRXTR | CLRXIN;
271         outb_p(b, dev->iobase + 8);
272
273         /* register 9    */
274         b = IRQ | CONVSRC | BURSTEN | INTE;
275         outb_p(b, dev->iobase + 9);
276
277         /* register 10   */
278         b = TGSEL | TGEN;
279         outb_p(b, dev->iobase + 10);
280
281         b = 0x07;
282         outb_p(b, dev->iobase + 8);
283
284         das6402_setcounter(dev);
285
286         outw_p(SCANL, dev->iobase + 2); /* reset card fifo */
287
288         devpriv->das6402_ignoreirq = 0;
289
290         return 0;
291 }
292
293 static int das6402_detach(struct comedi_device *dev)
294 {
295         if (dev->irq)
296                 free_irq(dev->irq, dev);
297         if (dev->iobase)
298                 release_region(dev->iobase, DAS6402_SIZE);
299
300         return 0;
301 }
302
303 static int das6402_attach(struct comedi_device *dev, struct comedi_devconfig *it)
304 {
305         unsigned int irq;
306         unsigned long iobase;
307         int ret;
308         struct comedi_subdevice *s;
309
310         dev->board_name = "das6402";
311
312         iobase = it->options[0];
313         if (iobase == 0)
314                 iobase = 0x300;
315
316         printk("comedi%d: das6402: 0x%04lx", dev->minor, iobase);
317
318         if (!request_region(iobase, DAS6402_SIZE, "das6402")) {
319                 printk(" I/O port conflict\n");
320                 return -EIO;
321         }
322         dev->iobase = iobase;
323
324         /* should do a probe here */
325
326         irq = it->options[0];
327         printk(" ( irq = %u )", irq);
328         ret = request_irq(irq, intr_handler, 0, "das6402", dev);
329         if (ret < 0) {
330                 printk("irq conflict\n");
331                 return ret;
332         }
333         dev->irq = irq;
334
335         ret = alloc_private(dev, sizeof(struct das6402_private));
336         if (ret < 0)
337                 return ret;
338
339         ret = alloc_subdevices(dev, 1);
340         if (ret < 0)
341                 return ret;
342
343         /* ai subdevice */
344         s = dev->subdevices + 0;
345         s->type = COMEDI_SUBD_AI;
346         s->subdev_flags = SDF_READABLE | SDF_GROUND;
347         s->n_chan = 8;
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;
353
354         board_init(dev);
355
356         return 0;
357 }