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
49
50
51
52
53
54
55
56
57
58
59#include "../comedidev.h"
60
61#include <linux/gfp.h>
62#include <linux/ioport.h>
63#include <linux/interrupt.h>
64#include <linux/io.h>
65#include <asm/dma.h>
66#include "comedi_fc.h"
67
68#define DEBUG
69
70#define DT2821_TIMEOUT 100
71#define DT2821_SIZE 0x10
72
73
74
75
76
77#define DT2821_ADCSR 0x00
78#define DT2821_CHANCSR 0x02
79#define DT2821_ADDAT 0x04
80#define DT2821_DACSR 0x06
81#define DT2821_DADAT 0x08
82#define DT2821_DIODAT 0x0a
83#define DT2821_SUPCSR 0x0c
84#define DT2821_TMRCTR 0x0e
85
86
87
88
89
90
91#define DT2821_ADCSR_MASK 0xfff0
92#define DT2821_ADCSR_VAL 0x7c00
93
94#define DT2821_CHANCSR_MASK 0xf0f0
95#define DT2821_CHANCSR_VAL 0x70f0
96
97#define DT2821_DACSR_MASK 0x7c93
98#define DT2821_DACSR_VAL 0x7c90
99
100#define DT2821_SUPCSR_MASK 0xf8ff
101#define DT2821_SUPCSR_VAL 0x0000
102
103#define DT2821_TMRCTR_MASK 0xff00
104#define DT2821_TMRCTR_VAL 0xf000
105
106
107
108
109
110
111
112#define DT2821_ADERR 0x8000
113#define DT2821_ADCLK 0x0200
114
115#define DT2821_MUXBUSY 0x0100
116#define DT2821_ADDONE 0x0080
117#define DT2821_IADDONE 0x0040
118
119
120
121
122
123#define DT2821_LLE 0x8000
124
125
126
127
128
129
130
131#define DT2821_DAERR 0x8000
132#define DT2821_YSEL 0x0200
133#define DT2821_SSEL 0x0100
134#define DT2821_DACRDY 0x0080
135#define DT2821_IDARDY 0x0040
136#define DT2821_DACLK 0x0020
137#define DT2821_HBOE 0x0002
138#define DT2821_LBOE 0x0001
139
140
141
142#define DT2821_DMAD 0x8000
143#define DT2821_ERRINTEN 0x4000
144#define DT2821_CLRDMADNE 0x2000
145#define DT2821_DDMA 0x1000
146#define DT2821_DS1 0x0800
147#define DT2821_DS0 0x0400
148#define DT2821_BUFFB 0x0200
149#define DT2821_SCDN 0x0100
150#define DT2821_DACON 0x0080
151#define DT2821_ADCINIT 0x0040
152#define DT2821_DACINIT 0x0020
153#define DT2821_PRLD 0x0010
154#define DT2821_STRIG 0x0008
155#define DT2821_XTRIG 0x0004
156#define DT2821_XCLK 0x0002
157#define DT2821_BDINIT 0x0001
158
159static const struct comedi_lrange range_dt282x_ai_lo_bipolar = {
160 4, {
161 RANGE(-10, 10),
162 RANGE(-5, 5),
163 RANGE(-2.5, 2.5),
164 RANGE(-1.25, 1.25)
165 }
166};
167
168static const struct comedi_lrange range_dt282x_ai_lo_unipolar = {
169 4, {
170 RANGE(0, 10),
171 RANGE(0, 5),
172 RANGE(0, 2.5),
173 RANGE(0, 1.25)
174 }
175};
176
177static const struct comedi_lrange range_dt282x_ai_5_bipolar = {
178 4, {
179 RANGE(-5, 5),
180 RANGE(-2.5, 2.5),
181 RANGE(-1.25, 1.25),
182 RANGE(-0.625, 0.625)
183 }
184};
185
186static const struct comedi_lrange range_dt282x_ai_5_unipolar = {
187 4, {
188 RANGE(0, 5),
189 RANGE(0, 2.5),
190 RANGE(0, 1.25),
191 RANGE(0, 0.625),
192 }
193};
194
195static const struct comedi_lrange range_dt282x_ai_hi_bipolar = {
196 4, {
197 RANGE(-10, 10),
198 RANGE(-1, 1),
199 RANGE(-0.1, 0.1),
200 RANGE(-0.02, 0.02)
201 }
202};
203
204static const struct comedi_lrange range_dt282x_ai_hi_unipolar = {
205 4, {
206 RANGE(0, 10),
207 RANGE(0, 1),
208 RANGE(0, 0.1),
209 RANGE(0, 0.02)
210 }
211};
212
213struct dt282x_board {
214 const char *name;
215 int adbits;
216 int adchan_se;
217 int adchan_di;
218 int ai_speed;
219 int ispgl;
220 int dachan;
221 int dabits;
222};
223
224static const struct dt282x_board boardtypes[] = {
225 {.name = "dt2821",
226 .adbits = 12,
227 .adchan_se = 16,
228 .adchan_di = 8,
229 .ai_speed = 20000,
230 .ispgl = 0,
231 .dachan = 2,
232 .dabits = 12,
233 },
234 {.name = "dt2821-f",
235 .adbits = 12,
236 .adchan_se = 16,
237 .adchan_di = 8,
238 .ai_speed = 6500,
239 .ispgl = 0,
240 .dachan = 2,
241 .dabits = 12,
242 },
243 {.name = "dt2821-g",
244 .adbits = 12,
245 .adchan_se = 16,
246 .adchan_di = 8,
247 .ai_speed = 4000,
248 .ispgl = 0,
249 .dachan = 2,
250 .dabits = 12,
251 },
252 {.name = "dt2823",
253 .adbits = 16,
254 .adchan_se = 0,
255 .adchan_di = 4,
256 .ai_speed = 10000,
257 .ispgl = 0,
258 .dachan = 2,
259 .dabits = 16,
260 },
261 {.name = "dt2824-pgh",
262 .adbits = 12,
263 .adchan_se = 16,
264 .adchan_di = 8,
265 .ai_speed = 20000,
266 .ispgl = 0,
267 .dachan = 0,
268 .dabits = 0,
269 },
270 {.name = "dt2824-pgl",
271 .adbits = 12,
272 .adchan_se = 16,
273 .adchan_di = 8,
274 .ai_speed = 20000,
275 .ispgl = 1,
276 .dachan = 0,
277 .dabits = 0,
278 },
279 {.name = "dt2825",
280 .adbits = 12,
281 .adchan_se = 16,
282 .adchan_di = 8,
283 .ai_speed = 20000,
284 .ispgl = 1,
285 .dachan = 2,
286 .dabits = 12,
287 },
288 {.name = "dt2827",
289 .adbits = 16,
290 .adchan_se = 0,
291 .adchan_di = 4,
292 .ai_speed = 10000,
293 .ispgl = 0,
294 .dachan = 2,
295 .dabits = 12,
296 },
297 {.name = "dt2828",
298 .adbits = 12,
299 .adchan_se = 4,
300 .adchan_di = 0,
301 .ai_speed = 10000,
302 .ispgl = 0,
303 .dachan = 2,
304 .dabits = 12,
305 },
306 {.name = "dt2829",
307 .adbits = 16,
308 .adchan_se = 8,
309 .adchan_di = 0,
310 .ai_speed = 33250,
311 .ispgl = 0,
312 .dachan = 2,
313 .dabits = 16,
314 },
315 {.name = "dt21-ez",
316 .adbits = 12,
317 .adchan_se = 16,
318 .adchan_di = 8,
319 .ai_speed = 10000,
320 .ispgl = 0,
321 .dachan = 2,
322 .dabits = 12,
323 },
324 {.name = "dt23-ez",
325 .adbits = 16,
326 .adchan_se = 16,
327 .adchan_di = 8,
328 .ai_speed = 10000,
329 .ispgl = 0,
330 .dachan = 0,
331 .dabits = 0,
332 },
333 {.name = "dt24-ez",
334 .adbits = 12,
335 .adchan_se = 16,
336 .adchan_di = 8,
337 .ai_speed = 10000,
338 .ispgl = 0,
339 .dachan = 0,
340 .dabits = 0,
341 },
342 {.name = "dt24-ez-pgl",
343 .adbits = 12,
344 .adchan_se = 16,
345 .adchan_di = 8,
346 .ai_speed = 10000,
347 .ispgl = 1,
348 .dachan = 0,
349 .dabits = 0,
350 },
351};
352
353#define n_boardtypes (sizeof(boardtypes)/sizeof(struct dt282x_board))
354#define this_board ((const struct dt282x_board *)dev->board_ptr)
355
356struct dt282x_private {
357 int ad_2scomp;
358 int da0_2scomp;
359 int da1_2scomp;
360
361 const struct comedi_lrange *darangelist[2];
362
363 short ao[2];
364
365 volatile int dacsr;
366 volatile int adcsr;
367 volatile int supcsr;
368
369 volatile int ntrig;
370 volatile int nread;
371
372 struct {
373 int chan;
374 short *buf;
375 volatile int size;
376 } dma[2];
377 int dma_maxsize;
378 int usedma;
379 volatile int current_dma_index;
380 int dma_dir;
381};
382
383#define devpriv ((struct dt282x_private *)dev->private)
384#define boardtype (*(const struct dt282x_board *)dev->board_ptr)
385
386
387
388
389#define chan_to_DAC(a) ((a)&1)
390#define update_dacsr(a) outw(devpriv->dacsr|(a), dev->iobase+DT2821_DACSR)
391#define update_adcsr(a) outw(devpriv->adcsr|(a), dev->iobase+DT2821_ADCSR)
392#define mux_busy() (inw(dev->iobase+DT2821_ADCSR)&DT2821_MUXBUSY)
393#define ad_done() (inw(dev->iobase+DT2821_ADCSR)&DT2821_ADDONE)
394#define update_supcsr(a) outw(devpriv->supcsr|(a), dev->iobase+DT2821_SUPCSR)
395
396
397
398
399
400#define wait_for(a, b) \
401 do { \
402 int _i; \
403 for (_i = 0; _i < DT2821_TIMEOUT; _i++) { \
404 if (a) { \
405 _i = 0; \
406 break; \
407 } \
408 udelay(5); \
409 } \
410 if (_i) \
411 b \
412 } while (0)
413
414static int dt282x_attach(struct comedi_device *dev,
415 struct comedi_devconfig *it);
416static int dt282x_detach(struct comedi_device *dev);
417static struct comedi_driver driver_dt282x = {
418 .driver_name = "dt282x",
419 .module = THIS_MODULE,
420 .attach = dt282x_attach,
421 .detach = dt282x_detach,
422 .board_name = &boardtypes[0].name,
423 .num_names = n_boardtypes,
424 .offset = sizeof(struct dt282x_board),
425};
426
427static int __init driver_dt282x_init_module(void)
428{
429 return comedi_driver_register(&driver_dt282x);
430}
431
432static void __exit driver_dt282x_cleanup_module(void)
433{
434 comedi_driver_unregister(&driver_dt282x);
435}
436
437module_init(driver_dt282x_init_module);
438module_exit(driver_dt282x_cleanup_module);
439
440static void free_resources(struct comedi_device *dev);
441static int prep_ai_dma(struct comedi_device *dev, int chan, int size);
442static int prep_ao_dma(struct comedi_device *dev, int chan, int size);
443static int dt282x_ai_cancel(struct comedi_device *dev,
444 struct comedi_subdevice *s);
445static int dt282x_ao_cancel(struct comedi_device *dev,
446 struct comedi_subdevice *s);
447static int dt282x_ns_to_timer(int *nanosec, int round_mode);
448static void dt282x_disable_dma(struct comedi_device *dev);
449
450static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2);
451
452static void dt282x_munge(struct comedi_device *dev, short *buf,
453 unsigned int nbytes)
454{
455 unsigned int i;
456 unsigned short mask = (1 << boardtype.adbits) - 1;
457 unsigned short sign = 1 << (boardtype.adbits - 1);
458 int n;
459
460 if (devpriv->ad_2scomp)
461 sign = 1 << (boardtype.adbits - 1);
462 else
463 sign = 0;
464
465 if (nbytes % 2)
466 comedi_error(dev, "bug! odd number of bytes from dma xfer");
467 n = nbytes / 2;
468 for (i = 0; i < n; i++)
469 buf[i] = (buf[i] & mask) ^ sign;
470}
471
472static void dt282x_ao_dma_interrupt(struct comedi_device *dev)
473{
474 void *ptr;
475 int size;
476 int i;
477 struct comedi_subdevice *s = dev->subdevices + 1;
478
479 update_supcsr(DT2821_CLRDMADNE);
480
481 if (!s->async->prealloc_buf) {
482 printk(KERN_ERR "async->data disappeared. dang!\n");
483 return;
484 }
485
486 i = devpriv->current_dma_index;
487 ptr = devpriv->dma[i].buf;
488
489 disable_dma(devpriv->dma[i].chan);
490
491 devpriv->current_dma_index = 1 - i;
492
493 size = cfc_read_array_from_buffer(s, ptr, devpriv->dma_maxsize);
494 if (size == 0) {
495 printk(KERN_ERR "dt282x: AO underrun\n");
496 dt282x_ao_cancel(dev, s);
497 s->async->events |= COMEDI_CB_OVERFLOW;
498 return;
499 }
500 prep_ao_dma(dev, i, size);
501 return;
502}
503
504static void dt282x_ai_dma_interrupt(struct comedi_device *dev)
505{
506 void *ptr;
507 int size;
508 int i;
509 int ret;
510 struct comedi_subdevice *s = dev->subdevices;
511
512 update_supcsr(DT2821_CLRDMADNE);
513
514 if (!s->async->prealloc_buf) {
515 printk(KERN_ERR "async->data disappeared. dang!\n");
516 return;
517 }
518
519 i = devpriv->current_dma_index;
520 ptr = devpriv->dma[i].buf;
521 size = devpriv->dma[i].size;
522
523 disable_dma(devpriv->dma[i].chan);
524
525 devpriv->current_dma_index = 1 - i;
526
527 dt282x_munge(dev, ptr, size);
528 ret = cfc_write_array_to_buffer(s, ptr, size);
529 if (ret != size) {
530 dt282x_ai_cancel(dev, s);
531 return;
532 }
533 devpriv->nread -= size / 2;
534
535 if (devpriv->nread < 0) {
536 printk(KERN_INFO "dt282x: off by one\n");
537 devpriv->nread = 0;
538 }
539 if (!devpriv->nread) {
540 dt282x_ai_cancel(dev, s);
541 s->async->events |= COMEDI_CB_EOA;
542 return;
543 }
544#if 0
545
546
547 if (!devpriv->ntrig) {
548 devpriv->supcsr &= ~(DT2821_DDMA);
549 update_supcsr(0);
550 }
551#endif
552
553 prep_ai_dma(dev, i, 0);
554}
555
556static int prep_ai_dma(struct comedi_device *dev, int dma_index, int n)
557{
558 int dma_chan;
559 unsigned long dma_ptr;
560 unsigned long flags;
561
562 if (!devpriv->ntrig)
563 return 0;
564
565 if (n == 0)
566 n = devpriv->dma_maxsize;
567 if (n > devpriv->ntrig * 2)
568 n = devpriv->ntrig * 2;
569 devpriv->ntrig -= n / 2;
570
571 devpriv->dma[dma_index].size = n;
572 dma_chan = devpriv->dma[dma_index].chan;
573 dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
574
575 set_dma_mode(dma_chan, DMA_MODE_READ);
576 flags = claim_dma_lock();
577 clear_dma_ff(dma_chan);
578 set_dma_addr(dma_chan, dma_ptr);
579 set_dma_count(dma_chan, n);
580 release_dma_lock(flags);
581
582 enable_dma(dma_chan);
583
584 return n;
585}
586
587static int prep_ao_dma(struct comedi_device *dev, int dma_index, int n)
588{
589 int dma_chan;
590 unsigned long dma_ptr;
591 unsigned long flags;
592
593 devpriv->dma[dma_index].size = n;
594 dma_chan = devpriv->dma[dma_index].chan;
595 dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
596
597 set_dma_mode(dma_chan, DMA_MODE_WRITE);
598 flags = claim_dma_lock();
599 clear_dma_ff(dma_chan);
600 set_dma_addr(dma_chan, dma_ptr);
601 set_dma_count(dma_chan, n);
602 release_dma_lock(flags);
603
604 enable_dma(dma_chan);
605
606 return n;
607}
608
609static irqreturn_t dt282x_interrupt(int irq, void *d)
610{
611 struct comedi_device *dev = d;
612 struct comedi_subdevice *s;
613 struct comedi_subdevice *s_ao;
614 unsigned int supcsr, adcsr, dacsr;
615 int handled = 0;
616
617 if (!dev->attached) {
618 comedi_error(dev, "spurious interrupt");
619 return IRQ_HANDLED;
620 }
621
622 s = dev->subdevices + 0;
623 s_ao = dev->subdevices + 1;
624 adcsr = inw(dev->iobase + DT2821_ADCSR);
625 dacsr = inw(dev->iobase + DT2821_DACSR);
626 supcsr = inw(dev->iobase + DT2821_SUPCSR);
627 if (supcsr & DT2821_DMAD) {
628 if (devpriv->dma_dir == DMA_MODE_READ)
629 dt282x_ai_dma_interrupt(dev);
630 else
631 dt282x_ao_dma_interrupt(dev);
632 handled = 1;
633 }
634 if (adcsr & DT2821_ADERR) {
635 if (devpriv->nread != 0) {
636 comedi_error(dev, "A/D error");
637 dt282x_ai_cancel(dev, s);
638 s->async->events |= COMEDI_CB_ERROR;
639 }
640 handled = 1;
641 }
642 if (dacsr & DT2821_DAERR) {
643#if 0
644 static int warn = 5;
645 if (--warn <= 0) {
646 disable_irq(dev->irq);
647 printk(KERN_INFO "disabling irq\n");
648 }
649#endif
650 comedi_error(dev, "D/A error");
651 dt282x_ao_cancel(dev, s_ao);
652 s->async->events |= COMEDI_CB_ERROR;
653 handled = 1;
654 }
655#if 0
656 if (adcsr & DT2821_ADDONE) {
657 int ret;
658 short data;
659
660 data = (short)inw(dev->iobase + DT2821_ADDAT);
661 data &= (1 << boardtype.adbits) - 1;
662
663 if (devpriv->ad_2scomp)
664 data ^= 1 << (boardtype.adbits - 1);
665 ret = comedi_buf_put(s->async, data);
666
667 if (ret == 0)
668 s->async->events |= COMEDI_CB_OVERFLOW;
669
670 devpriv->nread--;
671 if (!devpriv->nread) {
672 s->async->events |= COMEDI_CB_EOA;
673 } else {
674 if (supcsr & DT2821_SCDN)
675 update_supcsr(DT2821_STRIG);
676 }
677 handled = 1;
678 }
679#endif
680 comedi_event(dev, s);
681
682
683 return IRQ_RETVAL(handled);
684}
685
686static void dt282x_load_changain(struct comedi_device *dev, int n,
687 unsigned int *chanlist)
688{
689 unsigned int i;
690 unsigned int chan, range;
691
692 outw(DT2821_LLE | (n - 1), dev->iobase + DT2821_CHANCSR);
693 for (i = 0; i < n; i++) {
694 chan = CR_CHAN(chanlist[i]);
695 range = CR_RANGE(chanlist[i]);
696 update_adcsr((range << 4) | (chan));
697 }
698 outw(n - 1, dev->iobase + DT2821_CHANCSR);
699}
700
701
702
703
704
705
706
707static int dt282x_ai_insn_read(struct comedi_device *dev,
708 struct comedi_subdevice *s,
709 struct comedi_insn *insn, unsigned int *data)
710{
711 int i;
712
713
714 devpriv->adcsr = DT2821_ADCLK;
715 update_adcsr(0);
716
717 dt282x_load_changain(dev, 1, &insn->chanspec);
718
719 update_supcsr(DT2821_PRLD);
720 wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;);
721
722 for (i = 0; i < insn->n; i++) {
723 update_supcsr(DT2821_STRIG);
724 wait_for(ad_done(), comedi_error(dev, "timeout\n");
725 return -ETIME;);
726
727 data[i] =
728 inw(dev->iobase +
729 DT2821_ADDAT) & ((1 << boardtype.adbits) - 1);
730 if (devpriv->ad_2scomp)
731 data[i] ^= (1 << (boardtype.adbits - 1));
732 }
733
734 return i;
735}
736
737static int dt282x_ai_cmdtest(struct comedi_device *dev,
738 struct comedi_subdevice *s, struct comedi_cmd *cmd)
739{
740 int err = 0;
741 int tmp;
742
743
744
745 tmp = cmd->start_src;
746 cmd->start_src &= TRIG_NOW;
747 if (!cmd->start_src || tmp != cmd->start_src)
748 err++;
749
750 tmp = cmd->scan_begin_src;
751 cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_EXT;
752 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
753 err++;
754
755 tmp = cmd->convert_src;
756 cmd->convert_src &= TRIG_TIMER;
757 if (!cmd->convert_src || tmp != cmd->convert_src)
758 err++;
759
760 tmp = cmd->scan_end_src;
761 cmd->scan_end_src &= TRIG_COUNT;
762 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
763 err++;
764
765 tmp = cmd->stop_src;
766 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
767 if (!cmd->stop_src || tmp != cmd->stop_src)
768 err++;
769
770 if (err)
771 return 1;
772
773
774
775
776
777
778
779 if (cmd->scan_begin_src != TRIG_FOLLOW &&
780 cmd->scan_begin_src != TRIG_EXT)
781 err++;
782 if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
783 err++;
784
785 if (err)
786 return 2;
787
788
789
790 if (cmd->start_arg != 0) {
791 cmd->start_arg = 0;
792 err++;
793 }
794 if (cmd->scan_begin_src == TRIG_FOLLOW) {
795
796 if (cmd->scan_begin_arg != 0) {
797 cmd->scan_begin_arg = 0;
798 err++;
799 }
800 } else {
801
802
803 if (cmd->scan_begin_arg != 0) {
804 cmd->scan_begin_arg = 0;
805 err++;
806 }
807 }
808 if (cmd->convert_arg < 4000) {
809
810 cmd->convert_arg = 4000;
811 err++;
812 }
813#define SLOWEST_TIMER (250*(1<<15)*255)
814 if (cmd->convert_arg > SLOWEST_TIMER) {
815 cmd->convert_arg = SLOWEST_TIMER;
816 err++;
817 }
818 if (cmd->convert_arg < this_board->ai_speed) {
819 cmd->convert_arg = this_board->ai_speed;
820 err++;
821 }
822 if (cmd->scan_end_arg != cmd->chanlist_len) {
823 cmd->scan_end_arg = cmd->chanlist_len;
824 err++;
825 }
826 if (cmd->stop_src == TRIG_COUNT) {
827
828 } else {
829
830 if (cmd->stop_arg != 0) {
831 cmd->stop_arg = 0;
832 err++;
833 }
834 }
835
836 if (err)
837 return 3;
838
839
840
841 tmp = cmd->convert_arg;
842 dt282x_ns_to_timer(&cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK);
843 if (tmp != cmd->convert_arg)
844 err++;
845
846 if (err)
847 return 4;
848
849 return 0;
850}
851
852static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
853{
854 struct comedi_cmd *cmd = &s->async->cmd;
855 int timer;
856
857 if (devpriv->usedma == 0) {
858 comedi_error(dev,
859 "driver requires 2 dma channels"
860 " to execute command");
861 return -EIO;
862 }
863
864 dt282x_disable_dma(dev);
865
866 if (cmd->convert_arg < this_board->ai_speed)
867 cmd->convert_arg = this_board->ai_speed;
868 timer = dt282x_ns_to_timer(&cmd->convert_arg, TRIG_ROUND_NEAREST);
869 outw(timer, dev->iobase + DT2821_TMRCTR);
870
871 if (cmd->scan_begin_src == TRIG_FOLLOW) {
872
873 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0;
874 } else {
875
876 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0 | DT2821_DS1;
877 }
878 update_supcsr(DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_ADCINIT);
879
880 devpriv->ntrig = cmd->stop_arg * cmd->scan_end_arg;
881 devpriv->nread = devpriv->ntrig;
882
883 devpriv->dma_dir = DMA_MODE_READ;
884 devpriv->current_dma_index = 0;
885 prep_ai_dma(dev, 0, 0);
886 if (devpriv->ntrig) {
887 prep_ai_dma(dev, 1, 0);
888 devpriv->supcsr |= DT2821_DDMA;
889 update_supcsr(0);
890 }
891
892 devpriv->adcsr = 0;
893
894 dt282x_load_changain(dev, cmd->chanlist_len, cmd->chanlist);
895
896 devpriv->adcsr = DT2821_ADCLK | DT2821_IADDONE;
897 update_adcsr(0);
898
899 update_supcsr(DT2821_PRLD);
900 wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;);
901
902 if (cmd->scan_begin_src == TRIG_FOLLOW) {
903 update_supcsr(DT2821_STRIG);
904 } else {
905 devpriv->supcsr |= DT2821_XTRIG;
906 update_supcsr(0);
907 }
908
909 return 0;
910}
911
912static void dt282x_disable_dma(struct comedi_device *dev)
913{
914 if (devpriv->usedma) {
915 disable_dma(devpriv->dma[0].chan);
916 disable_dma(devpriv->dma[1].chan);
917 }
918}
919
920static int dt282x_ai_cancel(struct comedi_device *dev,
921 struct comedi_subdevice *s)
922{
923 dt282x_disable_dma(dev);
924
925 devpriv->adcsr = 0;
926 update_adcsr(0);
927
928 devpriv->supcsr = 0;
929 update_supcsr(DT2821_ADCINIT);
930
931 return 0;
932}
933
934static int dt282x_ns_to_timer(int *nanosec, int round_mode)
935{
936 int prescale, base, divider;
937
938 for (prescale = 0; prescale < 16; prescale++) {
939 if (prescale == 1)
940 continue;
941 base = 250 * (1 << prescale);
942 switch (round_mode) {
943 case TRIG_ROUND_NEAREST:
944 default:
945 divider = (*nanosec + base / 2) / base;
946 break;
947 case TRIG_ROUND_DOWN:
948 divider = (*nanosec) / base;
949 break;
950 case TRIG_ROUND_UP:
951 divider = (*nanosec + base - 1) / base;
952 break;
953 }
954 if (divider < 256) {
955 *nanosec = divider * base;
956 return (prescale << 8) | (255 - divider);
957 }
958 }
959 base = 250 * (1 << 15);
960 divider = 255;
961 *nanosec = divider * base;
962 return (15 << 8) | (255 - divider);
963}
964
965
966
967
968
969
970
971static int dt282x_ao_insn_read(struct comedi_device *dev,
972 struct comedi_subdevice *s,
973 struct comedi_insn *insn, unsigned int *data)
974{
975 data[0] = devpriv->ao[CR_CHAN(insn->chanspec)];
976
977 return 1;
978}
979
980static int dt282x_ao_insn_write(struct comedi_device *dev,
981 struct comedi_subdevice *s,
982 struct comedi_insn *insn, unsigned int *data)
983{
984 short d;
985 unsigned int chan;
986
987 chan = CR_CHAN(insn->chanspec);
988 d = data[0];
989 d &= (1 << boardtype.dabits) - 1;
990 devpriv->ao[chan] = d;
991
992 devpriv->dacsr |= DT2821_SSEL;
993
994 if (chan) {
995
996 devpriv->dacsr |= DT2821_YSEL;
997 if (devpriv->da0_2scomp)
998 d ^= (1 << (boardtype.dabits - 1));
999 } else {
1000 devpriv->dacsr &= ~DT2821_YSEL;
1001 if (devpriv->da1_2scomp)
1002 d ^= (1 << (boardtype.dabits - 1));
1003 }
1004
1005 update_dacsr(0);
1006
1007 outw(d, dev->iobase + DT2821_DADAT);
1008
1009 update_supcsr(DT2821_DACON);
1010
1011 return 1;
1012}
1013
1014static int dt282x_ao_cmdtest(struct comedi_device *dev,
1015 struct comedi_subdevice *s, struct comedi_cmd *cmd)
1016{
1017 int err = 0;
1018 int tmp;
1019
1020
1021
1022 tmp = cmd->start_src;
1023 cmd->start_src &= TRIG_INT;
1024 if (!cmd->start_src || tmp != cmd->start_src)
1025 err++;
1026
1027 tmp = cmd->scan_begin_src;
1028 cmd->scan_begin_src &= TRIG_TIMER;
1029 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
1030 err++;
1031
1032 tmp = cmd->convert_src;
1033 cmd->convert_src &= TRIG_NOW;
1034 if (!cmd->convert_src || tmp != cmd->convert_src)
1035 err++;
1036
1037 tmp = cmd->scan_end_src;
1038 cmd->scan_end_src &= TRIG_COUNT;
1039 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
1040 err++;
1041
1042 tmp = cmd->stop_src;
1043 cmd->stop_src &= TRIG_NONE;
1044 if (!cmd->stop_src || tmp != cmd->stop_src)
1045 err++;
1046
1047 if (err)
1048 return 1;
1049
1050
1051
1052
1053
1054
1055
1056 if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
1057 err++;
1058
1059 if (err)
1060 return 2;
1061
1062
1063
1064 if (cmd->start_arg != 0) {
1065 cmd->start_arg = 0;
1066 err++;
1067 }
1068 if (cmd->scan_begin_arg < 5000 ) {
1069 cmd->scan_begin_arg = 5000;
1070 err++;
1071 }
1072 if (cmd->convert_arg != 0) {
1073 cmd->convert_arg = 0;
1074 err++;
1075 }
1076 if (cmd->scan_end_arg > 2) {
1077
1078 cmd->scan_end_arg = 2;
1079 err++;
1080 }
1081 if (cmd->stop_src == TRIG_COUNT) {
1082
1083 } else {
1084
1085 if (cmd->stop_arg != 0) {
1086 cmd->stop_arg = 0;
1087 err++;
1088 }
1089 }
1090
1091 if (err)
1092 return 3;
1093
1094
1095
1096 tmp = cmd->scan_begin_arg;
1097 dt282x_ns_to_timer(&cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK);
1098 if (tmp != cmd->scan_begin_arg)
1099 err++;
1100
1101 if (err)
1102 return 4;
1103
1104 return 0;
1105
1106}
1107
1108static int dt282x_ao_inttrig(struct comedi_device *dev,
1109 struct comedi_subdevice *s, unsigned int x)
1110{
1111 int size;
1112
1113 if (x != 0)
1114 return -EINVAL;
1115
1116 size = cfc_read_array_from_buffer(s, devpriv->dma[0].buf,
1117 devpriv->dma_maxsize);
1118 if (size == 0) {
1119 printk(KERN_ERR "dt282x: AO underrun\n");
1120 return -EPIPE;
1121 }
1122 prep_ao_dma(dev, 0, size);
1123
1124 size = cfc_read_array_from_buffer(s, devpriv->dma[1].buf,
1125 devpriv->dma_maxsize);
1126 if (size == 0) {
1127 printk(KERN_ERR "dt282x: AO underrun\n");
1128 return -EPIPE;
1129 }
1130 prep_ao_dma(dev, 1, size);
1131
1132 update_supcsr(DT2821_STRIG);
1133 s->async->inttrig = NULL;
1134
1135 return 1;
1136}
1137
1138static int dt282x_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1139{
1140 int timer;
1141 struct comedi_cmd *cmd = &s->async->cmd;
1142
1143 if (devpriv->usedma == 0) {
1144 comedi_error(dev,
1145 "driver requires 2 dma channels"
1146 " to execute command");
1147 return -EIO;
1148 }
1149
1150 dt282x_disable_dma(dev);
1151
1152 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS1 | DT2821_DDMA;
1153 update_supcsr(DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_DACINIT);
1154
1155 devpriv->ntrig = cmd->stop_arg * cmd->chanlist_len;
1156 devpriv->nread = devpriv->ntrig;
1157
1158 devpriv->dma_dir = DMA_MODE_WRITE;
1159 devpriv->current_dma_index = 0;
1160
1161 timer = dt282x_ns_to_timer(&cmd->scan_begin_arg, TRIG_ROUND_NEAREST);
1162 outw(timer, dev->iobase + DT2821_TMRCTR);
1163
1164 devpriv->dacsr = DT2821_SSEL | DT2821_DACLK | DT2821_IDARDY;
1165 update_dacsr(0);
1166
1167 s->async->inttrig = dt282x_ao_inttrig;
1168
1169 return 0;
1170}
1171
1172static int dt282x_ao_cancel(struct comedi_device *dev,
1173 struct comedi_subdevice *s)
1174{
1175 dt282x_disable_dma(dev);
1176
1177 devpriv->dacsr = 0;
1178 update_dacsr(0);
1179
1180 devpriv->supcsr = 0;
1181 update_supcsr(DT2821_DACINIT);
1182
1183 return 0;
1184}
1185
1186static int dt282x_dio_insn_bits(struct comedi_device *dev,
1187 struct comedi_subdevice *s,
1188 struct comedi_insn *insn, unsigned int *data)
1189{
1190 if (data[0]) {
1191 s->state &= ~data[0];
1192 s->state |= (data[0] & data[1]);
1193
1194 outw(s->state, dev->iobase + DT2821_DIODAT);
1195 }
1196 data[1] = inw(dev->iobase + DT2821_DIODAT);
1197
1198 return 2;
1199}
1200
1201static int dt282x_dio_insn_config(struct comedi_device *dev,
1202 struct comedi_subdevice *s,
1203 struct comedi_insn *insn, unsigned int *data)
1204{
1205 int mask;
1206
1207 mask = (CR_CHAN(insn->chanspec) < 8) ? 0x00ff : 0xff00;
1208 if (data[0])
1209 s->io_bits |= mask;
1210 else
1211 s->io_bits &= ~mask;
1212
1213 if (s->io_bits & 0x00ff)
1214 devpriv->dacsr |= DT2821_LBOE;
1215 else
1216 devpriv->dacsr &= ~DT2821_LBOE;
1217 if (s->io_bits & 0xff00)
1218 devpriv->dacsr |= DT2821_HBOE;
1219 else
1220 devpriv->dacsr &= ~DT2821_HBOE;
1221
1222 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
1223
1224 return 1;
1225}
1226
1227static const struct comedi_lrange *const ai_range_table[] = {
1228 &range_dt282x_ai_lo_bipolar,
1229 &range_dt282x_ai_lo_unipolar,
1230 &range_dt282x_ai_5_bipolar,
1231 &range_dt282x_ai_5_unipolar
1232};
1233
1234static const struct comedi_lrange *const ai_range_pgl_table[] = {
1235 &range_dt282x_ai_hi_bipolar,
1236 &range_dt282x_ai_hi_unipolar
1237};
1238
1239static const struct comedi_lrange *opt_ai_range_lkup(int ispgl, int x)
1240{
1241 if (ispgl) {
1242 if (x < 0 || x >= 2)
1243 x = 0;
1244 return ai_range_pgl_table[x];
1245 } else {
1246 if (x < 0 || x >= 4)
1247 x = 0;
1248 return ai_range_table[x];
1249 }
1250}
1251
1252static const struct comedi_lrange *const ao_range_table[] = {
1253 &range_bipolar10,
1254 &range_unipolar10,
1255 &range_bipolar5,
1256 &range_unipolar5,
1257 &range_bipolar2_5
1258};
1259
1260static const struct comedi_lrange *opt_ao_range_lkup(int x)
1261{
1262 if (x < 0 || x >= 5)
1263 x = 0;
1264 return ao_range_table[x];
1265}
1266
1267enum {
1268 opt_iobase = 0, opt_irq, opt_dma1, opt_dma2,
1269 opt_diff,
1270 opt_ai_twos, opt_ao0_twos, opt_ao1_twos,
1271 opt_ai_range, opt_ao0_range, opt_ao1_range,
1272};
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1289{
1290 int i, irq;
1291 int ret;
1292 struct comedi_subdevice *s;
1293 unsigned long iobase;
1294
1295 dev->board_name = this_board->name;
1296
1297 iobase = it->options[opt_iobase];
1298 if (!iobase)
1299 iobase = 0x240;
1300
1301 printk(KERN_INFO "comedi%d: dt282x: 0x%04lx", dev->minor, iobase);
1302 if (!request_region(iobase, DT2821_SIZE, "dt282x")) {
1303 printk(KERN_INFO " I/O port conflict\n");
1304 return -EBUSY;
1305 }
1306 dev->iobase = iobase;
1307
1308 outw(DT2821_BDINIT, dev->iobase + DT2821_SUPCSR);
1309 i = inw(dev->iobase + DT2821_ADCSR);
1310#ifdef DEBUG
1311 printk(KERN_DEBUG " fingerprint=%x,%x,%x,%x,%x",
1312 inw(dev->iobase + DT2821_ADCSR),
1313 inw(dev->iobase + DT2821_CHANCSR),
1314 inw(dev->iobase + DT2821_DACSR),
1315 inw(dev->iobase + DT2821_SUPCSR),
1316 inw(dev->iobase + DT2821_TMRCTR));
1317#endif
1318
1319 if (((inw(dev->iobase + DT2821_ADCSR) & DT2821_ADCSR_MASK)
1320 != DT2821_ADCSR_VAL) ||
1321 ((inw(dev->iobase + DT2821_CHANCSR) & DT2821_CHANCSR_MASK)
1322 != DT2821_CHANCSR_VAL) ||
1323 ((inw(dev->iobase + DT2821_DACSR) & DT2821_DACSR_MASK)
1324 != DT2821_DACSR_VAL) ||
1325 ((inw(dev->iobase + DT2821_SUPCSR) & DT2821_SUPCSR_MASK)
1326 != DT2821_SUPCSR_VAL) ||
1327 ((inw(dev->iobase + DT2821_TMRCTR) & DT2821_TMRCTR_MASK)
1328 != DT2821_TMRCTR_VAL)) {
1329 printk(KERN_ERR " board not found");
1330 return -EIO;
1331 }
1332
1333
1334 irq = it->options[opt_irq];
1335#if 0
1336 if (irq < 0) {
1337 unsigned long flags;
1338 int irqs;
1339
1340 save_flags(flags);
1341 sti();
1342 irqs = probe_irq_on();
1343
1344
1345
1346 udelay(100);
1347
1348 irq = probe_irq_off(irqs);
1349 restore_flags(flags);
1350 if (0 )
1351 printk(KERN_ERR " error probing irq (bad)");
1352 }
1353#endif
1354 if (irq > 0) {
1355 printk(KERN_INFO " ( irq = %d )", irq);
1356 ret = request_irq(irq, dt282x_interrupt, 0, "dt282x", dev);
1357 if (ret < 0) {
1358 printk(KERN_ERR " failed to get irq\n");
1359 return -EIO;
1360 }
1361 dev->irq = irq;
1362 } else if (irq == 0) {
1363 printk(KERN_INFO " (no irq)");
1364 } else {
1365#if 0
1366 printk(KERN_INFO " (probe returned multiple irqs--bad)");
1367#else
1368 printk(KERN_INFO " (irq probe not implemented)");
1369#endif
1370 }
1371
1372 ret = alloc_private(dev, sizeof(struct dt282x_private));
1373 if (ret < 0)
1374 return ret;
1375
1376 ret = dt282x_grab_dma(dev, it->options[opt_dma1],
1377 it->options[opt_dma2]);
1378 if (ret < 0)
1379 return ret;
1380
1381 ret = alloc_subdevices(dev, 3);
1382 if (ret < 0)
1383 return ret;
1384
1385 s = dev->subdevices + 0;
1386
1387 dev->read_subdev = s;
1388
1389 s->type = COMEDI_SUBD_AI;
1390 s->subdev_flags = SDF_READABLE | SDF_CMD_READ |
1391 ((it->options[opt_diff]) ? SDF_DIFF : SDF_COMMON);
1392 s->n_chan =
1393 (it->options[opt_diff]) ? boardtype.adchan_di : boardtype.adchan_se;
1394 s->insn_read = dt282x_ai_insn_read;
1395 s->do_cmdtest = dt282x_ai_cmdtest;
1396 s->do_cmd = dt282x_ai_cmd;
1397 s->cancel = dt282x_ai_cancel;
1398 s->maxdata = (1 << boardtype.adbits) - 1;
1399 s->len_chanlist = 16;
1400 s->range_table =
1401 opt_ai_range_lkup(boardtype.ispgl, it->options[opt_ai_range]);
1402 devpriv->ad_2scomp = it->options[opt_ai_twos];
1403
1404 s++;
1405
1406 s->n_chan = boardtype.dachan;
1407 if (s->n_chan) {
1408
1409 s->type = COMEDI_SUBD_AO;
1410 dev->write_subdev = s;
1411 s->subdev_flags = SDF_WRITABLE | SDF_CMD_WRITE;
1412 s->insn_read = dt282x_ao_insn_read;
1413 s->insn_write = dt282x_ao_insn_write;
1414 s->do_cmdtest = dt282x_ao_cmdtest;
1415 s->do_cmd = dt282x_ao_cmd;
1416 s->cancel = dt282x_ao_cancel;
1417 s->maxdata = (1 << boardtype.dabits) - 1;
1418 s->len_chanlist = 2;
1419 s->range_table_list = devpriv->darangelist;
1420 devpriv->darangelist[0] =
1421 opt_ao_range_lkup(it->options[opt_ao0_range]);
1422 devpriv->darangelist[1] =
1423 opt_ao_range_lkup(it->options[opt_ao1_range]);
1424 devpriv->da0_2scomp = it->options[opt_ao0_twos];
1425 devpriv->da1_2scomp = it->options[opt_ao1_twos];
1426 } else {
1427 s->type = COMEDI_SUBD_UNUSED;
1428 }
1429
1430 s++;
1431
1432 s->type = COMEDI_SUBD_DIO;
1433 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1434 s->n_chan = 16;
1435 s->insn_bits = dt282x_dio_insn_bits;
1436 s->insn_config = dt282x_dio_insn_config;
1437 s->maxdata = 1;
1438 s->range_table = &range_digital;
1439
1440 printk(KERN_INFO "\n");
1441
1442 return 0;
1443}
1444
1445static void free_resources(struct comedi_device *dev)
1446{
1447 if (dev->irq)
1448 free_irq(dev->irq, dev);
1449 if (dev->iobase)
1450 release_region(dev->iobase, DT2821_SIZE);
1451 if (dev->private) {
1452 if (devpriv->dma[0].chan)
1453 free_dma(devpriv->dma[0].chan);
1454 if (devpriv->dma[1].chan)
1455 free_dma(devpriv->dma[1].chan);
1456 if (devpriv->dma[0].buf)
1457 free_page((unsigned long)devpriv->dma[0].buf);
1458 if (devpriv->dma[1].buf)
1459 free_page((unsigned long)devpriv->dma[1].buf);
1460 }
1461}
1462
1463static int dt282x_detach(struct comedi_device *dev)
1464{
1465 printk(KERN_INFO "comedi%d: dt282x: remove\n", dev->minor);
1466
1467 free_resources(dev);
1468
1469 return 0;
1470}
1471
1472static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2)
1473{
1474 int ret;
1475
1476 devpriv->usedma = 0;
1477
1478 if (!dma1 && !dma2) {
1479 printk(KERN_ERR " (no dma)");
1480 return 0;
1481 }
1482
1483 if (dma1 == dma2 || dma1 < 5 || dma2 < 5 || dma1 > 7 || dma2 > 7)
1484 return -EINVAL;
1485
1486 if (dma2 < dma1) {
1487 int i;
1488 i = dma1;
1489 dma1 = dma2;
1490 dma2 = i;
1491 }
1492
1493 ret = request_dma(dma1, "dt282x A");
1494 if (ret)
1495 return -EBUSY;
1496 devpriv->dma[0].chan = dma1;
1497
1498 ret = request_dma(dma2, "dt282x B");
1499 if (ret)
1500 return -EBUSY;
1501 devpriv->dma[1].chan = dma2;
1502
1503 devpriv->dma_maxsize = PAGE_SIZE;
1504 devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
1505 devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
1506 if (!devpriv->dma[0].buf || !devpriv->dma[1].buf) {
1507 printk(KERN_ERR " can't get DMA memory");
1508 return -ENOMEM;
1509 }
1510
1511 printk(KERN_INFO " (dma=%d,%d)", dma1, dma2);
1512
1513 devpriv->usedma = 1;
1514
1515 return 0;
1516}
1517
1518MODULE_AUTHOR("Comedi http://www.comedi.org");
1519MODULE_DESCRIPTION("Comedi low-level driver");
1520MODULE_LICENSE("GPL");
1521