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, {
164 static const struct comedi_lrange range_dt282x_ai_lo_unipolar = { 4, {
171 static const struct comedi_lrange range_dt282x_ai_5_bipolar = { 4, {
175 RANGE(-0.625, 0.625),
178 static const struct comedi_lrange range_dt282x_ai_5_unipolar = { 4, {
185 static const struct comedi_lrange range_dt282x_ai_hi_bipolar = { 4, {
192 static const struct comedi_lrange range_dt282x_ai_hi_unipolar = { 4, {
211 static const boardtype_t boardtypes[] = {
340 #define n_boardtypes sizeof(boardtypes)/sizeof(boardtype_t)
341 #define this_board ((const boardtype_t *)dev->board_ptr)
344 int ad_2scomp; /* we have 2's comp jumper set */
345 int da0_2scomp; /* same, for DAC0 */
346 int da1_2scomp; /* same, for DAC1 */
348 const struct comedi_lrange *darangelist[2];
352 volatile int dacsr; /* software copies of registers */
361 short *buf; /* DMA buffer */
362 volatile int size; /* size of current transfer */
364 int dma_maxsize; /* max size of DMA transfer (in bytes) */
365 int usedma; /* driver uses DMA */
366 volatile int current_dma_index;
370 #define devpriv ((dt282x_private *)dev->private)
371 #define boardtype (*(const boardtype_t *)dev->board_ptr)
374 * Some useless abstractions
376 #define chan_to_DAC(a) ((a)&1)
377 #define update_dacsr(a) outw(devpriv->dacsr|(a),dev->iobase+DT2821_DACSR)
378 #define update_adcsr(a) outw(devpriv->adcsr|(a),dev->iobase+DT2821_ADCSR)
379 #define mux_busy() (inw(dev->iobase+DT2821_ADCSR)&DT2821_MUXBUSY)
380 #define ad_done() (inw(dev->iobase+DT2821_ADCSR)&DT2821_ADDONE)
381 #define update_supcsr(a) outw(devpriv->supcsr|(a),dev->iobase+DT2821_SUPCSR)
384 * danger! macro abuse... a is the expression to wait on, and b is
385 * the statement(s) to execute if it doesn't happen.
387 #define wait_for(a,b) \
390 for(_i=0;_i<DT2821_TIMEOUT;_i++){ \
397 static int dt282x_attach(struct comedi_device * dev, struct comedi_devconfig * it);
398 static int dt282x_detach(struct comedi_device * dev);
399 static struct comedi_driver driver_dt282x = {
400 driver_name:"dt282x",
402 attach:dt282x_attach,
403 detach:dt282x_detach,
404 board_name:&boardtypes[0].name,
405 num_names:n_boardtypes,
406 offset:sizeof(boardtype_t),
409 COMEDI_INITCLEANUP(driver_dt282x);
411 static void free_resources(struct comedi_device * dev);
412 static int prep_ai_dma(struct comedi_device * dev, int chan, int size);
413 static int prep_ao_dma(struct comedi_device * dev, int chan, int size);
414 static int dt282x_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s);
415 static int dt282x_ao_cancel(struct comedi_device * dev, struct comedi_subdevice * s);
416 static int dt282x_ns_to_timer(int *nanosec, int round_mode);
417 static void dt282x_disable_dma(struct comedi_device * dev);
419 static int dt282x_grab_dma(struct comedi_device * dev, int dma1, int dma2);
421 static void dt282x_munge(struct comedi_device * dev, short * buf,
425 unsigned short mask = (1 << boardtype.adbits) - 1;
426 unsigned short sign = 1 << (boardtype.adbits - 1);
429 if (devpriv->ad_2scomp) {
430 sign = 1 << (boardtype.adbits - 1);
436 comedi_error(dev, "bug! odd number of bytes from dma xfer");
438 for (i = 0; i < n; i++) {
439 buf[i] = (buf[i] & mask) ^ sign;
443 static void dt282x_ao_dma_interrupt(struct comedi_device * dev)
448 struct comedi_subdevice *s = dev->subdevices + 1;
450 update_supcsr(DT2821_CLRDMADNE);
452 if (!s->async->prealloc_buf) {
453 printk("async->data disappeared. dang!\n");
457 i = devpriv->current_dma_index;
458 ptr = devpriv->dma[i].buf;
460 disable_dma(devpriv->dma[i].chan);
462 devpriv->current_dma_index = 1 - i;
464 size = cfc_read_array_from_buffer(s, ptr, devpriv->dma_maxsize);
466 rt_printk("dt282x: AO underrun\n");
467 dt282x_ao_cancel(dev, s);
468 s->async->events |= COMEDI_CB_OVERFLOW;
471 prep_ao_dma(dev, i, size);
475 static void dt282x_ai_dma_interrupt(struct comedi_device * dev)
481 struct comedi_subdevice *s = dev->subdevices;
483 update_supcsr(DT2821_CLRDMADNE);
485 if (!s->async->prealloc_buf) {
486 printk("async->data disappeared. dang!\n");
490 i = devpriv->current_dma_index;
491 ptr = devpriv->dma[i].buf;
492 size = devpriv->dma[i].size;
494 disable_dma(devpriv->dma[i].chan);
496 devpriv->current_dma_index = 1 - i;
498 dt282x_munge(dev, ptr, size);
499 ret = cfc_write_array_to_buffer(s, ptr, size);
501 dt282x_ai_cancel(dev, s);
504 devpriv->nread -= size / 2;
506 if (devpriv->nread < 0) {
507 printk("dt282x: off by one\n");
510 if (!devpriv->nread) {
511 dt282x_ai_cancel(dev, s);
512 s->async->events |= COMEDI_CB_EOA;
516 /* clear the dual dma flag, making this the last dma segment */
517 /* XXX probably wrong */
518 if (!devpriv->ntrig) {
519 devpriv->supcsr &= ~(DT2821_DDMA);
523 /* restart the channel */
524 prep_ai_dma(dev, i, 0);
527 static int prep_ai_dma(struct comedi_device * dev, int dma_index, int n)
530 unsigned long dma_ptr;
537 n = devpriv->dma_maxsize;
538 if (n > devpriv->ntrig * 2)
539 n = devpriv->ntrig * 2;
540 devpriv->ntrig -= n / 2;
542 devpriv->dma[dma_index].size = n;
543 dma_chan = devpriv->dma[dma_index].chan;
544 dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
546 set_dma_mode(dma_chan, DMA_MODE_READ);
547 flags = claim_dma_lock();
548 clear_dma_ff(dma_chan);
549 set_dma_addr(dma_chan, dma_ptr);
550 set_dma_count(dma_chan, n);
551 release_dma_lock(flags);
553 enable_dma(dma_chan);
558 static int prep_ao_dma(struct comedi_device * dev, int dma_index, int n)
561 unsigned long dma_ptr;
564 devpriv->dma[dma_index].size = n;
565 dma_chan = devpriv->dma[dma_index].chan;
566 dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
568 set_dma_mode(dma_chan, DMA_MODE_WRITE);
569 flags = claim_dma_lock();
570 clear_dma_ff(dma_chan);
571 set_dma_addr(dma_chan, dma_ptr);
572 set_dma_count(dma_chan, n);
573 release_dma_lock(flags);
575 enable_dma(dma_chan);
580 static irqreturn_t dt282x_interrupt(int irq, void *d PT_REGS_ARG)
582 struct comedi_device *dev = d;
583 struct comedi_subdevice *s;
584 struct comedi_subdevice *s_ao;
585 unsigned int supcsr, adcsr, dacsr;
588 if (!dev->attached) {
589 comedi_error(dev, "spurious interrupt");
593 s = dev->subdevices + 0;
594 s_ao = dev->subdevices + 1;
595 adcsr = inw(dev->iobase + DT2821_ADCSR);
596 dacsr = inw(dev->iobase + DT2821_DACSR);
597 supcsr = inw(dev->iobase + DT2821_SUPCSR);
598 if (supcsr & DT2821_DMAD) {
599 if (devpriv->dma_dir == DMA_MODE_READ)
600 dt282x_ai_dma_interrupt(dev);
602 dt282x_ao_dma_interrupt(dev);
605 if (adcsr & DT2821_ADERR) {
606 if (devpriv->nread != 0) {
607 comedi_error(dev, "A/D error");
608 dt282x_ai_cancel(dev, s);
609 s->async->events |= COMEDI_CB_ERROR;
613 if (dacsr & DT2821_DAERR) {
617 disable_irq(dev->irq);
618 printk("disabling irq\n");
621 comedi_error(dev, "D/A error");
622 dt282x_ao_cancel(dev, s_ao);
623 s->async->events |= COMEDI_CB_ERROR;
627 if (adcsr & DT2821_ADDONE) {
631 data = (short) inw(dev->iobase + DT2821_ADDAT);
632 data &= (1 << boardtype.adbits) - 1;
633 if (devpriv->ad_2scomp) {
634 data ^= 1 << (boardtype.adbits - 1);
636 ret = comedi_buf_put(s->async, data);
638 s->async->events |= COMEDI_CB_OVERFLOW;
642 if (!devpriv->nread) {
643 s->async->events |= COMEDI_CB_EOA;
645 if (supcsr & DT2821_SCDN)
646 update_supcsr(DT2821_STRIG);
651 comedi_event(dev, s);
652 /* printk("adcsr=0x%02x dacsr-0x%02x supcsr=0x%02x\n", adcsr, dacsr, supcsr); */
653 return IRQ_RETVAL(handled);
656 static void dt282x_load_changain(struct comedi_device * dev, int n,
657 unsigned int *chanlist)
660 unsigned int chan, range;
662 outw(DT2821_LLE | (n - 1), dev->iobase + DT2821_CHANCSR);
663 for (i = 0; i < n; i++) {
664 chan = CR_CHAN(chanlist[i]);
665 range = CR_RANGE(chanlist[i]);
666 update_adcsr((range << 4) | (chan));
668 outw(n - 1, dev->iobase + DT2821_CHANCSR);
672 * Performs a single A/D conversion.
673 * - Put channel/gain into channel-gain list
674 * - preload multiplexer
675 * - trigger conversion and wait for it to finish
677 static int dt282x_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
678 struct comedi_insn * insn, unsigned int * data)
682 /* XXX should we really be enabling the ad clock here? */
683 devpriv->adcsr = DT2821_ADCLK;
686 dt282x_load_changain(dev, 1, &insn->chanspec);
688 update_supcsr(DT2821_PRLD);
689 wait_for(!mux_busy(), comedi_error(dev, "timeout\n");
693 for (i = 0; i < insn->n; i++) {
694 update_supcsr(DT2821_STRIG);
695 wait_for(ad_done(), comedi_error(dev, "timeout\n");
701 DT2821_ADDAT) & ((1 << boardtype.adbits) - 1);
702 if (devpriv->ad_2scomp)
703 data[i] ^= (1 << (boardtype.adbits - 1));
709 static int dt282x_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s,
710 struct comedi_cmd * cmd)
715 /* step 1: make sure trigger sources are trivially valid */
717 tmp = cmd->start_src;
718 cmd->start_src &= TRIG_NOW;
719 if (!cmd->start_src || tmp != cmd->start_src)
722 tmp = cmd->scan_begin_src;
723 cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_EXT;
724 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
727 tmp = cmd->convert_src;
728 cmd->convert_src &= TRIG_TIMER;
729 if (!cmd->convert_src || tmp != cmd->convert_src)
732 tmp = cmd->scan_end_src;
733 cmd->scan_end_src &= TRIG_COUNT;
734 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
738 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
739 if (!cmd->stop_src || tmp != cmd->stop_src)
745 /* step 2: make sure trigger sources are unique and mutually compatible */
747 /* note that mutual compatiblity is not an issue here */
748 if (cmd->scan_begin_src != TRIG_FOLLOW &&
749 cmd->scan_begin_src != TRIG_EXT)
751 if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
757 /* step 3: make sure arguments are trivially compatible */
759 if (cmd->start_arg != 0) {
763 if (cmd->scan_begin_src == TRIG_FOLLOW) {
764 /* internal trigger */
765 if (cmd->scan_begin_arg != 0) {
766 cmd->scan_begin_arg = 0;
770 /* external trigger */
771 /* should be level/edge, hi/lo specification here */
772 if (cmd->scan_begin_arg != 0) {
773 cmd->scan_begin_arg = 0;
777 if (cmd->convert_arg < 4000) {
778 /* XXX board dependent */
779 cmd->convert_arg = 4000;
782 #define SLOWEST_TIMER (250*(1<<15)*255)
783 if (cmd->convert_arg > SLOWEST_TIMER) {
784 cmd->convert_arg = SLOWEST_TIMER;
787 if (cmd->convert_arg < this_board->ai_speed) {
788 cmd->convert_arg = this_board->ai_speed;
791 if (cmd->scan_end_arg != cmd->chanlist_len) {
792 cmd->scan_end_arg = cmd->chanlist_len;
795 if (cmd->stop_src == TRIG_COUNT) {
796 /* any count is allowed */
799 if (cmd->stop_arg != 0) {
808 /* step 4: fix up any arguments */
810 tmp = cmd->convert_arg;
811 dt282x_ns_to_timer(&cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK);
812 if (tmp != cmd->convert_arg)
821 static int dt282x_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s)
823 struct comedi_cmd *cmd = &s->async->cmd;
826 if (devpriv->usedma == 0) {
828 "driver requires 2 dma channels to execute command");
832 dt282x_disable_dma(dev);
834 if (cmd->convert_arg < this_board->ai_speed)
835 cmd->convert_arg = this_board->ai_speed;
836 timer = dt282x_ns_to_timer(&cmd->convert_arg, TRIG_ROUND_NEAREST);
837 outw(timer, dev->iobase + DT2821_TMRCTR);
839 if (cmd->scan_begin_src == TRIG_FOLLOW) {
840 /* internal trigger */
841 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0;
843 /* external trigger */
844 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0 | DT2821_DS1;
846 update_supcsr(DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_ADCINIT);
848 devpriv->ntrig = cmd->stop_arg * cmd->scan_end_arg;
849 devpriv->nread = devpriv->ntrig;
851 devpriv->dma_dir = DMA_MODE_READ;
852 devpriv->current_dma_index = 0;
853 prep_ai_dma(dev, 0, 0);
854 if (devpriv->ntrig) {
855 prep_ai_dma(dev, 1, 0);
856 devpriv->supcsr |= DT2821_DDMA;
862 dt282x_load_changain(dev, cmd->chanlist_len, cmd->chanlist);
864 devpriv->adcsr = DT2821_ADCLK | DT2821_IADDONE;
867 update_supcsr(DT2821_PRLD);
868 wait_for(!mux_busy(), comedi_error(dev, "timeout\n");
872 if (cmd->scan_begin_src == TRIG_FOLLOW) {
873 update_supcsr(DT2821_STRIG);
875 devpriv->supcsr |= DT2821_XTRIG;
882 static void dt282x_disable_dma(struct comedi_device * dev)
884 if (devpriv->usedma) {
885 disable_dma(devpriv->dma[0].chan);
886 disable_dma(devpriv->dma[1].chan);
890 static int dt282x_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s)
892 dt282x_disable_dma(dev);
898 update_supcsr(DT2821_ADCINIT);
903 static int dt282x_ns_to_timer(int *nanosec, int round_mode)
905 int prescale, base, divider;
907 for (prescale = 0; prescale < 16; prescale++) {
910 base = 250 * (1 << prescale);
911 switch (round_mode) {
912 case TRIG_ROUND_NEAREST:
914 divider = (*nanosec + base / 2) / base;
916 case TRIG_ROUND_DOWN:
917 divider = (*nanosec) / base;
920 divider = (*nanosec + base - 1) / base;
924 *nanosec = divider * base;
925 return (prescale << 8) | (255 - divider);
928 base = 250 * (1 << 15);
930 *nanosec = divider * base;
931 return (15 << 8) | (255 - divider);
935 * Analog output routine. Selects single channel conversion,
936 * selects correct channel, converts from 2's compliment to
937 * offset binary if necessary, loads the data into the DAC
938 * data register, and performs the conversion.
940 static int dt282x_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
941 struct comedi_insn * insn, unsigned int * data)
943 data[0] = devpriv->ao[CR_CHAN(insn->chanspec)];
948 static int dt282x_ao_insn_write(struct comedi_device * dev, struct comedi_subdevice * s,
949 struct comedi_insn * insn, unsigned int * data)
954 chan = CR_CHAN(insn->chanspec);
956 d &= (1 << boardtype.dabits) - 1;
957 devpriv->ao[chan] = d;
959 devpriv->dacsr |= DT2821_SSEL;
963 devpriv->dacsr |= DT2821_YSEL;
964 if (devpriv->da0_2scomp)
965 d ^= (1 << (boardtype.dabits - 1));
967 devpriv->dacsr &= ~DT2821_YSEL;
968 if (devpriv->da1_2scomp)
969 d ^= (1 << (boardtype.dabits - 1));
974 outw(d, dev->iobase + DT2821_DADAT);
976 update_supcsr(DT2821_DACON);
981 static int dt282x_ao_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s,
982 struct comedi_cmd * cmd)
987 /* step 1: make sure trigger sources are trivially valid */
989 tmp = cmd->start_src;
990 cmd->start_src &= TRIG_INT;
991 if (!cmd->start_src || tmp != cmd->start_src)
994 tmp = cmd->scan_begin_src;
995 cmd->scan_begin_src &= TRIG_TIMER;
996 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
999 tmp = cmd->convert_src;
1000 cmd->convert_src &= TRIG_NOW;
1001 if (!cmd->convert_src || tmp != cmd->convert_src)
1004 tmp = cmd->scan_end_src;
1005 cmd->scan_end_src &= TRIG_COUNT;
1006 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
1009 tmp = cmd->stop_src;
1010 cmd->stop_src &= TRIG_NONE;
1011 if (!cmd->stop_src || tmp != cmd->stop_src)
1017 /* step 2: make sure trigger sources are unique and mutually compatible */
1019 /* note that mutual compatiblity is not an issue here */
1020 if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
1026 /* step 3: make sure arguments are trivially compatible */
1028 if (cmd->start_arg != 0) {
1032 if (cmd->scan_begin_arg < 5000 /* XXX unknown */ ) {
1033 cmd->scan_begin_arg = 5000;
1036 if (cmd->convert_arg != 0) {
1037 cmd->convert_arg = 0;
1040 if (cmd->scan_end_arg > 2) {
1041 /* XXX chanlist stuff? */
1042 cmd->scan_end_arg = 2;
1045 if (cmd->stop_src == TRIG_COUNT) {
1046 /* any count is allowed */
1049 if (cmd->stop_arg != 0) {
1058 /* step 4: fix up any arguments */
1060 tmp = cmd->scan_begin_arg;
1061 dt282x_ns_to_timer(&cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK);
1062 if (tmp != cmd->scan_begin_arg)
1072 static int dt282x_ao_inttrig(struct comedi_device * dev, struct comedi_subdevice * s,
1080 size = cfc_read_array_from_buffer(s, devpriv->dma[0].buf,
1081 devpriv->dma_maxsize);
1083 rt_printk("dt282x: AO underrun\n");
1086 prep_ao_dma(dev, 0, size);
1088 size = cfc_read_array_from_buffer(s, devpriv->dma[1].buf,
1089 devpriv->dma_maxsize);
1091 rt_printk("dt282x: AO underrun\n");
1094 prep_ao_dma(dev, 1, size);
1096 update_supcsr(DT2821_STRIG);
1097 s->async->inttrig = NULL;
1102 static int dt282x_ao_cmd(struct comedi_device * dev, struct comedi_subdevice * s)
1105 struct comedi_cmd *cmd = &s->async->cmd;
1107 if (devpriv->usedma == 0) {
1109 "driver requires 2 dma channels to execute command");
1113 dt282x_disable_dma(dev);
1115 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS1 | DT2821_DDMA;
1116 update_supcsr(DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_DACINIT);
1118 devpriv->ntrig = cmd->stop_arg * cmd->chanlist_len;
1119 devpriv->nread = devpriv->ntrig;
1121 devpriv->dma_dir = DMA_MODE_WRITE;
1122 devpriv->current_dma_index = 0;
1124 timer = dt282x_ns_to_timer(&cmd->scan_begin_arg, TRIG_ROUND_NEAREST);
1125 outw(timer, dev->iobase + DT2821_TMRCTR);
1127 devpriv->dacsr = DT2821_SSEL | DT2821_DACLK | DT2821_IDARDY;
1130 s->async->inttrig = dt282x_ao_inttrig;
1135 static int dt282x_ao_cancel(struct comedi_device * dev, struct comedi_subdevice * s)
1137 dt282x_disable_dma(dev);
1142 devpriv->supcsr = 0;
1143 update_supcsr(DT2821_DACINIT);
1148 static int dt282x_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
1149 struct comedi_insn * insn, unsigned int * data)
1152 s->state &= ~data[0];
1153 s->state |= (data[0] & data[1]);
1155 outw(s->state, dev->iobase + DT2821_DIODAT);
1157 data[1] = inw(dev->iobase + DT2821_DIODAT);
1162 static int dt282x_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s,
1163 struct comedi_insn * insn, unsigned int * data)
1167 mask = (CR_CHAN(insn->chanspec) < 8) ? 0x00ff : 0xff00;
1171 s->io_bits &= ~mask;
1173 if (s->io_bits & 0x00ff)
1174 devpriv->dacsr |= DT2821_LBOE;
1176 devpriv->dacsr &= ~DT2821_LBOE;
1177 if (s->io_bits & 0xff00)
1178 devpriv->dacsr |= DT2821_HBOE;
1180 devpriv->dacsr &= ~DT2821_HBOE;
1182 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
1187 static const struct comedi_lrange *const ai_range_table[] = {
1188 &range_dt282x_ai_lo_bipolar,
1189 &range_dt282x_ai_lo_unipolar,
1190 &range_dt282x_ai_5_bipolar,
1191 &range_dt282x_ai_5_unipolar
1193 static const struct comedi_lrange *const ai_range_pgl_table[] = {
1194 &range_dt282x_ai_hi_bipolar,
1195 &range_dt282x_ai_hi_unipolar
1197 static const struct comedi_lrange *opt_ai_range_lkup(int ispgl, int x)
1200 if (x < 0 || x >= 2)
1202 return ai_range_pgl_table[x];
1204 if (x < 0 || x >= 4)
1206 return ai_range_table[x];
1209 static const struct comedi_lrange *const ao_range_table[] = {
1216 static const struct comedi_lrange *opt_ao_range_lkup(int x)
1218 if (x < 0 || x >= 5)
1220 return ao_range_table[x];
1223 enum { opt_iobase = 0, opt_irq, opt_dma1, opt_dma2, /* i/o base, irq, dma channels */
1224 opt_diff, /* differential */
1225 opt_ai_twos, opt_ao0_twos, opt_ao1_twos, /* twos comp */
1226 opt_ai_range, opt_ao0_range, opt_ao1_range, /* range */
1235 4 0=single ended, 1=differential
1236 5 ai 0=straight binary, 1=2's comp
1237 6 ao0 0=straight binary, 1=2's comp
1238 7 ao1 0=straight binary, 1=2's comp
1239 8 ai 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V
1240 9 ao0 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1241 10 ao1 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1243 static int dt282x_attach(struct comedi_device * dev, struct comedi_devconfig * it)
1247 struct comedi_subdevice *s;
1248 unsigned long iobase;
1250 dev->board_name = this_board->name;
1252 iobase = it->options[opt_iobase];
1256 printk("comedi%d: dt282x: 0x%04lx", dev->minor, iobase);
1257 if (!request_region(iobase, DT2821_SIZE, "dt282x")) {
1258 printk(" I/O port conflict\n");
1261 dev->iobase = iobase;
1263 outw(DT2821_BDINIT, dev->iobase + DT2821_SUPCSR);
1264 i = inw(dev->iobase + DT2821_ADCSR);
1266 printk(" fingerprint=%x,%x,%x,%x,%x",
1267 inw(dev->iobase + DT2821_ADCSR),
1268 inw(dev->iobase + DT2821_CHANCSR),
1269 inw(dev->iobase + DT2821_DACSR),
1270 inw(dev->iobase + DT2821_SUPCSR),
1271 inw(dev->iobase + DT2821_TMRCTR));
1274 if (((inw(dev->iobase + DT2821_ADCSR) & DT2821_ADCSR_MASK)
1275 != DT2821_ADCSR_VAL) ||
1276 ((inw(dev->iobase + DT2821_CHANCSR) & DT2821_CHANCSR_MASK)
1277 != DT2821_CHANCSR_VAL) ||
1278 ((inw(dev->iobase + DT2821_DACSR) & DT2821_DACSR_MASK)
1279 != DT2821_DACSR_VAL) ||
1280 ((inw(dev->iobase + DT2821_SUPCSR) & DT2821_SUPCSR_MASK)
1281 != DT2821_SUPCSR_VAL) ||
1282 ((inw(dev->iobase + DT2821_TMRCTR) & DT2821_TMRCTR_MASK)
1283 != DT2821_TMRCTR_VAL)) {
1284 printk(" board not found");
1287 /* should do board test */
1289 irq = it->options[opt_irq];
1292 unsigned long flags;
1297 irqs = probe_irq_on();
1299 /* trigger interrupt */
1303 irq = probe_irq_off(irqs);
1304 restore_flags(flags);
1305 if (0 /* error */ ) {
1306 printk(" error probing irq (bad)");
1311 printk(" ( irq = %d )", irq);
1312 ret = comedi_request_irq(irq, dt282x_interrupt, 0, "dt282x",
1315 printk(" failed to get irq\n");
1319 } else if (irq == 0) {
1320 printk(" (no irq)");
1323 printk(" (probe returned multiple irqs--bad)");
1325 printk(" (irq probe not implemented)");
1329 if ((ret = alloc_private(dev, sizeof(dt282x_private))) < 0)
1332 ret = dt282x_grab_dma(dev, it->options[opt_dma1],
1333 it->options[opt_dma2]);
1337 if ((ret = alloc_subdevices(dev, 3)) < 0)
1340 s = dev->subdevices + 0;
1342 dev->read_subdev = s;
1344 s->type = COMEDI_SUBD_AI;
1345 s->subdev_flags = SDF_READABLE | SDF_CMD_READ |
1346 ((it->options[opt_diff]) ? SDF_DIFF : SDF_COMMON);
1348 (it->options[opt_diff]) ? boardtype.adchan_di : boardtype.
1350 s->insn_read = dt282x_ai_insn_read;
1351 s->do_cmdtest = dt282x_ai_cmdtest;
1352 s->do_cmd = dt282x_ai_cmd;
1353 s->cancel = dt282x_ai_cancel;
1354 s->maxdata = (1 << boardtype.adbits) - 1;
1355 s->len_chanlist = 16;
1357 opt_ai_range_lkup(boardtype.ispgl, it->options[opt_ai_range]);
1358 devpriv->ad_2scomp = it->options[opt_ai_twos];
1361 if ((s->n_chan = boardtype.dachan)) {
1363 s->type = COMEDI_SUBD_AO;
1364 dev->write_subdev = s;
1365 s->subdev_flags = SDF_WRITABLE | SDF_CMD_WRITE;
1366 s->insn_read = dt282x_ao_insn_read;
1367 s->insn_write = dt282x_ao_insn_write;
1368 s->do_cmdtest = dt282x_ao_cmdtest;
1369 s->do_cmd = dt282x_ao_cmd;
1370 s->cancel = dt282x_ao_cancel;
1371 s->maxdata = (1 << boardtype.dabits) - 1;
1372 s->len_chanlist = 2;
1373 s->range_table_list = devpriv->darangelist;
1374 devpriv->darangelist[0] =
1375 opt_ao_range_lkup(it->options[opt_ao0_range]);
1376 devpriv->darangelist[1] =
1377 opt_ao_range_lkup(it->options[opt_ao1_range]);
1378 devpriv->da0_2scomp = it->options[opt_ao0_twos];
1379 devpriv->da1_2scomp = it->options[opt_ao1_twos];
1381 s->type = COMEDI_SUBD_UNUSED;
1386 s->type = COMEDI_SUBD_DIO;
1387 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1389 s->insn_bits = dt282x_dio_insn_bits;
1390 s->insn_config = dt282x_dio_insn_config;
1392 s->range_table = &range_digital;
1399 static void free_resources(struct comedi_device * dev)
1402 comedi_free_irq(dev->irq, dev);
1405 release_region(dev->iobase, DT2821_SIZE);
1407 if (devpriv->dma[0].chan)
1408 free_dma(devpriv->dma[0].chan);
1409 if (devpriv->dma[1].chan)
1410 free_dma(devpriv->dma[1].chan);
1411 if (devpriv->dma[0].buf)
1412 free_page((unsigned long)devpriv->dma[0].buf);
1413 if (devpriv->dma[1].buf)
1414 free_page((unsigned long)devpriv->dma[1].buf);
1418 static int dt282x_detach(struct comedi_device * dev)
1420 printk("comedi%d: dt282x: remove\n", dev->minor);
1422 free_resources(dev);
1427 static int dt282x_grab_dma(struct comedi_device * dev, int dma1, int dma2)
1431 devpriv->usedma = 0;
1433 if (!dma1 && !dma2) {
1434 printk(" (no dma)");
1438 if (dma1 == dma2 || dma1 < 5 || dma2 < 5 || dma1 > 7 || dma2 > 7)
1448 ret = request_dma(dma1, "dt282x A");
1451 devpriv->dma[0].chan = dma1;
1453 ret = request_dma(dma2, "dt282x B");
1456 devpriv->dma[1].chan = dma2;
1458 devpriv->dma_maxsize = PAGE_SIZE;
1459 devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
1460 devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
1461 if (!devpriv->dma[0].buf || !devpriv->dma[1].buf) {
1462 printk(" can't get DMA memory");
1466 printk(" (dma=%d,%d)", dma1, dma2);
1468 devpriv->usedma = 1;