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>
66 #include "comedi_fc.h"
70 #define DT2821_TIMEOUT 100 /* 500 us */
71 #define DT2821_SIZE 0x10
74 * Registers in the DT282x
77 #define DT2821_ADCSR 0x00 /* A/D Control/Status */
78 #define DT2821_CHANCSR 0x02 /* Channel Control/Status */
79 #define DT2821_ADDAT 0x04 /* A/D data */
80 #define DT2821_DACSR 0x06 /* D/A Control/Status */
81 #define DT2821_DADAT 0x08 /* D/A data */
82 #define DT2821_DIODAT 0x0a /* digital data */
83 #define DT2821_SUPCSR 0x0c /* Supervisor Control/Status */
84 #define DT2821_TMRCTR 0x0e /* Timer/Counter */
87 * At power up, some registers are in a well-known state. The
88 * masks and values are as follows:
91 #define DT2821_ADCSR_MASK 0xfff0
92 #define DT2821_ADCSR_VAL 0x7c00
94 #define DT2821_CHANCSR_MASK 0xf0f0
95 #define DT2821_CHANCSR_VAL 0x70f0
97 #define DT2821_DACSR_MASK 0x7c93
98 #define DT2821_DACSR_VAL 0x7c90
100 #define DT2821_SUPCSR_MASK 0xf8ff
101 #define DT2821_SUPCSR_VAL 0x0000
103 #define DT2821_TMRCTR_MASK 0xff00
104 #define DT2821_TMRCTR_VAL 0xf000
107 * Bit fields of each register
112 #define DT2821_ADERR 0x8000 /* (R) 1 for A/D error */
113 #define DT2821_ADCLK 0x0200 /* (R/W) A/D clock enable */
114 /* 0x7c00 read as 1's */
115 #define DT2821_MUXBUSY 0x0100 /* (R) multiplexer busy */
116 #define DT2821_ADDONE 0x0080 /* (R) A/D done */
117 #define DT2821_IADDONE 0x0040 /* (R/W) interrupt on A/D done */
118 /* 0x0030 gain select */
119 /* 0x000f channel select */
123 #define DT2821_LLE 0x8000 /* (R/W) Load List Enable */
124 /* 0x7000 read as 1's */
125 /* 0x0f00 (R) present address */
126 /* 0x00f0 read as 1's */
127 /* 0x000f (R) number of entries - 1 */
131 #define DT2821_DAERR 0x8000 /* (R) D/A error */
132 #define DT2821_YSEL 0x0200 /* (R/W) DAC 1 select */
133 #define DT2821_SSEL 0x0100 /* (R/W) single channel select */
134 #define DT2821_DACRDY 0x0080 /* (R) DAC ready */
135 #define DT2821_IDARDY 0x0040 /* (R/W) interrupt on DAC ready */
136 #define DT2821_DACLK 0x0020 /* (R/W) D/A clock enable */
137 #define DT2821_HBOE 0x0002 /* (R/W) DIO high byte output enable */
138 #define DT2821_LBOE 0x0001 /* (R/W) DIO low byte output enable */
142 #define DT2821_DMAD 0x8000 /* (R) DMA done */
143 #define DT2821_ERRINTEN 0x4000 /* (R/W) interrupt on error */
144 #define DT2821_CLRDMADNE 0x2000 /* (W) clear DMA done */
145 #define DT2821_DDMA 0x1000 /* (R/W) dual DMA */
146 #define DT2821_DS1 0x0800 /* (R/W) DMA select 1 */
147 #define DT2821_DS0 0x0400 /* (R/W) DMA select 0 */
148 #define DT2821_BUFFB 0x0200 /* (R/W) buffer B selected */
149 #define DT2821_SCDN 0x0100 /* (R) scan done */
150 #define DT2821_DACON 0x0080 /* (W) DAC single conversion */
151 #define DT2821_ADCINIT 0x0040 /* (W) A/D initialize */
152 #define DT2821_DACINIT 0x0020 /* (W) D/A initialize */
153 #define DT2821_PRLD 0x0010 /* (W) preload multiplexer */
154 #define DT2821_STRIG 0x0008 /* (W) software trigger */
155 #define DT2821_XTRIG 0x0004 /* (R/W) external trigger enable */
156 #define DT2821_XCLK 0x0002 /* (R/W) external clock enable */
157 #define DT2821_BDINIT 0x0001 /* (W) initialize board */
159 static const struct comedi_lrange range_dt282x_ai_lo_bipolar = {
168 static const struct comedi_lrange range_dt282x_ai_lo_unipolar = {
177 static const struct comedi_lrange range_dt282x_ai_5_bipolar = {
186 static const struct comedi_lrange range_dt282x_ai_5_unipolar = {
195 static const struct comedi_lrange range_dt282x_ai_hi_bipolar = {
204 static const struct comedi_lrange range_dt282x_ai_hi_unipolar = {
213 struct dt282x_board {
224 #define this_board ((const struct dt282x_board *)dev->board_ptr)
226 struct dt282x_private {
227 int ad_2scomp; /* we have 2's comp jumper set */
228 int da0_2scomp; /* same, for DAC0 */
229 int da1_2scomp; /* same, for DAC1 */
231 const struct comedi_lrange *darangelist[2];
235 volatile int dacsr; /* software copies of registers */
244 short *buf; /* DMA buffer */
245 volatile int size; /* size of current transfer */
247 int dma_maxsize; /* max size of DMA transfer (in bytes) */
248 int usedma; /* driver uses DMA */
249 volatile int current_dma_index;
253 #define devpriv ((struct dt282x_private *)dev->private)
254 #define boardtype (*(const struct dt282x_board *)dev->board_ptr)
257 * Some useless abstractions
259 #define chan_to_DAC(a) ((a)&1)
260 #define update_dacsr(a) outw(devpriv->dacsr|(a), dev->iobase+DT2821_DACSR)
261 #define update_adcsr(a) outw(devpriv->adcsr|(a), dev->iobase+DT2821_ADCSR)
262 #define mux_busy() (inw(dev->iobase+DT2821_ADCSR)&DT2821_MUXBUSY)
263 #define ad_done() (inw(dev->iobase+DT2821_ADCSR)&DT2821_ADDONE)
264 #define update_supcsr(a) outw(devpriv->supcsr|(a), dev->iobase+DT2821_SUPCSR)
267 * danger! macro abuse... a is the expression to wait on, and b is
268 * the statement(s) to execute if it doesn't happen.
270 #define wait_for(a, b) \
273 for (_i = 0; _i < DT2821_TIMEOUT; _i++) { \
284 static int prep_ai_dma(struct comedi_device *dev, int chan, int size);
285 static int prep_ao_dma(struct comedi_device *dev, int chan, int size);
286 static int dt282x_ai_cancel(struct comedi_device *dev,
287 struct comedi_subdevice *s);
288 static int dt282x_ao_cancel(struct comedi_device *dev,
289 struct comedi_subdevice *s);
290 static int dt282x_ns_to_timer(int *nanosec, int round_mode);
291 static void dt282x_disable_dma(struct comedi_device *dev);
293 static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2);
295 static void dt282x_munge(struct comedi_device *dev, short *buf,
299 unsigned short mask = (1 << boardtype.adbits) - 1;
300 unsigned short sign = 1 << (boardtype.adbits - 1);
303 if (devpriv->ad_2scomp)
304 sign = 1 << (boardtype.adbits - 1);
309 comedi_error(dev, "bug! odd number of bytes from dma xfer");
311 for (i = 0; i < n; i++)
312 buf[i] = (buf[i] & mask) ^ sign;
315 static void dt282x_ao_dma_interrupt(struct comedi_device *dev)
320 struct comedi_subdevice *s = dev->subdevices + 1;
322 update_supcsr(DT2821_CLRDMADNE);
324 if (!s->async->prealloc_buf) {
325 printk(KERN_ERR "async->data disappeared. dang!\n");
329 i = devpriv->current_dma_index;
330 ptr = devpriv->dma[i].buf;
332 disable_dma(devpriv->dma[i].chan);
334 devpriv->current_dma_index = 1 - i;
336 size = cfc_read_array_from_buffer(s, ptr, devpriv->dma_maxsize);
338 printk(KERN_ERR "dt282x: AO underrun\n");
339 dt282x_ao_cancel(dev, s);
340 s->async->events |= COMEDI_CB_OVERFLOW;
343 prep_ao_dma(dev, i, size);
347 static void dt282x_ai_dma_interrupt(struct comedi_device *dev)
353 struct comedi_subdevice *s = dev->subdevices;
355 update_supcsr(DT2821_CLRDMADNE);
357 if (!s->async->prealloc_buf) {
358 printk(KERN_ERR "async->data disappeared. dang!\n");
362 i = devpriv->current_dma_index;
363 ptr = devpriv->dma[i].buf;
364 size = devpriv->dma[i].size;
366 disable_dma(devpriv->dma[i].chan);
368 devpriv->current_dma_index = 1 - i;
370 dt282x_munge(dev, ptr, size);
371 ret = cfc_write_array_to_buffer(s, ptr, size);
373 dt282x_ai_cancel(dev, s);
376 devpriv->nread -= size / 2;
378 if (devpriv->nread < 0) {
379 printk(KERN_INFO "dt282x: off by one\n");
382 if (!devpriv->nread) {
383 dt282x_ai_cancel(dev, s);
384 s->async->events |= COMEDI_CB_EOA;
388 /* clear the dual dma flag, making this the last dma segment */
389 /* XXX probably wrong */
390 if (!devpriv->ntrig) {
391 devpriv->supcsr &= ~(DT2821_DDMA);
395 /* restart the channel */
396 prep_ai_dma(dev, i, 0);
399 static int prep_ai_dma(struct comedi_device *dev, int dma_index, int n)
402 unsigned long dma_ptr;
409 n = devpriv->dma_maxsize;
410 if (n > devpriv->ntrig * 2)
411 n = devpriv->ntrig * 2;
412 devpriv->ntrig -= n / 2;
414 devpriv->dma[dma_index].size = n;
415 dma_chan = devpriv->dma[dma_index].chan;
416 dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
418 set_dma_mode(dma_chan, DMA_MODE_READ);
419 flags = claim_dma_lock();
420 clear_dma_ff(dma_chan);
421 set_dma_addr(dma_chan, dma_ptr);
422 set_dma_count(dma_chan, n);
423 release_dma_lock(flags);
425 enable_dma(dma_chan);
430 static int prep_ao_dma(struct comedi_device *dev, int dma_index, int n)
433 unsigned long dma_ptr;
436 devpriv->dma[dma_index].size = n;
437 dma_chan = devpriv->dma[dma_index].chan;
438 dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
440 set_dma_mode(dma_chan, DMA_MODE_WRITE);
441 flags = claim_dma_lock();
442 clear_dma_ff(dma_chan);
443 set_dma_addr(dma_chan, dma_ptr);
444 set_dma_count(dma_chan, n);
445 release_dma_lock(flags);
447 enable_dma(dma_chan);
452 static irqreturn_t dt282x_interrupt(int irq, void *d)
454 struct comedi_device *dev = d;
455 struct comedi_subdevice *s;
456 struct comedi_subdevice *s_ao;
457 unsigned int supcsr, adcsr, dacsr;
460 if (!dev->attached) {
461 comedi_error(dev, "spurious interrupt");
465 s = dev->subdevices + 0;
466 s_ao = dev->subdevices + 1;
467 adcsr = inw(dev->iobase + DT2821_ADCSR);
468 dacsr = inw(dev->iobase + DT2821_DACSR);
469 supcsr = inw(dev->iobase + DT2821_SUPCSR);
470 if (supcsr & DT2821_DMAD) {
471 if (devpriv->dma_dir == DMA_MODE_READ)
472 dt282x_ai_dma_interrupt(dev);
474 dt282x_ao_dma_interrupt(dev);
477 if (adcsr & DT2821_ADERR) {
478 if (devpriv->nread != 0) {
479 comedi_error(dev, "A/D error");
480 dt282x_ai_cancel(dev, s);
481 s->async->events |= COMEDI_CB_ERROR;
485 if (dacsr & DT2821_DAERR) {
489 disable_irq(dev->irq);
490 printk(KERN_INFO "disabling irq\n");
493 comedi_error(dev, "D/A error");
494 dt282x_ao_cancel(dev, s_ao);
495 s->async->events |= COMEDI_CB_ERROR;
499 if (adcsr & DT2821_ADDONE) {
503 data = (short)inw(dev->iobase + DT2821_ADDAT);
504 data &= (1 << boardtype.adbits) - 1;
506 if (devpriv->ad_2scomp)
507 data ^= 1 << (boardtype.adbits - 1);
508 ret = comedi_buf_put(s->async, data);
511 s->async->events |= COMEDI_CB_OVERFLOW;
514 if (!devpriv->nread) {
515 s->async->events |= COMEDI_CB_EOA;
517 if (supcsr & DT2821_SCDN)
518 update_supcsr(DT2821_STRIG);
523 comedi_event(dev, s);
524 /* printk("adcsr=0x%02x dacsr-0x%02x supcsr=0x%02x\n",
525 adcsr, dacsr, supcsr); */
526 return IRQ_RETVAL(handled);
529 static void dt282x_load_changain(struct comedi_device *dev, int n,
530 unsigned int *chanlist)
533 unsigned int chan, range;
535 outw(DT2821_LLE | (n - 1), dev->iobase + DT2821_CHANCSR);
536 for (i = 0; i < n; i++) {
537 chan = CR_CHAN(chanlist[i]);
538 range = CR_RANGE(chanlist[i]);
539 update_adcsr((range << 4) | (chan));
541 outw(n - 1, dev->iobase + DT2821_CHANCSR);
545 * Performs a single A/D conversion.
546 * - Put channel/gain into channel-gain list
547 * - preload multiplexer
548 * - trigger conversion and wait for it to finish
550 static int dt282x_ai_insn_read(struct comedi_device *dev,
551 struct comedi_subdevice *s,
552 struct comedi_insn *insn, unsigned int *data)
556 /* XXX should we really be enabling the ad clock here? */
557 devpriv->adcsr = DT2821_ADCLK;
560 dt282x_load_changain(dev, 1, &insn->chanspec);
562 update_supcsr(DT2821_PRLD);
563 wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;);
565 for (i = 0; i < insn->n; i++) {
566 update_supcsr(DT2821_STRIG);
567 wait_for(ad_done(), comedi_error(dev, "timeout\n");
572 DT2821_ADDAT) & ((1 << boardtype.adbits) - 1);
573 if (devpriv->ad_2scomp)
574 data[i] ^= (1 << (boardtype.adbits - 1));
580 static int dt282x_ai_cmdtest(struct comedi_device *dev,
581 struct comedi_subdevice *s, struct comedi_cmd *cmd)
586 /* step 1: make sure trigger sources are trivially valid */
588 tmp = cmd->start_src;
589 cmd->start_src &= TRIG_NOW;
590 if (!cmd->start_src || tmp != cmd->start_src)
593 tmp = cmd->scan_begin_src;
594 cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_EXT;
595 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
598 tmp = cmd->convert_src;
599 cmd->convert_src &= TRIG_TIMER;
600 if (!cmd->convert_src || tmp != cmd->convert_src)
603 tmp = cmd->scan_end_src;
604 cmd->scan_end_src &= TRIG_COUNT;
605 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
609 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
610 if (!cmd->stop_src || tmp != cmd->stop_src)
617 * step 2: make sure trigger sources are unique
618 * and mutually compatible
621 /* note that mutual compatibility is not an issue here */
622 if (cmd->scan_begin_src != TRIG_FOLLOW &&
623 cmd->scan_begin_src != TRIG_EXT)
625 if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
631 /* step 3: make sure arguments are trivially compatible */
633 if (cmd->start_arg != 0) {
637 if (cmd->scan_begin_src == TRIG_FOLLOW) {
638 /* internal trigger */
639 if (cmd->scan_begin_arg != 0) {
640 cmd->scan_begin_arg = 0;
644 /* external trigger */
645 /* should be level/edge, hi/lo specification here */
646 if (cmd->scan_begin_arg != 0) {
647 cmd->scan_begin_arg = 0;
651 if (cmd->convert_arg < 4000) {
652 /* XXX board dependent */
653 cmd->convert_arg = 4000;
656 #define SLOWEST_TIMER (250*(1<<15)*255)
657 if (cmd->convert_arg > SLOWEST_TIMER) {
658 cmd->convert_arg = SLOWEST_TIMER;
661 if (cmd->convert_arg < this_board->ai_speed) {
662 cmd->convert_arg = this_board->ai_speed;
665 if (cmd->scan_end_arg != cmd->chanlist_len) {
666 cmd->scan_end_arg = cmd->chanlist_len;
669 if (cmd->stop_src == TRIG_COUNT) {
670 /* any count is allowed */
673 if (cmd->stop_arg != 0) {
682 /* step 4: fix up any arguments */
684 tmp = cmd->convert_arg;
685 dt282x_ns_to_timer(&cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK);
686 if (tmp != cmd->convert_arg)
695 static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
697 struct comedi_cmd *cmd = &s->async->cmd;
700 if (devpriv->usedma == 0) {
702 "driver requires 2 dma channels"
703 " to execute command");
707 dt282x_disable_dma(dev);
709 if (cmd->convert_arg < this_board->ai_speed)
710 cmd->convert_arg = this_board->ai_speed;
711 timer = dt282x_ns_to_timer(&cmd->convert_arg, TRIG_ROUND_NEAREST);
712 outw(timer, dev->iobase + DT2821_TMRCTR);
714 if (cmd->scan_begin_src == TRIG_FOLLOW) {
715 /* internal trigger */
716 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0;
718 /* external trigger */
719 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0 | DT2821_DS1;
721 update_supcsr(DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_ADCINIT);
723 devpriv->ntrig = cmd->stop_arg * cmd->scan_end_arg;
724 devpriv->nread = devpriv->ntrig;
726 devpriv->dma_dir = DMA_MODE_READ;
727 devpriv->current_dma_index = 0;
728 prep_ai_dma(dev, 0, 0);
729 if (devpriv->ntrig) {
730 prep_ai_dma(dev, 1, 0);
731 devpriv->supcsr |= DT2821_DDMA;
737 dt282x_load_changain(dev, cmd->chanlist_len, cmd->chanlist);
739 devpriv->adcsr = DT2821_ADCLK | DT2821_IADDONE;
742 update_supcsr(DT2821_PRLD);
743 wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;);
745 if (cmd->scan_begin_src == TRIG_FOLLOW) {
746 update_supcsr(DT2821_STRIG);
748 devpriv->supcsr |= DT2821_XTRIG;
755 static void dt282x_disable_dma(struct comedi_device *dev)
757 if (devpriv->usedma) {
758 disable_dma(devpriv->dma[0].chan);
759 disable_dma(devpriv->dma[1].chan);
763 static int dt282x_ai_cancel(struct comedi_device *dev,
764 struct comedi_subdevice *s)
766 dt282x_disable_dma(dev);
772 update_supcsr(DT2821_ADCINIT);
777 static int dt282x_ns_to_timer(int *nanosec, int round_mode)
779 int prescale, base, divider;
781 for (prescale = 0; prescale < 16; prescale++) {
784 base = 250 * (1 << prescale);
785 switch (round_mode) {
786 case TRIG_ROUND_NEAREST:
788 divider = (*nanosec + base / 2) / base;
790 case TRIG_ROUND_DOWN:
791 divider = (*nanosec) / base;
794 divider = (*nanosec + base - 1) / base;
798 *nanosec = divider * base;
799 return (prescale << 8) | (255 - divider);
802 base = 250 * (1 << 15);
804 *nanosec = divider * base;
805 return (15 << 8) | (255 - divider);
809 * Analog output routine. Selects single channel conversion,
810 * selects correct channel, converts from 2's compliment to
811 * offset binary if necessary, loads the data into the DAC
812 * data register, and performs the conversion.
814 static int dt282x_ao_insn_read(struct comedi_device *dev,
815 struct comedi_subdevice *s,
816 struct comedi_insn *insn, unsigned int *data)
818 data[0] = devpriv->ao[CR_CHAN(insn->chanspec)];
823 static int dt282x_ao_insn_write(struct comedi_device *dev,
824 struct comedi_subdevice *s,
825 struct comedi_insn *insn, unsigned int *data)
830 chan = CR_CHAN(insn->chanspec);
832 d &= (1 << boardtype.dabits) - 1;
833 devpriv->ao[chan] = d;
835 devpriv->dacsr |= DT2821_SSEL;
839 devpriv->dacsr |= DT2821_YSEL;
840 if (devpriv->da0_2scomp)
841 d ^= (1 << (boardtype.dabits - 1));
843 devpriv->dacsr &= ~DT2821_YSEL;
844 if (devpriv->da1_2scomp)
845 d ^= (1 << (boardtype.dabits - 1));
850 outw(d, dev->iobase + DT2821_DADAT);
852 update_supcsr(DT2821_DACON);
857 static int dt282x_ao_cmdtest(struct comedi_device *dev,
858 struct comedi_subdevice *s, struct comedi_cmd *cmd)
863 /* step 1: make sure trigger sources are trivially valid */
865 tmp = cmd->start_src;
866 cmd->start_src &= TRIG_INT;
867 if (!cmd->start_src || tmp != cmd->start_src)
870 tmp = cmd->scan_begin_src;
871 cmd->scan_begin_src &= TRIG_TIMER;
872 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
875 tmp = cmd->convert_src;
876 cmd->convert_src &= TRIG_NOW;
877 if (!cmd->convert_src || tmp != cmd->convert_src)
880 tmp = cmd->scan_end_src;
881 cmd->scan_end_src &= TRIG_COUNT;
882 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
886 cmd->stop_src &= TRIG_NONE;
887 if (!cmd->stop_src || tmp != cmd->stop_src)
894 * step 2: make sure trigger sources are unique
895 * and mutually compatible
898 /* note that mutual compatibility is not an issue here */
899 if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
905 /* step 3: make sure arguments are trivially compatible */
907 if (cmd->start_arg != 0) {
911 if (cmd->scan_begin_arg < 5000 /* XXX unknown */) {
912 cmd->scan_begin_arg = 5000;
915 if (cmd->convert_arg != 0) {
916 cmd->convert_arg = 0;
919 if (cmd->scan_end_arg > 2) {
920 /* XXX chanlist stuff? */
921 cmd->scan_end_arg = 2;
924 if (cmd->stop_src == TRIG_COUNT) {
925 /* any count is allowed */
928 if (cmd->stop_arg != 0) {
937 /* step 4: fix up any arguments */
939 tmp = cmd->scan_begin_arg;
940 dt282x_ns_to_timer(&cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK);
941 if (tmp != cmd->scan_begin_arg)
951 static int dt282x_ao_inttrig(struct comedi_device *dev,
952 struct comedi_subdevice *s, unsigned int x)
959 size = cfc_read_array_from_buffer(s, devpriv->dma[0].buf,
960 devpriv->dma_maxsize);
962 printk(KERN_ERR "dt282x: AO underrun\n");
965 prep_ao_dma(dev, 0, size);
967 size = cfc_read_array_from_buffer(s, devpriv->dma[1].buf,
968 devpriv->dma_maxsize);
970 printk(KERN_ERR "dt282x: AO underrun\n");
973 prep_ao_dma(dev, 1, size);
975 update_supcsr(DT2821_STRIG);
976 s->async->inttrig = NULL;
981 static int dt282x_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
984 struct comedi_cmd *cmd = &s->async->cmd;
986 if (devpriv->usedma == 0) {
988 "driver requires 2 dma channels"
989 " to execute command");
993 dt282x_disable_dma(dev);
995 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS1 | DT2821_DDMA;
996 update_supcsr(DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_DACINIT);
998 devpriv->ntrig = cmd->stop_arg * cmd->chanlist_len;
999 devpriv->nread = devpriv->ntrig;
1001 devpriv->dma_dir = DMA_MODE_WRITE;
1002 devpriv->current_dma_index = 0;
1004 timer = dt282x_ns_to_timer(&cmd->scan_begin_arg, TRIG_ROUND_NEAREST);
1005 outw(timer, dev->iobase + DT2821_TMRCTR);
1007 devpriv->dacsr = DT2821_SSEL | DT2821_DACLK | DT2821_IDARDY;
1010 s->async->inttrig = dt282x_ao_inttrig;
1015 static int dt282x_ao_cancel(struct comedi_device *dev,
1016 struct comedi_subdevice *s)
1018 dt282x_disable_dma(dev);
1023 devpriv->supcsr = 0;
1024 update_supcsr(DT2821_DACINIT);
1029 static int dt282x_dio_insn_bits(struct comedi_device *dev,
1030 struct comedi_subdevice *s,
1031 struct comedi_insn *insn, unsigned int *data)
1034 s->state &= ~data[0];
1035 s->state |= (data[0] & data[1]);
1037 outw(s->state, dev->iobase + DT2821_DIODAT);
1039 data[1] = inw(dev->iobase + DT2821_DIODAT);
1044 static int dt282x_dio_insn_config(struct comedi_device *dev,
1045 struct comedi_subdevice *s,
1046 struct comedi_insn *insn, unsigned int *data)
1050 mask = (CR_CHAN(insn->chanspec) < 8) ? 0x00ff : 0xff00;
1054 s->io_bits &= ~mask;
1056 if (s->io_bits & 0x00ff)
1057 devpriv->dacsr |= DT2821_LBOE;
1059 devpriv->dacsr &= ~DT2821_LBOE;
1060 if (s->io_bits & 0xff00)
1061 devpriv->dacsr |= DT2821_HBOE;
1063 devpriv->dacsr &= ~DT2821_HBOE;
1065 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
1070 static const struct comedi_lrange *const ai_range_table[] = {
1071 &range_dt282x_ai_lo_bipolar,
1072 &range_dt282x_ai_lo_unipolar,
1073 &range_dt282x_ai_5_bipolar,
1074 &range_dt282x_ai_5_unipolar
1077 static const struct comedi_lrange *const ai_range_pgl_table[] = {
1078 &range_dt282x_ai_hi_bipolar,
1079 &range_dt282x_ai_hi_unipolar
1082 static const struct comedi_lrange *opt_ai_range_lkup(int ispgl, int x)
1085 if (x < 0 || x >= 2)
1087 return ai_range_pgl_table[x];
1089 if (x < 0 || x >= 4)
1091 return ai_range_table[x];
1095 static const struct comedi_lrange *const ao_range_table[] = {
1103 static const struct comedi_lrange *opt_ao_range_lkup(int x)
1105 if (x < 0 || x >= 5)
1107 return ao_range_table[x];
1110 enum { /* i/o base, irq, dma channels */
1111 opt_iobase = 0, opt_irq, opt_dma1, opt_dma2,
1112 opt_diff, /* differential */
1113 opt_ai_twos, opt_ao0_twos, opt_ao1_twos, /* twos comp */
1114 opt_ai_range, opt_ao0_range, opt_ao1_range, /* range */
1117 static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2)
1121 devpriv->usedma = 0;
1123 if (!dma1 && !dma2) {
1124 printk(KERN_ERR " (no dma)");
1128 if (dma1 == dma2 || dma1 < 5 || dma2 < 5 || dma1 > 7 || dma2 > 7)
1138 ret = request_dma(dma1, "dt282x A");
1141 devpriv->dma[0].chan = dma1;
1143 ret = request_dma(dma2, "dt282x B");
1146 devpriv->dma[1].chan = dma2;
1148 devpriv->dma_maxsize = PAGE_SIZE;
1149 devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
1150 devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
1151 if (!devpriv->dma[0].buf || !devpriv->dma[1].buf) {
1152 printk(KERN_ERR " can't get DMA memory");
1156 printk(KERN_INFO " (dma=%d,%d)", dma1, dma2);
1158 devpriv->usedma = 1;
1169 4 0=single ended, 1=differential
1170 5 ai 0=straight binary, 1=2's comp
1171 6 ao0 0=straight binary, 1=2's comp
1172 7 ao1 0=straight binary, 1=2's comp
1173 8 ai 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V
1174 9 ao0 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1175 10 ao1 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1177 static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1181 struct comedi_subdevice *s;
1182 unsigned long iobase;
1184 dev->board_name = this_board->name;
1186 iobase = it->options[opt_iobase];
1190 printk(KERN_INFO "comedi%d: dt282x: 0x%04lx", dev->minor, iobase);
1191 if (!request_region(iobase, DT2821_SIZE, "dt282x")) {
1192 printk(KERN_INFO " I/O port conflict\n");
1195 dev->iobase = iobase;
1197 outw(DT2821_BDINIT, dev->iobase + DT2821_SUPCSR);
1198 i = inw(dev->iobase + DT2821_ADCSR);
1200 printk(KERN_DEBUG " fingerprint=%x,%x,%x,%x,%x",
1201 inw(dev->iobase + DT2821_ADCSR),
1202 inw(dev->iobase + DT2821_CHANCSR),
1203 inw(dev->iobase + DT2821_DACSR),
1204 inw(dev->iobase + DT2821_SUPCSR),
1205 inw(dev->iobase + DT2821_TMRCTR));
1208 if (((inw(dev->iobase + DT2821_ADCSR) & DT2821_ADCSR_MASK)
1209 != DT2821_ADCSR_VAL) ||
1210 ((inw(dev->iobase + DT2821_CHANCSR) & DT2821_CHANCSR_MASK)
1211 != DT2821_CHANCSR_VAL) ||
1212 ((inw(dev->iobase + DT2821_DACSR) & DT2821_DACSR_MASK)
1213 != DT2821_DACSR_VAL) ||
1214 ((inw(dev->iobase + DT2821_SUPCSR) & DT2821_SUPCSR_MASK)
1215 != DT2821_SUPCSR_VAL) ||
1216 ((inw(dev->iobase + DT2821_TMRCTR) & DT2821_TMRCTR_MASK)
1217 != DT2821_TMRCTR_VAL)) {
1218 printk(KERN_ERR " board not found");
1221 /* should do board test */
1223 irq = it->options[opt_irq];
1226 unsigned long flags;
1231 irqs = probe_irq_on();
1233 /* trigger interrupt */
1237 irq = probe_irq_off(irqs);
1238 restore_flags(flags);
1240 printk(KERN_ERR " error probing irq (bad)");
1244 printk(KERN_INFO " ( irq = %d )", irq);
1245 ret = request_irq(irq, dt282x_interrupt, 0, "dt282x", dev);
1247 printk(KERN_ERR " failed to get irq\n");
1251 } else if (irq == 0) {
1252 printk(KERN_INFO " (no irq)");
1255 printk(KERN_INFO " (probe returned multiple irqs--bad)");
1257 printk(KERN_INFO " (irq probe not implemented)");
1261 ret = alloc_private(dev, sizeof(struct dt282x_private));
1265 ret = dt282x_grab_dma(dev, it->options[opt_dma1],
1266 it->options[opt_dma2]);
1270 ret = alloc_subdevices(dev, 3);
1274 s = dev->subdevices + 0;
1276 dev->read_subdev = s;
1278 s->type = COMEDI_SUBD_AI;
1279 s->subdev_flags = SDF_READABLE | SDF_CMD_READ |
1280 ((it->options[opt_diff]) ? SDF_DIFF : SDF_COMMON);
1282 (it->options[opt_diff]) ? boardtype.adchan_di : boardtype.adchan_se;
1283 s->insn_read = dt282x_ai_insn_read;
1284 s->do_cmdtest = dt282x_ai_cmdtest;
1285 s->do_cmd = dt282x_ai_cmd;
1286 s->cancel = dt282x_ai_cancel;
1287 s->maxdata = (1 << boardtype.adbits) - 1;
1288 s->len_chanlist = 16;
1290 opt_ai_range_lkup(boardtype.ispgl, it->options[opt_ai_range]);
1291 devpriv->ad_2scomp = it->options[opt_ai_twos];
1295 s->n_chan = boardtype.dachan;
1298 s->type = COMEDI_SUBD_AO;
1299 dev->write_subdev = s;
1300 s->subdev_flags = SDF_WRITABLE | SDF_CMD_WRITE;
1301 s->insn_read = dt282x_ao_insn_read;
1302 s->insn_write = dt282x_ao_insn_write;
1303 s->do_cmdtest = dt282x_ao_cmdtest;
1304 s->do_cmd = dt282x_ao_cmd;
1305 s->cancel = dt282x_ao_cancel;
1306 s->maxdata = (1 << boardtype.dabits) - 1;
1307 s->len_chanlist = 2;
1308 s->range_table_list = devpriv->darangelist;
1309 devpriv->darangelist[0] =
1310 opt_ao_range_lkup(it->options[opt_ao0_range]);
1311 devpriv->darangelist[1] =
1312 opt_ao_range_lkup(it->options[opt_ao1_range]);
1313 devpriv->da0_2scomp = it->options[opt_ao0_twos];
1314 devpriv->da1_2scomp = it->options[opt_ao1_twos];
1316 s->type = COMEDI_SUBD_UNUSED;
1321 s->type = COMEDI_SUBD_DIO;
1322 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1324 s->insn_bits = dt282x_dio_insn_bits;
1325 s->insn_config = dt282x_dio_insn_config;
1327 s->range_table = &range_digital;
1329 printk(KERN_INFO "\n");
1334 static void dt282x_detach(struct comedi_device *dev)
1337 free_irq(dev->irq, dev);
1339 release_region(dev->iobase, DT2821_SIZE);
1341 if (devpriv->dma[0].chan)
1342 free_dma(devpriv->dma[0].chan);
1343 if (devpriv->dma[1].chan)
1344 free_dma(devpriv->dma[1].chan);
1345 if (devpriv->dma[0].buf)
1346 free_page((unsigned long)devpriv->dma[0].buf);
1347 if (devpriv->dma[1].buf)
1348 free_page((unsigned long)devpriv->dma[1].buf);
1352 static const struct dt282x_board boardtypes[] = {
1390 .name = "dt2824-pgh",
1399 .name = "dt2824-pgl",
1471 .name = "dt24-ez-pgl",
1482 static struct comedi_driver dt282x_driver = {
1483 .driver_name = "dt282x",
1484 .module = THIS_MODULE,
1485 .attach = dt282x_attach,
1486 .detach = dt282x_detach,
1487 .board_name = &boardtypes[0].name,
1488 .num_names = ARRAY_SIZE(boardtypes),
1489 .offset = sizeof(struct dt282x_board),
1491 module_comedi_driver(dt282x_driver);
1493 MODULE_AUTHOR("Comedi http://www.comedi.org");
1494 MODULE_DESCRIPTION("Comedi low-level driver");
1495 MODULE_LICENSE("GPL");