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 <linux/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 comedi_lrange range_dt282x_ai_lo_bipolar = { 4, {
163 static comedi_lrange range_dt282x_ai_lo_unipolar = { 4, {
169 static comedi_lrange range_dt282x_ai_5_bipolar = { 4, {
172 RANGE( -1.25, 1.25 ),
173 RANGE( -0.625, 0.625 ),
175 static comedi_lrange range_dt282x_ai_5_unipolar = { 4, {
181 static comedi_lrange range_dt282x_ai_hi_bipolar = { 4, {
187 static comedi_lrange range_dt282x_ai_hi_unipolar = { 4, {
206 static boardtype_t boardtypes[] =
244 { name: "dt2824-pgh",
253 { name: "dt2824-pgl",
325 { name: "dt24-ez-pgl",
335 #define n_boardtypes sizeof(boardtypes)/sizeof(boardtype_t)
336 #define this_board ((boardtype_t *)dev->board_ptr)
340 int ad_2scomp; /* we have 2's comp jumper set */
341 int da0_2scomp; /* same, for DAC0 */
342 int da1_2scomp; /* same, for DAC1 */
344 comedi_lrange *darangelist[2];
348 volatile int dacsr; /* software copies of registers */
357 short *buf; /* DMA buffer */
358 volatile int size; /* size of current transfer */
360 int dma_maxsize; /* max size of DMA transfer (in bytes) */
361 int usedma; /* driver uses DMA */
362 volatile int current_dma_index;
366 #define devpriv ((dt282x_private *)dev->private)
367 #define boardtype (*(boardtype_t *)dev->board_ptr)
370 * Some useless abstractions
372 #define chan_to_DAC(a) ((a)&1)
373 #define update_dacsr(a) outw(devpriv->dacsr|(a),dev->iobase+DT2821_DACSR)
374 #define update_adcsr(a) outw(devpriv->adcsr|(a),dev->iobase+DT2821_ADCSR)
375 #define mux_busy() (inw(dev->iobase+DT2821_ADCSR)&DT2821_MUXBUSY)
376 #define ad_done() (inw(dev->iobase+DT2821_ADCSR)&DT2821_ADDONE)
377 #define update_supcsr(a) outw(devpriv->supcsr|(a),dev->iobase+DT2821_SUPCSR)
380 * danger! macro abuse... a is the expression to wait on, and b is
381 * the statement(s) to execute if it doesn't happen.
383 #define wait_for(a,b) \
386 for(_i=0;_i<DT2821_TIMEOUT;_i++){ \
393 static int dt282x_attach(comedi_device * dev, comedi_devconfig * it);
394 static int dt282x_detach(comedi_device * dev);
395 static comedi_driver driver_dt282x={
396 driver_name: "dt282x",
398 attach: dt282x_attach,
399 detach: dt282x_detach,
400 board_name: &boardtypes[0].name,
401 num_names: n_boardtypes,
402 offset: sizeof(boardtype_t),
404 COMEDI_INITCLEANUP(driver_dt282x);
406 static void free_resources(comedi_device *dev);
407 static int prep_ai_dma(comedi_device * dev,int chan,int size);
408 static int prep_ao_dma(comedi_device * dev,int chan,int size);
409 static int dt282x_ai_cancel(comedi_device * dev, comedi_subdevice * s);
410 static int dt282x_ao_cancel(comedi_device * dev, comedi_subdevice * s);
411 static int dt282x_ns_to_timer(int *nanosec,int round_mode);
412 static void dt282x_disable_dma(comedi_device *dev);
415 static int dt282x_grab_dma(comedi_device *dev,int dma1,int dma2);
417 static void dt282x_munge(comedi_device *dev,sampl_t *buf,
421 unsigned short mask=(1<<boardtype.adbits)-1;
422 unsigned short sign=1<<(boardtype.adbits-1);
425 if(devpriv->ad_2scomp){
426 sign = 1<<(boardtype.adbits-1);
432 comedi_error( dev, "bug! odd number of bytes from dma xfer" );
435 buf[i] = (buf[i]&mask)^sign;
439 static void dt282x_ao_dma_interrupt(comedi_device * dev)
444 comedi_subdevice *s=dev->subdevices+1;
446 update_supcsr(DT2821_CLRDMADNE);
448 if(!s->async->prealloc_buf){
449 printk("async->data disappeared. dang!\n");
453 i=devpriv->current_dma_index;
454 ptr=devpriv->dma[i].buf;
456 disable_dma(devpriv->dma[i].chan);
458 devpriv->current_dma_index=1-i;
460 size = cfc_read_array_from_buffer(s, ptr, devpriv->dma_maxsize);
462 rt_printk("dt282x: AO underrun\n");
463 dt282x_ao_cancel(dev,s);
464 s->async->events |= COMEDI_CB_OVERFLOW;
467 prep_ao_dma(dev,i,size);
471 static void dt282x_ai_dma_interrupt(comedi_device * dev)
477 comedi_subdevice *s=dev->subdevices;
479 update_supcsr(DT2821_CLRDMADNE);
481 if(!s->async->prealloc_buf){
482 printk("async->data disappeared. dang!\n");
486 i = devpriv->current_dma_index;
487 ptr = devpriv->dma[i].buf;
488 size = devpriv->dma[i].size;
490 disable_dma(devpriv->dma[i].chan);
492 devpriv->current_dma_index = 1-i;
494 dt282x_munge(dev, ptr, size );
495 ret = cfc_write_array_to_buffer( s, ptr, size );
498 dt282x_ai_cancel(dev,s);
501 devpriv->nread-=size/2;
503 if(devpriv->nread<0){
504 printk("dt282x: off by one\n");
507 if (!devpriv->nread) {
508 dt282x_ai_cancel(dev, s);
509 s->async->events |= COMEDI_CB_EOA;
514 /* clear the dual dma flag, making this the last dma segment */
515 /* XXX probably wrong */
517 devpriv->supcsr &= ~(DT2821_DDMA);
521 /* restart the channel */
522 prep_ai_dma(dev,i,0);
525 static int prep_ai_dma(comedi_device * dev,int dma_index,int n)
528 unsigned long dma_ptr;
535 n = devpriv->dma_maxsize;
536 if (n > devpriv->ntrig*2)
537 n = devpriv->ntrig*2;
538 devpriv->ntrig -= n/2;
540 devpriv->dma[dma_index].size = n;
541 dma_chan = devpriv->dma[dma_index].chan;
542 dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
544 set_dma_mode(dma_chan, DMA_MODE_READ);
545 flags=claim_dma_lock();
546 clear_dma_ff(dma_chan);
547 set_dma_addr(dma_chan, dma_ptr);
548 set_dma_count(dma_chan, n);
549 release_dma_lock(flags);
551 enable_dma(dma_chan);
556 static int prep_ao_dma(comedi_device * dev,int dma_index,int n)
559 unsigned long dma_ptr;
562 devpriv->dma[dma_index].size = n;
563 dma_chan = devpriv->dma[dma_index].chan;
564 dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
566 set_dma_mode(dma_chan, DMA_MODE_WRITE);
567 flags=claim_dma_lock();
568 clear_dma_ff(dma_chan);
569 set_dma_addr(dma_chan, dma_ptr);
570 set_dma_count(dma_chan, n );
571 release_dma_lock(flags);
573 enable_dma(dma_chan);
578 static irqreturn_t dt282x_interrupt(int irq, void *d PT_REGS_ARG)
580 comedi_device *dev = d;
581 comedi_subdevice *s = dev->subdevices+0;
582 comedi_subdevice *s_ao = dev->subdevices+1;
583 unsigned int supcsr, adcsr, dacsr;
586 adcsr = inw(dev->iobase + DT2821_ADCSR);
587 dacsr = inw(dev->iobase + DT2821_DACSR);
588 supcsr = inw(dev->iobase + DT2821_SUPCSR);
589 if (supcsr & DT2821_DMAD) {
590 if(devpriv->dma_dir==DMA_MODE_READ)
591 dt282x_ai_dma_interrupt(dev);
593 dt282x_ao_dma_interrupt(dev);
596 if (adcsr & DT2821_ADERR) {
597 if(devpriv->nread != 0 ){
598 comedi_error(dev, "A/D error");
599 dt282x_ai_cancel(dev,s);
600 s->async->events |= COMEDI_CB_ERROR;
604 if (dacsr & DT2821_DAERR) {
608 disable_irq(dev->irq);
609 printk("disabling irq\n");
612 comedi_error(dev, "D/A error");
613 dt282x_ao_cancel(dev,s_ao);
614 s->async->events |= COMEDI_CB_ERROR;
618 if (adcsr & DT2821_ADDONE) {
622 data = (sampl_t) inw(dev->iobase + DT2821_ADDAT);
623 data&=(1<<boardtype.adbits)-1;
624 if(devpriv->ad_2scomp){
625 data^=1<<(boardtype.adbits-1);
627 ret = comedi_buf_put( s->async, data );
629 s->async->events |= COMEDI_CB_OVERFLOW;
634 s->async->events |= COMEDI_CB_EOA;
636 if(supcsr&DT2821_SCDN)
637 update_supcsr(DT2821_STRIG);
642 comedi_event(dev, s, s->async->events);
643 /* printk("adcsr=0x%02x dacsr-0x%02x supcsr=0x%02x\n", adcsr, dacsr, supcsr); */
644 return IRQ_RETVAL(handled);
648 static void dt282x_load_changain(comedi_device * dev, int n, unsigned int *chanlist)
651 unsigned int chan, range;
653 outw(DT2821_LLE | (n - 1), dev->iobase + DT2821_CHANCSR);
654 for (i = 0; i < n; i++) {
655 chan = CR_CHAN(chanlist[i]);
656 range = CR_RANGE(chanlist[i]);
657 update_adcsr((range << 4) | (chan));
659 outw(n - 1, dev->iobase + DT2821_CHANCSR);
664 * Performs a single A/D conversion.
665 * - Put channel/gain into channel-gain list
666 * - preload multiplexer
667 * - trigger conversion and wait for it to finish
669 static int dt282x_ai_insn_read(comedi_device *dev,comedi_subdevice *s,
670 comedi_insn *insn, lsampl_t *data)
674 /* XXX should we really be enabling the ad clock here? */
675 devpriv->adcsr = DT2821_ADCLK;
678 dt282x_load_changain(dev, 1, &insn->chanspec);
680 update_supcsr(DT2821_PRLD);
681 wait_for(!mux_busy(),
682 comedi_error(dev, "timeout\n");
686 for(i=0;i<insn->n;i++){
687 update_supcsr(DT2821_STRIG);
689 comedi_error(dev, "timeout\n");
693 data[i] = inw(dev->iobase + DT2821_ADDAT) & ((1<<boardtype.adbits)-1);
694 if (devpriv->ad_2scomp)
695 data[i] ^= (1 << (boardtype.adbits - 1));
701 static int dt282x_ai_cmdtest(comedi_device * dev, comedi_subdevice * s,comedi_cmd *cmd)
706 /* step 1: make sure trigger sources are trivially valid */
709 cmd->start_src &= TRIG_NOW;
710 if(!cmd->start_src || tmp!=cmd->start_src)err++;
712 tmp=cmd->scan_begin_src;
713 cmd->scan_begin_src &= TRIG_FOLLOW|TRIG_EXT;
714 if(!cmd->scan_begin_src || tmp!=cmd->scan_begin_src)err++;
716 tmp=cmd->convert_src;
717 cmd->convert_src &= TRIG_TIMER;
718 if(!cmd->convert_src || tmp!=cmd->convert_src)err++;
720 tmp=cmd->scan_end_src;
721 cmd->scan_end_src &= TRIG_COUNT;
722 if(!cmd->scan_end_src || tmp!=cmd->scan_end_src)err++;
725 cmd->stop_src &= TRIG_COUNT|TRIG_NONE;
726 if(!cmd->stop_src || tmp!=cmd->stop_src)err++;
730 /* step 2: make sure trigger sources are unique and mutually compatible */
732 /* note that mutual compatiblity is not an issue here */
733 if(cmd->scan_begin_src!=TRIG_FOLLOW &&
734 cmd->scan_begin_src!=TRIG_EXT)err++;
735 if(cmd->stop_src!=TRIG_COUNT &&
736 cmd->stop_src!=TRIG_NONE)err++;
740 /* step 3: make sure arguments are trivially compatible */
742 if(cmd->start_arg!=0){
746 if(cmd->scan_begin_src==TRIG_FOLLOW){
747 /* internal trigger */
748 if(cmd->scan_begin_arg!=0){
749 cmd->scan_begin_arg=0;
753 /* external trigger */
754 /* should be level/edge, hi/lo specification here */
755 if(cmd->scan_begin_arg!=0){
756 cmd->scan_begin_arg=0;
760 if(cmd->convert_arg<4000){
761 /* XXX board dependent */
762 cmd->convert_arg=4000;
765 #define SLOWEST_TIMER (250*(1<<15)*255)
766 if(cmd->convert_arg>SLOWEST_TIMER){
767 cmd->convert_arg=SLOWEST_TIMER;
770 if(cmd->convert_arg < this_board->ai_speed ){
771 cmd->convert_arg = this_board->ai_speed;
774 if(cmd->scan_end_arg!=cmd->chanlist_len){
775 cmd->scan_end_arg=cmd->chanlist_len;
778 if(cmd->stop_src==TRIG_COUNT){
779 /* any count is allowed */
782 if(cmd->stop_arg!=0){
790 /* step 4: fix up any arguments */
792 tmp=cmd->convert_arg;
793 dt282x_ns_to_timer(&cmd->convert_arg,cmd->flags&TRIG_ROUND_MASK);
794 if(tmp!=cmd->convert_arg)err++;
801 static int dt282x_ai_cmd(comedi_device * dev, comedi_subdevice * s)
803 comedi_cmd *cmd=&s->async->cmd;
806 if(devpriv->usedma == 0){
807 comedi_error(dev, "driver requires 2 dma channels to execute command");
811 dt282x_disable_dma(dev);
813 if(cmd->convert_arg < this_board->ai_speed )
814 cmd->convert_arg = this_board->ai_speed;
815 timer=dt282x_ns_to_timer(&cmd->convert_arg,TRIG_ROUND_NEAREST);
816 outw(timer, dev->iobase + DT2821_TMRCTR);
818 if(cmd->scan_begin_src==TRIG_FOLLOW){
819 /* internal trigger */
820 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0;
822 /* external trigger */
823 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0 | DT2821_DS1;
825 update_supcsr(DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_ADCINIT);
827 devpriv->ntrig=cmd->stop_arg*cmd->scan_end_arg;
828 devpriv->nread=devpriv->ntrig;
830 devpriv->dma_dir=DMA_MODE_READ;
831 devpriv->current_dma_index=0;
832 prep_ai_dma(dev,0,0);
834 prep_ai_dma(dev,1,0);
835 devpriv->supcsr |= DT2821_DDMA;
841 dt282x_load_changain(dev,cmd->chanlist_len,cmd->chanlist);
843 devpriv->adcsr = DT2821_ADCLK | DT2821_IADDONE;
846 update_supcsr(DT2821_PRLD);
847 wait_for(!mux_busy(),
848 comedi_error(dev, "timeout\n");
852 if(cmd->scan_begin_src==TRIG_FOLLOW){
853 update_supcsr(DT2821_STRIG);
855 devpriv->supcsr |= DT2821_XTRIG;
862 static void dt282x_disable_dma(comedi_device *dev)
864 if( devpriv->usedma ){
865 disable_dma(devpriv->dma[0].chan);
866 disable_dma(devpriv->dma[1].chan);
870 static int dt282x_ai_cancel(comedi_device * dev, comedi_subdevice * s)
872 dt282x_disable_dma(dev);
878 update_supcsr(DT2821_ADCINIT);
884 static int dt282x_ns_to_timer(int *nanosec,int round_mode)
886 int prescale,base,divider;
888 for(prescale=0;prescale<16;prescale++){
889 if(prescale==1)continue;
890 base=250*(1<<prescale);
892 case TRIG_ROUND_NEAREST:
894 divider=(*nanosec+base/2)/base;
896 case TRIG_ROUND_DOWN:
897 divider=(*nanosec)/base;
900 divider=(*nanosec+base-1)/base;
904 *nanosec=divider*base;
905 return (prescale<<8)|(255-divider);
910 *nanosec=divider*base;
911 return (15<<8)|(255-divider);
916 * Analog output routine. Selects single channel conversion,
917 * selects correct channel, converts from 2's compliment to
918 * offset binary if necessary, loads the data into the DAC
919 * data register, and performs the conversion.
921 static int dt282x_ao_insn_read(comedi_device *dev,comedi_subdevice *s,
922 comedi_insn *insn, lsampl_t *data)
924 data[0] = devpriv->ao[CR_CHAN(insn->chanspec)];
929 static int dt282x_ao_insn_write(comedi_device * dev, comedi_subdevice * s,
930 comedi_insn *insn, lsampl_t *data)
935 chan = CR_CHAN(insn->chanspec);
937 d &= (1<<boardtype.dabits)-1;
938 devpriv->ao[chan] = d;
940 devpriv->dacsr |= DT2821_SSEL;
944 devpriv->dacsr |= DT2821_YSEL;
945 if (devpriv->da0_2scomp)
946 d ^= (1<<(boardtype.dabits-1));
948 devpriv->dacsr &= ~DT2821_YSEL;
949 if (devpriv->da1_2scomp)
950 d ^= (1<<(boardtype.dabits-1));
955 outw(d, dev->iobase + DT2821_DADAT);
957 update_supcsr(DT2821_DACON);
962 static int dt282x_ao_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd)
967 /* step 1: make sure trigger sources are trivially valid */
970 cmd->start_src &= TRIG_INT;
971 if(!cmd->start_src || tmp!=cmd->start_src)err++;
973 tmp=cmd->scan_begin_src;
974 cmd->scan_begin_src &= TRIG_TIMER;
975 if(!cmd->scan_begin_src || tmp!=cmd->scan_begin_src)err++;
977 tmp=cmd->convert_src;
978 cmd->convert_src &= TRIG_NOW;
979 if(!cmd->convert_src || tmp!=cmd->convert_src)err++;
981 tmp=cmd->scan_end_src;
982 cmd->scan_end_src &= TRIG_COUNT;
983 if(!cmd->scan_end_src || tmp!=cmd->scan_end_src)err++;
986 cmd->stop_src &= TRIG_NONE;
987 if(!cmd->stop_src || tmp!=cmd->stop_src)err++;
991 /* step 2: make sure trigger sources are unique and mutually compatible */
993 /* note that mutual compatiblity is not an issue here */
994 if(cmd->stop_src!=TRIG_COUNT &&
995 cmd->stop_src!=TRIG_NONE)err++;
999 /* step 3: make sure arguments are trivially compatible */
1001 if(cmd->start_arg!=0){
1005 if(cmd->scan_begin_arg < 5000 /* XXX unknown */){
1006 cmd->scan_begin_arg = 5000;
1009 if(cmd->convert_arg != 0){
1010 cmd->convert_arg = 0;
1013 if(cmd->scan_end_arg > 2){
1014 /* XXX chanlist stuff? */
1015 cmd->scan_end_arg = 2;
1018 if(cmd->stop_src==TRIG_COUNT){
1019 /* any count is allowed */
1022 if(cmd->stop_arg!=0){
1030 /* step 4: fix up any arguments */
1032 tmp=cmd->scan_begin_arg;
1033 dt282x_ns_to_timer(&cmd->scan_begin_arg,cmd->flags&TRIG_ROUND_MASK);
1034 if(tmp!=cmd->scan_begin_arg)err++;
1042 static int dt282x_ao_inttrig(comedi_device *dev,comedi_subdevice *s,
1047 if(x!=0)return -EINVAL;
1049 size = cfc_read_array_from_buffer(s, devpriv->dma[0].buf, devpriv->dma_maxsize);
1051 rt_printk("dt282x: AO underrun\n");
1054 prep_ao_dma(dev,0,size);
1056 size = cfc_read_array_from_buffer(s, devpriv->dma[1].buf, devpriv->dma_maxsize);
1058 rt_printk("dt282x: AO underrun\n");
1061 prep_ao_dma(dev,1,size);
1063 update_supcsr(DT2821_STRIG);
1064 s->async->inttrig=NULL;
1069 static int dt282x_ao_cmd(comedi_device *dev,comedi_subdevice *s)
1072 comedi_cmd *cmd=&s->async->cmd;
1074 if(devpriv->usedma == 0){
1075 comedi_error(dev, "driver requires 2 dma channels to execute command");
1079 dt282x_disable_dma(dev);
1081 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS1 | DT2821_DDMA;
1082 update_supcsr(DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_DACINIT);
1084 devpriv->ntrig=cmd->stop_arg*cmd->chanlist_len;
1085 devpriv->nread=devpriv->ntrig;
1087 devpriv->dma_dir=DMA_MODE_WRITE;
1088 devpriv->current_dma_index=0;
1090 timer=dt282x_ns_to_timer(&cmd->scan_begin_arg,TRIG_ROUND_NEAREST);
1091 outw(timer, dev->iobase + DT2821_TMRCTR);
1093 devpriv->dacsr = DT2821_SSEL| DT2821_DACLK | DT2821_IDARDY;
1096 s->async->inttrig=dt282x_ao_inttrig;
1101 static int dt282x_ao_cancel(comedi_device * dev, comedi_subdevice * s)
1103 dt282x_disable_dma(dev);
1108 devpriv->supcsr = 0;
1109 update_supcsr(DT2821_DACINIT);
1114 static int dt282x_dio_insn_bits(comedi_device *dev,comedi_subdevice *s,
1115 comedi_insn *insn,lsampl_t *data)
1118 s->state &= ~data[0];
1119 s->state |= (data[0]&data[1]);
1121 outw(s->state, dev->iobase + DT2821_DIODAT);
1123 data[1] = inw(dev->iobase + DT2821_DIODAT);
1128 static int dt282x_dio_insn_config(comedi_device *dev,comedi_subdevice *s,
1129 comedi_insn *insn,lsampl_t *data)
1133 mask=(CR_CHAN(insn->chanspec)<8)?0x00ff:0xff00;
1134 if(data[0])s->io_bits|=mask;
1135 else s->io_bits&=~mask;
1137 if(s->io_bits&0x00ff)devpriv->dacsr|=DT2821_LBOE;
1138 else devpriv->dacsr&=~DT2821_LBOE;
1139 if(s->io_bits&0xff00)devpriv->dacsr|=DT2821_HBOE;
1140 else devpriv->dacsr&=~DT2821_HBOE;
1142 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
1148 static comedi_lrange *ai_range_table[]={
1149 &range_dt282x_ai_lo_bipolar,
1150 &range_dt282x_ai_lo_unipolar,
1151 &range_dt282x_ai_5_bipolar,
1152 &range_dt282x_ai_5_unipolar };
1153 static comedi_lrange *ai_range_pgl_table[]={
1154 &range_dt282x_ai_hi_bipolar,
1155 &range_dt282x_ai_hi_unipolar };
1156 static comedi_lrange *opt_ai_range_lkup(int ispgl,int x)
1160 return ai_range_pgl_table[x];
1163 return ai_range_table[x];
1166 static comedi_lrange *ao_range_table[]={
1171 &range_bipolar2_5 };
1172 static comedi_lrange *opt_ao_range_lkup(int x)
1175 return ao_range_table[x];
1178 enum{ opt_iobase=0, opt_irq, opt_dma1, opt_dma2, /* i/o base, irq, dma channels */
1179 opt_diff, /* differential */
1180 opt_ai_twos, opt_ao0_twos, opt_ao1_twos, /* twos comp */
1181 opt_ai_range, opt_ao0_range, opt_ao1_range, /* range */
1191 4 0=single ended, 1=differential
1192 5 ai 0=straight binary, 1=2's comp
1193 6 ao0 0=straight binary, 1=2's comp
1194 7 ao1 0=straight binary, 1=2's comp
1195 8 ai 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V
1196 9 ao0 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1197 10 ao1 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1199 static int dt282x_attach(comedi_device * dev, comedi_devconfig * it)
1203 comedi_subdevice *s;
1204 unsigned long iobase;
1206 dev->board_name = this_board->name;
1208 iobase = it->options[opt_iobase];
1209 if(!iobase)iobase = 0x240;
1211 printk("comedi%d: dt282x: 0x%04lx", dev->minor, iobase);
1212 if (!request_region(iobase, DT2821_SIZE, "dt282x")) {
1213 printk(" I/O port conflict\n");
1216 dev->iobase = iobase;
1218 outw(DT2821_BDINIT, dev->iobase + DT2821_SUPCSR);
1219 i = inw(dev->iobase + DT2821_ADCSR);
1221 printk(" fingerprint=%x,%x,%x,%x,%x",
1222 inw(dev->iobase + DT2821_ADCSR),
1223 inw(dev->iobase + DT2821_CHANCSR),
1224 inw(dev->iobase + DT2821_DACSR),
1225 inw(dev->iobase + DT2821_SUPCSR),
1226 inw(dev->iobase + DT2821_TMRCTR));
1230 ((inw(dev->iobase + DT2821_ADCSR) & DT2821_ADCSR_MASK)
1231 != DT2821_ADCSR_VAL) ||
1232 ((inw(dev->iobase + DT2821_CHANCSR) & DT2821_CHANCSR_MASK)
1233 != DT2821_CHANCSR_VAL) ||
1234 ((inw(dev->iobase + DT2821_DACSR) & DT2821_DACSR_MASK)
1235 != DT2821_DACSR_VAL) ||
1236 ((inw(dev->iobase + DT2821_SUPCSR) & DT2821_SUPCSR_MASK)
1237 != DT2821_SUPCSR_VAL) ||
1238 ((inw(dev->iobase + DT2821_TMRCTR) & DT2821_TMRCTR_MASK)
1239 != DT2821_TMRCTR_VAL)) {
1240 printk(" board not found");
1243 /* should do board test */
1245 irq = it->options[opt_irq];
1248 unsigned long flags;
1253 irqs = probe_irq_on();
1255 /* trigger interrupt */
1259 irq = probe_irq_off(irqs);
1260 restore_flags(flags);
1261 if (0 /* error */ ) {
1262 printk(" error probing irq (bad)");
1267 printk(" ( irq = %d )", irq);
1268 ret = comedi_request_irq(irq, dt282x_interrupt, 0, "dt282x", dev);
1270 printk(" failed to get irq\n");
1274 } else if (irq == 0) {
1275 printk(" (no irq)");
1278 printk(" (probe returned multiple irqs--bad)");
1280 printk(" (irq probe not implemented)");
1284 if((ret=alloc_private(dev,sizeof(dt282x_private)))<0)
1287 ret=dt282x_grab_dma(dev,it->options[opt_dma1],it->options[opt_dma2]);
1291 if((ret=alloc_subdevices(dev, 3))<0)
1294 s=dev->subdevices+0;
1298 s->type=COMEDI_SUBD_AI;
1299 s->subdev_flags=SDF_READABLE | SDF_CMD_READ |
1300 ((it->options[opt_diff])?SDF_DIFF:SDF_COMMON);
1301 s->n_chan=(it->options[opt_diff])?boardtype.adchan_di:boardtype.adchan_se;
1302 s->insn_read=dt282x_ai_insn_read;
1303 s->do_cmdtest=dt282x_ai_cmdtest;
1304 s->do_cmd=dt282x_ai_cmd;
1305 s->cancel=dt282x_ai_cancel;
1306 s->maxdata=(1<<boardtype.adbits)-1;
1308 s->range_table = opt_ai_range_lkup(boardtype.ispgl,it->options[opt_ai_range]);
1309 devpriv->ad_2scomp=it->options[opt_ai_twos];
1312 if((s->n_chan=boardtype.dachan)){
1314 s->type=COMEDI_SUBD_AO;
1315 dev->write_subdev=s;
1316 s->subdev_flags = SDF_WRITABLE | SDF_CMD_WRITE;
1317 s->insn_read=dt282x_ao_insn_read;
1318 s->insn_write=dt282x_ao_insn_write;
1319 s->do_cmdtest=dt282x_ao_cmdtest;
1320 s->do_cmd=dt282x_ao_cmd;
1321 s->cancel=dt282x_ao_cancel;
1322 s->maxdata=(1<<boardtype.dabits)-1;
1324 s->range_table_list=devpriv->darangelist;
1325 devpriv->darangelist[0]=
1326 opt_ao_range_lkup(it->options[opt_ao0_range]);
1327 devpriv->darangelist[1]=
1328 opt_ao_range_lkup(it->options[opt_ao1_range]);
1329 devpriv->da0_2scomp=it->options[opt_ao0_twos];
1330 devpriv->da1_2scomp=it->options[opt_ao1_twos];
1332 s->type=COMEDI_SUBD_UNUSED;
1337 s->type=COMEDI_SUBD_DIO;
1338 s->subdev_flags=SDF_READABLE|SDF_WRITABLE;
1340 s->insn_bits = dt282x_dio_insn_bits;
1341 s->insn_config = dt282x_dio_insn_config;
1343 s->range_table = &range_digital;
1351 static void free_resources(comedi_device *dev)
1354 comedi_free_irq(dev->irq, dev);
1357 release_region(dev->iobase, DT2821_SIZE);
1359 if (devpriv->dma[0].chan)
1360 free_dma(devpriv->dma[0].chan);
1361 if (devpriv->dma[1].chan)
1362 free_dma(devpriv->dma[1].chan);
1363 if (devpriv->dma[0].buf)
1364 free_page((unsigned long) devpriv->dma[0].buf);
1365 if (devpriv->dma[1].buf)
1366 free_page((unsigned long) devpriv->dma[1].buf);
1370 static int dt282x_detach(comedi_device * dev)
1372 printk("comedi%d: dt282x: remove\n", dev->minor);
1374 free_resources(dev);
1379 static int dt282x_grab_dma(comedi_device *dev,int dma1,int dma2)
1386 printk(" (no dma)");
1390 if(dma1==dma2 || dma1<5 || dma2<5 || dma1>7 || dma2>7)
1394 int i;i=dma1;dma1=dma2;dma2=i;
1397 ret = request_dma(dma1, "dt282x A");
1400 devpriv->dma[0].chan=dma1;
1402 ret = request_dma(dma2, "dt282x B");
1405 devpriv->dma[1].chan=dma2;
1407 devpriv->dma_maxsize = PAGE_SIZE;
1408 devpriv->dma[0].buf = (void *) __get_free_page(GFP_KERNEL | GFP_DMA);
1409 devpriv->dma[1].buf = (void *) __get_free_page(GFP_KERNEL | GFP_DMA);
1410 if (!devpriv->dma[0].buf || !devpriv->dma[1].buf) {
1411 printk(" can't get DMA memory");
1415 printk(" (dma=%d,%d)",dma1,dma2);