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/gfp.h>
62 #include <linux/ioport.h>
63 #include <linux/interrupt.h>
65 #include "comedi_fc.h"
69 #define DT2821_TIMEOUT 100 /* 500 us */
70 #define DT2821_SIZE 0x10
73 * Registers in the DT282x
76 #define DT2821_ADCSR 0x00 /* A/D Control/Status */
77 #define DT2821_CHANCSR 0x02 /* Channel Control/Status */
78 #define DT2821_ADDAT 0x04 /* A/D data */
79 #define DT2821_DACSR 0x06 /* D/A Control/Status */
80 #define DT2821_DADAT 0x08 /* D/A data */
81 #define DT2821_DIODAT 0x0a /* digital data */
82 #define DT2821_SUPCSR 0x0c /* Supervisor Control/Status */
83 #define DT2821_TMRCTR 0x0e /* Timer/Counter */
86 * At power up, some registers are in a well-known state. The
87 * masks and values are as follows:
90 #define DT2821_ADCSR_MASK 0xfff0
91 #define DT2821_ADCSR_VAL 0x7c00
93 #define DT2821_CHANCSR_MASK 0xf0f0
94 #define DT2821_CHANCSR_VAL 0x70f0
96 #define DT2821_DACSR_MASK 0x7c93
97 #define DT2821_DACSR_VAL 0x7c90
99 #define DT2821_SUPCSR_MASK 0xf8ff
100 #define DT2821_SUPCSR_VAL 0x0000
102 #define DT2821_TMRCTR_MASK 0xff00
103 #define DT2821_TMRCTR_VAL 0xf000
106 * Bit fields of each register
111 #define DT2821_ADERR 0x8000 /* (R) 1 for A/D error */
112 #define DT2821_ADCLK 0x0200 /* (R/W) A/D clock enable */
113 /* 0x7c00 read as 1's */
114 #define DT2821_MUXBUSY 0x0100 /* (R) multiplexer busy */
115 #define DT2821_ADDONE 0x0080 /* (R) A/D done */
116 #define DT2821_IADDONE 0x0040 /* (R/W) interrupt on A/D done */
117 /* 0x0030 gain select */
118 /* 0x000f channel select */
122 #define DT2821_LLE 0x8000 /* (R/W) Load List Enable */
123 /* 0x7000 read as 1's */
124 /* 0x0f00 (R) present address */
125 /* 0x00f0 read as 1's */
126 /* 0x000f (R) number of entries - 1 */
130 #define DT2821_DAERR 0x8000 /* (R) D/A error */
131 #define DT2821_YSEL 0x0200 /* (R/W) DAC 1 select */
132 #define DT2821_SSEL 0x0100 /* (R/W) single channel select */
133 #define DT2821_DACRDY 0x0080 /* (R) DAC ready */
134 #define DT2821_IDARDY 0x0040 /* (R/W) interrupt on DAC ready */
135 #define DT2821_DACLK 0x0020 /* (R/W) D/A clock enable */
136 #define DT2821_HBOE 0x0002 /* (R/W) DIO high byte output enable */
137 #define DT2821_LBOE 0x0001 /* (R/W) DIO low byte output enable */
141 #define DT2821_DMAD 0x8000 /* (R) DMA done */
142 #define DT2821_ERRINTEN 0x4000 /* (R/W) interrupt on error */
143 #define DT2821_CLRDMADNE 0x2000 /* (W) clear DMA done */
144 #define DT2821_DDMA 0x1000 /* (R/W) dual DMA */
145 #define DT2821_DS1 0x0800 /* (R/W) DMA select 1 */
146 #define DT2821_DS0 0x0400 /* (R/W) DMA select 0 */
147 #define DT2821_BUFFB 0x0200 /* (R/W) buffer B selected */
148 #define DT2821_SCDN 0x0100 /* (R) scan done */
149 #define DT2821_DACON 0x0080 /* (W) DAC single conversion */
150 #define DT2821_ADCINIT 0x0040 /* (W) A/D initialize */
151 #define DT2821_DACINIT 0x0020 /* (W) D/A initialize */
152 #define DT2821_PRLD 0x0010 /* (W) preload multiplexer */
153 #define DT2821_STRIG 0x0008 /* (W) software trigger */
154 #define DT2821_XTRIG 0x0004 /* (R/W) external trigger enable */
155 #define DT2821_XCLK 0x0002 /* (R/W) external clock enable */
156 #define DT2821_BDINIT 0x0001 /* (W) initialize board */
158 static const struct comedi_lrange range_dt282x_ai_lo_bipolar = {
167 static const struct comedi_lrange range_dt282x_ai_lo_unipolar = {
176 static const struct comedi_lrange range_dt282x_ai_5_bipolar = {
185 static const struct comedi_lrange range_dt282x_ai_5_unipolar = {
194 static const struct comedi_lrange range_dt282x_ai_hi_bipolar = {
203 static const struct comedi_lrange range_dt282x_ai_hi_unipolar = {
212 struct dt282x_board {
223 static const struct dt282x_board boardtypes[] = {
260 {.name = "dt2824-pgh",
269 {.name = "dt2824-pgl",
341 {.name = "dt24-ez-pgl",
352 #define n_boardtypes (sizeof(boardtypes)/sizeof(struct dt282x_board))
353 #define this_board ((const struct dt282x_board *)dev->board_ptr)
355 struct dt282x_private {
356 int ad_2scomp; /* we have 2's comp jumper set */
357 int da0_2scomp; /* same, for DAC0 */
358 int da1_2scomp; /* same, for DAC1 */
360 const struct comedi_lrange *darangelist[2];
364 volatile int dacsr; /* software copies of registers */
373 short *buf; /* DMA buffer */
374 volatile int size; /* size of current transfer */
376 int dma_maxsize; /* max size of DMA transfer (in bytes) */
377 int usedma; /* driver uses DMA */
378 volatile int current_dma_index;
382 #define devpriv ((struct dt282x_private *)dev->private)
383 #define boardtype (*(const struct dt282x_board *)dev->board_ptr)
386 * Some useless abstractions
388 #define chan_to_DAC(a) ((a)&1)
389 #define update_dacsr(a) outw(devpriv->dacsr|(a), dev->iobase+DT2821_DACSR)
390 #define update_adcsr(a) outw(devpriv->adcsr|(a), dev->iobase+DT2821_ADCSR)
391 #define mux_busy() (inw(dev->iobase+DT2821_ADCSR)&DT2821_MUXBUSY)
392 #define ad_done() (inw(dev->iobase+DT2821_ADCSR)&DT2821_ADDONE)
393 #define update_supcsr(a) outw(devpriv->supcsr|(a), dev->iobase+DT2821_SUPCSR)
396 * danger! macro abuse... a is the expression to wait on, and b is
397 * the statement(s) to execute if it doesn't happen.
399 #define wait_for(a, b) \
402 for (_i = 0; _i < DT2821_TIMEOUT; _i++) { \
413 static int dt282x_attach(struct comedi_device *dev,
414 struct comedi_devconfig *it);
415 static int dt282x_detach(struct comedi_device *dev);
416 static struct comedi_driver driver_dt282x = {
417 .driver_name = "dt282x",
418 .module = THIS_MODULE,
419 .attach = dt282x_attach,
420 .detach = dt282x_detach,
421 .board_name = &boardtypes[0].name,
422 .num_names = n_boardtypes,
423 .offset = sizeof(struct dt282x_board),
426 COMEDI_INITCLEANUP(driver_dt282x);
428 static void free_resources(struct comedi_device *dev);
429 static int prep_ai_dma(struct comedi_device *dev, int chan, int size);
430 static int prep_ao_dma(struct comedi_device *dev, int chan, int size);
431 static int dt282x_ai_cancel(struct comedi_device *dev,
432 struct comedi_subdevice *s);
433 static int dt282x_ao_cancel(struct comedi_device *dev,
434 struct comedi_subdevice *s);
435 static int dt282x_ns_to_timer(int *nanosec, int round_mode);
436 static void dt282x_disable_dma(struct comedi_device *dev);
438 static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2);
440 static void dt282x_munge(struct comedi_device *dev, short *buf,
444 unsigned short mask = (1 << boardtype.adbits) - 1;
445 unsigned short sign = 1 << (boardtype.adbits - 1);
448 if (devpriv->ad_2scomp)
449 sign = 1 << (boardtype.adbits - 1);
454 comedi_error(dev, "bug! odd number of bytes from dma xfer");
456 for (i = 0; i < n; i++)
457 buf[i] = (buf[i] & mask) ^ sign;
460 static void dt282x_ao_dma_interrupt(struct comedi_device *dev)
465 struct comedi_subdevice *s = dev->subdevices + 1;
467 update_supcsr(DT2821_CLRDMADNE);
469 if (!s->async->prealloc_buf) {
470 printk(KERN_ERR "async->data disappeared. dang!\n");
474 i = devpriv->current_dma_index;
475 ptr = devpriv->dma[i].buf;
477 disable_dma(devpriv->dma[i].chan);
479 devpriv->current_dma_index = 1 - i;
481 size = cfc_read_array_from_buffer(s, ptr, devpriv->dma_maxsize);
483 printk(KERN_ERR "dt282x: AO underrun\n");
484 dt282x_ao_cancel(dev, s);
485 s->async->events |= COMEDI_CB_OVERFLOW;
488 prep_ao_dma(dev, i, size);
492 static void dt282x_ai_dma_interrupt(struct comedi_device *dev)
498 struct comedi_subdevice *s = dev->subdevices;
500 update_supcsr(DT2821_CLRDMADNE);
502 if (!s->async->prealloc_buf) {
503 printk(KERN_ERR "async->data disappeared. dang!\n");
507 i = devpriv->current_dma_index;
508 ptr = devpriv->dma[i].buf;
509 size = devpriv->dma[i].size;
511 disable_dma(devpriv->dma[i].chan);
513 devpriv->current_dma_index = 1 - i;
515 dt282x_munge(dev, ptr, size);
516 ret = cfc_write_array_to_buffer(s, ptr, size);
518 dt282x_ai_cancel(dev, s);
521 devpriv->nread -= size / 2;
523 if (devpriv->nread < 0) {
524 printk(KERN_INFO "dt282x: off by one\n");
527 if (!devpriv->nread) {
528 dt282x_ai_cancel(dev, s);
529 s->async->events |= COMEDI_CB_EOA;
533 /* clear the dual dma flag, making this the last dma segment */
534 /* XXX probably wrong */
535 if (!devpriv->ntrig) {
536 devpriv->supcsr &= ~(DT2821_DDMA);
540 /* restart the channel */
541 prep_ai_dma(dev, i, 0);
544 static int prep_ai_dma(struct comedi_device *dev, int dma_index, int n)
547 unsigned long dma_ptr;
554 n = devpriv->dma_maxsize;
555 if (n > devpriv->ntrig * 2)
556 n = devpriv->ntrig * 2;
557 devpriv->ntrig -= n / 2;
559 devpriv->dma[dma_index].size = n;
560 dma_chan = devpriv->dma[dma_index].chan;
561 dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
563 set_dma_mode(dma_chan, DMA_MODE_READ);
564 flags = claim_dma_lock();
565 clear_dma_ff(dma_chan);
566 set_dma_addr(dma_chan, dma_ptr);
567 set_dma_count(dma_chan, n);
568 release_dma_lock(flags);
570 enable_dma(dma_chan);
575 static int prep_ao_dma(struct comedi_device *dev, int dma_index, int n)
578 unsigned long dma_ptr;
581 devpriv->dma[dma_index].size = n;
582 dma_chan = devpriv->dma[dma_index].chan;
583 dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
585 set_dma_mode(dma_chan, DMA_MODE_WRITE);
586 flags = claim_dma_lock();
587 clear_dma_ff(dma_chan);
588 set_dma_addr(dma_chan, dma_ptr);
589 set_dma_count(dma_chan, n);
590 release_dma_lock(flags);
592 enable_dma(dma_chan);
597 static irqreturn_t dt282x_interrupt(int irq, void *d)
599 struct comedi_device *dev = d;
600 struct comedi_subdevice *s;
601 struct comedi_subdevice *s_ao;
602 unsigned int supcsr, adcsr, dacsr;
605 if (!dev->attached) {
606 comedi_error(dev, "spurious interrupt");
610 s = dev->subdevices + 0;
611 s_ao = dev->subdevices + 1;
612 adcsr = inw(dev->iobase + DT2821_ADCSR);
613 dacsr = inw(dev->iobase + DT2821_DACSR);
614 supcsr = inw(dev->iobase + DT2821_SUPCSR);
615 if (supcsr & DT2821_DMAD) {
616 if (devpriv->dma_dir == DMA_MODE_READ)
617 dt282x_ai_dma_interrupt(dev);
619 dt282x_ao_dma_interrupt(dev);
622 if (adcsr & DT2821_ADERR) {
623 if (devpriv->nread != 0) {
624 comedi_error(dev, "A/D error");
625 dt282x_ai_cancel(dev, s);
626 s->async->events |= COMEDI_CB_ERROR;
630 if (dacsr & DT2821_DAERR) {
634 disable_irq(dev->irq);
635 printk(KERN_INFO "disabling irq\n");
638 comedi_error(dev, "D/A error");
639 dt282x_ao_cancel(dev, s_ao);
640 s->async->events |= COMEDI_CB_ERROR;
644 if (adcsr & DT2821_ADDONE) {
648 data = (short)inw(dev->iobase + DT2821_ADDAT);
649 data &= (1 << boardtype.adbits) - 1;
651 if (devpriv->ad_2scomp)
652 data ^= 1 << (boardtype.adbits - 1);
653 ret = comedi_buf_put(s->async, data);
656 s->async->events |= COMEDI_CB_OVERFLOW;
659 if (!devpriv->nread) {
660 s->async->events |= COMEDI_CB_EOA;
662 if (supcsr & DT2821_SCDN)
663 update_supcsr(DT2821_STRIG);
668 comedi_event(dev, s);
669 /* printk("adcsr=0x%02x dacsr-0x%02x supcsr=0x%02x\n",
670 adcsr, dacsr, supcsr); */
671 return IRQ_RETVAL(handled);
674 static void dt282x_load_changain(struct comedi_device *dev, int n,
675 unsigned int *chanlist)
678 unsigned int chan, range;
680 outw(DT2821_LLE | (n - 1), dev->iobase + DT2821_CHANCSR);
681 for (i = 0; i < n; i++) {
682 chan = CR_CHAN(chanlist[i]);
683 range = CR_RANGE(chanlist[i]);
684 update_adcsr((range << 4) | (chan));
686 outw(n - 1, dev->iobase + DT2821_CHANCSR);
690 * Performs a single A/D conversion.
691 * - Put channel/gain into channel-gain list
692 * - preload multiplexer
693 * - trigger conversion and wait for it to finish
695 static int dt282x_ai_insn_read(struct comedi_device *dev,
696 struct comedi_subdevice *s,
697 struct comedi_insn *insn, unsigned int *data)
701 /* XXX should we really be enabling the ad clock here? */
702 devpriv->adcsr = DT2821_ADCLK;
705 dt282x_load_changain(dev, 1, &insn->chanspec);
707 update_supcsr(DT2821_PRLD);
708 wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;);
710 for (i = 0; i < insn->n; i++) {
711 update_supcsr(DT2821_STRIG);
712 wait_for(ad_done(), comedi_error(dev, "timeout\n");
717 DT2821_ADDAT) & ((1 << boardtype.adbits) - 1);
718 if (devpriv->ad_2scomp)
719 data[i] ^= (1 << (boardtype.adbits - 1));
725 static int dt282x_ai_cmdtest(struct comedi_device *dev,
726 struct comedi_subdevice *s, struct comedi_cmd *cmd)
731 /* step 1: make sure trigger sources are trivially valid */
733 tmp = cmd->start_src;
734 cmd->start_src &= TRIG_NOW;
735 if (!cmd->start_src || tmp != cmd->start_src)
738 tmp = cmd->scan_begin_src;
739 cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_EXT;
740 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
743 tmp = cmd->convert_src;
744 cmd->convert_src &= TRIG_TIMER;
745 if (!cmd->convert_src || tmp != cmd->convert_src)
748 tmp = cmd->scan_end_src;
749 cmd->scan_end_src &= TRIG_COUNT;
750 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
754 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
755 if (!cmd->stop_src || tmp != cmd->stop_src)
762 * step 2: make sure trigger sources are unique
763 * and mutually compatible
766 /* note that mutual compatibility is not an issue here */
767 if (cmd->scan_begin_src != TRIG_FOLLOW &&
768 cmd->scan_begin_src != TRIG_EXT)
770 if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
776 /* step 3: make sure arguments are trivially compatible */
778 if (cmd->start_arg != 0) {
782 if (cmd->scan_begin_src == TRIG_FOLLOW) {
783 /* internal trigger */
784 if (cmd->scan_begin_arg != 0) {
785 cmd->scan_begin_arg = 0;
789 /* external trigger */
790 /* should be level/edge, hi/lo specification here */
791 if (cmd->scan_begin_arg != 0) {
792 cmd->scan_begin_arg = 0;
796 if (cmd->convert_arg < 4000) {
797 /* XXX board dependent */
798 cmd->convert_arg = 4000;
801 #define SLOWEST_TIMER (250*(1<<15)*255)
802 if (cmd->convert_arg > SLOWEST_TIMER) {
803 cmd->convert_arg = SLOWEST_TIMER;
806 if (cmd->convert_arg < this_board->ai_speed) {
807 cmd->convert_arg = this_board->ai_speed;
810 if (cmd->scan_end_arg != cmd->chanlist_len) {
811 cmd->scan_end_arg = cmd->chanlist_len;
814 if (cmd->stop_src == TRIG_COUNT) {
815 /* any count is allowed */
818 if (cmd->stop_arg != 0) {
827 /* step 4: fix up any arguments */
829 tmp = cmd->convert_arg;
830 dt282x_ns_to_timer(&cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK);
831 if (tmp != cmd->convert_arg)
840 static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
842 struct comedi_cmd *cmd = &s->async->cmd;
845 if (devpriv->usedma == 0) {
847 "driver requires 2 dma channels"
848 " to execute command");
852 dt282x_disable_dma(dev);
854 if (cmd->convert_arg < this_board->ai_speed)
855 cmd->convert_arg = this_board->ai_speed;
856 timer = dt282x_ns_to_timer(&cmd->convert_arg, TRIG_ROUND_NEAREST);
857 outw(timer, dev->iobase + DT2821_TMRCTR);
859 if (cmd->scan_begin_src == TRIG_FOLLOW) {
860 /* internal trigger */
861 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0;
863 /* external trigger */
864 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0 | DT2821_DS1;
866 update_supcsr(DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_ADCINIT);
868 devpriv->ntrig = cmd->stop_arg * cmd->scan_end_arg;
869 devpriv->nread = devpriv->ntrig;
871 devpriv->dma_dir = DMA_MODE_READ;
872 devpriv->current_dma_index = 0;
873 prep_ai_dma(dev, 0, 0);
874 if (devpriv->ntrig) {
875 prep_ai_dma(dev, 1, 0);
876 devpriv->supcsr |= DT2821_DDMA;
882 dt282x_load_changain(dev, cmd->chanlist_len, cmd->chanlist);
884 devpriv->adcsr = DT2821_ADCLK | DT2821_IADDONE;
887 update_supcsr(DT2821_PRLD);
888 wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;);
890 if (cmd->scan_begin_src == TRIG_FOLLOW) {
891 update_supcsr(DT2821_STRIG);
893 devpriv->supcsr |= DT2821_XTRIG;
900 static void dt282x_disable_dma(struct comedi_device *dev)
902 if (devpriv->usedma) {
903 disable_dma(devpriv->dma[0].chan);
904 disable_dma(devpriv->dma[1].chan);
908 static int dt282x_ai_cancel(struct comedi_device *dev,
909 struct comedi_subdevice *s)
911 dt282x_disable_dma(dev);
917 update_supcsr(DT2821_ADCINIT);
922 static int dt282x_ns_to_timer(int *nanosec, int round_mode)
924 int prescale, base, divider;
926 for (prescale = 0; prescale < 16; prescale++) {
929 base = 250 * (1 << prescale);
930 switch (round_mode) {
931 case TRIG_ROUND_NEAREST:
933 divider = (*nanosec + base / 2) / base;
935 case TRIG_ROUND_DOWN:
936 divider = (*nanosec) / base;
939 divider = (*nanosec + base - 1) / base;
943 *nanosec = divider * base;
944 return (prescale << 8) | (255 - divider);
947 base = 250 * (1 << 15);
949 *nanosec = divider * base;
950 return (15 << 8) | (255 - divider);
954 * Analog output routine. Selects single channel conversion,
955 * selects correct channel, converts from 2's compliment to
956 * offset binary if necessary, loads the data into the DAC
957 * data register, and performs the conversion.
959 static int dt282x_ao_insn_read(struct comedi_device *dev,
960 struct comedi_subdevice *s,
961 struct comedi_insn *insn, unsigned int *data)
963 data[0] = devpriv->ao[CR_CHAN(insn->chanspec)];
968 static int dt282x_ao_insn_write(struct comedi_device *dev,
969 struct comedi_subdevice *s,
970 struct comedi_insn *insn, unsigned int *data)
975 chan = CR_CHAN(insn->chanspec);
977 d &= (1 << boardtype.dabits) - 1;
978 devpriv->ao[chan] = d;
980 devpriv->dacsr |= DT2821_SSEL;
984 devpriv->dacsr |= DT2821_YSEL;
985 if (devpriv->da0_2scomp)
986 d ^= (1 << (boardtype.dabits - 1));
988 devpriv->dacsr &= ~DT2821_YSEL;
989 if (devpriv->da1_2scomp)
990 d ^= (1 << (boardtype.dabits - 1));
995 outw(d, dev->iobase + DT2821_DADAT);
997 update_supcsr(DT2821_DACON);
1002 static int dt282x_ao_cmdtest(struct comedi_device *dev,
1003 struct comedi_subdevice *s, struct comedi_cmd *cmd)
1008 /* step 1: make sure trigger sources are trivially valid */
1010 tmp = cmd->start_src;
1011 cmd->start_src &= TRIG_INT;
1012 if (!cmd->start_src || tmp != cmd->start_src)
1015 tmp = cmd->scan_begin_src;
1016 cmd->scan_begin_src &= TRIG_TIMER;
1017 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
1020 tmp = cmd->convert_src;
1021 cmd->convert_src &= TRIG_NOW;
1022 if (!cmd->convert_src || tmp != cmd->convert_src)
1025 tmp = cmd->scan_end_src;
1026 cmd->scan_end_src &= TRIG_COUNT;
1027 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
1030 tmp = cmd->stop_src;
1031 cmd->stop_src &= TRIG_NONE;
1032 if (!cmd->stop_src || tmp != cmd->stop_src)
1039 * step 2: make sure trigger sources are unique
1040 * and mutually compatible
1043 /* note that mutual compatibility is not an issue here */
1044 if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
1050 /* step 3: make sure arguments are trivially compatible */
1052 if (cmd->start_arg != 0) {
1056 if (cmd->scan_begin_arg < 5000 /* XXX unknown */) {
1057 cmd->scan_begin_arg = 5000;
1060 if (cmd->convert_arg != 0) {
1061 cmd->convert_arg = 0;
1064 if (cmd->scan_end_arg > 2) {
1065 /* XXX chanlist stuff? */
1066 cmd->scan_end_arg = 2;
1069 if (cmd->stop_src == TRIG_COUNT) {
1070 /* any count is allowed */
1073 if (cmd->stop_arg != 0) {
1082 /* step 4: fix up any arguments */
1084 tmp = cmd->scan_begin_arg;
1085 dt282x_ns_to_timer(&cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK);
1086 if (tmp != cmd->scan_begin_arg)
1096 static int dt282x_ao_inttrig(struct comedi_device *dev,
1097 struct comedi_subdevice *s, unsigned int x)
1104 size = cfc_read_array_from_buffer(s, devpriv->dma[0].buf,
1105 devpriv->dma_maxsize);
1107 printk(KERN_ERR "dt282x: AO underrun\n");
1110 prep_ao_dma(dev, 0, size);
1112 size = cfc_read_array_from_buffer(s, devpriv->dma[1].buf,
1113 devpriv->dma_maxsize);
1115 printk(KERN_ERR "dt282x: AO underrun\n");
1118 prep_ao_dma(dev, 1, size);
1120 update_supcsr(DT2821_STRIG);
1121 s->async->inttrig = NULL;
1126 static int dt282x_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1129 struct comedi_cmd *cmd = &s->async->cmd;
1131 if (devpriv->usedma == 0) {
1133 "driver requires 2 dma channels"
1134 " to execute command");
1138 dt282x_disable_dma(dev);
1140 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS1 | DT2821_DDMA;
1141 update_supcsr(DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_DACINIT);
1143 devpriv->ntrig = cmd->stop_arg * cmd->chanlist_len;
1144 devpriv->nread = devpriv->ntrig;
1146 devpriv->dma_dir = DMA_MODE_WRITE;
1147 devpriv->current_dma_index = 0;
1149 timer = dt282x_ns_to_timer(&cmd->scan_begin_arg, TRIG_ROUND_NEAREST);
1150 outw(timer, dev->iobase + DT2821_TMRCTR);
1152 devpriv->dacsr = DT2821_SSEL | DT2821_DACLK | DT2821_IDARDY;
1155 s->async->inttrig = dt282x_ao_inttrig;
1160 static int dt282x_ao_cancel(struct comedi_device *dev,
1161 struct comedi_subdevice *s)
1163 dt282x_disable_dma(dev);
1168 devpriv->supcsr = 0;
1169 update_supcsr(DT2821_DACINIT);
1174 static int dt282x_dio_insn_bits(struct comedi_device *dev,
1175 struct comedi_subdevice *s,
1176 struct comedi_insn *insn, unsigned int *data)
1179 s->state &= ~data[0];
1180 s->state |= (data[0] & data[1]);
1182 outw(s->state, dev->iobase + DT2821_DIODAT);
1184 data[1] = inw(dev->iobase + DT2821_DIODAT);
1189 static int dt282x_dio_insn_config(struct comedi_device *dev,
1190 struct comedi_subdevice *s,
1191 struct comedi_insn *insn, unsigned int *data)
1195 mask = (CR_CHAN(insn->chanspec) < 8) ? 0x00ff : 0xff00;
1199 s->io_bits &= ~mask;
1201 if (s->io_bits & 0x00ff)
1202 devpriv->dacsr |= DT2821_LBOE;
1204 devpriv->dacsr &= ~DT2821_LBOE;
1205 if (s->io_bits & 0xff00)
1206 devpriv->dacsr |= DT2821_HBOE;
1208 devpriv->dacsr &= ~DT2821_HBOE;
1210 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
1215 static const struct comedi_lrange *const ai_range_table[] = {
1216 &range_dt282x_ai_lo_bipolar,
1217 &range_dt282x_ai_lo_unipolar,
1218 &range_dt282x_ai_5_bipolar,
1219 &range_dt282x_ai_5_unipolar
1222 static const struct comedi_lrange *const ai_range_pgl_table[] = {
1223 &range_dt282x_ai_hi_bipolar,
1224 &range_dt282x_ai_hi_unipolar
1227 static const struct comedi_lrange *opt_ai_range_lkup(int ispgl, int x)
1230 if (x < 0 || x >= 2)
1232 return ai_range_pgl_table[x];
1234 if (x < 0 || x >= 4)
1236 return ai_range_table[x];
1240 static const struct comedi_lrange *const ao_range_table[] = {
1248 static const struct comedi_lrange *opt_ao_range_lkup(int x)
1250 if (x < 0 || x >= 5)
1252 return ao_range_table[x];
1255 enum { /* i/o base, irq, dma channels */
1256 opt_iobase = 0, opt_irq, opt_dma1, opt_dma2,
1257 opt_diff, /* differential */
1258 opt_ai_twos, opt_ao0_twos, opt_ao1_twos, /* twos comp */
1259 opt_ai_range, opt_ao0_range, opt_ao1_range, /* range */
1268 4 0=single ended, 1=differential
1269 5 ai 0=straight binary, 1=2's comp
1270 6 ao0 0=straight binary, 1=2's comp
1271 7 ao1 0=straight binary, 1=2's comp
1272 8 ai 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V
1273 9 ao0 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1274 10 ao1 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1276 static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1280 struct comedi_subdevice *s;
1281 unsigned long iobase;
1283 dev->board_name = this_board->name;
1285 iobase = it->options[opt_iobase];
1289 printk(KERN_INFO "comedi%d: dt282x: 0x%04lx", dev->minor, iobase);
1290 if (!request_region(iobase, DT2821_SIZE, "dt282x")) {
1291 printk(KERN_INFO " I/O port conflict\n");
1294 dev->iobase = iobase;
1296 outw(DT2821_BDINIT, dev->iobase + DT2821_SUPCSR);
1297 i = inw(dev->iobase + DT2821_ADCSR);
1299 printk(KERN_DEBUG " fingerprint=%x,%x,%x,%x,%x",
1300 inw(dev->iobase + DT2821_ADCSR),
1301 inw(dev->iobase + DT2821_CHANCSR),
1302 inw(dev->iobase + DT2821_DACSR),
1303 inw(dev->iobase + DT2821_SUPCSR),
1304 inw(dev->iobase + DT2821_TMRCTR));
1307 if (((inw(dev->iobase + DT2821_ADCSR) & DT2821_ADCSR_MASK)
1308 != DT2821_ADCSR_VAL) ||
1309 ((inw(dev->iobase + DT2821_CHANCSR) & DT2821_CHANCSR_MASK)
1310 != DT2821_CHANCSR_VAL) ||
1311 ((inw(dev->iobase + DT2821_DACSR) & DT2821_DACSR_MASK)
1312 != DT2821_DACSR_VAL) ||
1313 ((inw(dev->iobase + DT2821_SUPCSR) & DT2821_SUPCSR_MASK)
1314 != DT2821_SUPCSR_VAL) ||
1315 ((inw(dev->iobase + DT2821_TMRCTR) & DT2821_TMRCTR_MASK)
1316 != DT2821_TMRCTR_VAL)) {
1317 printk(KERN_ERR " board not found");
1320 /* should do board test */
1322 irq = it->options[opt_irq];
1325 unsigned long flags;
1330 irqs = probe_irq_on();
1332 /* trigger interrupt */
1336 irq = probe_irq_off(irqs);
1337 restore_flags(flags);
1339 printk(KERN_ERR " error probing irq (bad)");
1343 printk(KERN_INFO " ( irq = %d )", irq);
1344 ret = request_irq(irq, dt282x_interrupt, 0, "dt282x", dev);
1346 printk(KERN_ERR " failed to get irq\n");
1350 } else if (irq == 0) {
1351 printk(KERN_INFO " (no irq)");
1354 printk(KERN_INFO " (probe returned multiple irqs--bad)");
1356 printk(KERN_INFO " (irq probe not implemented)");
1360 ret = alloc_private(dev, sizeof(struct dt282x_private));
1364 ret = dt282x_grab_dma(dev, it->options[opt_dma1],
1365 it->options[opt_dma2]);
1369 ret = alloc_subdevices(dev, 3);
1373 s = dev->subdevices + 0;
1375 dev->read_subdev = s;
1377 s->type = COMEDI_SUBD_AI;
1378 s->subdev_flags = SDF_READABLE | SDF_CMD_READ |
1379 ((it->options[opt_diff]) ? SDF_DIFF : SDF_COMMON);
1381 (it->options[opt_diff]) ? boardtype.adchan_di : boardtype.adchan_se;
1382 s->insn_read = dt282x_ai_insn_read;
1383 s->do_cmdtest = dt282x_ai_cmdtest;
1384 s->do_cmd = dt282x_ai_cmd;
1385 s->cancel = dt282x_ai_cancel;
1386 s->maxdata = (1 << boardtype.adbits) - 1;
1387 s->len_chanlist = 16;
1389 opt_ai_range_lkup(boardtype.ispgl, it->options[opt_ai_range]);
1390 devpriv->ad_2scomp = it->options[opt_ai_twos];
1394 s->n_chan = boardtype.dachan;
1397 s->type = COMEDI_SUBD_AO;
1398 dev->write_subdev = s;
1399 s->subdev_flags = SDF_WRITABLE | SDF_CMD_WRITE;
1400 s->insn_read = dt282x_ao_insn_read;
1401 s->insn_write = dt282x_ao_insn_write;
1402 s->do_cmdtest = dt282x_ao_cmdtest;
1403 s->do_cmd = dt282x_ao_cmd;
1404 s->cancel = dt282x_ao_cancel;
1405 s->maxdata = (1 << boardtype.dabits) - 1;
1406 s->len_chanlist = 2;
1407 s->range_table_list = devpriv->darangelist;
1408 devpriv->darangelist[0] =
1409 opt_ao_range_lkup(it->options[opt_ao0_range]);
1410 devpriv->darangelist[1] =
1411 opt_ao_range_lkup(it->options[opt_ao1_range]);
1412 devpriv->da0_2scomp = it->options[opt_ao0_twos];
1413 devpriv->da1_2scomp = it->options[opt_ao1_twos];
1415 s->type = COMEDI_SUBD_UNUSED;
1420 s->type = COMEDI_SUBD_DIO;
1421 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1423 s->insn_bits = dt282x_dio_insn_bits;
1424 s->insn_config = dt282x_dio_insn_config;
1426 s->range_table = &range_digital;
1428 printk(KERN_INFO "\n");
1433 static void free_resources(struct comedi_device *dev)
1436 free_irq(dev->irq, dev);
1438 release_region(dev->iobase, DT2821_SIZE);
1440 if (devpriv->dma[0].chan)
1441 free_dma(devpriv->dma[0].chan);
1442 if (devpriv->dma[1].chan)
1443 free_dma(devpriv->dma[1].chan);
1444 if (devpriv->dma[0].buf)
1445 free_page((unsigned long)devpriv->dma[0].buf);
1446 if (devpriv->dma[1].buf)
1447 free_page((unsigned long)devpriv->dma[1].buf);
1451 static int dt282x_detach(struct comedi_device *dev)
1453 printk(KERN_INFO "comedi%d: dt282x: remove\n", dev->minor);
1455 free_resources(dev);
1460 static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2)
1464 devpriv->usedma = 0;
1466 if (!dma1 && !dma2) {
1467 printk(KERN_ERR " (no dma)");
1471 if (dma1 == dma2 || dma1 < 5 || dma2 < 5 || dma1 > 7 || dma2 > 7)
1481 ret = request_dma(dma1, "dt282x A");
1484 devpriv->dma[0].chan = dma1;
1486 ret = request_dma(dma2, "dt282x B");
1489 devpriv->dma[1].chan = dma2;
1491 devpriv->dma_maxsize = PAGE_SIZE;
1492 devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
1493 devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
1494 if (!devpriv->dma[0].buf || !devpriv->dma[1].buf) {
1495 printk(KERN_ERR " can't get DMA memory");
1499 printk(KERN_INFO " (dma=%d,%d)", dma1, dma2);
1501 devpriv->usedma = 1;