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