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 = { 4, {
171 static const struct comedi_lrange range_dt282x_ai_lo_unipolar = { 4, {
183 static const struct comedi_lrange range_dt282x_ai_5_bipolar = { 4, {
196 static const struct comedi_lrange range_dt282x_ai_5_unipolar = { 4, {
208 static const struct comedi_lrange range_dt282x_ai_hi_bipolar = { 4, {
221 static const struct comedi_lrange range_dt282x_ai_hi_unipolar = { 4, {
233 struct dt282x_board {
244 static const struct dt282x_board boardtypes[] = {
281 {.name = "dt2824-pgh",
290 {.name = "dt2824-pgl",
362 {.name = "dt24-ez-pgl",
373 #define n_boardtypes sizeof(boardtypes)/sizeof(struct dt282x_board)
374 #define this_board ((const struct dt282x_board *)dev->board_ptr)
376 struct dt282x_private {
377 int ad_2scomp; /* we have 2's comp jumper set */
378 int da0_2scomp; /* same, for DAC0 */
379 int da1_2scomp; /* same, for DAC1 */
381 const struct comedi_lrange *darangelist[2];
385 volatile int dacsr; /* software copies of registers */
394 short *buf; /* DMA buffer */
395 volatile int size; /* size of current transfer */
397 int dma_maxsize; /* max size of DMA transfer (in bytes) */
398 int usedma; /* driver uses DMA */
399 volatile int current_dma_index;
403 #define devpriv ((struct dt282x_private *)dev->private)
404 #define boardtype (*(const struct dt282x_board *)dev->board_ptr)
407 * Some useless abstractions
409 #define chan_to_DAC(a) ((a)&1)
410 #define update_dacsr(a) outw(devpriv->dacsr|(a), dev->iobase+DT2821_DACSR)
411 #define update_adcsr(a) outw(devpriv->adcsr|(a), dev->iobase+DT2821_ADCSR)
412 #define mux_busy() (inw(dev->iobase+DT2821_ADCSR)&DT2821_MUXBUSY)
413 #define ad_done() (inw(dev->iobase+DT2821_ADCSR)&DT2821_ADDONE)
414 #define update_supcsr(a) outw(devpriv->supcsr|(a), dev->iobase+DT2821_SUPCSR)
417 * danger! macro abuse... a is the expression to wait on, and b is
418 * the statement(s) to execute if it doesn't happen.
420 #define wait_for(a, b) \
423 for (_i=0;_i<DT2821_TIMEOUT;_i++){ \
424 if (a){_i=0;break;} \
430 static int dt282x_attach(struct comedi_device *dev,
431 struct comedi_devconfig *it);
432 static int dt282x_detach(struct comedi_device *dev);
433 static struct comedi_driver driver_dt282x = {
434 .driver_name = "dt282x",
435 .module = THIS_MODULE,
436 .attach = dt282x_attach,
437 .detach = dt282x_detach,
438 .board_name = &boardtypes[0].name,
439 .num_names = n_boardtypes,
440 .offset = sizeof(struct dt282x_board),
443 COMEDI_INITCLEANUP(driver_dt282x);
445 static void free_resources(struct comedi_device *dev);
446 static int prep_ai_dma(struct comedi_device *dev, int chan, int size);
447 static int prep_ao_dma(struct comedi_device *dev, int chan, int size);
448 static int dt282x_ai_cancel(struct comedi_device *dev,
449 struct comedi_subdevice *s);
450 static int dt282x_ao_cancel(struct comedi_device *dev,
451 struct comedi_subdevice *s);
452 static int dt282x_ns_to_timer(int *nanosec, int round_mode);
453 static void dt282x_disable_dma(struct comedi_device *dev);
455 static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2);
457 static void dt282x_munge(struct comedi_device *dev, short *buf,
461 unsigned short mask = (1 << boardtype.adbits) - 1;
462 unsigned short sign = 1 << (boardtype.adbits - 1);
465 if (devpriv->ad_2scomp) {
466 sign = 1 << (boardtype.adbits - 1);
472 comedi_error(dev, "bug! odd number of bytes from dma xfer");
474 for (i = 0; i < n; i++) {
475 buf[i] = (buf[i] & mask) ^ sign;
479 static void dt282x_ao_dma_interrupt(struct comedi_device *dev)
484 struct comedi_subdevice *s = dev->subdevices + 1;
486 update_supcsr(DT2821_CLRDMADNE);
488 if (!s->async->prealloc_buf) {
489 printk("async->data disappeared. dang!\n");
493 i = devpriv->current_dma_index;
494 ptr = devpriv->dma[i].buf;
496 disable_dma(devpriv->dma[i].chan);
498 devpriv->current_dma_index = 1 - i;
500 size = cfc_read_array_from_buffer(s, ptr, devpriv->dma_maxsize);
502 printk("dt282x: AO underrun\n");
503 dt282x_ao_cancel(dev, s);
504 s->async->events |= COMEDI_CB_OVERFLOW;
507 prep_ao_dma(dev, i, size);
511 static void dt282x_ai_dma_interrupt(struct comedi_device *dev)
517 struct comedi_subdevice *s = dev->subdevices;
519 update_supcsr(DT2821_CLRDMADNE);
521 if (!s->async->prealloc_buf) {
522 printk("async->data disappeared. dang!\n");
526 i = devpriv->current_dma_index;
527 ptr = devpriv->dma[i].buf;
528 size = devpriv->dma[i].size;
530 disable_dma(devpriv->dma[i].chan);
532 devpriv->current_dma_index = 1 - i;
534 dt282x_munge(dev, ptr, size);
535 ret = cfc_write_array_to_buffer(s, ptr, size);
537 dt282x_ai_cancel(dev, s);
540 devpriv->nread -= size / 2;
542 if (devpriv->nread < 0) {
543 printk("dt282x: off by one\n");
546 if (!devpriv->nread) {
547 dt282x_ai_cancel(dev, s);
548 s->async->events |= COMEDI_CB_EOA;
552 /* clear the dual dma flag, making this the last dma segment */
553 /* XXX probably wrong */
554 if (!devpriv->ntrig) {
555 devpriv->supcsr &= ~(DT2821_DDMA);
559 /* restart the channel */
560 prep_ai_dma(dev, i, 0);
563 static int prep_ai_dma(struct comedi_device *dev, int dma_index, int n)
566 unsigned long dma_ptr;
573 n = devpriv->dma_maxsize;
574 if (n > devpriv->ntrig * 2)
575 n = devpriv->ntrig * 2;
576 devpriv->ntrig -= n / 2;
578 devpriv->dma[dma_index].size = n;
579 dma_chan = devpriv->dma[dma_index].chan;
580 dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
582 set_dma_mode(dma_chan, DMA_MODE_READ);
583 flags = claim_dma_lock();
584 clear_dma_ff(dma_chan);
585 set_dma_addr(dma_chan, dma_ptr);
586 set_dma_count(dma_chan, n);
587 release_dma_lock(flags);
589 enable_dma(dma_chan);
594 static int prep_ao_dma(struct comedi_device *dev, int dma_index, int n)
597 unsigned long dma_ptr;
600 devpriv->dma[dma_index].size = n;
601 dma_chan = devpriv->dma[dma_index].chan;
602 dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
604 set_dma_mode(dma_chan, DMA_MODE_WRITE);
605 flags = claim_dma_lock();
606 clear_dma_ff(dma_chan);
607 set_dma_addr(dma_chan, dma_ptr);
608 set_dma_count(dma_chan, n);
609 release_dma_lock(flags);
611 enable_dma(dma_chan);
616 static irqreturn_t dt282x_interrupt(int irq, void *d)
618 struct comedi_device *dev = d;
619 struct comedi_subdevice *s;
620 struct comedi_subdevice *s_ao;
621 unsigned int supcsr, adcsr, dacsr;
624 if (!dev->attached) {
625 comedi_error(dev, "spurious interrupt");
629 s = dev->subdevices + 0;
630 s_ao = dev->subdevices + 1;
631 adcsr = inw(dev->iobase + DT2821_ADCSR);
632 dacsr = inw(dev->iobase + DT2821_DACSR);
633 supcsr = inw(dev->iobase + DT2821_SUPCSR);
634 if (supcsr & DT2821_DMAD) {
635 if (devpriv->dma_dir == DMA_MODE_READ)
636 dt282x_ai_dma_interrupt(dev);
638 dt282x_ao_dma_interrupt(dev);
641 if (adcsr & DT2821_ADERR) {
642 if (devpriv->nread != 0) {
643 comedi_error(dev, "A/D error");
644 dt282x_ai_cancel(dev, s);
645 s->async->events |= COMEDI_CB_ERROR;
649 if (dacsr & DT2821_DAERR) {
653 disable_irq(dev->irq);
654 printk("disabling irq\n");
657 comedi_error(dev, "D/A error");
658 dt282x_ao_cancel(dev, s_ao);
659 s->async->events |= COMEDI_CB_ERROR;
663 if (adcsr & DT2821_ADDONE) {
667 data = (short)inw(dev->iobase + DT2821_ADDAT);
668 data &= (1 << boardtype.adbits) - 1;
669 if (devpriv->ad_2scomp) {
670 data ^= 1 << (boardtype.adbits - 1);
672 ret = comedi_buf_put(s->async, data);
674 s->async->events |= COMEDI_CB_OVERFLOW;
678 if (!devpriv->nread) {
679 s->async->events |= COMEDI_CB_EOA;
681 if (supcsr & DT2821_SCDN)
682 update_supcsr(DT2821_STRIG);
687 comedi_event(dev, s);
688 /* printk("adcsr=0x%02x dacsr-0x%02x supcsr=0x%02x\n", adcsr, dacsr, supcsr); */
689 return IRQ_RETVAL(handled);
692 static void dt282x_load_changain(struct comedi_device *dev, int n,
693 unsigned int *chanlist)
696 unsigned int chan, range;
698 outw(DT2821_LLE | (n - 1), dev->iobase + DT2821_CHANCSR);
699 for (i = 0; i < n; i++) {
700 chan = CR_CHAN(chanlist[i]);
701 range = CR_RANGE(chanlist[i]);
702 update_adcsr((range << 4) | (chan));
704 outw(n - 1, dev->iobase + DT2821_CHANCSR);
708 * Performs a single A/D conversion.
709 * - Put channel/gain into channel-gain list
710 * - preload multiplexer
711 * - trigger conversion and wait for it to finish
713 static int dt282x_ai_insn_read(struct comedi_device *dev,
714 struct comedi_subdevice *s,
715 struct comedi_insn *insn, unsigned int *data)
719 /* XXX should we really be enabling the ad clock here? */
720 devpriv->adcsr = DT2821_ADCLK;
723 dt282x_load_changain(dev, 1, &insn->chanspec);
725 update_supcsr(DT2821_PRLD);
726 wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;);
728 for (i = 0; i < insn->n; i++) {
729 update_supcsr(DT2821_STRIG);
730 wait_for(ad_done(), comedi_error(dev, "timeout\n");
735 DT2821_ADDAT) & ((1 << boardtype.adbits) - 1);
736 if (devpriv->ad_2scomp)
737 data[i] ^= (1 << (boardtype.adbits - 1));
743 static int dt282x_ai_cmdtest(struct comedi_device *dev,
744 struct comedi_subdevice *s, struct comedi_cmd *cmd)
749 /* step 1: make sure trigger sources are trivially valid */
751 tmp = cmd->start_src;
752 cmd->start_src &= TRIG_NOW;
753 if (!cmd->start_src || tmp != cmd->start_src)
756 tmp = cmd->scan_begin_src;
757 cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_EXT;
758 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
761 tmp = cmd->convert_src;
762 cmd->convert_src &= TRIG_TIMER;
763 if (!cmd->convert_src || tmp != cmd->convert_src)
766 tmp = cmd->scan_end_src;
767 cmd->scan_end_src &= TRIG_COUNT;
768 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
772 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
773 if (!cmd->stop_src || tmp != cmd->stop_src)
779 /* step 2: make sure trigger sources are unique and mutually compatible */
781 /* note that mutual compatibility is not an issue here */
782 if (cmd->scan_begin_src != TRIG_FOLLOW &&
783 cmd->scan_begin_src != TRIG_EXT)
785 if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
791 /* step 3: make sure arguments are trivially compatible */
793 if (cmd->start_arg != 0) {
797 if (cmd->scan_begin_src == TRIG_FOLLOW) {
798 /* internal trigger */
799 if (cmd->scan_begin_arg != 0) {
800 cmd->scan_begin_arg = 0;
804 /* external trigger */
805 /* should be level/edge, hi/lo specification here */
806 if (cmd->scan_begin_arg != 0) {
807 cmd->scan_begin_arg = 0;
811 if (cmd->convert_arg < 4000) {
812 /* XXX board dependent */
813 cmd->convert_arg = 4000;
816 #define SLOWEST_TIMER (250*(1<<15)*255)
817 if (cmd->convert_arg > SLOWEST_TIMER) {
818 cmd->convert_arg = SLOWEST_TIMER;
821 if (cmd->convert_arg < this_board->ai_speed) {
822 cmd->convert_arg = this_board->ai_speed;
825 if (cmd->scan_end_arg != cmd->chanlist_len) {
826 cmd->scan_end_arg = cmd->chanlist_len;
829 if (cmd->stop_src == TRIG_COUNT) {
830 /* any count is allowed */
833 if (cmd->stop_arg != 0) {
842 /* step 4: fix up any arguments */
844 tmp = cmd->convert_arg;
845 dt282x_ns_to_timer(&cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK);
846 if (tmp != cmd->convert_arg)
855 static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
857 struct comedi_cmd *cmd = &s->async->cmd;
860 if (devpriv->usedma == 0) {
862 "driver requires 2 dma channels to execute command");
866 dt282x_disable_dma(dev);
868 if (cmd->convert_arg < this_board->ai_speed)
869 cmd->convert_arg = this_board->ai_speed;
870 timer = dt282x_ns_to_timer(&cmd->convert_arg, TRIG_ROUND_NEAREST);
871 outw(timer, dev->iobase + DT2821_TMRCTR);
873 if (cmd->scan_begin_src == TRIG_FOLLOW) {
874 /* internal trigger */
875 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0;
877 /* external trigger */
878 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0 | DT2821_DS1;
880 update_supcsr(DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_ADCINIT);
882 devpriv->ntrig = cmd->stop_arg * cmd->scan_end_arg;
883 devpriv->nread = devpriv->ntrig;
885 devpriv->dma_dir = DMA_MODE_READ;
886 devpriv->current_dma_index = 0;
887 prep_ai_dma(dev, 0, 0);
888 if (devpriv->ntrig) {
889 prep_ai_dma(dev, 1, 0);
890 devpriv->supcsr |= DT2821_DDMA;
896 dt282x_load_changain(dev, cmd->chanlist_len, cmd->chanlist);
898 devpriv->adcsr = DT2821_ADCLK | DT2821_IADDONE;
901 update_supcsr(DT2821_PRLD);
902 wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;);
904 if (cmd->scan_begin_src == TRIG_FOLLOW) {
905 update_supcsr(DT2821_STRIG);
907 devpriv->supcsr |= DT2821_XTRIG;
914 static void dt282x_disable_dma(struct comedi_device *dev)
916 if (devpriv->usedma) {
917 disable_dma(devpriv->dma[0].chan);
918 disable_dma(devpriv->dma[1].chan);
922 static int dt282x_ai_cancel(struct comedi_device *dev,
923 struct comedi_subdevice *s)
925 dt282x_disable_dma(dev);
931 update_supcsr(DT2821_ADCINIT);
936 static int dt282x_ns_to_timer(int *nanosec, int round_mode)
938 int prescale, base, divider;
940 for (prescale = 0; prescale < 16; prescale++) {
943 base = 250 * (1 << prescale);
944 switch (round_mode) {
945 case TRIG_ROUND_NEAREST:
947 divider = (*nanosec + base / 2) / base;
949 case TRIG_ROUND_DOWN:
950 divider = (*nanosec) / base;
953 divider = (*nanosec + base - 1) / base;
957 *nanosec = divider * base;
958 return (prescale << 8) | (255 - divider);
961 base = 250 * (1 << 15);
963 *nanosec = divider * base;
964 return (15 << 8) | (255 - divider);
968 * Analog output routine. Selects single channel conversion,
969 * selects correct channel, converts from 2's compliment to
970 * offset binary if necessary, loads the data into the DAC
971 * data register, and performs the conversion.
973 static int dt282x_ao_insn_read(struct comedi_device *dev,
974 struct comedi_subdevice *s,
975 struct comedi_insn *insn, unsigned int *data)
977 data[0] = devpriv->ao[CR_CHAN(insn->chanspec)];
982 static int dt282x_ao_insn_write(struct comedi_device *dev,
983 struct comedi_subdevice *s,
984 struct comedi_insn *insn, unsigned int *data)
989 chan = CR_CHAN(insn->chanspec);
991 d &= (1 << boardtype.dabits) - 1;
992 devpriv->ao[chan] = d;
994 devpriv->dacsr |= DT2821_SSEL;
998 devpriv->dacsr |= DT2821_YSEL;
999 if (devpriv->da0_2scomp)
1000 d ^= (1 << (boardtype.dabits - 1));
1002 devpriv->dacsr &= ~DT2821_YSEL;
1003 if (devpriv->da1_2scomp)
1004 d ^= (1 << (boardtype.dabits - 1));
1009 outw(d, dev->iobase + DT2821_DADAT);
1011 update_supcsr(DT2821_DACON);
1016 static int dt282x_ao_cmdtest(struct comedi_device *dev,
1017 struct comedi_subdevice *s, struct comedi_cmd *cmd)
1022 /* step 1: make sure trigger sources are trivially valid */
1024 tmp = cmd->start_src;
1025 cmd->start_src &= TRIG_INT;
1026 if (!cmd->start_src || tmp != cmd->start_src)
1029 tmp = cmd->scan_begin_src;
1030 cmd->scan_begin_src &= TRIG_TIMER;
1031 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
1034 tmp = cmd->convert_src;
1035 cmd->convert_src &= TRIG_NOW;
1036 if (!cmd->convert_src || tmp != cmd->convert_src)
1039 tmp = cmd->scan_end_src;
1040 cmd->scan_end_src &= TRIG_COUNT;
1041 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
1044 tmp = cmd->stop_src;
1045 cmd->stop_src &= TRIG_NONE;
1046 if (!cmd->stop_src || tmp != cmd->stop_src)
1052 /* step 2: make sure trigger sources are unique and mutually compatible */
1054 /* note that mutual compatibility is not an issue here */
1055 if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
1061 /* step 3: make sure arguments are trivially compatible */
1063 if (cmd->start_arg != 0) {
1067 if (cmd->scan_begin_arg < 5000 /* XXX unknown */ ) {
1068 cmd->scan_begin_arg = 5000;
1071 if (cmd->convert_arg != 0) {
1072 cmd->convert_arg = 0;
1075 if (cmd->scan_end_arg > 2) {
1076 /* XXX chanlist stuff? */
1077 cmd->scan_end_arg = 2;
1080 if (cmd->stop_src == TRIG_COUNT) {
1081 /* any count is allowed */
1084 if (cmd->stop_arg != 0) {
1093 /* step 4: fix up any arguments */
1095 tmp = cmd->scan_begin_arg;
1096 dt282x_ns_to_timer(&cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK);
1097 if (tmp != cmd->scan_begin_arg)
1107 static int dt282x_ao_inttrig(struct comedi_device *dev,
1108 struct comedi_subdevice *s, unsigned int x)
1115 size = cfc_read_array_from_buffer(s, devpriv->dma[0].buf,
1116 devpriv->dma_maxsize);
1118 printk("dt282x: AO underrun\n");
1121 prep_ao_dma(dev, 0, size);
1123 size = cfc_read_array_from_buffer(s, devpriv->dma[1].buf,
1124 devpriv->dma_maxsize);
1126 printk("dt282x: AO underrun\n");
1129 prep_ao_dma(dev, 1, size);
1131 update_supcsr(DT2821_STRIG);
1132 s->async->inttrig = NULL;
1137 static int dt282x_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1140 struct comedi_cmd *cmd = &s->async->cmd;
1142 if (devpriv->usedma == 0) {
1144 "driver requires 2 dma channels to execute command");
1148 dt282x_disable_dma(dev);
1150 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS1 | DT2821_DDMA;
1151 update_supcsr(DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_DACINIT);
1153 devpriv->ntrig = cmd->stop_arg * cmd->chanlist_len;
1154 devpriv->nread = devpriv->ntrig;
1156 devpriv->dma_dir = DMA_MODE_WRITE;
1157 devpriv->current_dma_index = 0;
1159 timer = dt282x_ns_to_timer(&cmd->scan_begin_arg, TRIG_ROUND_NEAREST);
1160 outw(timer, dev->iobase + DT2821_TMRCTR);
1162 devpriv->dacsr = DT2821_SSEL | DT2821_DACLK | DT2821_IDARDY;
1165 s->async->inttrig = dt282x_ao_inttrig;
1170 static int dt282x_ao_cancel(struct comedi_device *dev,
1171 struct comedi_subdevice *s)
1173 dt282x_disable_dma(dev);
1178 devpriv->supcsr = 0;
1179 update_supcsr(DT2821_DACINIT);
1184 static int dt282x_dio_insn_bits(struct comedi_device *dev,
1185 struct comedi_subdevice *s,
1186 struct comedi_insn *insn, unsigned int *data)
1189 s->state &= ~data[0];
1190 s->state |= (data[0] & data[1]);
1192 outw(s->state, dev->iobase + DT2821_DIODAT);
1194 data[1] = inw(dev->iobase + DT2821_DIODAT);
1199 static int dt282x_dio_insn_config(struct comedi_device *dev,
1200 struct comedi_subdevice *s,
1201 struct comedi_insn *insn, unsigned int *data)
1205 mask = (CR_CHAN(insn->chanspec) < 8) ? 0x00ff : 0xff00;
1209 s->io_bits &= ~mask;
1211 if (s->io_bits & 0x00ff)
1212 devpriv->dacsr |= DT2821_LBOE;
1214 devpriv->dacsr &= ~DT2821_LBOE;
1215 if (s->io_bits & 0xff00)
1216 devpriv->dacsr |= DT2821_HBOE;
1218 devpriv->dacsr &= ~DT2821_HBOE;
1220 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
1225 static const struct comedi_lrange *const ai_range_table[] = {
1226 &range_dt282x_ai_lo_bipolar,
1227 &range_dt282x_ai_lo_unipolar,
1228 &range_dt282x_ai_5_bipolar,
1229 &range_dt282x_ai_5_unipolar
1232 static const struct comedi_lrange *const ai_range_pgl_table[] = {
1233 &range_dt282x_ai_hi_bipolar,
1234 &range_dt282x_ai_hi_unipolar
1237 static const struct comedi_lrange *opt_ai_range_lkup(int ispgl, int x)
1240 if (x < 0 || x >= 2)
1242 return ai_range_pgl_table[x];
1244 if (x < 0 || x >= 4)
1246 return ai_range_table[x];
1250 static const struct comedi_lrange *const ao_range_table[] = {
1258 static const struct comedi_lrange *opt_ao_range_lkup(int x)
1260 if (x < 0 || x >= 5)
1262 return ao_range_table[x];
1265 enum { opt_iobase = 0, opt_irq, opt_dma1, opt_dma2, /* i/o base, irq, dma channels */
1266 opt_diff, /* differential */
1267 opt_ai_twos, opt_ao0_twos, opt_ao1_twos, /* twos comp */
1268 opt_ai_range, opt_ao0_range, opt_ao1_range, /* range */
1277 4 0=single ended, 1=differential
1278 5 ai 0=straight binary, 1=2's comp
1279 6 ao0 0=straight binary, 1=2's comp
1280 7 ao1 0=straight binary, 1=2's comp
1281 8 ai 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V
1282 9 ao0 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1283 10 ao1 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1285 static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1289 struct comedi_subdevice *s;
1290 unsigned long iobase;
1292 dev->board_name = this_board->name;
1294 iobase = it->options[opt_iobase];
1298 printk("comedi%d: dt282x: 0x%04lx", dev->minor, iobase);
1299 if (!request_region(iobase, DT2821_SIZE, "dt282x")) {
1300 printk(" I/O port conflict\n");
1303 dev->iobase = iobase;
1305 outw(DT2821_BDINIT, dev->iobase + DT2821_SUPCSR);
1306 i = inw(dev->iobase + DT2821_ADCSR);
1308 printk(" fingerprint=%x,%x,%x,%x,%x",
1309 inw(dev->iobase + DT2821_ADCSR),
1310 inw(dev->iobase + DT2821_CHANCSR),
1311 inw(dev->iobase + DT2821_DACSR),
1312 inw(dev->iobase + DT2821_SUPCSR),
1313 inw(dev->iobase + DT2821_TMRCTR));
1316 if (((inw(dev->iobase + DT2821_ADCSR) & DT2821_ADCSR_MASK)
1317 != DT2821_ADCSR_VAL) ||
1318 ((inw(dev->iobase + DT2821_CHANCSR) & DT2821_CHANCSR_MASK)
1319 != DT2821_CHANCSR_VAL) ||
1320 ((inw(dev->iobase + DT2821_DACSR) & DT2821_DACSR_MASK)
1321 != DT2821_DACSR_VAL) ||
1322 ((inw(dev->iobase + DT2821_SUPCSR) & DT2821_SUPCSR_MASK)
1323 != DT2821_SUPCSR_VAL) ||
1324 ((inw(dev->iobase + DT2821_TMRCTR) & DT2821_TMRCTR_MASK)
1325 != DT2821_TMRCTR_VAL)) {
1326 printk(" board not found");
1329 /* should do board test */
1331 irq = it->options[opt_irq];
1334 unsigned long flags;
1339 irqs = probe_irq_on();
1341 /* trigger interrupt */
1345 irq = probe_irq_off(irqs);
1346 restore_flags(flags);
1347 if (0 /* error */ ) {
1348 printk(" error probing irq (bad)");
1353 printk(" ( irq = %d )", irq);
1354 ret = request_irq(irq, dt282x_interrupt, 0, "dt282x", dev);
1356 printk(" failed to get irq\n");
1360 } else if (irq == 0) {
1361 printk(" (no irq)");
1364 printk(" (probe returned multiple irqs--bad)");
1366 printk(" (irq probe not implemented)");
1370 ret = alloc_private(dev, sizeof(struct dt282x_private));
1374 ret = dt282x_grab_dma(dev, it->options[opt_dma1],
1375 it->options[opt_dma2]);
1379 ret = alloc_subdevices(dev, 3);
1383 s = dev->subdevices + 0;
1385 dev->read_subdev = s;
1387 s->type = COMEDI_SUBD_AI;
1388 s->subdev_flags = SDF_READABLE | SDF_CMD_READ |
1389 ((it->options[opt_diff]) ? SDF_DIFF : SDF_COMMON);
1391 (it->options[opt_diff]) ? boardtype.adchan_di : boardtype.adchan_se;
1392 s->insn_read = dt282x_ai_insn_read;
1393 s->do_cmdtest = dt282x_ai_cmdtest;
1394 s->do_cmd = dt282x_ai_cmd;
1395 s->cancel = dt282x_ai_cancel;
1396 s->maxdata = (1 << boardtype.adbits) - 1;
1397 s->len_chanlist = 16;
1399 opt_ai_range_lkup(boardtype.ispgl, it->options[opt_ai_range]);
1400 devpriv->ad_2scomp = it->options[opt_ai_twos];
1404 s->n_chan = boardtype.dachan;
1407 s->type = COMEDI_SUBD_AO;
1408 dev->write_subdev = s;
1409 s->subdev_flags = SDF_WRITABLE | SDF_CMD_WRITE;
1410 s->insn_read = dt282x_ao_insn_read;
1411 s->insn_write = dt282x_ao_insn_write;
1412 s->do_cmdtest = dt282x_ao_cmdtest;
1413 s->do_cmd = dt282x_ao_cmd;
1414 s->cancel = dt282x_ao_cancel;
1415 s->maxdata = (1 << boardtype.dabits) - 1;
1416 s->len_chanlist = 2;
1417 s->range_table_list = devpriv->darangelist;
1418 devpriv->darangelist[0] =
1419 opt_ao_range_lkup(it->options[opt_ao0_range]);
1420 devpriv->darangelist[1] =
1421 opt_ao_range_lkup(it->options[opt_ao1_range]);
1422 devpriv->da0_2scomp = it->options[opt_ao0_twos];
1423 devpriv->da1_2scomp = it->options[opt_ao1_twos];
1425 s->type = COMEDI_SUBD_UNUSED;
1430 s->type = COMEDI_SUBD_DIO;
1431 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1433 s->insn_bits = dt282x_dio_insn_bits;
1434 s->insn_config = dt282x_dio_insn_config;
1436 s->range_table = &range_digital;
1443 static void free_resources(struct comedi_device *dev)
1446 free_irq(dev->irq, dev);
1449 release_region(dev->iobase, DT2821_SIZE);
1451 if (devpriv->dma[0].chan)
1452 free_dma(devpriv->dma[0].chan);
1453 if (devpriv->dma[1].chan)
1454 free_dma(devpriv->dma[1].chan);
1455 if (devpriv->dma[0].buf)
1456 free_page((unsigned long)devpriv->dma[0].buf);
1457 if (devpriv->dma[1].buf)
1458 free_page((unsigned long)devpriv->dma[1].buf);
1462 static int dt282x_detach(struct comedi_device *dev)
1464 printk("comedi%d: dt282x: remove\n", dev->minor);
1466 free_resources(dev);
1471 static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2)
1475 devpriv->usedma = 0;
1477 if (!dma1 && !dma2) {
1478 printk(" (no dma)");
1482 if (dma1 == dma2 || dma1 < 5 || dma2 < 5 || dma1 > 7 || dma2 > 7)
1492 ret = request_dma(dma1, "dt282x A");
1495 devpriv->dma[0].chan = dma1;
1497 ret = request_dma(dma2, "dt282x B");
1500 devpriv->dma[1].chan = dma2;
1502 devpriv->dma_maxsize = PAGE_SIZE;
1503 devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
1504 devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
1505 if (!devpriv->dma[0].buf || !devpriv->dma[1].buf) {
1506 printk(" can't get DMA memory");
1510 printk(" (dma=%d,%d)", dma1, dma2);
1512 devpriv->usedma = 1;