2 comedi/drivers/dt282x.c
3 Hardware driver for Data Translation DT2821 series
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 1997-8 David A. Schleef <ds@schleef.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 Description: Data Translation DT2821 series (including DT-EZ)
27 Devices: [Data Translation] DT2821 (dt2821),
28 DT2821-F-16SE (dt2821-f), DT2821-F-8DI (dt2821-f),
29 DT2821-G-16SE (dt2821-f), DT2821-G-8DI (dt2821-g),
31 DT2824-PGH (dt2824-pgh), DT2824-PGL (dt2824-pgl), DT2825 (dt2825),
32 DT2827 (dt2827), DT2828 (dt2828), DT21-EZ (dt21-ez), DT23-EZ (dt23-ez),
33 DT24-EZ (dt24-ez), DT24-EZ-PGL (dt24-ez-pgl)
35 Updated: Wed, 22 Aug 2001 17:11:34 -0700
37 Configuration options:
38 [0] - I/O port base address
42 [4] - AI jumpered for 0=single ended, 1=differential
43 [5] - AI jumpered for 0=straight binary, 1=2's complement
44 [6] - AO 0 jumpered for 0=straight binary, 1=2's complement
45 [7] - AO 1 jumpered for 0=straight binary, 1=2's complement
46 [8] - AI jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5]
47 [9] - AO 0 jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5],
49 [10]- A0 1 jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5],
53 - AO commands might be broken.
54 - If you try to run a command on both the AI and AO subdevices
55 simultaneously, bad things will happen. The driver needs to
56 be fixed to check for this situation and return an error.
59 #include "../comedidev.h"
61 #include <linux/ioport.h>
62 #include <linux/interrupt.h>
64 #include "comedi_fc.h"
68 #define DT2821_TIMEOUT 100 /* 500 us */
69 #define DT2821_SIZE 0x10
72 * Registers in the DT282x
75 #define DT2821_ADCSR 0x00 /* A/D Control/Status */
76 #define DT2821_CHANCSR 0x02 /* Channel Control/Status */
77 #define DT2821_ADDAT 0x04 /* A/D data */
78 #define DT2821_DACSR 0x06 /* D/A Control/Status */
79 #define DT2821_DADAT 0x08 /* D/A data */
80 #define DT2821_DIODAT 0x0a /* digital data */
81 #define DT2821_SUPCSR 0x0c /* Supervisor Control/Status */
82 #define DT2821_TMRCTR 0x0e /* Timer/Counter */
85 * At power up, some registers are in a well-known state. The
86 * masks and values are as follows:
89 #define DT2821_ADCSR_MASK 0xfff0
90 #define DT2821_ADCSR_VAL 0x7c00
92 #define DT2821_CHANCSR_MASK 0xf0f0
93 #define DT2821_CHANCSR_VAL 0x70f0
95 #define DT2821_DACSR_MASK 0x7c93
96 #define DT2821_DACSR_VAL 0x7c90
98 #define DT2821_SUPCSR_MASK 0xf8ff
99 #define DT2821_SUPCSR_VAL 0x0000
101 #define DT2821_TMRCTR_MASK 0xff00
102 #define DT2821_TMRCTR_VAL 0xf000
105 * Bit fields of each register
110 #define DT2821_ADERR 0x8000 /* (R) 1 for A/D error */
111 #define DT2821_ADCLK 0x0200 /* (R/W) A/D clock enable */
112 /* 0x7c00 read as 1's */
113 #define DT2821_MUXBUSY 0x0100 /* (R) multiplexer busy */
114 #define DT2821_ADDONE 0x0080 /* (R) A/D done */
115 #define DT2821_IADDONE 0x0040 /* (R/W) interrupt on A/D done */
116 /* 0x0030 gain select */
117 /* 0x000f channel select */
121 #define DT2821_LLE 0x8000 /* (R/W) Load List Enable */
122 /* 0x7000 read as 1's */
123 /* 0x0f00 (R) present address */
124 /* 0x00f0 read as 1's */
125 /* 0x000f (R) number of entries - 1 */
129 #define DT2821_DAERR 0x8000 /* (R) D/A error */
130 #define DT2821_YSEL 0x0200 /* (R/W) DAC 1 select */
131 #define DT2821_SSEL 0x0100 /* (R/W) single channel select */
132 #define DT2821_DACRDY 0x0080 /* (R) DAC ready */
133 #define DT2821_IDARDY 0x0040 /* (R/W) interrupt on DAC ready */
134 #define DT2821_DACLK 0x0020 /* (R/W) D/A clock enable */
135 #define DT2821_HBOE 0x0002 /* (R/W) DIO high byte output enable */
136 #define DT2821_LBOE 0x0001 /* (R/W) DIO low byte output enable */
140 #define DT2821_DMAD 0x8000 /* (R) DMA done */
141 #define DT2821_ERRINTEN 0x4000 /* (R/W) interrupt on error */
142 #define DT2821_CLRDMADNE 0x2000 /* (W) clear DMA done */
143 #define DT2821_DDMA 0x1000 /* (R/W) dual DMA */
144 #define DT2821_DS1 0x0800 /* (R/W) DMA select 1 */
145 #define DT2821_DS0 0x0400 /* (R/W) DMA select 0 */
146 #define DT2821_BUFFB 0x0200 /* (R/W) buffer B selected */
147 #define DT2821_SCDN 0x0100 /* (R) scan done */
148 #define DT2821_DACON 0x0080 /* (W) DAC single conversion */
149 #define DT2821_ADCINIT 0x0040 /* (W) A/D initialize */
150 #define DT2821_DACINIT 0x0020 /* (W) D/A initialize */
151 #define DT2821_PRLD 0x0010 /* (W) preload multiplexer */
152 #define DT2821_STRIG 0x0008 /* (W) software trigger */
153 #define DT2821_XTRIG 0x0004 /* (R/W) external trigger enable */
154 #define DT2821_XCLK 0x0002 /* (R/W) external clock enable */
155 #define DT2821_BDINIT 0x0001 /* (W) initialize board */
157 static const struct comedi_lrange range_dt282x_ai_lo_bipolar = { 4, {
170 static const struct comedi_lrange range_dt282x_ai_lo_unipolar = { 4, {
182 static const struct comedi_lrange range_dt282x_ai_5_bipolar = { 4, {
195 static const struct comedi_lrange range_dt282x_ai_5_unipolar = { 4, {
207 static const struct comedi_lrange range_dt282x_ai_hi_bipolar = { 4, {
220 static const struct comedi_lrange range_dt282x_ai_hi_unipolar = { 4, {
232 struct dt282x_board {
243 static const struct dt282x_board boardtypes[] = {
280 {.name = "dt2824-pgh",
289 {.name = "dt2824-pgl",
361 {.name = "dt24-ez-pgl",
372 #define n_boardtypes sizeof(boardtypes)/sizeof(struct dt282x_board)
373 #define this_board ((const struct dt282x_board *)dev->board_ptr)
375 struct dt282x_private {
376 int ad_2scomp; /* we have 2's comp jumper set */
377 int da0_2scomp; /* same, for DAC0 */
378 int da1_2scomp; /* same, for DAC1 */
380 const struct comedi_lrange *darangelist[2];
384 volatile int dacsr; /* software copies of registers */
393 short *buf; /* DMA buffer */
394 volatile int size; /* size of current transfer */
396 int dma_maxsize; /* max size of DMA transfer (in bytes) */
397 int usedma; /* driver uses DMA */
398 volatile int current_dma_index;
402 #define devpriv ((struct dt282x_private *)dev->private)
403 #define boardtype (*(const struct dt282x_board *)dev->board_ptr)
406 * Some useless abstractions
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)
416 * danger! macro abuse... a is the expression to wait on, and b is
417 * the statement(s) to execute if it doesn't happen.
419 #define wait_for(a, b) \
422 for (_i=0;_i<DT2821_TIMEOUT;_i++){ \
423 if (a){_i=0;break;} \
429 static int dt282x_attach(struct comedi_device *dev,
430 struct comedi_devconfig *it);
431 static int dt282x_detach(struct comedi_device *dev);
432 static 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),
442 COMEDI_INITCLEANUP(driver_dt282x);
444 static void free_resources(struct comedi_device *dev);
445 static int prep_ai_dma(struct comedi_device *dev, int chan, int size);
446 static int prep_ao_dma(struct comedi_device *dev, int chan, int size);
447 static int dt282x_ai_cancel(struct comedi_device *dev,
448 struct comedi_subdevice *s);
449 static int dt282x_ao_cancel(struct comedi_device *dev,
450 struct comedi_subdevice *s);
451 static int dt282x_ns_to_timer(int *nanosec, int round_mode);
452 static void dt282x_disable_dma(struct comedi_device *dev);
454 static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2);
456 static void dt282x_munge(struct comedi_device *dev, short *buf,
460 unsigned short mask = (1 << boardtype.adbits) - 1;
461 unsigned short sign = 1 << (boardtype.adbits - 1);
464 if (devpriv->ad_2scomp) {
465 sign = 1 << (boardtype.adbits - 1);
471 comedi_error(dev, "bug! odd number of bytes from dma xfer");
473 for (i = 0; i < n; i++) {
474 buf[i] = (buf[i] & mask) ^ sign;
478 static void dt282x_ao_dma_interrupt(struct comedi_device *dev)
483 struct comedi_subdevice *s = dev->subdevices + 1;
485 update_supcsr(DT2821_CLRDMADNE);
487 if (!s->async->prealloc_buf) {
488 printk("async->data disappeared. dang!\n");
492 i = devpriv->current_dma_index;
493 ptr = devpriv->dma[i].buf;
495 disable_dma(devpriv->dma[i].chan);
497 devpriv->current_dma_index = 1 - i;
499 size = cfc_read_array_from_buffer(s, ptr, devpriv->dma_maxsize);
501 printk("dt282x: AO underrun\n");
502 dt282x_ao_cancel(dev, s);
503 s->async->events |= COMEDI_CB_OVERFLOW;
506 prep_ao_dma(dev, i, size);
510 static void dt282x_ai_dma_interrupt(struct comedi_device *dev)
516 struct comedi_subdevice *s = dev->subdevices;
518 update_supcsr(DT2821_CLRDMADNE);
520 if (!s->async->prealloc_buf) {
521 printk("async->data disappeared. dang!\n");
525 i = devpriv->current_dma_index;
526 ptr = devpriv->dma[i].buf;
527 size = devpriv->dma[i].size;
529 disable_dma(devpriv->dma[i].chan);
531 devpriv->current_dma_index = 1 - i;
533 dt282x_munge(dev, ptr, size);
534 ret = cfc_write_array_to_buffer(s, ptr, size);
536 dt282x_ai_cancel(dev, s);
539 devpriv->nread -= size / 2;
541 if (devpriv->nread < 0) {
542 printk("dt282x: off by one\n");
545 if (!devpriv->nread) {
546 dt282x_ai_cancel(dev, s);
547 s->async->events |= COMEDI_CB_EOA;
551 /* clear the dual dma flag, making this the last dma segment */
552 /* XXX probably wrong */
553 if (!devpriv->ntrig) {
554 devpriv->supcsr &= ~(DT2821_DDMA);
558 /* restart the channel */
559 prep_ai_dma(dev, i, 0);
562 static int prep_ai_dma(struct comedi_device *dev, int dma_index, int n)
565 unsigned long dma_ptr;
572 n = devpriv->dma_maxsize;
573 if (n > devpriv->ntrig * 2)
574 n = devpriv->ntrig * 2;
575 devpriv->ntrig -= n / 2;
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);
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);
588 enable_dma(dma_chan);
593 static int prep_ao_dma(struct comedi_device *dev, int dma_index, int n)
596 unsigned long dma_ptr;
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);
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);
610 enable_dma(dma_chan);
615 static irqreturn_t dt282x_interrupt(int irq, void *d)
617 struct comedi_device *dev = d;
618 struct comedi_subdevice *s;
619 struct comedi_subdevice *s_ao;
620 unsigned int supcsr, adcsr, dacsr;
623 if (!dev->attached) {
624 comedi_error(dev, "spurious interrupt");
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);
637 dt282x_ao_dma_interrupt(dev);
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;
648 if (dacsr & DT2821_DAERR) {
652 disable_irq(dev->irq);
653 printk("disabling irq\n");
656 comedi_error(dev, "D/A error");
657 dt282x_ao_cancel(dev, s_ao);
658 s->async->events |= COMEDI_CB_ERROR;
662 if (adcsr & DT2821_ADDONE) {
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);
671 ret = comedi_buf_put(s->async, data);
673 s->async->events |= COMEDI_CB_OVERFLOW;
677 if (!devpriv->nread) {
678 s->async->events |= COMEDI_CB_EOA;
680 if (supcsr & DT2821_SCDN)
681 update_supcsr(DT2821_STRIG);
686 comedi_event(dev, s);
687 /* printk("adcsr=0x%02x dacsr-0x%02x supcsr=0x%02x\n", adcsr, dacsr, supcsr); */
688 return IRQ_RETVAL(handled);
691 static void dt282x_load_changain(struct comedi_device *dev, int n,
692 unsigned int *chanlist)
695 unsigned int chan, range;
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));
703 outw(n - 1, dev->iobase + DT2821_CHANCSR);
707 * Performs a single A/D conversion.
708 * - Put channel/gain into channel-gain list
709 * - preload multiplexer
710 * - trigger conversion and wait for it to finish
712 static int dt282x_ai_insn_read(struct comedi_device *dev,
713 struct comedi_subdevice *s,
714 struct comedi_insn *insn, unsigned int *data)
718 /* XXX should we really be enabling the ad clock here? */
719 devpriv->adcsr = DT2821_ADCLK;
722 dt282x_load_changain(dev, 1, &insn->chanspec);
724 update_supcsr(DT2821_PRLD);
725 wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;);
727 for (i = 0; i < insn->n; i++) {
728 update_supcsr(DT2821_STRIG);
729 wait_for(ad_done(), comedi_error(dev, "timeout\n");
734 DT2821_ADDAT) & ((1 << boardtype.adbits) - 1);
735 if (devpriv->ad_2scomp)
736 data[i] ^= (1 << (boardtype.adbits - 1));
742 static int dt282x_ai_cmdtest(struct comedi_device *dev,
743 struct comedi_subdevice *s, struct comedi_cmd *cmd)
748 /* step 1: make sure trigger sources are trivially valid */
750 tmp = cmd->start_src;
751 cmd->start_src &= TRIG_NOW;
752 if (!cmd->start_src || tmp != cmd->start_src)
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)
760 tmp = cmd->convert_src;
761 cmd->convert_src &= TRIG_TIMER;
762 if (!cmd->convert_src || tmp != cmd->convert_src)
765 tmp = cmd->scan_end_src;
766 cmd->scan_end_src &= TRIG_COUNT;
767 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
771 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
772 if (!cmd->stop_src || tmp != cmd->stop_src)
778 /* step 2: make sure trigger sources are unique and mutually compatible */
780 /* note that mutual compatibility is not an issue here */
781 if (cmd->scan_begin_src != TRIG_FOLLOW &&
782 cmd->scan_begin_src != TRIG_EXT)
784 if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
790 /* step 3: make sure arguments are trivially compatible */
792 if (cmd->start_arg != 0) {
796 if (cmd->scan_begin_src == TRIG_FOLLOW) {
797 /* internal trigger */
798 if (cmd->scan_begin_arg != 0) {
799 cmd->scan_begin_arg = 0;
803 /* external trigger */
804 /* should be level/edge, hi/lo specification here */
805 if (cmd->scan_begin_arg != 0) {
806 cmd->scan_begin_arg = 0;
810 if (cmd->convert_arg < 4000) {
811 /* XXX board dependent */
812 cmd->convert_arg = 4000;
815 #define SLOWEST_TIMER (250*(1<<15)*255)
816 if (cmd->convert_arg > SLOWEST_TIMER) {
817 cmd->convert_arg = SLOWEST_TIMER;
820 if (cmd->convert_arg < this_board->ai_speed) {
821 cmd->convert_arg = this_board->ai_speed;
824 if (cmd->scan_end_arg != cmd->chanlist_len) {
825 cmd->scan_end_arg = cmd->chanlist_len;
828 if (cmd->stop_src == TRIG_COUNT) {
829 /* any count is allowed */
832 if (cmd->stop_arg != 0) {
841 /* step 4: fix up any arguments */
843 tmp = cmd->convert_arg;
844 dt282x_ns_to_timer(&cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK);
845 if (tmp != cmd->convert_arg)
854 static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
856 struct comedi_cmd *cmd = &s->async->cmd;
859 if (devpriv->usedma == 0) {
861 "driver requires 2 dma channels to execute command");
865 dt282x_disable_dma(dev);
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);
872 if (cmd->scan_begin_src == TRIG_FOLLOW) {
873 /* internal trigger */
874 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0;
876 /* external trigger */
877 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0 | DT2821_DS1;
879 update_supcsr(DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_ADCINIT);
881 devpriv->ntrig = cmd->stop_arg * cmd->scan_end_arg;
882 devpriv->nread = devpriv->ntrig;
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;
895 dt282x_load_changain(dev, cmd->chanlist_len, cmd->chanlist);
897 devpriv->adcsr = DT2821_ADCLK | DT2821_IADDONE;
900 update_supcsr(DT2821_PRLD);
901 wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;);
903 if (cmd->scan_begin_src == TRIG_FOLLOW) {
904 update_supcsr(DT2821_STRIG);
906 devpriv->supcsr |= DT2821_XTRIG;
913 static void dt282x_disable_dma(struct comedi_device *dev)
915 if (devpriv->usedma) {
916 disable_dma(devpriv->dma[0].chan);
917 disable_dma(devpriv->dma[1].chan);
921 static int dt282x_ai_cancel(struct comedi_device *dev,
922 struct comedi_subdevice *s)
924 dt282x_disable_dma(dev);
930 update_supcsr(DT2821_ADCINIT);
935 static int dt282x_ns_to_timer(int *nanosec, int round_mode)
937 int prescale, base, divider;
939 for (prescale = 0; prescale < 16; prescale++) {
942 base = 250 * (1 << prescale);
943 switch (round_mode) {
944 case TRIG_ROUND_NEAREST:
946 divider = (*nanosec + base / 2) / base;
948 case TRIG_ROUND_DOWN:
949 divider = (*nanosec) / base;
952 divider = (*nanosec + base - 1) / base;
956 *nanosec = divider * base;
957 return (prescale << 8) | (255 - divider);
960 base = 250 * (1 << 15);
962 *nanosec = divider * base;
963 return (15 << 8) | (255 - divider);
967 * Analog output routine. Selects single channel conversion,
968 * selects correct channel, converts from 2's compliment to
969 * offset binary if necessary, loads the data into the DAC
970 * data register, and performs the conversion.
972 static int dt282x_ao_insn_read(struct comedi_device *dev,
973 struct comedi_subdevice *s,
974 struct comedi_insn *insn, unsigned int *data)
976 data[0] = devpriv->ao[CR_CHAN(insn->chanspec)];
981 static int dt282x_ao_insn_write(struct comedi_device *dev,
982 struct comedi_subdevice *s,
983 struct comedi_insn *insn, unsigned int *data)
988 chan = CR_CHAN(insn->chanspec);
990 d &= (1 << boardtype.dabits) - 1;
991 devpriv->ao[chan] = d;
993 devpriv->dacsr |= DT2821_SSEL;
997 devpriv->dacsr |= DT2821_YSEL;
998 if (devpriv->da0_2scomp)
999 d ^= (1 << (boardtype.dabits - 1));
1001 devpriv->dacsr &= ~DT2821_YSEL;
1002 if (devpriv->da1_2scomp)
1003 d ^= (1 << (boardtype.dabits - 1));
1008 outw(d, dev->iobase + DT2821_DADAT);
1010 update_supcsr(DT2821_DACON);
1015 static int dt282x_ao_cmdtest(struct comedi_device *dev,
1016 struct comedi_subdevice *s, struct comedi_cmd *cmd)
1021 /* step 1: make sure trigger sources are trivially valid */
1023 tmp = cmd->start_src;
1024 cmd->start_src &= TRIG_INT;
1025 if (!cmd->start_src || tmp != cmd->start_src)
1028 tmp = cmd->scan_begin_src;
1029 cmd->scan_begin_src &= TRIG_TIMER;
1030 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
1033 tmp = cmd->convert_src;
1034 cmd->convert_src &= TRIG_NOW;
1035 if (!cmd->convert_src || tmp != cmd->convert_src)
1038 tmp = cmd->scan_end_src;
1039 cmd->scan_end_src &= TRIG_COUNT;
1040 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
1043 tmp = cmd->stop_src;
1044 cmd->stop_src &= TRIG_NONE;
1045 if (!cmd->stop_src || tmp != cmd->stop_src)
1051 /* step 2: make sure trigger sources are unique and mutually compatible */
1053 /* note that mutual compatibility is not an issue here */
1054 if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
1060 /* step 3: make sure arguments are trivially compatible */
1062 if (cmd->start_arg != 0) {
1066 if (cmd->scan_begin_arg < 5000 /* XXX unknown */ ) {
1067 cmd->scan_begin_arg = 5000;
1070 if (cmd->convert_arg != 0) {
1071 cmd->convert_arg = 0;
1074 if (cmd->scan_end_arg > 2) {
1075 /* XXX chanlist stuff? */
1076 cmd->scan_end_arg = 2;
1079 if (cmd->stop_src == TRIG_COUNT) {
1080 /* any count is allowed */
1083 if (cmd->stop_arg != 0) {
1092 /* step 4: fix up any arguments */
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)
1106 static int dt282x_ao_inttrig(struct comedi_device *dev,
1107 struct comedi_subdevice *s, unsigned int x)
1114 size = cfc_read_array_from_buffer(s, devpriv->dma[0].buf,
1115 devpriv->dma_maxsize);
1117 printk("dt282x: AO underrun\n");
1120 prep_ao_dma(dev, 0, size);
1122 size = cfc_read_array_from_buffer(s, devpriv->dma[1].buf,
1123 devpriv->dma_maxsize);
1125 printk("dt282x: AO underrun\n");
1128 prep_ao_dma(dev, 1, size);
1130 update_supcsr(DT2821_STRIG);
1131 s->async->inttrig = NULL;
1136 static int dt282x_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1139 struct comedi_cmd *cmd = &s->async->cmd;
1141 if (devpriv->usedma == 0) {
1143 "driver requires 2 dma channels to execute command");
1147 dt282x_disable_dma(dev);
1149 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS1 | DT2821_DDMA;
1150 update_supcsr(DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_DACINIT);
1152 devpriv->ntrig = cmd->stop_arg * cmd->chanlist_len;
1153 devpriv->nread = devpriv->ntrig;
1155 devpriv->dma_dir = DMA_MODE_WRITE;
1156 devpriv->current_dma_index = 0;
1158 timer = dt282x_ns_to_timer(&cmd->scan_begin_arg, TRIG_ROUND_NEAREST);
1159 outw(timer, dev->iobase + DT2821_TMRCTR);
1161 devpriv->dacsr = DT2821_SSEL | DT2821_DACLK | DT2821_IDARDY;
1164 s->async->inttrig = dt282x_ao_inttrig;
1169 static int dt282x_ao_cancel(struct comedi_device *dev,
1170 struct comedi_subdevice *s)
1172 dt282x_disable_dma(dev);
1177 devpriv->supcsr = 0;
1178 update_supcsr(DT2821_DACINIT);
1183 static int dt282x_dio_insn_bits(struct comedi_device *dev,
1184 struct comedi_subdevice *s,
1185 struct comedi_insn *insn, unsigned int *data)
1188 s->state &= ~data[0];
1189 s->state |= (data[0] & data[1]);
1191 outw(s->state, dev->iobase + DT2821_DIODAT);
1193 data[1] = inw(dev->iobase + DT2821_DIODAT);
1198 static int dt282x_dio_insn_config(struct comedi_device *dev,
1199 struct comedi_subdevice *s,
1200 struct comedi_insn *insn, unsigned int *data)
1204 mask = (CR_CHAN(insn->chanspec) < 8) ? 0x00ff : 0xff00;
1208 s->io_bits &= ~mask;
1210 if (s->io_bits & 0x00ff)
1211 devpriv->dacsr |= DT2821_LBOE;
1213 devpriv->dacsr &= ~DT2821_LBOE;
1214 if (s->io_bits & 0xff00)
1215 devpriv->dacsr |= DT2821_HBOE;
1217 devpriv->dacsr &= ~DT2821_HBOE;
1219 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
1224 static 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
1231 static const struct comedi_lrange *const ai_range_pgl_table[] = {
1232 &range_dt282x_ai_hi_bipolar,
1233 &range_dt282x_ai_hi_unipolar
1236 static const struct comedi_lrange *opt_ai_range_lkup(int ispgl, int x)
1239 if (x < 0 || x >= 2)
1241 return ai_range_pgl_table[x];
1243 if (x < 0 || x >= 4)
1245 return ai_range_table[x];
1249 static const struct comedi_lrange *const ao_range_table[] = {
1257 static const struct comedi_lrange *opt_ao_range_lkup(int x)
1259 if (x < 0 || x >= 5)
1261 return ao_range_table[x];
1264 enum { opt_iobase = 0, opt_irq, opt_dma1, opt_dma2, /* i/o base, irq, dma channels */
1265 opt_diff, /* differential */
1266 opt_ai_twos, opt_ao0_twos, opt_ao1_twos, /* twos comp */
1267 opt_ai_range, opt_ao0_range, opt_ao1_range, /* range */
1276 4 0=single ended, 1=differential
1277 5 ai 0=straight binary, 1=2's comp
1278 6 ao0 0=straight binary, 1=2's comp
1279 7 ao1 0=straight binary, 1=2's comp
1280 8 ai 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V
1281 9 ao0 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1282 10 ao1 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1284 static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1288 struct comedi_subdevice *s;
1289 unsigned long iobase;
1291 dev->board_name = this_board->name;
1293 iobase = it->options[opt_iobase];
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");
1302 dev->iobase = iobase;
1304 outw(DT2821_BDINIT, dev->iobase + DT2821_SUPCSR);
1305 i = inw(dev->iobase + DT2821_ADCSR);
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));
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");
1328 /* should do board test */
1330 irq = it->options[opt_irq];
1333 unsigned long flags;
1338 irqs = probe_irq_on();
1340 /* trigger interrupt */
1344 irq = probe_irq_off(irqs);
1345 restore_flags(flags);
1346 if (0 /* error */ ) {
1347 printk(" error probing irq (bad)");
1352 printk(" ( irq = %d )", irq);
1353 ret = request_irq(irq, dt282x_interrupt, 0, "dt282x", dev);
1355 printk(" failed to get irq\n");
1359 } else if (irq == 0) {
1360 printk(" (no irq)");
1363 printk(" (probe returned multiple irqs--bad)");
1365 printk(" (irq probe not implemented)");
1369 ret = alloc_private(dev, sizeof(struct dt282x_private));
1373 ret = dt282x_grab_dma(dev, it->options[opt_dma1],
1374 it->options[opt_dma2]);
1378 ret = alloc_subdevices(dev, 3);
1382 s = dev->subdevices + 0;
1384 dev->read_subdev = s;
1386 s->type = COMEDI_SUBD_AI;
1387 s->subdev_flags = SDF_READABLE | SDF_CMD_READ |
1388 ((it->options[opt_diff]) ? SDF_DIFF : SDF_COMMON);
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;
1398 opt_ai_range_lkup(boardtype.ispgl, it->options[opt_ai_range]);
1399 devpriv->ad_2scomp = it->options[opt_ai_twos];
1403 s->n_chan = boardtype.dachan;
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];
1424 s->type = COMEDI_SUBD_UNUSED;
1429 s->type = COMEDI_SUBD_DIO;
1430 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1432 s->insn_bits = dt282x_dio_insn_bits;
1433 s->insn_config = dt282x_dio_insn_config;
1435 s->range_table = &range_digital;
1442 static void free_resources(struct comedi_device *dev)
1445 free_irq(dev->irq, dev);
1448 release_region(dev->iobase, DT2821_SIZE);
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);
1461 static int dt282x_detach(struct comedi_device *dev)
1463 printk("comedi%d: dt282x: remove\n", dev->minor);
1465 free_resources(dev);
1470 static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2)
1474 devpriv->usedma = 0;
1476 if (!dma1 && !dma2) {
1477 printk(" (no dma)");
1481 if (dma1 == dma2 || dma1 < 5 || dma2 < 5 || dma1 > 7 || dma2 > 7)
1491 ret = request_dma(dma1, "dt282x A");
1494 devpriv->dma[0].chan = dma1;
1496 ret = request_dma(dma2, "dt282x B");
1499 devpriv->dma[1].chan = dma2;
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");
1509 printk(" (dma=%d,%d)", dma1, dma2);
1511 devpriv->usedma = 1;