Staging: comedi: Remove cb_pcidas_private typedef
[linux-2.6] / 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 "../comedidev.h"
42
43 #include <linux/ioport.h>
44
45 #define DAS6402_SIZE 16
46
47 #define N_WORDS 3000*64
48
49 #define STOP    0
50 #define START   1
51
52 #define SCANL 0x3f00
53 #define BYTE unsigned char
54 #define WORD unsigned short
55
56 /*----- register 8 ----*/
57 #define CLRINT 0x01
58 #define CLRXTR 0x02
59 #define CLRXIN 0x04
60 #define EXTEND 0x10
61 #define ARMED 0x20              /* enable conting of post sample conv */
62 #define POSTMODE 0x40
63 #define MHZ 0x80                /* 10 MHz clock */
64 /*---------------------*/
65
66 /*----- register 9 ----*/
67 #define IRQ (0x04 << 4)         /* these two are                         */
68 #define IRQV 10                 /*               dependent on each other */
69
70 #define CONVSRC 0x03            /* trig src is Intarnal pacer */
71 #define BURSTEN 0x04            /* enable burst */
72 #define XINTE 0x08              /* use external int. trig */
73 #define INTE 0x80               /* enable analog interrupts */
74 /*---------------------*/
75
76 /*----- register 10 ---*/
77 #define TGEN 0x01               /* Use pin DI1 for externl trigging? */
78 #define TGSEL 0x02              /* Use edge triggering */
79 #define TGPOL 0x04              /* active edge is falling */
80 #define PRETRIG 0x08            /* pretrig */
81 /*---------------------*/
82
83 /*----- register 11 ---*/
84 #define EOB 0x0c
85 #define FIFOHFULL 0x08
86 #define GAIN 0x01
87 #define FIFONEPTY 0x04
88 #define MODE 0x10
89 #define SEM 0x20
90 #define BIP 0x40
91 /*---------------------*/
92
93 #define M0 0x00
94 #define M2 0x04
95
96 #define C0 0x00
97 #define C1 0x40
98 #define C2 0x80
99 #define RWLH 0x30
100
101 static int das6402_attach(struct comedi_device * dev, struct comedi_devconfig * it);
102 static int das6402_detach(struct comedi_device * dev);
103 static struct comedi_driver driver_das6402 = {
104       driver_name:"das6402",
105       module:THIS_MODULE,
106       attach:das6402_attach,
107       detach:das6402_detach,
108 };
109
110 COMEDI_INITCLEANUP(driver_das6402);
111
112 typedef struct {
113         int ai_bytes_to_read;
114
115         int das6402_ignoreirq;
116 } das6402_private;
117 #define devpriv ((das6402_private *)dev->private)
118
119 static void das6402_ai_fifo_dregs(struct comedi_device * dev, struct comedi_subdevice * s);
120
121 static void das6402_setcounter(struct comedi_device * dev)
122 {
123         BYTE p;
124         unsigned short ctrlwrd;
125
126         /* set up counter0 first, mode 0 */
127         p = M0 | C0 | RWLH;
128         outb_p(p, dev->iobase + 15);
129         ctrlwrd = 2000;
130         p = (BYTE) (0xff & ctrlwrd);
131         outb_p(p, dev->iobase + 12);
132         p = (BYTE) (0xff & (ctrlwrd >> 8));
133         outb_p(p, dev->iobase + 12);
134
135         /* set up counter1, mode 2 */
136         p = M2 | C1 | RWLH;
137         outb_p(p, dev->iobase + 15);
138         ctrlwrd = 10;
139         p = (BYTE) (0xff & ctrlwrd);
140         outb_p(p, dev->iobase + 13);
141         p = (BYTE) (0xff & (ctrlwrd >> 8));
142         outb_p(p, dev->iobase + 13);
143
144         /* set up counter1, mode 2 */
145         p = M2 | C2 | RWLH;
146         outb_p(p, dev->iobase + 15);
147         ctrlwrd = 1000;
148         p = (BYTE) (0xff & ctrlwrd);
149         outb_p(p, dev->iobase + 14);
150         p = (BYTE) (0xff & (ctrlwrd >> 8));
151         outb_p(p, dev->iobase + 14);
152 }
153
154 static irqreturn_t intr_handler(int irq, void *d PT_REGS_ARG)
155 {
156         struct comedi_device *dev = d;
157         struct comedi_subdevice *s = dev->subdevices;
158
159         if (!dev->attached || devpriv->das6402_ignoreirq) {
160                 printk("das6402: BUG: spurious interrupt\n");
161                 return IRQ_HANDLED;
162         }
163 #ifdef DEBUG
164         printk("das6402: interrupt! das6402_irqcount=%i\n",
165                 devpriv->das6402_irqcount);
166         printk("das6402: iobase+2=%i\n", inw_p(dev->iobase + 2));
167 #endif
168
169         das6402_ai_fifo_dregs(dev, s);
170
171         if (s->async->buf_write_count >= devpriv->ai_bytes_to_read) {
172                 outw_p(SCANL, dev->iobase + 2); /* clears the fifo */
173                 outb(0x07, dev->iobase + 8);    /* clears all flip-flops */
174 #ifdef DEBUG
175                 printk("das6402: Got %i samples\n\n",
176                         devpriv->das6402_wordsread - diff);
177 #endif
178                 s->async->events |= COMEDI_CB_EOA;
179                 comedi_event(dev, s);
180         }
181
182         outb(0x01, dev->iobase + 8);    /* clear only the interrupt flip-flop */
183
184         comedi_event(dev, s);
185         return IRQ_HANDLED;
186 }
187
188 #if 0
189 static void das6402_ai_fifo_read(struct comedi_device * dev, short * data, int n)
190 {
191         int i;
192
193         for (i = 0; i < n; i++)
194                 data[i] = inw(dev->iobase);
195 }
196 #endif
197
198 static void das6402_ai_fifo_dregs(struct comedi_device * dev, struct comedi_subdevice * s)
199 {
200         while (1) {
201                 if (!(inb(dev->iobase + 8) & 0x01))
202                         return;
203                 comedi_buf_put(s->async, inw(dev->iobase));
204         }
205 }
206
207 static int das6402_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s)
208 {
209         /*
210          *  This function should reset the board from whatever condition it
211          *  is in (i.e., acquiring data), to a non-active state.
212          */
213
214         devpriv->das6402_ignoreirq = 1;
215 #ifdef DEBUG
216         printk("das6402: Stopping acquisition\n");
217 #endif
218         devpriv->das6402_ignoreirq = 1;
219         outb_p(0x02, dev->iobase + 10); /* disable external trigging */
220         outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */
221         outb_p(0, dev->iobase + 9);     /* disables interrupts */
222
223         outw_p(SCANL, dev->iobase + 2);
224
225         return 0;
226 }
227
228 #ifdef unused
229 static int das6402_ai_mode2(struct comedi_device * dev, struct comedi_subdevice * s,
230         comedi_trig * it)
231 {
232         devpriv->das6402_ignoreirq = 1;
233
234 #ifdef DEBUG
235         printk("das6402: Starting acquisition\n");
236 #endif
237         outb_p(0x03, dev->iobase + 10); /* enable external trigging */
238         outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */
239         outb_p(IRQ | CONVSRC | BURSTEN | INTE, dev->iobase + 9);
240
241         devpriv->ai_bytes_to_read = it->n * sizeof(short);
242
243         /* um... ignoreirq is a nasty race condition */
244         devpriv->das6402_ignoreirq = 0;
245
246         outw_p(SCANL, dev->iobase + 2);
247
248         return 0;
249 }
250 #endif
251
252 static int board_init(struct comedi_device * dev)
253 {
254         BYTE b;
255
256         devpriv->das6402_ignoreirq = 1;
257
258         outb(0x07, dev->iobase + 8);
259
260         /* register 11  */
261         outb_p(MODE, dev->iobase + 11);
262         b = BIP | SEM | MODE | GAIN | FIFOHFULL;
263         outb_p(b, dev->iobase + 11);
264
265         /* register 8   */
266         outb_p(EXTEND, dev->iobase + 8);
267         b = EXTEND | MHZ;
268         outb_p(b, dev->iobase + 8);
269         b = MHZ | CLRINT | CLRXTR | CLRXIN;
270         outb_p(b, dev->iobase + 8);
271
272         /* register 9    */
273         b = IRQ | CONVSRC | BURSTEN | INTE;
274         outb_p(b, dev->iobase + 9);
275
276         /* register 10   */
277         b = TGSEL | TGEN;
278         outb_p(b, dev->iobase + 10);
279
280         b = 0x07;
281         outb_p(b, dev->iobase + 8);
282
283         das6402_setcounter(dev);
284
285         outw_p(SCANL, dev->iobase + 2); /* reset card fifo */
286
287         devpriv->das6402_ignoreirq = 0;
288
289         return 0;
290 }
291
292 static int das6402_detach(struct comedi_device * dev)
293 {
294         if (dev->irq)
295                 comedi_free_irq(dev->irq, dev);
296         if (dev->iobase)
297                 release_region(dev->iobase, DAS6402_SIZE);
298
299         return 0;
300 }
301
302 static int das6402_attach(struct comedi_device * dev, struct comedi_devconfig * it)
303 {
304         unsigned int irq;
305         unsigned long iobase;
306         int ret;
307         struct comedi_subdevice *s;
308
309         dev->board_name = "das6402";
310
311         iobase = it->options[0];
312         if (iobase == 0)
313                 iobase = 0x300;
314
315         printk("comedi%d: das6402: 0x%04lx", dev->minor, iobase);
316
317         if (!request_region(iobase, DAS6402_SIZE, "das6402")) {
318                 printk(" I/O port conflict\n");
319                 return -EIO;
320         }
321         dev->iobase = iobase;
322
323         /* should do a probe here */
324
325         irq = it->options[0];
326         printk(" ( irq = %u )", irq);
327         ret = comedi_request_irq(irq, intr_handler, 0, "das6402", dev);
328         if (ret < 0) {
329                 printk("irq conflict\n");
330                 return ret;
331         }
332         dev->irq = irq;
333
334         if ((ret = alloc_private(dev, sizeof(das6402_private))) < 0)
335                 return ret;
336
337         if ((ret = alloc_subdevices(dev, 1)) < 0)
338                 return ret;
339
340         /* ai subdevice */
341         s = dev->subdevices + 0;
342         s->type = COMEDI_SUBD_AI;
343         s->subdev_flags = SDF_READABLE | SDF_GROUND;
344         s->n_chan = 8;
345         //s->trig[2]=das6402_ai_mode2;
346         s->cancel = das6402_ai_cancel;
347         s->maxdata = (1 << 12) - 1;
348         s->len_chanlist = 16;   /* ? */
349         s->range_table = &range_unknown;
350
351         board_init(dev);
352
353         return 0;
354 }