Got rid of unnecessary casts when initializing comedi_driver.board_name
[comedi.git] / comedi / drivers / dt282x.c
1 /*
2    modules/dt282x.c
3    hardware driver for Data Translation DT2821 series
4
5    COMEDI - Linux Control and Measurement Device Interface
6    Copyright (C) 1997-8 David A. Schleef <ds@schleef.org>
7
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.
12
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.
17
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.
21
22  */
23 /*
24 Driver: dt282x.o
25 Description: Data Translation DT2821 series (including DT-EZ)
26 Author: ds
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),
30   DT2823 (dt2823),
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)
34 Status: complete
35 Updated: Wed, 22 Aug 2001 17:11:34 -0700
36
37 Configuration options:
38   [0] - I/O port base address
39   [1] - IRQ
40   [2] - DMA 1
41   [3] - DMA 2
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],
48         4=[-2.5,2.5]
49   [10]- A0 1 jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5],
50         4=[-2.5,2.5]
51
52 Notes:
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.
57 */
58
59 #include <linux/comedidev.h>
60
61 #include <linux/ioport.h>
62 #include <linux/interrupt.h>
63 #include <asm/dma.h>
64 #include "comedi_fc.h"
65
66 #define DEBUG
67
68 #define DT2821_TIMEOUT          100     /* 500 us */
69 #define DT2821_SIZE 0x10
70
71 /*
72  *    Registers in the DT282x
73  */
74
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          */
83
84 /*
85  *  At power up, some registers are in a well-known state.  The
86  *  masks and values are as follows:
87  */
88
89 #define DT2821_ADCSR_MASK 0xfff0
90 #define DT2821_ADCSR_VAL 0x7c00
91
92 #define DT2821_CHANCSR_MASK 0xf0f0
93 #define DT2821_CHANCSR_VAL 0x70f0
94
95 #define DT2821_DACSR_MASK 0x7c93
96 #define DT2821_DACSR_VAL 0x7c90
97
98 #define DT2821_SUPCSR_MASK 0xf8ff
99 #define DT2821_SUPCSR_VAL 0x0000
100
101 #define DT2821_TMRCTR_MASK 0xff00
102 #define DT2821_TMRCTR_VAL 0xf000
103
104 /*
105  *    Bit fields of each register
106  */
107
108 /* ADCSR */
109
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         */
118
119 /* CHANCSR */
120
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  */
126
127 /* DACSR */
128
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       */
137
138 /* SUPCSR */
139
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         */
156
157 static comedi_lrange range_dt282x_ai_lo_bipolar = { 4, {
158         RANGE( -10,     10 ),
159         RANGE( -5,      5 ),
160         RANGE( -2.5,    2.5 ),
161         RANGE( -1.25,   1.25 )
162 }};
163 static comedi_lrange range_dt282x_ai_lo_unipolar = { 4, {
164         RANGE( 0,       10 ),
165         RANGE( 0,       5 ),
166         RANGE( 0,       2.5 ),
167         RANGE( 0,       1.25 )
168 }};
169 static comedi_lrange range_dt282x_ai_5_bipolar = { 4, {
170         RANGE( -5,      5 ),
171         RANGE( -2.5,    2.5 ),
172         RANGE( -1.25,   1.25 ),
173         RANGE( -0.625,  0.625 ),
174 }};
175 static comedi_lrange range_dt282x_ai_5_unipolar = { 4, {
176         RANGE( 0,       5 ),
177         RANGE( 0,       2.5 ),
178         RANGE( 0,       1.25 ),
179         RANGE( 0,       0.625 ),
180 }};
181 static comedi_lrange range_dt282x_ai_hi_bipolar = { 4, {
182         RANGE( -10,     10 ),
183         RANGE( -1,      1 ),
184         RANGE( -0.1,    0.1 ),
185         RANGE( -0.02,   0.02 )
186 }};
187 static comedi_lrange range_dt282x_ai_hi_unipolar = { 4, {
188         RANGE( 0,       10 ),
189         RANGE( 0,       1 ),
190         RANGE( 0,       0.1 ),
191         RANGE( 0,       0.02 )
192 }};
193
194
195 typedef struct {
196         const char *name;
197         int adbits;
198         int adchan_se;
199         int adchan_di;
200         int ai_speed;
201         int ispgl;
202         int dachan;
203         int dabits;
204 } boardtype_t;
205
206 static boardtype_t boardtypes[] =
207 {
208         {       name:           "dt2821",
209                 adbits:         12,
210                 adchan_se:      16,
211                 adchan_di:      8,
212                 ai_speed:       20000,
213                 ispgl:          0,
214                 dachan:         2,
215                 dabits:         12,
216         },
217         {       name:           "dt2821-f",
218                 adbits:         12,
219                 adchan_se:      16,
220                 adchan_di:      8,
221                 ai_speed:       6500,
222                 ispgl:          0,
223                 dachan:         2,
224                 dabits:         12,
225         },
226         {       name:           "dt2821-g",
227                 adbits:         12,
228                 adchan_se:      16,
229                 adchan_di:      8,
230                 ai_speed:       4000,
231                 ispgl:          0,
232                 dachan:         2,
233                 dabits:         12,
234         },
235         {       name:           "dt2823",
236                 adbits:         16,
237                 adchan_se:      0,
238                 adchan_di:      4,
239                 ai_speed:       10000,
240                 ispgl:          0,
241                 dachan:         2,
242                 dabits:         16,
243         },
244         {       name:           "dt2824-pgh",
245                 adbits:         12,
246                 adchan_se:      16,
247                 adchan_di:      8,
248                 ai_speed:       20000,
249                 ispgl:          0,
250                 dachan:         0,
251                 dabits:         0,
252         },
253         {       name:           "dt2824-pgl",
254                 adbits:         12,
255                 adchan_se:      16,
256                 adchan_di:      8,
257                 ai_speed:       20000,
258                 ispgl:          1,
259                 dachan:         0,
260                 dabits:         0,
261         },
262         {       name:           "dt2825",
263                 adbits:         12,
264                 adchan_se:      16,
265                 adchan_di:      8,
266                 ai_speed:       20000,
267                 ispgl:          1,
268                 dachan:         2,
269                 dabits:         12,
270         },
271         {       name:           "dt2827",
272                 adbits:         16,
273                 adchan_se:      0,
274                 adchan_di:      4,
275                 ai_speed:       10000,
276                 ispgl:          0,
277                 dachan:         2,
278                 dabits:         12,
279         },
280         {       name:           "dt2828",
281                 adbits:         12,
282                 adchan_se:      4,
283                 adchan_di:      0,
284                 ai_speed:       10000,
285                 ispgl:          0,
286                 dachan:         2,
287                 dabits:         12,
288         },
289         {       name:           "dt2829",
290                 adbits:         16,
291                 adchan_se:      8,
292                 adchan_di:      0,
293                 ai_speed:       33250,
294                 ispgl:          0,
295                 dachan:         2,
296                 dabits:         16,
297         },
298         {       name:           "dt21-ez",
299                 adbits:         12,
300                 adchan_se:      16,
301                 adchan_di:      8,
302                 ai_speed:       10000,
303                 ispgl:          0,
304                 dachan:         2,
305                 dabits:         12,
306         },
307         {       name:           "dt23-ez",
308                 adbits:         16,
309                 adchan_se:      16,
310                 adchan_di:      8,
311                 ai_speed:       10000,
312                 ispgl:          0,
313                 dachan:         0,
314                 dabits:         0,
315         },
316         {       name:           "dt24-ez",
317                 adbits:         12,
318                 adchan_se:      16,
319                 adchan_di:      8,
320                 ai_speed:       10000,
321                 ispgl:          0,
322                 dachan:         0,
323                 dabits:         0,
324         },
325         {       name:           "dt24-ez-pgl",
326                 adbits:         12,
327                 adchan_se:      16,
328                 adchan_di:      8,
329                 ai_speed:       10000,
330                 ispgl:          1,
331                 dachan:         0,
332                 dabits:         0,
333         },
334 };
335 #define n_boardtypes sizeof(boardtypes)/sizeof(boardtype_t)
336 #define this_board ((boardtype_t *)dev->board_ptr)
337
338
339 typedef struct {
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               */
343
344         comedi_lrange *darangelist[2];
345
346         sampl_t ao[2];
347
348         volatile int dacsr;             /* software copies of registers */
349         volatile int adcsr;
350         volatile int supcsr;
351
352         volatile int ntrig;
353         volatile int nread;
354
355         struct{
356                 int chan;
357                 short *buf;     /* DMA buffer */
358                 volatile int size;      /* size of current transfer */
359         }dma[2];
360         int dma_maxsize;        /* max size of DMA transfer (in bytes) */
361         int usedma;             /* driver uses DMA              */
362         volatile int current_dma_index;
363         int dma_dir;
364 } dt282x_private;
365
366 #define devpriv ((dt282x_private *)dev->private)
367 #define boardtype (*(boardtype_t *)dev->board_ptr)
368
369 /*
370  *    Some useless abstractions
371  */
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)
378
379 /*
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.
382  */
383 #define wait_for(a,b)                                   \
384         do{                                             \
385                 int _i;                                 \
386                 for(_i=0;_i<DT2821_TIMEOUT;_i++){       \
387                         if(a){_i=0;break;}              \
388                         comedi_udelay(5);                       \
389                 }                                       \
390                 if(_i){b}                               \
391         }while(0)
392
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",
397         module:         THIS_MODULE,
398         attach:         dt282x_attach,
399         detach:         dt282x_detach,
400         board_name:     &boardtypes[0].name,
401         num_names:      n_boardtypes,
402         offset:         sizeof(boardtype_t),
403 };
404 COMEDI_INITCLEANUP(driver_dt282x);
405
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);
413
414
415 static int dt282x_grab_dma(comedi_device *dev,int dma1,int dma2);
416
417 static void dt282x_munge(comedi_device *dev,sampl_t *buf,
418         unsigned int nbytes)
419 {
420         unsigned int i;
421         unsigned short mask=(1<<boardtype.adbits)-1;
422         unsigned short sign=1<<(boardtype.adbits-1);
423         int n;
424
425         if(devpriv->ad_2scomp){
426                 sign = 1<<(boardtype.adbits-1);
427         }else{
428                 sign = 0;
429         }
430
431         if( nbytes % 2 )
432                 comedi_error( dev, "bug! odd number of bytes from dma xfer" );
433         n = nbytes/2;
434         for(i=0;i<n;i++){
435                 buf[i] = (buf[i]&mask)^sign;
436         }
437 }
438
439 static void dt282x_ao_dma_interrupt(comedi_device * dev)
440 {
441         void *ptr;
442         int size;
443         int i;
444         comedi_subdevice *s=dev->subdevices+1;
445
446         update_supcsr(DT2821_CLRDMADNE);
447
448         if(!s->async->prealloc_buf){
449                 printk("async->data disappeared.  dang!\n");
450                 return;
451         }
452
453         i=devpriv->current_dma_index;
454         ptr=devpriv->dma[i].buf;
455
456         disable_dma(devpriv->dma[i].chan);
457
458         devpriv->current_dma_index=1-i;
459
460         size = cfc_read_array_from_buffer(s, ptr, devpriv->dma_maxsize);
461         if( size == 0){
462                 rt_printk("dt282x: AO underrun\n");
463                 dt282x_ao_cancel(dev,s);
464                 s->async->events |= COMEDI_CB_OVERFLOW;
465                 return;
466         }
467         prep_ao_dma(dev,i,size);
468         return;
469 }
470
471 static void dt282x_ai_dma_interrupt(comedi_device * dev)
472 {
473         void *ptr;
474         int size;
475         int i;
476         int ret;
477         comedi_subdevice *s=dev->subdevices;
478
479         update_supcsr(DT2821_CLRDMADNE);
480
481         if(!s->async->prealloc_buf){
482                 printk("async->data disappeared.  dang!\n");
483                 return;
484         }
485
486         i = devpriv->current_dma_index;
487         ptr = devpriv->dma[i].buf;
488         size = devpriv->dma[i].size;
489
490         disable_dma(devpriv->dma[i].chan);
491
492         devpriv->current_dma_index = 1-i;
493
494         dt282x_munge(dev, ptr, size );
495         ret = cfc_write_array_to_buffer( s, ptr, size );
496         if( ret != size )
497         {
498                 dt282x_ai_cancel(dev,s);
499                 return;
500         }
501         devpriv->nread-=size/2;
502
503         if(devpriv->nread<0){
504                 printk("dt282x: off by one\n");
505                 devpriv->nread=0;
506         }
507         if (!devpriv->nread) {
508                 dt282x_ai_cancel(dev, s);
509                 s->async->events |= COMEDI_CB_EOA;
510                 return;
511         }
512
513 #if 0
514         /* clear the dual dma flag, making this the last dma segment */
515         /* XXX probably wrong */
516         if(!devpriv->ntrig){
517                 devpriv->supcsr &= ~(DT2821_DDMA);
518                 update_supcsr(0);
519         }
520 #endif
521         /* restart the channel */
522         prep_ai_dma(dev,i,0);
523 }
524
525 static int prep_ai_dma(comedi_device * dev,int dma_index,int n)
526 {
527         int dma_chan;
528         unsigned long dma_ptr;
529         unsigned long flags;
530
531         if(!devpriv->ntrig)
532                 return 0;
533
534         if(n==0)
535                 n = devpriv->dma_maxsize;
536         if (n > devpriv->ntrig*2)
537                 n = devpriv->ntrig*2;
538         devpriv->ntrig -= n/2;
539
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);
543
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);
550
551         enable_dma(dma_chan);
552
553         return n;
554 }
555
556 static int prep_ao_dma(comedi_device * dev,int dma_index,int n)
557 {
558         int dma_chan;
559         unsigned long dma_ptr;
560         unsigned long flags;
561
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);
565
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);
572
573         enable_dma(dma_chan);
574
575         return n;
576 }
577
578 static irqreturn_t dt282x_interrupt(int irq, void *d PT_REGS_ARG)
579 {
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;
584         int handled = 0;
585
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);
592                 else
593                         dt282x_ao_dma_interrupt(dev);
594                 handled = 1;
595         }
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;
601                 }
602                 handled = 1;
603         }
604         if (dacsr & DT2821_DAERR) {
605 #if 0
606                 static int warn = 5;
607                 if(--warn<=0){
608                         disable_irq(dev->irq);
609                         printk("disabling irq\n");
610                 }
611 #endif
612                 comedi_error(dev, "D/A error");
613                 dt282x_ao_cancel(dev,s_ao);
614                 s->async->events |= COMEDI_CB_ERROR;
615                 handled = 1;
616         }
617 #if 0
618         if (adcsr & DT2821_ADDONE) {
619                 int ret;
620                 sampl_t data;
621
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);
626                 }
627                 ret = comedi_buf_put( s->async, data );
628                 if(ret==0){
629                         s->async->events |= COMEDI_CB_OVERFLOW;
630                 }
631
632                 devpriv->nread--;
633                 if(!devpriv->nread){
634                         s->async->events |= COMEDI_CB_EOA;
635                 }else{
636                         if(supcsr&DT2821_SCDN)
637                                 update_supcsr(DT2821_STRIG);
638                 }
639                 handled = 1;
640         }
641 #endif
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);
645 }
646
647
648 static void dt282x_load_changain(comedi_device * dev, int n, unsigned int *chanlist)
649 {
650         unsigned int i;
651         unsigned int chan, range;
652
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));
658         }
659         outw(n - 1, dev->iobase + DT2821_CHANCSR);
660 }
661
662
663 /*
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
668  */
669 static int dt282x_ai_insn_read(comedi_device *dev,comedi_subdevice *s,
670         comedi_insn *insn, lsampl_t *data)
671 {
672         int i;
673
674         /* XXX should we really be enabling the ad clock here? */
675         devpriv->adcsr = DT2821_ADCLK;
676         update_adcsr(0);
677
678         dt282x_load_changain(dev, 1, &insn->chanspec);
679
680         update_supcsr(DT2821_PRLD);
681         wait_for(!mux_busy(),
682                  comedi_error(dev, "timeout\n");
683                  return -ETIME;
684             );
685
686         for(i=0;i<insn->n;i++){
687                 update_supcsr(DT2821_STRIG);
688                 wait_for(ad_done(),
689                         comedi_error(dev, "timeout\n");
690                         return -ETIME;
691                     );
692
693                 data[i] = inw(dev->iobase + DT2821_ADDAT) & ((1<<boardtype.adbits)-1);
694                 if (devpriv->ad_2scomp)
695                         data[i] ^= (1 << (boardtype.adbits - 1));
696         }
697
698         return i;
699 }
700
701 static int dt282x_ai_cmdtest(comedi_device * dev, comedi_subdevice * s,comedi_cmd *cmd)
702 {
703         int err=0;
704         int tmp;
705
706         /* step 1: make sure trigger sources are trivially valid */
707
708         tmp=cmd->start_src;
709         cmd->start_src &= TRIG_NOW;
710         if(!cmd->start_src || tmp!=cmd->start_src)err++;
711
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++;
715
716         tmp=cmd->convert_src;
717         cmd->convert_src &= TRIG_TIMER;
718         if(!cmd->convert_src || tmp!=cmd->convert_src)err++;
719
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++;
723
724         tmp=cmd->stop_src;
725         cmd->stop_src &= TRIG_COUNT|TRIG_NONE;
726         if(!cmd->stop_src || tmp!=cmd->stop_src)err++;
727
728         if(err)return 1;
729
730         /* step 2: make sure trigger sources are unique and mutually compatible */
731
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++;
737
738         if(err)return 2;
739
740         /* step 3: make sure arguments are trivially compatible */
741
742         if(cmd->start_arg!=0){
743                 cmd->start_arg=0;
744                 err++;
745         }
746         if(cmd->scan_begin_src==TRIG_FOLLOW){
747                 /* internal trigger */
748                 if(cmd->scan_begin_arg!=0){
749                         cmd->scan_begin_arg=0;
750                         err++;
751                 }
752         }else{
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;
757                         err++;
758                 }
759         }
760         if(cmd->convert_arg<4000){
761                 /* XXX board dependent */
762                 cmd->convert_arg=4000;
763                 err++;
764         }
765 #define SLOWEST_TIMER   (250*(1<<15)*255)
766         if(cmd->convert_arg>SLOWEST_TIMER){
767                 cmd->convert_arg=SLOWEST_TIMER;
768                 err++;
769         }
770         if(cmd->convert_arg < this_board->ai_speed ){
771                 cmd->convert_arg = this_board->ai_speed;
772                 err++;
773         }
774         if(cmd->scan_end_arg!=cmd->chanlist_len){
775                 cmd->scan_end_arg=cmd->chanlist_len;
776                 err++;
777         }
778         if(cmd->stop_src==TRIG_COUNT){
779                 /* any count is allowed */
780         }else{
781                 /* TRIG_NONE */
782                 if(cmd->stop_arg!=0){
783                         cmd->stop_arg=0;
784                         err++;
785                 }
786         }
787
788         if(err)return 3;
789
790         /* step 4: fix up any arguments */
791
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++;
795
796         if(err)return 4;
797
798         return 0;
799 }
800
801 static int dt282x_ai_cmd(comedi_device * dev, comedi_subdevice * s)
802 {
803         comedi_cmd *cmd=&s->async->cmd;
804         int timer;
805
806         if(devpriv->usedma == 0){
807                 comedi_error(dev, "driver requires 2 dma channels to execute command");
808                 return -EIO;
809         }
810
811         dt282x_disable_dma(dev);
812
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);
817
818         if(cmd->scan_begin_src==TRIG_FOLLOW){
819                 /* internal trigger */
820                 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0;
821         }else{
822                 /* external trigger */
823                 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0 | DT2821_DS1;
824         }
825         update_supcsr(DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_ADCINIT);
826
827         devpriv->ntrig=cmd->stop_arg*cmd->scan_end_arg;
828         devpriv->nread=devpriv->ntrig;
829
830         devpriv->dma_dir=DMA_MODE_READ;
831         devpriv->current_dma_index=0;
832         prep_ai_dma(dev,0,0);
833         if(devpriv->ntrig){
834                 prep_ai_dma(dev,1,0);
835                 devpriv->supcsr |= DT2821_DDMA;
836                 update_supcsr(0);
837         }
838
839         devpriv->adcsr = 0;
840
841         dt282x_load_changain(dev,cmd->chanlist_len,cmd->chanlist);
842
843         devpriv->adcsr = DT2821_ADCLK | DT2821_IADDONE;
844         update_adcsr(0);
845
846         update_supcsr(DT2821_PRLD);
847         wait_for(!mux_busy(),
848                  comedi_error(dev, "timeout\n");
849                  return -ETIME;
850             );
851
852         if(cmd->scan_begin_src==TRIG_FOLLOW){
853                 update_supcsr(DT2821_STRIG);
854         }else{
855                 devpriv->supcsr |= DT2821_XTRIG;
856                 update_supcsr(0);
857         }
858
859         return 0;
860 }
861
862 static void dt282x_disable_dma(comedi_device *dev)
863 {
864         if( devpriv->usedma ){
865                 disable_dma(devpriv->dma[0].chan);
866                 disable_dma(devpriv->dma[1].chan);
867         }
868 }
869
870 static int dt282x_ai_cancel(comedi_device * dev, comedi_subdevice * s)
871 {
872         dt282x_disable_dma(dev);
873
874         devpriv->adcsr=0;
875         update_adcsr(0);
876
877         devpriv->supcsr = 0;
878         update_supcsr(DT2821_ADCINIT);
879
880         return 0;
881 }
882
883
884 static int dt282x_ns_to_timer(int *nanosec,int round_mode)
885 {
886         int prescale,base,divider;
887
888         for(prescale=0;prescale<16;prescale++){
889                 if(prescale==1)continue;
890                 base=250*(1<<prescale);
891                 switch(round_mode){
892                 case TRIG_ROUND_NEAREST:
893                 default:
894                         divider=(*nanosec+base/2)/base;
895                         break;
896                 case TRIG_ROUND_DOWN:
897                         divider=(*nanosec)/base;
898                         break;
899                 case TRIG_ROUND_UP:
900                         divider=(*nanosec+base-1)/base;
901                         break;
902                 }
903                 if(divider<256){
904                         *nanosec=divider*base;
905                         return (prescale<<8)|(255-divider);
906                 }
907         }
908         base=250*(1<<15);
909         divider=255;
910         *nanosec=divider*base;
911         return (15<<8)|(255-divider);
912 }
913
914
915 /*
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.
920  */
921 static int dt282x_ao_insn_read(comedi_device *dev,comedi_subdevice *s,
922         comedi_insn *insn, lsampl_t *data)
923 {
924         data[0] = devpriv->ao[CR_CHAN(insn->chanspec)];
925
926         return 1;
927 }
928
929 static int dt282x_ao_insn_write(comedi_device * dev, comedi_subdevice * s,
930         comedi_insn *insn, lsampl_t *data)
931 {
932         sampl_t d;
933         unsigned int chan;
934
935         chan = CR_CHAN(insn->chanspec);
936         d = data[0];
937         d &= (1<<boardtype.dabits)-1;
938         devpriv->ao[chan] = d;
939
940         devpriv->dacsr |= DT2821_SSEL;
941
942         if (chan) {
943                 /* select channel */
944                 devpriv->dacsr |= DT2821_YSEL;
945                 if (devpriv->da0_2scomp)
946                         d ^= (1<<(boardtype.dabits-1));
947         } else {
948                 devpriv->dacsr &= ~DT2821_YSEL;
949                 if (devpriv->da1_2scomp)
950                         d ^= (1<<(boardtype.dabits-1));
951         }
952
953         update_dacsr(0);
954
955         outw(d, dev->iobase + DT2821_DADAT);
956
957         update_supcsr(DT2821_DACON);
958
959         return 1;
960 }
961
962 static int dt282x_ao_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd)
963 {
964         int err=0;
965         int tmp;
966
967         /* step 1: make sure trigger sources are trivially valid */
968
969         tmp=cmd->start_src;
970         cmd->start_src &= TRIG_INT;
971         if(!cmd->start_src || tmp!=cmd->start_src)err++;
972
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++;
976
977         tmp=cmd->convert_src;
978         cmd->convert_src &= TRIG_NOW;
979         if(!cmd->convert_src || tmp!=cmd->convert_src)err++;
980
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++;
984
985         tmp=cmd->stop_src;
986         cmd->stop_src &= TRIG_NONE;
987         if(!cmd->stop_src || tmp!=cmd->stop_src)err++;
988
989         if(err)return 1;
990
991         /* step 2: make sure trigger sources are unique and mutually compatible */
992
993         /* note that mutual compatiblity is not an issue here */
994         if(cmd->stop_src!=TRIG_COUNT &&
995            cmd->stop_src!=TRIG_NONE)err++;
996
997         if(err)return 2;
998
999         /* step 3: make sure arguments are trivially compatible */
1000
1001         if(cmd->start_arg!=0){
1002                 cmd->start_arg=0;
1003                 err++;
1004         }
1005         if(cmd->scan_begin_arg < 5000 /* XXX unknown */){
1006                 cmd->scan_begin_arg = 5000;
1007                 err++;
1008         }
1009         if(cmd->convert_arg != 0){
1010                 cmd->convert_arg = 0;
1011                 err++;
1012         }
1013         if(cmd->scan_end_arg > 2){
1014                 /* XXX chanlist stuff? */
1015                 cmd->scan_end_arg = 2;
1016                 err++;
1017         }
1018         if(cmd->stop_src==TRIG_COUNT){
1019                 /* any count is allowed */
1020         }else{
1021                 /* TRIG_NONE */
1022                 if(cmd->stop_arg!=0){
1023                         cmd->stop_arg=0;
1024                         err++;
1025                 }
1026         }
1027
1028         if(err)return 3;
1029
1030         /* step 4: fix up any arguments */
1031
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++;
1035
1036         if(err)return 4;
1037
1038         return 0;
1039
1040 }
1041
1042 static int dt282x_ao_inttrig(comedi_device *dev,comedi_subdevice *s,
1043                 unsigned int x)
1044 {
1045         int size;
1046
1047         if(x!=0)return -EINVAL;
1048
1049         size = cfc_read_array_from_buffer(s, devpriv->dma[0].buf, devpriv->dma_maxsize);
1050         if( size == 0){
1051                 rt_printk("dt282x: AO underrun\n");
1052                 return -EPIPE;
1053         }
1054         prep_ao_dma(dev,0,size);
1055
1056         size = cfc_read_array_from_buffer(s, devpriv->dma[1].buf, devpriv->dma_maxsize);
1057         if( size == 0){
1058                 rt_printk("dt282x: AO underrun\n");
1059                 return -EPIPE;
1060         }
1061         prep_ao_dma(dev,1,size);
1062
1063         update_supcsr(DT2821_STRIG);
1064         s->async->inttrig=NULL;
1065
1066         return 1;
1067 }
1068
1069 static int dt282x_ao_cmd(comedi_device *dev,comedi_subdevice *s)
1070 {
1071         int timer;
1072         comedi_cmd *cmd=&s->async->cmd;
1073
1074         if(devpriv->usedma == 0){
1075                 comedi_error(dev, "driver requires 2 dma channels to execute command");
1076                 return -EIO;
1077         }
1078
1079         dt282x_disable_dma(dev);
1080
1081         devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS1 | DT2821_DDMA;
1082         update_supcsr(DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_DACINIT);
1083
1084         devpriv->ntrig=cmd->stop_arg*cmd->chanlist_len;
1085         devpriv->nread=devpriv->ntrig;
1086
1087         devpriv->dma_dir=DMA_MODE_WRITE;
1088         devpriv->current_dma_index=0;
1089
1090         timer=dt282x_ns_to_timer(&cmd->scan_begin_arg,TRIG_ROUND_NEAREST);
1091         outw(timer, dev->iobase + DT2821_TMRCTR);
1092
1093         devpriv->dacsr = DT2821_SSEL| DT2821_DACLK | DT2821_IDARDY;
1094         update_dacsr(0);
1095
1096         s->async->inttrig=dt282x_ao_inttrig;
1097
1098         return 0;
1099 }
1100
1101 static int dt282x_ao_cancel(comedi_device * dev, comedi_subdevice * s)
1102 {
1103         dt282x_disable_dma(dev);
1104
1105         devpriv->dacsr=0;
1106         update_dacsr(0);
1107
1108         devpriv->supcsr = 0;
1109         update_supcsr(DT2821_DACINIT);
1110
1111         return 0;
1112 }
1113
1114 static int dt282x_dio_insn_bits(comedi_device *dev,comedi_subdevice *s,
1115         comedi_insn *insn,lsampl_t *data)
1116 {
1117         if(data[0]){
1118                 s->state &= ~data[0];
1119                 s->state |= (data[0]&data[1]);
1120
1121                 outw(s->state, dev->iobase + DT2821_DIODAT);
1122         }
1123         data[1] = inw(dev->iobase + DT2821_DIODAT);
1124
1125         return 2;
1126 }
1127
1128 static int dt282x_dio_insn_config(comedi_device *dev,comedi_subdevice *s,
1129         comedi_insn *insn,lsampl_t *data)
1130 {
1131         int mask;
1132
1133         mask=(CR_CHAN(insn->chanspec)<8)?0x00ff:0xff00;
1134         if(data[0])s->io_bits|=mask;
1135         else s->io_bits&=~mask;
1136
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;
1141
1142         outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
1143
1144         return 1;
1145 }
1146
1147
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)
1157 {
1158         if(ispgl){
1159                 if(x<0 || x>=2)x=0;
1160                 return ai_range_pgl_table[x];
1161         }else{
1162                 if(x<0 || x>=4)x=0;
1163                 return ai_range_table[x];
1164         }
1165 }
1166 static comedi_lrange *ao_range_table[]={
1167         &range_bipolar10,
1168         &range_unipolar10,
1169         &range_bipolar5,
1170         &range_unipolar5,
1171         &range_bipolar2_5 };
1172 static comedi_lrange *opt_ao_range_lkup(int x)
1173 {
1174         if(x<0 || x>=5)x=0;
1175         return ao_range_table[x];
1176 }
1177
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 */
1182 };
1183
1184
1185 /*
1186    options:
1187    0    i/o base
1188    1    irq
1189    2    dma1
1190    3    dma2
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
1198  */
1199 static int dt282x_attach(comedi_device * dev, comedi_devconfig * it)
1200 {
1201         int i, irq;
1202         int ret;
1203         comedi_subdevice *s;
1204         unsigned long iobase;
1205
1206         dev->board_name = this_board->name;
1207
1208         iobase = it->options[opt_iobase];
1209         if(!iobase)iobase = 0x240;
1210
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");
1214                 return -EBUSY;
1215         }
1216         dev->iobase = iobase;
1217
1218         outw(DT2821_BDINIT, dev->iobase + DT2821_SUPCSR);
1219         i = inw(dev->iobase + DT2821_ADCSR);
1220 #ifdef DEBUG
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));
1227 #endif
1228
1229         if (
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");
1241                 return -EIO;
1242         }
1243         /* should do board test */
1244
1245         irq = it->options[opt_irq];
1246 #if 0
1247         if (irq < 0) {
1248                 unsigned long flags;
1249                 int irqs;
1250
1251                 save_flags(flags);
1252                 sti();
1253                 irqs = probe_irq_on();
1254
1255                 /* trigger interrupt */
1256
1257                 comedi_udelay(100);
1258
1259                 irq = probe_irq_off(irqs);
1260                 restore_flags(flags);
1261                 if (0 /* error */ ) {
1262                         printk(" error probing irq (bad)");
1263                 }
1264         }
1265 #endif
1266         if (irq > 0) {
1267                 printk(" ( irq = %d )", irq);
1268                 ret = comedi_request_irq(irq, dt282x_interrupt, 0, "dt282x", dev);
1269                 if(ret<0) {
1270                         printk(" failed to get irq\n");
1271                         return -EIO;
1272                 }
1273                 dev->irq = irq;
1274         } else if (irq == 0) {
1275                 printk(" (no irq)");
1276         } else {
1277 #if 0
1278                 printk(" (probe returned multiple irqs--bad)");
1279 #else
1280                 printk(" (irq probe not implemented)");
1281 #endif
1282         }
1283
1284         if((ret=alloc_private(dev,sizeof(dt282x_private)))<0)
1285                 return ret;
1286
1287         ret=dt282x_grab_dma(dev,it->options[opt_dma1],it->options[opt_dma2]);
1288         if(ret<0)
1289                 return ret;
1290
1291         if((ret=alloc_subdevices(dev, 3))<0)
1292                 return ret;
1293
1294         s=dev->subdevices+0;
1295
1296         dev->read_subdev=s;
1297         /* ai subdevice */
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;
1307         s->len_chanlist=16;
1308         s->range_table = opt_ai_range_lkup(boardtype.ispgl,it->options[opt_ai_range]);
1309         devpriv->ad_2scomp=it->options[opt_ai_twos];
1310
1311         s++;
1312         if((s->n_chan=boardtype.dachan)){
1313                 /* ao subsystem */
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;
1323                 s->len_chanlist=2;
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];
1331         }else{
1332                 s->type=COMEDI_SUBD_UNUSED;
1333         }
1334
1335         s++;
1336         /* dio subsystem */
1337         s->type=COMEDI_SUBD_DIO;
1338         s->subdev_flags=SDF_READABLE|SDF_WRITABLE;
1339         s->n_chan=16;
1340         s->insn_bits = dt282x_dio_insn_bits;
1341         s->insn_config = dt282x_dio_insn_config;
1342         s->maxdata=1;
1343         s->range_table = &range_digital;
1344
1345         printk("\n");
1346
1347         return 0;
1348 }
1349
1350
1351 static void free_resources(comedi_device *dev)
1352 {
1353         if (dev->irq) {
1354                 comedi_free_irq(dev->irq, dev);
1355         }
1356         if(dev->iobase)
1357                 release_region(dev->iobase, DT2821_SIZE);
1358         if(dev->private){
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);
1367         }
1368 }
1369
1370 static int dt282x_detach(comedi_device * dev)
1371 {
1372         printk("comedi%d: dt282x: remove\n", dev->minor);
1373
1374         free_resources(dev);
1375
1376         return 0;
1377 }
1378
1379 static int dt282x_grab_dma(comedi_device *dev,int dma1,int dma2)
1380 {
1381         int ret;
1382
1383         devpriv->usedma=0;
1384
1385         if(!dma1 && !dma2){
1386                 printk(" (no dma)");
1387                 return 0;
1388         }
1389
1390         if(dma1==dma2 || dma1<5 || dma2<5 || dma1>7 || dma2>7)
1391                 return -EINVAL;
1392
1393         if(dma2<dma1){
1394                 int i;i=dma1;dma1=dma2;dma2=i;
1395         }
1396
1397         ret = request_dma(dma1, "dt282x A");
1398         if (ret)
1399                 return -EBUSY;
1400         devpriv->dma[0].chan=dma1;
1401
1402         ret = request_dma(dma2, "dt282x B");
1403         if (ret)
1404                 return -EBUSY;
1405         devpriv->dma[1].chan=dma2;
1406
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");
1412                 return -ENOMEM;
1413         }
1414
1415         printk(" (dma=%d,%d)",dma1,dma2);
1416
1417         devpriv->usedma=1;
1418
1419         return 0;
1420 }
1421