Staging: comedi: drivers: fix coding style issues in pcl812.c
[GitHub/mt8127/android_kernel_alcatel_ttab.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,
103 struct comedi_devconfig *it);
104 static int das6402_detach(struct comedi_device *dev);
105 static struct comedi_driver driver_das6402 = {
106 .driver_name = "das6402",
107 .module = THIS_MODULE,
108 .attach = das6402_attach,
109 .detach = das6402_detach,
110 };
111
112 static int __init driver_das6402_init_module(void)
113 {
114 return comedi_driver_register(&driver_das6402);
115 }
116
117 static void __exit driver_das6402_cleanup_module(void)
118 {
119 comedi_driver_unregister(&driver_das6402);
120 }
121
122 module_init(driver_das6402_init_module);
123 module_exit(driver_das6402_cleanup_module);
124
125 struct das6402_private {
126 int ai_bytes_to_read;
127
128 int das6402_ignoreirq;
129 };
130 #define devpriv ((struct das6402_private *)dev->private)
131
132 static void das6402_ai_fifo_dregs(struct comedi_device *dev,
133 struct comedi_subdevice *s);
134
135 static void das6402_setcounter(struct comedi_device *dev)
136 {
137 BYTE p;
138 unsigned short ctrlwrd;
139
140 /* set up counter0 first, mode 0 */
141 p = M0 | C0 | RWLH;
142 outb_p(p, dev->iobase + 15);
143 ctrlwrd = 2000;
144 p = (BYTE) (0xff & ctrlwrd);
145 outb_p(p, dev->iobase + 12);
146 p = (BYTE) (0xff & (ctrlwrd >> 8));
147 outb_p(p, dev->iobase + 12);
148
149 /* set up counter1, mode 2 */
150 p = M2 | C1 | RWLH;
151 outb_p(p, dev->iobase + 15);
152 ctrlwrd = 10;
153 p = (BYTE) (0xff & ctrlwrd);
154 outb_p(p, dev->iobase + 13);
155 p = (BYTE) (0xff & (ctrlwrd >> 8));
156 outb_p(p, dev->iobase + 13);
157
158 /* set up counter1, mode 2 */
159 p = M2 | C2 | RWLH;
160 outb_p(p, dev->iobase + 15);
161 ctrlwrd = 1000;
162 p = (BYTE) (0xff & ctrlwrd);
163 outb_p(p, dev->iobase + 14);
164 p = (BYTE) (0xff & (ctrlwrd >> 8));
165 outb_p(p, dev->iobase + 14);
166 }
167
168 static irqreturn_t intr_handler(int irq, void *d)
169 {
170 struct comedi_device *dev = d;
171 struct comedi_subdevice *s = dev->subdevices;
172
173 if (!dev->attached || devpriv->das6402_ignoreirq) {
174 printk("das6402: BUG: spurious interrupt\n");
175 return IRQ_HANDLED;
176 }
177 #ifdef DEBUG
178 printk("das6402: interrupt! das6402_irqcount=%i\n",
179 devpriv->das6402_irqcount);
180 printk("das6402: iobase+2=%i\n", inw_p(dev->iobase + 2));
181 #endif
182
183 das6402_ai_fifo_dregs(dev, s);
184
185 if (s->async->buf_write_count >= devpriv->ai_bytes_to_read) {
186 outw_p(SCANL, dev->iobase + 2); /* clears the fifo */
187 outb(0x07, dev->iobase + 8); /* clears all flip-flops */
188 #ifdef DEBUG
189 printk("das6402: Got %i samples\n\n",
190 devpriv->das6402_wordsread - diff);
191 #endif
192 s->async->events |= COMEDI_CB_EOA;
193 comedi_event(dev, s);
194 }
195
196 outb(0x01, dev->iobase + 8); /* clear only the interrupt flip-flop */
197
198 comedi_event(dev, s);
199 return IRQ_HANDLED;
200 }
201
202 #if 0
203 static void das6402_ai_fifo_read(struct comedi_device *dev, short *data, int n)
204 {
205 int i;
206
207 for (i = 0; i < n; i++)
208 data[i] = inw(dev->iobase);
209 }
210 #endif
211
212 static void das6402_ai_fifo_dregs(struct comedi_device *dev,
213 struct comedi_subdevice *s)
214 {
215 while (1) {
216 if (!(inb(dev->iobase + 8) & 0x01))
217 return;
218 comedi_buf_put(s->async, inw(dev->iobase));
219 }
220 }
221
222 static int das6402_ai_cancel(struct comedi_device *dev,
223 struct comedi_subdevice *s)
224 {
225 /*
226 * This function should reset the board from whatever condition it
227 * is in (i.e., acquiring data), to a non-active state.
228 */
229
230 devpriv->das6402_ignoreirq = 1;
231 #ifdef DEBUG
232 printk("das6402: Stopping acquisition\n");
233 #endif
234 devpriv->das6402_ignoreirq = 1;
235 outb_p(0x02, dev->iobase + 10); /* disable external trigging */
236 outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */
237 outb_p(0, dev->iobase + 9); /* disables interrupts */
238
239 outw_p(SCANL, dev->iobase + 2);
240
241 return 0;
242 }
243
244 #ifdef unused
245 static int das6402_ai_mode2(struct comedi_device *dev,
246 struct comedi_subdevice *s, comedi_trig * it)
247 {
248 devpriv->das6402_ignoreirq = 1;
249
250 #ifdef DEBUG
251 printk("das6402: Starting acquisition\n");
252 #endif
253 outb_p(0x03, dev->iobase + 10); /* enable external trigging */
254 outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */
255 outb_p(IRQ | CONVSRC | BURSTEN | INTE, dev->iobase + 9);
256
257 devpriv->ai_bytes_to_read = it->n * sizeof(short);
258
259 /* um... ignoreirq is a nasty race condition */
260 devpriv->das6402_ignoreirq = 0;
261
262 outw_p(SCANL, dev->iobase + 2);
263
264 return 0;
265 }
266 #endif
267
268 static int board_init(struct comedi_device *dev)
269 {
270 BYTE b;
271
272 devpriv->das6402_ignoreirq = 1;
273
274 outb(0x07, dev->iobase + 8);
275
276 /* register 11 */
277 outb_p(MODE, dev->iobase + 11);
278 b = BIP | SEM | MODE | GAIN | FIFOHFULL;
279 outb_p(b, dev->iobase + 11);
280
281 /* register 8 */
282 outb_p(EXTEND, dev->iobase + 8);
283 b = EXTEND | MHZ;
284 outb_p(b, dev->iobase + 8);
285 b = MHZ | CLRINT | CLRXTR | CLRXIN;
286 outb_p(b, dev->iobase + 8);
287
288 /* register 9 */
289 b = IRQ | CONVSRC | BURSTEN | INTE;
290 outb_p(b, dev->iobase + 9);
291
292 /* register 10 */
293 b = TGSEL | TGEN;
294 outb_p(b, dev->iobase + 10);
295
296 b = 0x07;
297 outb_p(b, dev->iobase + 8);
298
299 das6402_setcounter(dev);
300
301 outw_p(SCANL, dev->iobase + 2); /* reset card fifo */
302
303 devpriv->das6402_ignoreirq = 0;
304
305 return 0;
306 }
307
308 static int das6402_detach(struct comedi_device *dev)
309 {
310 if (dev->irq)
311 free_irq(dev->irq, dev);
312 if (dev->iobase)
313 release_region(dev->iobase, DAS6402_SIZE);
314
315 return 0;
316 }
317
318 static int das6402_attach(struct comedi_device *dev,
319 struct comedi_devconfig *it)
320 {
321 unsigned int irq;
322 unsigned long iobase;
323 int ret;
324 struct comedi_subdevice *s;
325
326 dev->board_name = "das6402";
327
328 iobase = it->options[0];
329 if (iobase == 0)
330 iobase = 0x300;
331
332 printk("comedi%d: das6402: 0x%04lx", dev->minor, iobase);
333
334 if (!request_region(iobase, DAS6402_SIZE, "das6402")) {
335 printk(" I/O port conflict\n");
336 return -EIO;
337 }
338 dev->iobase = iobase;
339
340 /* should do a probe here */
341
342 irq = it->options[0];
343 printk(" ( irq = %u )", irq);
344 ret = request_irq(irq, intr_handler, 0, "das6402", dev);
345 if (ret < 0) {
346 printk("irq conflict\n");
347 return ret;
348 }
349 dev->irq = irq;
350
351 ret = alloc_private(dev, sizeof(struct das6402_private));
352 if (ret < 0)
353 return ret;
354
355 ret = alloc_subdevices(dev, 1);
356 if (ret < 0)
357 return ret;
358
359 /* ai subdevice */
360 s = dev->subdevices + 0;
361 s->type = COMEDI_SUBD_AI;
362 s->subdev_flags = SDF_READABLE | SDF_GROUND;
363 s->n_chan = 8;
364 /* s->trig[2]=das6402_ai_mode2; */
365 s->cancel = das6402_ai_cancel;
366 s->maxdata = (1 << 12) - 1;
367 s->len_chanlist = 16; /* ? */
368 s->range_table = &range_unknown;
369
370 board_init(dev);
371
372 return 0;
373 }
374
375 MODULE_AUTHOR("Comedi http://www.comedi.org");
376 MODULE_DESCRIPTION("Comedi low-level driver");
377 MODULE_LICENSE("GPL");