]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/comedi/drivers/das6402.c
Merge tag 'dm-3.11-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/agk...
[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 /*
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)
32
33 This driver has suffered bitrot.
34 */
35
36 #include <linux/interrupt.h>
37 #include "../comedidev.h"
38
39 #include <linux/ioport.h>
40
41 #define DAS6402_SIZE 16
42
43 #define N_WORDS (3000*64)
44
45 #define STOP    0
46 #define START   1
47
48 #define SCANL 0x3f00
49 #define BYTE unsigned char
50 #define WORD unsigned short
51
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 /*---------------------*/
61
62 /*----- register 9 ----*/
63 #define IRQ (0x04 << 4)         /* these two are                         */
64 #define IRQV 10                 /*               dependent on each other */
65
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 /*---------------------*/
71
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 /*---------------------*/
78
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 /*---------------------*/
88
89 #define M0 0x00
90 #define M2 0x04
91
92 #define C0 0x00
93 #define C1 0x40
94 #define C2 0x80
95 #define RWLH 0x30
96
97 struct das6402_private {
98         int ai_bytes_to_read;
99
100         int das6402_ignoreirq;
101 };
102
103 static void das6402_ai_fifo_dregs(struct comedi_device *dev,
104                                   struct comedi_subdevice *s)
105 {
106         while (1) {
107                 if (!(inb(dev->iobase + 8) & 0x01))
108                         return;
109                 comedi_buf_put(s->async, inw(dev->iobase));
110         }
111 }
112
113 static void das6402_setcounter(struct comedi_device *dev)
114 {
115         BYTE p;
116         unsigned short ctrlwrd;
117
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);
126
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);
135
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);
144 }
145
146 static irqreturn_t intr_handler(int irq, void *d)
147 {
148         struct comedi_device *dev = d;
149         struct das6402_private *devpriv = dev->private;
150         struct comedi_subdevice *s = &dev->subdevices[0];
151
152         if (!dev->attached || devpriv->das6402_ignoreirq) {
153                 dev_warn(dev->class_dev, "BUG: spurious interrupt\n");
154                 return IRQ_HANDLED;
155         }
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
161
162         das6402_ai_fifo_dregs(dev, s);
163
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);
173         }
174
175         outb(0x01, dev->iobase + 8);    /* clear only the interrupt flip-flop */
176
177         comedi_event(dev, s);
178         return IRQ_HANDLED;
179 }
180
181 #if 0
182 static void das6402_ai_fifo_read(struct comedi_device *dev, short *data, int n)
183 {
184         int i;
185
186         for (i = 0; i < n; i++)
187                 data[i] = inw(dev->iobase);
188 }
189 #endif
190
191 static int das6402_ai_cancel(struct comedi_device *dev,
192                              struct comedi_subdevice *s)
193 {
194         struct das6402_private *devpriv = dev->private;
195
196         /*
197          *  This function should reset the board from whatever condition it
198          *  is in (i.e., acquiring data), to a non-active state.
199          */
200
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 */
207
208         outw_p(SCANL, dev->iobase + 2);
209
210         return 0;
211 }
212
213 #ifdef unused
214 static int das6402_ai_mode2(struct comedi_device *dev,
215                             struct comedi_subdevice *s, comedi_trig * it)
216 {
217         struct das6402_private *devpriv = dev->private;
218
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);
224
225         devpriv->ai_bytes_to_read = it->n * sizeof(short);
226
227         /* um... ignoreirq is a nasty race condition */
228         devpriv->das6402_ignoreirq = 0;
229
230         outw_p(SCANL, dev->iobase + 2);
231
232         return 0;
233 }
234 #endif
235
236 static int board_init(struct comedi_device *dev)
237 {
238         struct das6402_private *devpriv = dev->private;
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
277 static int das6402_attach(struct comedi_device *dev,
278                           struct comedi_devconfig *it)
279 {
280         struct das6402_private *devpriv;
281         unsigned int irq;
282         int ret;
283         struct comedi_subdevice *s;
284
285         ret = comedi_request_region(dev, it->options[0], DAS6402_SIZE);
286         if (ret)
287                 return ret;
288
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;
294
295         dev->irq = irq;
296
297         devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
298         if (!devpriv)
299                 return -ENOMEM;
300         dev->private = devpriv;
301
302         ret = comedi_alloc_subdevices(dev, 1);
303         if (ret)
304                 return ret;
305
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;
316
317         board_init(dev);
318
319         return 0;
320 }
321
322 static struct comedi_driver das6402_driver = {
323         .driver_name    = "das6402",
324         .module         = THIS_MODULE,
325         .attach         = das6402_attach,
326         .detach         = comedi_legacy_detach,
327 };
328 module_comedi_driver(das6402_driver)
329
330 MODULE_AUTHOR("Comedi http://www.comedi.org");
331 MODULE_DESCRIPTION("Comedi low-level driver");
332 MODULE_LICENSE("GPL");