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