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
42
43
44
45
46
47
48#include <linux/interrupt.h>
49#include "../comedidev.h"
50
51#include <linux/ioport.h>
52
53static const char *driver_name = "dt2811";
54
55static const struct comedi_lrange range_dt2811_pgh_ai_5_unipolar = { 4, {
56 RANGE
57 (0, 5),
58 RANGE
59 (0,
60 2.5),
61 RANGE
62 (0,
63 1.25),
64 RANGE
65 (0,
66 0.625)
67 }
68};
69
70static const struct comedi_lrange range_dt2811_pgh_ai_2_5_bipolar = { 4, {
71 RANGE
72 (-2.5,
73 2.5),
74 RANGE
75 (-1.25,
76 1.25),
77 RANGE
78 (-0.625,
79 0.625),
80 RANGE
81 (-0.3125,
82 0.3125)
83 }
84};
85
86static const struct comedi_lrange range_dt2811_pgh_ai_5_bipolar = { 4, {
87 RANGE
88 (-5, 5),
89 RANGE
90 (-2.5,
91 2.5),
92 RANGE
93 (-1.25,
94 1.25),
95 RANGE
96 (-0.625,
97 0.625)
98 }
99};
100
101static const struct comedi_lrange range_dt2811_pgl_ai_5_unipolar = { 4, {
102 RANGE
103 (0, 5),
104 RANGE
105 (0,
106 0.5),
107 RANGE
108 (0,
109 0.05),
110 RANGE
111 (0,
112 0.01)
113 }
114};
115
116static const struct comedi_lrange range_dt2811_pgl_ai_2_5_bipolar = { 4, {
117 RANGE
118 (-2.5,
119 2.5),
120 RANGE
121 (-0.25,
122 0.25),
123 RANGE
124 (-0.025,
125 0.025),
126 RANGE
127 (-0.005,
128 0.005)
129 }
130};
131
132static const struct comedi_lrange range_dt2811_pgl_ai_5_bipolar = { 4, {
133 RANGE
134 (-5, 5),
135 RANGE
136 (-0.5,
137 0.5),
138 RANGE
139 (-0.05,
140 0.05),
141 RANGE
142 (-0.01,
143 0.01)
144 }
145};
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216#define TIMEOUT 10000
217
218#define DT2811_SIZE 8
219
220#define DT2811_ADCSR 0
221#define DT2811_ADGCR 1
222#define DT2811_ADDATLO 2
223#define DT2811_ADDATHI 3
224#define DT2811_DADAT0LO 2
225#define DT2811_DADAT0HI 3
226#define DT2811_DADAT1LO 4
227#define DT2811_DADAT1HI 5
228#define DT2811_DIO 6
229#define DT2811_TMRCTR 7
230
231
232
233
234
235
236
237#define DT2811_ADDONE 0x80
238#define DT2811_ADERROR 0x40
239#define DT2811_ADBUSY 0x20
240#define DT2811_CLRERROR 0x10
241#define DT2811_INTENB 0x04
242#define DT2811_ADMODE 0x03
243
244struct dt2811_board {
245
246 const char *name;
247 const struct comedi_lrange *bip_5;
248 const struct comedi_lrange *bip_2_5;
249 const struct comedi_lrange *unip_5;
250};
251
252static const struct dt2811_board boardtypes[] = {
253 {"dt2811-pgh",
254 &range_dt2811_pgh_ai_5_bipolar,
255 &range_dt2811_pgh_ai_2_5_bipolar,
256 &range_dt2811_pgh_ai_5_unipolar,
257 },
258 {"dt2811-pgl",
259 &range_dt2811_pgl_ai_5_bipolar,
260 &range_dt2811_pgl_ai_2_5_bipolar,
261 &range_dt2811_pgl_ai_5_unipolar,
262 },
263};
264
265#define this_board ((const struct dt2811_board *)dev->board_ptr)
266
267static int dt2811_attach(struct comedi_device *dev,
268 struct comedi_devconfig *it);
269static int dt2811_detach(struct comedi_device *dev);
270static struct comedi_driver driver_dt2811 = {
271 .driver_name = "dt2811",
272 .module = THIS_MODULE,
273 .attach = dt2811_attach,
274 .detach = dt2811_detach,
275 .board_name = &boardtypes[0].name,
276 .num_names = ARRAY_SIZE(boardtypes),
277 .offset = sizeof(struct dt2811_board),
278};
279
280COMEDI_INITCLEANUP(driver_dt2811);
281
282static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
283 struct comedi_insn *insn, unsigned int *data);
284static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
285 struct comedi_insn *insn, unsigned int *data);
286static int dt2811_ao_insn_read(struct comedi_device *dev,
287 struct comedi_subdevice *s,
288 struct comedi_insn *insn, unsigned int *data);
289static int dt2811_di_insn_bits(struct comedi_device *dev,
290 struct comedi_subdevice *s,
291 struct comedi_insn *insn, unsigned int *data);
292static int dt2811_do_insn_bits(struct comedi_device *dev,
293 struct comedi_subdevice *s,
294 struct comedi_insn *insn, unsigned int *data);
295
296enum { card_2811_pgh, card_2811_pgl };
297
298struct dt2811_private {
299 int ntrig;
300 int curadchan;
301 enum {
302 adc_singleended, adc_diff, adc_pseudo_diff
303 } adc_mux;
304 enum {
305 dac_bipolar_5, dac_bipolar_2_5, dac_unipolar_5
306 } dac_range[2];
307 const struct comedi_lrange *range_type_list[2];
308 unsigned int ao_readback[2];
309};
310
311#define devpriv ((struct dt2811_private *)dev->private)
312
313static const struct comedi_lrange *dac_range_types[] = {
314 &range_bipolar5,
315 &range_bipolar2_5,
316 &range_unipolar5
317};
318
319#define DT2811_TIMEOUT 5
320
321#if 0
322static irqreturn_t dt2811_interrupt(int irq, void *d)
323{
324 int lo, hi;
325 int data;
326 struct comedi_device *dev = d;
327
328 if (!dev->attached) {
329 comedi_error(dev, "spurious interrupt");
330 return IRQ_HANDLED;
331 }
332
333 lo = inb(dev->iobase + DT2811_ADDATLO);
334 hi = inb(dev->iobase + DT2811_ADDATHI);
335
336 data = lo + (hi << 8);
337
338 if (!(--devpriv->ntrig)) {
339
340 s->async->events |= COMEDI_SB_EOA;
341 }
342 comedi_event(dev, s);
343 return IRQ_HANDLED;
344}
345#endif
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it)
369{
370
371
372
373
374 int ret;
375 struct comedi_subdevice *s;
376 unsigned long iobase;
377
378 iobase = it->options[0];
379
380 printk("comedi%d: dt2811: base=0x%04lx\n", dev->minor, iobase);
381
382 if (!request_region(iobase, DT2811_SIZE, driver_name)) {
383 printk("I/O port conflict\n");
384 return -EIO;
385 }
386
387 dev->iobase = iobase;
388 dev->board_name = this_board->name;
389
390#if 0
391 outb(0, dev->iobase + DT2811_ADCSR);
392 udelay(100);
393 i = inb(dev->iobase + DT2811_ADDATLO);
394 i = inb(dev->iobase + DT2811_ADDATHI);
395#endif
396
397#if 0
398 irq = it->options[1];
399 if (irq < 0) {
400 save_flags(flags);
401 sti();
402 irqs = probe_irq_on();
403
404 outb(DT2811_CLRERROR | DT2811_INTENB,
405 dev->iobase + DT2811_ADCSR);
406 outb(0, dev->iobase + DT2811_ADGCR);
407
408 udelay(100);
409
410 irq = probe_irq_off(irqs);
411 restore_flags(flags);
412
413
414
415 if (inb(dev->iobase + DT2811_ADCSR) & DT2811_ADERROR) {
416 printk("error probing irq (bad) \n");
417 }
418 dev->irq = 0;
419 if (irq > 0) {
420 i = inb(dev->iobase + DT2811_ADDATLO);
421 i = inb(dev->iobase + DT2811_ADDATHI);
422 printk("(irq = %d)\n", irq);
423 ret = request_irq(irq, dt2811_interrupt, 0,
424 driver_name, dev);
425 if (ret < 0)
426 return -EIO;
427 dev->irq = irq;
428 } else if (irq == 0) {
429 printk("(no irq)\n");
430 } else {
431 printk("( multiple irq's -- this is bad! )\n");
432 }
433 }
434#endif
435
436 ret = alloc_subdevices(dev, 4);
437 if (ret < 0)
438 return ret;
439
440 ret = alloc_private(dev, sizeof(struct dt2811_private));
441 if (ret < 0)
442 return ret;
443
444 switch (it->options[2]) {
445 case 0:
446 devpriv->adc_mux = adc_singleended;
447 break;
448 case 1:
449 devpriv->adc_mux = adc_diff;
450 break;
451 case 2:
452 devpriv->adc_mux = adc_pseudo_diff;
453 break;
454 default:
455 devpriv->adc_mux = adc_singleended;
456 break;
457 }
458 switch (it->options[4]) {
459 case 0:
460 devpriv->dac_range[0] = dac_bipolar_5;
461 break;
462 case 1:
463 devpriv->dac_range[0] = dac_bipolar_2_5;
464 break;
465 case 2:
466 devpriv->dac_range[0] = dac_unipolar_5;
467 break;
468 default:
469 devpriv->dac_range[0] = dac_bipolar_5;
470 break;
471 }
472 switch (it->options[5]) {
473 case 0:
474 devpriv->dac_range[1] = dac_bipolar_5;
475 break;
476 case 1:
477 devpriv->dac_range[1] = dac_bipolar_2_5;
478 break;
479 case 2:
480 devpriv->dac_range[1] = dac_unipolar_5;
481 break;
482 default:
483 devpriv->dac_range[1] = dac_bipolar_5;
484 break;
485 }
486
487 s = dev->subdevices + 0;
488
489 s->type = COMEDI_SUBD_AI;
490 s->subdev_flags = SDF_READABLE | SDF_GROUND;
491 s->n_chan = devpriv->adc_mux == adc_diff ? 8 : 16;
492 s->insn_read = dt2811_ai_insn;
493 s->maxdata = 0xfff;
494 switch (it->options[3]) {
495 case 0:
496 default:
497 s->range_table = this_board->bip_5;
498 break;
499 case 1:
500 s->range_table = this_board->bip_2_5;
501 break;
502 case 2:
503 s->range_table = this_board->unip_5;
504 break;
505 }
506
507 s = dev->subdevices + 1;
508
509 s->type = COMEDI_SUBD_AO;
510 s->subdev_flags = SDF_WRITABLE;
511 s->n_chan = 2;
512 s->insn_write = dt2811_ao_insn;
513 s->insn_read = dt2811_ao_insn_read;
514 s->maxdata = 0xfff;
515 s->range_table_list = devpriv->range_type_list;
516 devpriv->range_type_list[0] = dac_range_types[devpriv->dac_range[0]];
517 devpriv->range_type_list[1] = dac_range_types[devpriv->dac_range[1]];
518
519 s = dev->subdevices + 2;
520
521 s->type = COMEDI_SUBD_DI;
522 s->subdev_flags = SDF_READABLE;
523 s->n_chan = 8;
524 s->insn_bits = dt2811_di_insn_bits;
525 s->maxdata = 1;
526 s->range_table = &range_digital;
527
528 s = dev->subdevices + 3;
529
530 s->type = COMEDI_SUBD_DO;
531 s->subdev_flags = SDF_WRITABLE;
532 s->n_chan = 8;
533 s->insn_bits = dt2811_do_insn_bits;
534 s->maxdata = 1;
535 s->state = 0;
536 s->range_table = &range_digital;
537
538 return 0;
539}
540
541static int dt2811_detach(struct comedi_device *dev)
542{
543 printk("comedi%d: dt2811: remove\n", dev->minor);
544
545 if (dev->irq) {
546 free_irq(dev->irq, dev);
547 }
548 if (dev->iobase) {
549 release_region(dev->iobase, DT2811_SIZE);
550 }
551
552 return 0;
553}
554
555static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
556 struct comedi_insn *insn, unsigned int *data)
557{
558 int chan = CR_CHAN(insn->chanspec);
559 int timeout = DT2811_TIMEOUT;
560 int i;
561
562 for (i = 0; i < insn->n; i++) {
563 outb(chan, dev->iobase + DT2811_ADGCR);
564
565 while (timeout
566 && inb(dev->iobase + DT2811_ADCSR) & DT2811_ADBUSY)
567 timeout--;
568 if (!timeout)
569 return -ETIME;
570
571 data[i] = inb(dev->iobase + DT2811_ADDATLO);
572 data[i] |= inb(dev->iobase + DT2811_ADDATHI) << 8;
573 data[i] &= 0xfff;
574 }
575
576 return i;
577}
578
579#if 0
580
581
582int dt2811_adtrig(kdev_t minor, comedi_adtrig * adtrig)
583{
584 struct comedi_device *dev = comedi_devices + minor;
585
586 if (adtrig->n < 1)
587 return 0;
588 dev->curadchan = adtrig->chan;
589 switch (dev->i_admode) {
590 case COMEDI_MDEMAND:
591 dev->ntrig = adtrig->n - 1;
592
593
594 outb(dev->curadchan, dev->iobase + DT2811_ADGCR);
595 do_gettimeofday(&trigtime);
596 break;
597 case COMEDI_MCONTS:
598 dev->ntrig = adtrig->n;
599 break;
600 }
601
602 return 0;
603}
604#endif
605
606static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
607 struct comedi_insn *insn, unsigned int *data)
608{
609 int i;
610 int chan;
611
612 chan = CR_CHAN(insn->chanspec);
613
614 for (i = 0; i < insn->n; i++) {
615 outb(data[i] & 0xff, dev->iobase + DT2811_DADAT0LO + 2 * chan);
616 outb((data[i] >> 8) & 0xff,
617 dev->iobase + DT2811_DADAT0HI + 2 * chan);
618 devpriv->ao_readback[chan] = data[i];
619 }
620
621 return i;
622}
623
624static int dt2811_ao_insn_read(struct comedi_device *dev,
625 struct comedi_subdevice *s,
626 struct comedi_insn *insn, unsigned int *data)
627{
628 int i;
629 int chan;
630
631 chan = CR_CHAN(insn->chanspec);
632
633 for (i = 0; i < insn->n; i++) {
634 data[i] = devpriv->ao_readback[chan];
635 }
636
637 return i;
638}
639
640static int dt2811_di_insn_bits(struct comedi_device *dev,
641 struct comedi_subdevice *s,
642 struct comedi_insn *insn, unsigned int *data)
643{
644 if (insn->n != 2)
645 return -EINVAL;
646
647 data[1] = inb(dev->iobase + DT2811_DIO);
648
649 return 2;
650}
651
652static int dt2811_do_insn_bits(struct comedi_device *dev,
653 struct comedi_subdevice *s,
654 struct comedi_insn *insn, unsigned int *data)
655{
656 if (insn->n != 2)
657 return -EINVAL;
658
659 s->state &= ~data[0];
660 s->state |= data[0] & data[1];
661 outb(s->state, dev->iobase + DT2811_DIO);
662
663 data[1] = s->state;
664
665 return 2;
666}
667