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