1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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
58#define CLRINT 0x01
59#define CLRXTR 0x02
60#define CLRXIN 0x04
61#define EXTEND 0x10
62#define ARMED 0x20
63#define POSTMODE 0x40
64#define MHZ 0x80
65
66
67
68#define IRQ (0x04 << 4)
69#define IRQV 10
70
71#define CONVSRC 0x03
72#define BURSTEN 0x04
73#define XINTE 0x08
74#define INTE 0x80
75
76
77
78#define TGEN 0x01
79#define TGSEL 0x02
80#define TGPOL 0x04
81#define PRETRIG 0x08
82
83
84
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
102static int das6402_attach(struct comedi_device *dev,
103 struct comedi_devconfig *it);
104static int das6402_detach(struct comedi_device *dev);
105static struct comedi_driver driver_das6402 = {
106 .driver_name = "das6402",
107 .module = THIS_MODULE,
108 .attach = das6402_attach,
109 .detach = das6402_detach,
110};
111
112COMEDI_INITCLEANUP(driver_das6402);
113
114struct das6402_private {
115 int ai_bytes_to_read;
116
117 int das6402_ignoreirq;
118};
119#define devpriv ((struct das6402_private *)dev->private)
120
121static void das6402_ai_fifo_dregs(struct comedi_device *dev,
122 struct comedi_subdevice *s);
123
124static void das6402_setcounter(struct comedi_device *dev)
125{
126 BYTE p;
127 unsigned short ctrlwrd;
128
129
130 p = M0 | C0 | RWLH;
131 outb_p(p, dev->iobase + 15);
132 ctrlwrd = 2000;
133 p = (BYTE) (0xff & ctrlwrd);
134 outb_p(p, dev->iobase + 12);
135 p = (BYTE) (0xff & (ctrlwrd >> 8));
136 outb_p(p, dev->iobase + 12);
137
138
139 p = M2 | C1 | RWLH;
140 outb_p(p, dev->iobase + 15);
141 ctrlwrd = 10;
142 p = (BYTE) (0xff & ctrlwrd);
143 outb_p(p, dev->iobase + 13);
144 p = (BYTE) (0xff & (ctrlwrd >> 8));
145 outb_p(p, dev->iobase + 13);
146
147
148 p = M2 | C2 | RWLH;
149 outb_p(p, dev->iobase + 15);
150 ctrlwrd = 1000;
151 p = (BYTE) (0xff & ctrlwrd);
152 outb_p(p, dev->iobase + 14);
153 p = (BYTE) (0xff & (ctrlwrd >> 8));
154 outb_p(p, dev->iobase + 14);
155}
156
157static irqreturn_t intr_handler(int irq, void *d)
158{
159 struct comedi_device *dev = d;
160 struct comedi_subdevice *s = dev->subdevices;
161
162 if (!dev->attached || devpriv->das6402_ignoreirq) {
163 printk("das6402: BUG: spurious interrupt\n");
164 return IRQ_HANDLED;
165 }
166#ifdef DEBUG
167 printk("das6402: interrupt! das6402_irqcount=%i\n",
168 devpriv->das6402_irqcount);
169 printk("das6402: iobase+2=%i\n", inw_p(dev->iobase + 2));
170#endif
171
172 das6402_ai_fifo_dregs(dev, s);
173
174 if (s->async->buf_write_count >= devpriv->ai_bytes_to_read) {
175 outw_p(SCANL, dev->iobase + 2);
176 outb(0x07, dev->iobase + 8);
177#ifdef DEBUG
178 printk("das6402: Got %i samples\n\n",
179 devpriv->das6402_wordsread - diff);
180#endif
181 s->async->events |= COMEDI_CB_EOA;
182 comedi_event(dev, s);
183 }
184
185 outb(0x01, dev->iobase + 8);
186
187 comedi_event(dev, s);
188 return IRQ_HANDLED;
189}
190
191#if 0
192static void das6402_ai_fifo_read(struct comedi_device *dev, short *data, int n)
193{
194 int i;
195
196 for (i = 0; i < n; i++)
197 data[i] = inw(dev->iobase);
198}
199#endif
200
201static void das6402_ai_fifo_dregs(struct comedi_device *dev,
202 struct comedi_subdevice *s)
203{
204 while (1) {
205 if (!(inb(dev->iobase + 8) & 0x01))
206 return;
207 comedi_buf_put(s->async, inw(dev->iobase));
208 }
209}
210
211static int das6402_ai_cancel(struct comedi_device *dev,
212 struct comedi_subdevice *s)
213{
214
215
216
217
218
219 devpriv->das6402_ignoreirq = 1;
220#ifdef DEBUG
221 printk("das6402: Stopping acquisition\n");
222#endif
223 devpriv->das6402_ignoreirq = 1;
224 outb_p(0x02, dev->iobase + 10);
225 outw_p(SCANL, dev->iobase + 2);
226 outb_p(0, dev->iobase + 9);
227
228 outw_p(SCANL, dev->iobase + 2);
229
230 return 0;
231}
232
233#ifdef unused
234static int das6402_ai_mode2(struct comedi_device *dev,
235 struct comedi_subdevice *s, comedi_trig * it)
236{
237 devpriv->das6402_ignoreirq = 1;
238
239#ifdef DEBUG
240 printk("das6402: Starting acquisition\n");
241#endif
242 outb_p(0x03, dev->iobase + 10);
243 outw_p(SCANL, dev->iobase + 2);
244 outb_p(IRQ | CONVSRC | BURSTEN | INTE, dev->iobase + 9);
245
246 devpriv->ai_bytes_to_read = it->n * sizeof(short);
247
248
249 devpriv->das6402_ignoreirq = 0;
250
251 outw_p(SCANL, dev->iobase + 2);
252
253 return 0;
254}
255#endif
256
257static int board_init(struct comedi_device *dev)
258{
259 BYTE b;
260
261 devpriv->das6402_ignoreirq = 1;
262
263 outb(0x07, dev->iobase + 8);
264
265
266 outb_p(MODE, dev->iobase + 11);
267 b = BIP | SEM | MODE | GAIN | FIFOHFULL;
268 outb_p(b, dev->iobase + 11);
269
270
271 outb_p(EXTEND, dev->iobase + 8);
272 b = EXTEND | MHZ;
273 outb_p(b, dev->iobase + 8);
274 b = MHZ | CLRINT | CLRXTR | CLRXIN;
275 outb_p(b, dev->iobase + 8);
276
277
278 b = IRQ | CONVSRC | BURSTEN | INTE;
279 outb_p(b, dev->iobase + 9);
280
281
282 b = TGSEL | TGEN;
283 outb_p(b, dev->iobase + 10);
284
285 b = 0x07;
286 outb_p(b, dev->iobase + 8);
287
288 das6402_setcounter(dev);
289
290 outw_p(SCANL, dev->iobase + 2);
291
292 devpriv->das6402_ignoreirq = 0;
293
294 return 0;
295}
296
297static int das6402_detach(struct comedi_device *dev)
298{
299 if (dev->irq)
300 free_irq(dev->irq, dev);
301 if (dev->iobase)
302 release_region(dev->iobase, DAS6402_SIZE);
303
304 return 0;
305}
306
307static int das6402_attach(struct comedi_device *dev,
308 struct comedi_devconfig *it)
309{
310 unsigned int irq;
311 unsigned long iobase;
312 int ret;
313 struct comedi_subdevice *s;
314
315 dev->board_name = "das6402";
316
317 iobase = it->options[0];
318 if (iobase == 0)
319 iobase = 0x300;
320
321 printk("comedi%d: das6402: 0x%04lx", dev->minor, iobase);
322
323 if (!request_region(iobase, DAS6402_SIZE, "das6402")) {
324 printk(" I/O port conflict\n");
325 return -EIO;
326 }
327 dev->iobase = iobase;
328
329
330
331 irq = it->options[0];
332 printk(" ( irq = %u )", irq);
333 ret = request_irq(irq, intr_handler, 0, "das6402", dev);
334 if (ret < 0) {
335 printk("irq conflict\n");
336 return ret;
337 }
338 dev->irq = irq;
339
340 ret = alloc_private(dev, sizeof(struct das6402_private));
341 if (ret < 0)
342 return ret;
343
344 ret = alloc_subdevices(dev, 1);
345 if (ret < 0)
346 return ret;
347
348
349 s = dev->subdevices + 0;
350 s->type = COMEDI_SUBD_AI;
351 s->subdev_flags = SDF_READABLE | SDF_GROUND;
352 s->n_chan = 8;
353
354 s->cancel = das6402_ai_cancel;
355 s->maxdata = (1 << 12) - 1;
356 s->len_chanlist = 16;
357 s->range_table = &range_unknown;
358
359 board_init(dev);
360
361 return 0;
362}
363