Staging: comedi: Remove comedi_devconfig typedef
[linux-2.6] / drivers / staging / comedi / drivers / dt282x.c
1 /*
2    comedi/drivers/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
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 "../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 const struct 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 };
164 static const struct comedi_lrange range_dt282x_ai_lo_unipolar = { 4, {
165                         RANGE(0, 10),
166                         RANGE(0, 5),
167                         RANGE(0, 2.5),
168                         RANGE(0, 1.25)
169         }
170 };
171 static const struct comedi_lrange range_dt282x_ai_5_bipolar = { 4, {
172                         RANGE(-5, 5),
173                         RANGE(-2.5, 2.5),
174                         RANGE(-1.25, 1.25),
175                         RANGE(-0.625, 0.625),
176         }
177 };
178 static const struct comedi_lrange range_dt282x_ai_5_unipolar = { 4, {
179                         RANGE(0, 5),
180                         RANGE(0, 2.5),
181                         RANGE(0, 1.25),
182                         RANGE(0, 0.625),
183         }
184 };
185 static const struct comedi_lrange range_dt282x_ai_hi_bipolar = { 4, {
186                         RANGE(-10, 10),
187                         RANGE(-1, 1),
188                         RANGE(-0.1, 0.1),
189                         RANGE(-0.02, 0.02)
190         }
191 };
192 static const struct comedi_lrange range_dt282x_ai_hi_unipolar = { 4, {
193                         RANGE(0, 10),
194                         RANGE(0, 1),
195                         RANGE(0, 0.1),
196                         RANGE(0, 0.02)
197         }
198 };
199
200 typedef struct {
201         const char *name;
202         int adbits;
203         int adchan_se;
204         int adchan_di;
205         int ai_speed;
206         int ispgl;
207         int dachan;
208         int dabits;
209 } boardtype_t;
210
211 static const boardtype_t boardtypes[] = {
212       {name:"dt2821",
213               adbits:   12,
214               adchan_se:16,
215               adchan_di:8,
216               ai_speed:20000,
217               ispgl:    0,
218               dachan:   2,
219               dabits:   12,
220                 },
221       {name:"dt2821-f",
222               adbits:   12,
223               adchan_se:16,
224               adchan_di:8,
225               ai_speed:6500,
226               ispgl:    0,
227               dachan:   2,
228               dabits:   12,
229                 },
230       {name:"dt2821-g",
231               adbits:   12,
232               adchan_se:16,
233               adchan_di:8,
234               ai_speed:4000,
235               ispgl:    0,
236               dachan:   2,
237               dabits:   12,
238                 },
239       {name:"dt2823",
240               adbits:   16,
241               adchan_se:0,
242               adchan_di:4,
243               ai_speed:10000,
244               ispgl:    0,
245               dachan:   2,
246               dabits:   16,
247                 },
248       {name:"dt2824-pgh",
249               adbits:   12,
250               adchan_se:16,
251               adchan_di:8,
252               ai_speed:20000,
253               ispgl:    0,
254               dachan:   0,
255               dabits:   0,
256                 },
257       {name:"dt2824-pgl",
258               adbits:   12,
259               adchan_se:16,
260               adchan_di:8,
261               ai_speed:20000,
262               ispgl:    1,
263               dachan:   0,
264               dabits:   0,
265                 },
266       {name:"dt2825",
267               adbits:   12,
268               adchan_se:16,
269               adchan_di:8,
270               ai_speed:20000,
271               ispgl:    1,
272               dachan:   2,
273               dabits:   12,
274                 },
275       {name:"dt2827",
276               adbits:   16,
277               adchan_se:0,
278               adchan_di:4,
279               ai_speed:10000,
280               ispgl:    0,
281               dachan:   2,
282               dabits:   12,
283                 },
284       {name:"dt2828",
285               adbits:   12,
286               adchan_se:4,
287               adchan_di:0,
288               ai_speed:10000,
289               ispgl:    0,
290               dachan:   2,
291               dabits:   12,
292                 },
293       {name:"dt2829",
294               adbits:   16,
295               adchan_se:8,
296               adchan_di:0,
297               ai_speed:33250,
298               ispgl:    0,
299               dachan:   2,
300               dabits:   16,
301                 },
302       {name:"dt21-ez",
303               adbits:   12,
304               adchan_se:16,
305               adchan_di:8,
306               ai_speed:10000,
307               ispgl:    0,
308               dachan:   2,
309               dabits:   12,
310                 },
311       {name:"dt23-ez",
312               adbits:   16,
313               adchan_se:16,
314               adchan_di:8,
315               ai_speed:10000,
316               ispgl:    0,
317               dachan:   0,
318               dabits:   0,
319                 },
320       {name:"dt24-ez",
321               adbits:   12,
322               adchan_se:16,
323               adchan_di:8,
324               ai_speed:10000,
325               ispgl:    0,
326               dachan:   0,
327               dabits:   0,
328                 },
329       {name:"dt24-ez-pgl",
330               adbits:   12,
331               adchan_se:16,
332               adchan_di:8,
333               ai_speed:10000,
334               ispgl:    1,
335               dachan:   0,
336               dabits:   0,
337                 },
338 };
339
340 #define n_boardtypes sizeof(boardtypes)/sizeof(boardtype_t)
341 #define this_board ((const boardtype_t *)dev->board_ptr)
342
343 typedef struct {
344         int ad_2scomp;          /* we have 2's comp jumper set  */
345         int da0_2scomp;         /* same, for DAC0               */
346         int da1_2scomp;         /* same, for DAC1               */
347
348         const struct comedi_lrange *darangelist[2];
349
350         short ao[2];
351
352         volatile int dacsr;     /* software copies of registers */
353         volatile int adcsr;
354         volatile int supcsr;
355
356         volatile int ntrig;
357         volatile int nread;
358
359         struct {
360                 int chan;
361                 short *buf;     /* DMA buffer */
362                 volatile int size;      /* size of current transfer */
363         } dma[2];
364         int dma_maxsize;        /* max size of DMA transfer (in bytes) */
365         int usedma;             /* driver uses DMA              */
366         volatile int current_dma_index;
367         int dma_dir;
368 } dt282x_private;
369
370 #define devpriv ((dt282x_private *)dev->private)
371 #define boardtype (*(const boardtype_t *)dev->board_ptr)
372
373 /*
374  *    Some useless abstractions
375  */
376 #define chan_to_DAC(a)  ((a)&1)
377 #define update_dacsr(a) outw(devpriv->dacsr|(a),dev->iobase+DT2821_DACSR)
378 #define update_adcsr(a) outw(devpriv->adcsr|(a),dev->iobase+DT2821_ADCSR)
379 #define mux_busy() (inw(dev->iobase+DT2821_ADCSR)&DT2821_MUXBUSY)
380 #define ad_done() (inw(dev->iobase+DT2821_ADCSR)&DT2821_ADDONE)
381 #define update_supcsr(a)        outw(devpriv->supcsr|(a),dev->iobase+DT2821_SUPCSR)
382
383 /*
384  *    danger! macro abuse... a is the expression to wait on, and b is
385  *      the statement(s) to execute if it doesn't happen.
386  */
387 #define wait_for(a,b)                                   \
388         do{                                             \
389                 int _i;                                 \
390                 for(_i=0;_i<DT2821_TIMEOUT;_i++){       \
391                         if(a){_i=0;break;}              \
392                         comedi_udelay(5);                       \
393                 }                                       \
394                 if(_i){b}                               \
395         }while(0)
396
397 static int dt282x_attach(struct comedi_device * dev, struct comedi_devconfig * it);
398 static int dt282x_detach(struct comedi_device * dev);
399 static struct comedi_driver driver_dt282x = {
400       driver_name:"dt282x",
401       module:THIS_MODULE,
402       attach:dt282x_attach,
403       detach:dt282x_detach,
404       board_name:&boardtypes[0].name,
405       num_names:n_boardtypes,
406       offset:sizeof(boardtype_t),
407 };
408
409 COMEDI_INITCLEANUP(driver_dt282x);
410
411 static void free_resources(struct comedi_device * dev);
412 static int prep_ai_dma(struct comedi_device * dev, int chan, int size);
413 static int prep_ao_dma(struct comedi_device * dev, int chan, int size);
414 static int dt282x_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s);
415 static int dt282x_ao_cancel(struct comedi_device * dev, struct comedi_subdevice * s);
416 static int dt282x_ns_to_timer(int *nanosec, int round_mode);
417 static void dt282x_disable_dma(struct comedi_device * dev);
418
419 static int dt282x_grab_dma(struct comedi_device * dev, int dma1, int dma2);
420
421 static void dt282x_munge(struct comedi_device * dev, short * buf,
422         unsigned int nbytes)
423 {
424         unsigned int i;
425         unsigned short mask = (1 << boardtype.adbits) - 1;
426         unsigned short sign = 1 << (boardtype.adbits - 1);
427         int n;
428
429         if (devpriv->ad_2scomp) {
430                 sign = 1 << (boardtype.adbits - 1);
431         } else {
432                 sign = 0;
433         }
434
435         if (nbytes % 2)
436                 comedi_error(dev, "bug! odd number of bytes from dma xfer");
437         n = nbytes / 2;
438         for (i = 0; i < n; i++) {
439                 buf[i] = (buf[i] & mask) ^ sign;
440         }
441 }
442
443 static void dt282x_ao_dma_interrupt(struct comedi_device * dev)
444 {
445         void *ptr;
446         int size;
447         int i;
448         struct comedi_subdevice *s = dev->subdevices + 1;
449
450         update_supcsr(DT2821_CLRDMADNE);
451
452         if (!s->async->prealloc_buf) {
453                 printk("async->data disappeared.  dang!\n");
454                 return;
455         }
456
457         i = devpriv->current_dma_index;
458         ptr = devpriv->dma[i].buf;
459
460         disable_dma(devpriv->dma[i].chan);
461
462         devpriv->current_dma_index = 1 - i;
463
464         size = cfc_read_array_from_buffer(s, ptr, devpriv->dma_maxsize);
465         if (size == 0) {
466                 rt_printk("dt282x: AO underrun\n");
467                 dt282x_ao_cancel(dev, s);
468                 s->async->events |= COMEDI_CB_OVERFLOW;
469                 return;
470         }
471         prep_ao_dma(dev, i, size);
472         return;
473 }
474
475 static void dt282x_ai_dma_interrupt(struct comedi_device * dev)
476 {
477         void *ptr;
478         int size;
479         int i;
480         int ret;
481         struct comedi_subdevice *s = dev->subdevices;
482
483         update_supcsr(DT2821_CLRDMADNE);
484
485         if (!s->async->prealloc_buf) {
486                 printk("async->data disappeared.  dang!\n");
487                 return;
488         }
489
490         i = devpriv->current_dma_index;
491         ptr = devpriv->dma[i].buf;
492         size = devpriv->dma[i].size;
493
494         disable_dma(devpriv->dma[i].chan);
495
496         devpriv->current_dma_index = 1 - i;
497
498         dt282x_munge(dev, ptr, size);
499         ret = cfc_write_array_to_buffer(s, ptr, size);
500         if (ret != size) {
501                 dt282x_ai_cancel(dev, s);
502                 return;
503         }
504         devpriv->nread -= size / 2;
505
506         if (devpriv->nread < 0) {
507                 printk("dt282x: off by one\n");
508                 devpriv->nread = 0;
509         }
510         if (!devpriv->nread) {
511                 dt282x_ai_cancel(dev, s);
512                 s->async->events |= COMEDI_CB_EOA;
513                 return;
514         }
515 #if 0
516         /* clear the dual dma flag, making this the last dma segment */
517         /* XXX probably wrong */
518         if (!devpriv->ntrig) {
519                 devpriv->supcsr &= ~(DT2821_DDMA);
520                 update_supcsr(0);
521         }
522 #endif
523         /* restart the channel */
524         prep_ai_dma(dev, i, 0);
525 }
526
527 static int prep_ai_dma(struct comedi_device * dev, int dma_index, int n)
528 {
529         int dma_chan;
530         unsigned long dma_ptr;
531         unsigned long flags;
532
533         if (!devpriv->ntrig)
534                 return 0;
535
536         if (n == 0)
537                 n = devpriv->dma_maxsize;
538         if (n > devpriv->ntrig * 2)
539                 n = devpriv->ntrig * 2;
540         devpriv->ntrig -= n / 2;
541
542         devpriv->dma[dma_index].size = n;
543         dma_chan = devpriv->dma[dma_index].chan;
544         dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
545
546         set_dma_mode(dma_chan, DMA_MODE_READ);
547         flags = claim_dma_lock();
548         clear_dma_ff(dma_chan);
549         set_dma_addr(dma_chan, dma_ptr);
550         set_dma_count(dma_chan, n);
551         release_dma_lock(flags);
552
553         enable_dma(dma_chan);
554
555         return n;
556 }
557
558 static int prep_ao_dma(struct comedi_device * dev, int dma_index, int n)
559 {
560         int dma_chan;
561         unsigned long dma_ptr;
562         unsigned long flags;
563
564         devpriv->dma[dma_index].size = n;
565         dma_chan = devpriv->dma[dma_index].chan;
566         dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
567
568         set_dma_mode(dma_chan, DMA_MODE_WRITE);
569         flags = claim_dma_lock();
570         clear_dma_ff(dma_chan);
571         set_dma_addr(dma_chan, dma_ptr);
572         set_dma_count(dma_chan, n);
573         release_dma_lock(flags);
574
575         enable_dma(dma_chan);
576
577         return n;
578 }
579
580 static irqreturn_t dt282x_interrupt(int irq, void *d PT_REGS_ARG)
581 {
582         struct comedi_device *dev = d;
583         struct comedi_subdevice *s;
584         struct comedi_subdevice *s_ao;
585         unsigned int supcsr, adcsr, dacsr;
586         int handled = 0;
587
588         if (!dev->attached) {
589                 comedi_error(dev, "spurious interrupt");
590                 return IRQ_HANDLED;
591         }
592
593         s = dev->subdevices + 0;
594         s_ao = dev->subdevices + 1;
595         adcsr = inw(dev->iobase + DT2821_ADCSR);
596         dacsr = inw(dev->iobase + DT2821_DACSR);
597         supcsr = inw(dev->iobase + DT2821_SUPCSR);
598         if (supcsr & DT2821_DMAD) {
599                 if (devpriv->dma_dir == DMA_MODE_READ)
600                         dt282x_ai_dma_interrupt(dev);
601                 else
602                         dt282x_ao_dma_interrupt(dev);
603                 handled = 1;
604         }
605         if (adcsr & DT2821_ADERR) {
606                 if (devpriv->nread != 0) {
607                         comedi_error(dev, "A/D error");
608                         dt282x_ai_cancel(dev, s);
609                         s->async->events |= COMEDI_CB_ERROR;
610                 }
611                 handled = 1;
612         }
613         if (dacsr & DT2821_DAERR) {
614 #if 0
615                 static int warn = 5;
616                 if (--warn <= 0) {
617                         disable_irq(dev->irq);
618                         printk("disabling irq\n");
619                 }
620 #endif
621                 comedi_error(dev, "D/A error");
622                 dt282x_ao_cancel(dev, s_ao);
623                 s->async->events |= COMEDI_CB_ERROR;
624                 handled = 1;
625         }
626 #if 0
627         if (adcsr & DT2821_ADDONE) {
628                 int ret;
629                 short data;
630
631                 data = (short) inw(dev->iobase + DT2821_ADDAT);
632                 data &= (1 << boardtype.adbits) - 1;
633                 if (devpriv->ad_2scomp) {
634                         data ^= 1 << (boardtype.adbits - 1);
635                 }
636                 ret = comedi_buf_put(s->async, data);
637                 if (ret == 0) {
638                         s->async->events |= COMEDI_CB_OVERFLOW;
639                 }
640
641                 devpriv->nread--;
642                 if (!devpriv->nread) {
643                         s->async->events |= COMEDI_CB_EOA;
644                 } else {
645                         if (supcsr & DT2821_SCDN)
646                                 update_supcsr(DT2821_STRIG);
647                 }
648                 handled = 1;
649         }
650 #endif
651         comedi_event(dev, s);
652         /* printk("adcsr=0x%02x dacsr-0x%02x supcsr=0x%02x\n", adcsr, dacsr, supcsr); */
653         return IRQ_RETVAL(handled);
654 }
655
656 static void dt282x_load_changain(struct comedi_device * dev, int n,
657         unsigned int *chanlist)
658 {
659         unsigned int i;
660         unsigned int chan, range;
661
662         outw(DT2821_LLE | (n - 1), dev->iobase + DT2821_CHANCSR);
663         for (i = 0; i < n; i++) {
664                 chan = CR_CHAN(chanlist[i]);
665                 range = CR_RANGE(chanlist[i]);
666                 update_adcsr((range << 4) | (chan));
667         }
668         outw(n - 1, dev->iobase + DT2821_CHANCSR);
669 }
670
671 /*
672  *    Performs a single A/D conversion.
673  *      - Put channel/gain into channel-gain list
674  *      - preload multiplexer
675  *      - trigger conversion and wait for it to finish
676  */
677 static int dt282x_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
678         struct comedi_insn * insn, unsigned int * data)
679 {
680         int i;
681
682         /* XXX should we really be enabling the ad clock here? */
683         devpriv->adcsr = DT2821_ADCLK;
684         update_adcsr(0);
685
686         dt282x_load_changain(dev, 1, &insn->chanspec);
687
688         update_supcsr(DT2821_PRLD);
689         wait_for(!mux_busy(), comedi_error(dev, "timeout\n");
690                 return -ETIME;
691                 );
692
693         for (i = 0; i < insn->n; i++) {
694                 update_supcsr(DT2821_STRIG);
695                 wait_for(ad_done(), comedi_error(dev, "timeout\n");
696                         return -ETIME;
697                         );
698
699                 data[i] =
700                         inw(dev->iobase +
701                         DT2821_ADDAT) & ((1 << boardtype.adbits) - 1);
702                 if (devpriv->ad_2scomp)
703                         data[i] ^= (1 << (boardtype.adbits - 1));
704         }
705
706         return i;
707 }
708
709 static int dt282x_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s,
710         struct comedi_cmd * cmd)
711 {
712         int err = 0;
713         int tmp;
714
715         /* step 1: make sure trigger sources are trivially valid */
716
717         tmp = cmd->start_src;
718         cmd->start_src &= TRIG_NOW;
719         if (!cmd->start_src || tmp != cmd->start_src)
720                 err++;
721
722         tmp = cmd->scan_begin_src;
723         cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_EXT;
724         if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
725                 err++;
726
727         tmp = cmd->convert_src;
728         cmd->convert_src &= TRIG_TIMER;
729         if (!cmd->convert_src || tmp != cmd->convert_src)
730                 err++;
731
732         tmp = cmd->scan_end_src;
733         cmd->scan_end_src &= TRIG_COUNT;
734         if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
735                 err++;
736
737         tmp = cmd->stop_src;
738         cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
739         if (!cmd->stop_src || tmp != cmd->stop_src)
740                 err++;
741
742         if (err)
743                 return 1;
744
745         /* step 2: make sure trigger sources are unique and mutually compatible */
746
747         /* note that mutual compatiblity is not an issue here */
748         if (cmd->scan_begin_src != TRIG_FOLLOW &&
749                 cmd->scan_begin_src != TRIG_EXT)
750                 err++;
751         if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
752                 err++;
753
754         if (err)
755                 return 2;
756
757         /* step 3: make sure arguments are trivially compatible */
758
759         if (cmd->start_arg != 0) {
760                 cmd->start_arg = 0;
761                 err++;
762         }
763         if (cmd->scan_begin_src == TRIG_FOLLOW) {
764                 /* internal trigger */
765                 if (cmd->scan_begin_arg != 0) {
766                         cmd->scan_begin_arg = 0;
767                         err++;
768                 }
769         } else {
770                 /* external trigger */
771                 /* should be level/edge, hi/lo specification here */
772                 if (cmd->scan_begin_arg != 0) {
773                         cmd->scan_begin_arg = 0;
774                         err++;
775                 }
776         }
777         if (cmd->convert_arg < 4000) {
778                 /* XXX board dependent */
779                 cmd->convert_arg = 4000;
780                 err++;
781         }
782 #define SLOWEST_TIMER   (250*(1<<15)*255)
783         if (cmd->convert_arg > SLOWEST_TIMER) {
784                 cmd->convert_arg = SLOWEST_TIMER;
785                 err++;
786         }
787         if (cmd->convert_arg < this_board->ai_speed) {
788                 cmd->convert_arg = this_board->ai_speed;
789                 err++;
790         }
791         if (cmd->scan_end_arg != cmd->chanlist_len) {
792                 cmd->scan_end_arg = cmd->chanlist_len;
793                 err++;
794         }
795         if (cmd->stop_src == TRIG_COUNT) {
796                 /* any count is allowed */
797         } else {
798                 /* TRIG_NONE */
799                 if (cmd->stop_arg != 0) {
800                         cmd->stop_arg = 0;
801                         err++;
802                 }
803         }
804
805         if (err)
806                 return 3;
807
808         /* step 4: fix up any arguments */
809
810         tmp = cmd->convert_arg;
811         dt282x_ns_to_timer(&cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK);
812         if (tmp != cmd->convert_arg)
813                 err++;
814
815         if (err)
816                 return 4;
817
818         return 0;
819 }
820
821 static int dt282x_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s)
822 {
823         struct comedi_cmd *cmd = &s->async->cmd;
824         int timer;
825
826         if (devpriv->usedma == 0) {
827                 comedi_error(dev,
828                         "driver requires 2 dma channels to execute command");
829                 return -EIO;
830         }
831
832         dt282x_disable_dma(dev);
833
834         if (cmd->convert_arg < this_board->ai_speed)
835                 cmd->convert_arg = this_board->ai_speed;
836         timer = dt282x_ns_to_timer(&cmd->convert_arg, TRIG_ROUND_NEAREST);
837         outw(timer, dev->iobase + DT2821_TMRCTR);
838
839         if (cmd->scan_begin_src == TRIG_FOLLOW) {
840                 /* internal trigger */
841                 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0;
842         } else {
843                 /* external trigger */
844                 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0 | DT2821_DS1;
845         }
846         update_supcsr(DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_ADCINIT);
847
848         devpriv->ntrig = cmd->stop_arg * cmd->scan_end_arg;
849         devpriv->nread = devpriv->ntrig;
850
851         devpriv->dma_dir = DMA_MODE_READ;
852         devpriv->current_dma_index = 0;
853         prep_ai_dma(dev, 0, 0);
854         if (devpriv->ntrig) {
855                 prep_ai_dma(dev, 1, 0);
856                 devpriv->supcsr |= DT2821_DDMA;
857                 update_supcsr(0);
858         }
859
860         devpriv->adcsr = 0;
861
862         dt282x_load_changain(dev, cmd->chanlist_len, cmd->chanlist);
863
864         devpriv->adcsr = DT2821_ADCLK | DT2821_IADDONE;
865         update_adcsr(0);
866
867         update_supcsr(DT2821_PRLD);
868         wait_for(!mux_busy(), comedi_error(dev, "timeout\n");
869                 return -ETIME;
870                 );
871
872         if (cmd->scan_begin_src == TRIG_FOLLOW) {
873                 update_supcsr(DT2821_STRIG);
874         } else {
875                 devpriv->supcsr |= DT2821_XTRIG;
876                 update_supcsr(0);
877         }
878
879         return 0;
880 }
881
882 static void dt282x_disable_dma(struct comedi_device * dev)
883 {
884         if (devpriv->usedma) {
885                 disable_dma(devpriv->dma[0].chan);
886                 disable_dma(devpriv->dma[1].chan);
887         }
888 }
889
890 static int dt282x_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s)
891 {
892         dt282x_disable_dma(dev);
893
894         devpriv->adcsr = 0;
895         update_adcsr(0);
896
897         devpriv->supcsr = 0;
898         update_supcsr(DT2821_ADCINIT);
899
900         return 0;
901 }
902
903 static int dt282x_ns_to_timer(int *nanosec, int round_mode)
904 {
905         int prescale, base, divider;
906
907         for (prescale = 0; prescale < 16; prescale++) {
908                 if (prescale == 1)
909                         continue;
910                 base = 250 * (1 << prescale);
911                 switch (round_mode) {
912                 case TRIG_ROUND_NEAREST:
913                 default:
914                         divider = (*nanosec + base / 2) / base;
915                         break;
916                 case TRIG_ROUND_DOWN:
917                         divider = (*nanosec) / base;
918                         break;
919                 case TRIG_ROUND_UP:
920                         divider = (*nanosec + base - 1) / base;
921                         break;
922                 }
923                 if (divider < 256) {
924                         *nanosec = divider * base;
925                         return (prescale << 8) | (255 - divider);
926                 }
927         }
928         base = 250 * (1 << 15);
929         divider = 255;
930         *nanosec = divider * base;
931         return (15 << 8) | (255 - divider);
932 }
933
934 /*
935  *    Analog output routine.  Selects single channel conversion,
936  *      selects correct channel, converts from 2's compliment to
937  *      offset binary if necessary, loads the data into the DAC
938  *      data register, and performs the conversion.
939  */
940 static int dt282x_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
941         struct comedi_insn * insn, unsigned int * data)
942 {
943         data[0] = devpriv->ao[CR_CHAN(insn->chanspec)];
944
945         return 1;
946 }
947
948 static int dt282x_ao_insn_write(struct comedi_device * dev, struct comedi_subdevice * s,
949         struct comedi_insn * insn, unsigned int * data)
950 {
951         short d;
952         unsigned int chan;
953
954         chan = CR_CHAN(insn->chanspec);
955         d = data[0];
956         d &= (1 << boardtype.dabits) - 1;
957         devpriv->ao[chan] = d;
958
959         devpriv->dacsr |= DT2821_SSEL;
960
961         if (chan) {
962                 /* select channel */
963                 devpriv->dacsr |= DT2821_YSEL;
964                 if (devpriv->da0_2scomp)
965                         d ^= (1 << (boardtype.dabits - 1));
966         } else {
967                 devpriv->dacsr &= ~DT2821_YSEL;
968                 if (devpriv->da1_2scomp)
969                         d ^= (1 << (boardtype.dabits - 1));
970         }
971
972         update_dacsr(0);
973
974         outw(d, dev->iobase + DT2821_DADAT);
975
976         update_supcsr(DT2821_DACON);
977
978         return 1;
979 }
980
981 static int dt282x_ao_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s,
982         struct comedi_cmd * cmd)
983 {
984         int err = 0;
985         int tmp;
986
987         /* step 1: make sure trigger sources are trivially valid */
988
989         tmp = cmd->start_src;
990         cmd->start_src &= TRIG_INT;
991         if (!cmd->start_src || tmp != cmd->start_src)
992                 err++;
993
994         tmp = cmd->scan_begin_src;
995         cmd->scan_begin_src &= TRIG_TIMER;
996         if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
997                 err++;
998
999         tmp = cmd->convert_src;
1000         cmd->convert_src &= TRIG_NOW;
1001         if (!cmd->convert_src || tmp != cmd->convert_src)
1002                 err++;
1003
1004         tmp = cmd->scan_end_src;
1005         cmd->scan_end_src &= TRIG_COUNT;
1006         if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
1007                 err++;
1008
1009         tmp = cmd->stop_src;
1010         cmd->stop_src &= TRIG_NONE;
1011         if (!cmd->stop_src || tmp != cmd->stop_src)
1012                 err++;
1013
1014         if (err)
1015                 return 1;
1016
1017         /* step 2: make sure trigger sources are unique and mutually compatible */
1018
1019         /* note that mutual compatiblity is not an issue here */
1020         if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
1021                 err++;
1022
1023         if (err)
1024                 return 2;
1025
1026         /* step 3: make sure arguments are trivially compatible */
1027
1028         if (cmd->start_arg != 0) {
1029                 cmd->start_arg = 0;
1030                 err++;
1031         }
1032         if (cmd->scan_begin_arg < 5000 /* XXX unknown */ ) {
1033                 cmd->scan_begin_arg = 5000;
1034                 err++;
1035         }
1036         if (cmd->convert_arg != 0) {
1037                 cmd->convert_arg = 0;
1038                 err++;
1039         }
1040         if (cmd->scan_end_arg > 2) {
1041                 /* XXX chanlist stuff? */
1042                 cmd->scan_end_arg = 2;
1043                 err++;
1044         }
1045         if (cmd->stop_src == TRIG_COUNT) {
1046                 /* any count is allowed */
1047         } else {
1048                 /* TRIG_NONE */
1049                 if (cmd->stop_arg != 0) {
1050                         cmd->stop_arg = 0;
1051                         err++;
1052                 }
1053         }
1054
1055         if (err)
1056                 return 3;
1057
1058         /* step 4: fix up any arguments */
1059
1060         tmp = cmd->scan_begin_arg;
1061         dt282x_ns_to_timer(&cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK);
1062         if (tmp != cmd->scan_begin_arg)
1063                 err++;
1064
1065         if (err)
1066                 return 4;
1067
1068         return 0;
1069
1070 }
1071
1072 static int dt282x_ao_inttrig(struct comedi_device * dev, struct comedi_subdevice * s,
1073         unsigned int x)
1074 {
1075         int size;
1076
1077         if (x != 0)
1078                 return -EINVAL;
1079
1080         size = cfc_read_array_from_buffer(s, devpriv->dma[0].buf,
1081                 devpriv->dma_maxsize);
1082         if (size == 0) {
1083                 rt_printk("dt282x: AO underrun\n");
1084                 return -EPIPE;
1085         }
1086         prep_ao_dma(dev, 0, size);
1087
1088         size = cfc_read_array_from_buffer(s, devpriv->dma[1].buf,
1089                 devpriv->dma_maxsize);
1090         if (size == 0) {
1091                 rt_printk("dt282x: AO underrun\n");
1092                 return -EPIPE;
1093         }
1094         prep_ao_dma(dev, 1, size);
1095
1096         update_supcsr(DT2821_STRIG);
1097         s->async->inttrig = NULL;
1098
1099         return 1;
1100 }
1101
1102 static int dt282x_ao_cmd(struct comedi_device * dev, struct comedi_subdevice * s)
1103 {
1104         int timer;
1105         struct comedi_cmd *cmd = &s->async->cmd;
1106
1107         if (devpriv->usedma == 0) {
1108                 comedi_error(dev,
1109                         "driver requires 2 dma channels to execute command");
1110                 return -EIO;
1111         }
1112
1113         dt282x_disable_dma(dev);
1114
1115         devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS1 | DT2821_DDMA;
1116         update_supcsr(DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_DACINIT);
1117
1118         devpriv->ntrig = cmd->stop_arg * cmd->chanlist_len;
1119         devpriv->nread = devpriv->ntrig;
1120
1121         devpriv->dma_dir = DMA_MODE_WRITE;
1122         devpriv->current_dma_index = 0;
1123
1124         timer = dt282x_ns_to_timer(&cmd->scan_begin_arg, TRIG_ROUND_NEAREST);
1125         outw(timer, dev->iobase + DT2821_TMRCTR);
1126
1127         devpriv->dacsr = DT2821_SSEL | DT2821_DACLK | DT2821_IDARDY;
1128         update_dacsr(0);
1129
1130         s->async->inttrig = dt282x_ao_inttrig;
1131
1132         return 0;
1133 }
1134
1135 static int dt282x_ao_cancel(struct comedi_device * dev, struct comedi_subdevice * s)
1136 {
1137         dt282x_disable_dma(dev);
1138
1139         devpriv->dacsr = 0;
1140         update_dacsr(0);
1141
1142         devpriv->supcsr = 0;
1143         update_supcsr(DT2821_DACINIT);
1144
1145         return 0;
1146 }
1147
1148 static int dt282x_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
1149         struct comedi_insn * insn, unsigned int * data)
1150 {
1151         if (data[0]) {
1152                 s->state &= ~data[0];
1153                 s->state |= (data[0] & data[1]);
1154
1155                 outw(s->state, dev->iobase + DT2821_DIODAT);
1156         }
1157         data[1] = inw(dev->iobase + DT2821_DIODAT);
1158
1159         return 2;
1160 }
1161
1162 static int dt282x_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s,
1163         struct comedi_insn * insn, unsigned int * data)
1164 {
1165         int mask;
1166
1167         mask = (CR_CHAN(insn->chanspec) < 8) ? 0x00ff : 0xff00;
1168         if (data[0])
1169                 s->io_bits |= mask;
1170         else
1171                 s->io_bits &= ~mask;
1172
1173         if (s->io_bits & 0x00ff)
1174                 devpriv->dacsr |= DT2821_LBOE;
1175         else
1176                 devpriv->dacsr &= ~DT2821_LBOE;
1177         if (s->io_bits & 0xff00)
1178                 devpriv->dacsr |= DT2821_HBOE;
1179         else
1180                 devpriv->dacsr &= ~DT2821_HBOE;
1181
1182         outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
1183
1184         return 1;
1185 }
1186
1187 static const struct comedi_lrange *const ai_range_table[] = {
1188         &range_dt282x_ai_lo_bipolar,
1189         &range_dt282x_ai_lo_unipolar,
1190         &range_dt282x_ai_5_bipolar,
1191         &range_dt282x_ai_5_unipolar
1192 };
1193 static const struct comedi_lrange *const ai_range_pgl_table[] = {
1194         &range_dt282x_ai_hi_bipolar,
1195         &range_dt282x_ai_hi_unipolar
1196 };
1197 static const struct comedi_lrange *opt_ai_range_lkup(int ispgl, int x)
1198 {
1199         if (ispgl) {
1200                 if (x < 0 || x >= 2)
1201                         x = 0;
1202                 return ai_range_pgl_table[x];
1203         } else {
1204                 if (x < 0 || x >= 4)
1205                         x = 0;
1206                 return ai_range_table[x];
1207         }
1208 }
1209 static const struct comedi_lrange *const ao_range_table[] = {
1210         &range_bipolar10,
1211         &range_unipolar10,
1212         &range_bipolar5,
1213         &range_unipolar5,
1214         &range_bipolar2_5
1215 };
1216 static const struct comedi_lrange *opt_ao_range_lkup(int x)
1217 {
1218         if (x < 0 || x >= 5)
1219                 x = 0;
1220         return ao_range_table[x];
1221 }
1222
1223 enum { opt_iobase = 0, opt_irq, opt_dma1, opt_dma2,     /* i/o base, irq, dma channels */
1224         opt_diff,               /* differential */
1225         opt_ai_twos, opt_ao0_twos, opt_ao1_twos,        /* twos comp */
1226         opt_ai_range, opt_ao0_range, opt_ao1_range,     /* range */
1227 };
1228
1229 /*
1230    options:
1231    0    i/o base
1232    1    irq
1233    2    dma1
1234    3    dma2
1235    4    0=single ended, 1=differential
1236    5    ai 0=straight binary, 1=2's comp
1237    6    ao0 0=straight binary, 1=2's comp
1238    7    ao1 0=straight binary, 1=2's comp
1239    8    ai 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V
1240    9    ao0 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1241    10   ao1 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1242  */
1243 static int dt282x_attach(struct comedi_device * dev, struct comedi_devconfig * it)
1244 {
1245         int i, irq;
1246         int ret;
1247         struct comedi_subdevice *s;
1248         unsigned long iobase;
1249
1250         dev->board_name = this_board->name;
1251
1252         iobase = it->options[opt_iobase];
1253         if (!iobase)
1254                 iobase = 0x240;
1255
1256         printk("comedi%d: dt282x: 0x%04lx", dev->minor, iobase);
1257         if (!request_region(iobase, DT2821_SIZE, "dt282x")) {
1258                 printk(" I/O port conflict\n");
1259                 return -EBUSY;
1260         }
1261         dev->iobase = iobase;
1262
1263         outw(DT2821_BDINIT, dev->iobase + DT2821_SUPCSR);
1264         i = inw(dev->iobase + DT2821_ADCSR);
1265 #ifdef DEBUG
1266         printk(" fingerprint=%x,%x,%x,%x,%x",
1267                 inw(dev->iobase + DT2821_ADCSR),
1268                 inw(dev->iobase + DT2821_CHANCSR),
1269                 inw(dev->iobase + DT2821_DACSR),
1270                 inw(dev->iobase + DT2821_SUPCSR),
1271                 inw(dev->iobase + DT2821_TMRCTR));
1272 #endif
1273
1274         if (((inw(dev->iobase + DT2821_ADCSR) & DT2821_ADCSR_MASK)
1275                         != DT2821_ADCSR_VAL) ||
1276                 ((inw(dev->iobase + DT2821_CHANCSR) & DT2821_CHANCSR_MASK)
1277                         != DT2821_CHANCSR_VAL) ||
1278                 ((inw(dev->iobase + DT2821_DACSR) & DT2821_DACSR_MASK)
1279                         != DT2821_DACSR_VAL) ||
1280                 ((inw(dev->iobase + DT2821_SUPCSR) & DT2821_SUPCSR_MASK)
1281                         != DT2821_SUPCSR_VAL) ||
1282                 ((inw(dev->iobase + DT2821_TMRCTR) & DT2821_TMRCTR_MASK)
1283                         != DT2821_TMRCTR_VAL)) {
1284                 printk(" board not found");
1285                 return -EIO;
1286         }
1287         /* should do board test */
1288
1289         irq = it->options[opt_irq];
1290 #if 0
1291         if (irq < 0) {
1292                 unsigned long flags;
1293                 int irqs;
1294
1295                 save_flags(flags);
1296                 sti();
1297                 irqs = probe_irq_on();
1298
1299                 /* trigger interrupt */
1300
1301                 comedi_udelay(100);
1302
1303                 irq = probe_irq_off(irqs);
1304                 restore_flags(flags);
1305                 if (0 /* error */ ) {
1306                         printk(" error probing irq (bad)");
1307                 }
1308         }
1309 #endif
1310         if (irq > 0) {
1311                 printk(" ( irq = %d )", irq);
1312                 ret = comedi_request_irq(irq, dt282x_interrupt, 0, "dt282x",
1313                         dev);
1314                 if (ret < 0) {
1315                         printk(" failed to get irq\n");
1316                         return -EIO;
1317                 }
1318                 dev->irq = irq;
1319         } else if (irq == 0) {
1320                 printk(" (no irq)");
1321         } else {
1322 #if 0
1323                 printk(" (probe returned multiple irqs--bad)");
1324 #else
1325                 printk(" (irq probe not implemented)");
1326 #endif
1327         }
1328
1329         if ((ret = alloc_private(dev, sizeof(dt282x_private))) < 0)
1330                 return ret;
1331
1332         ret = dt282x_grab_dma(dev, it->options[opt_dma1],
1333                 it->options[opt_dma2]);
1334         if (ret < 0)
1335                 return ret;
1336
1337         if ((ret = alloc_subdevices(dev, 3)) < 0)
1338                 return ret;
1339
1340         s = dev->subdevices + 0;
1341
1342         dev->read_subdev = s;
1343         /* ai subdevice */
1344         s->type = COMEDI_SUBD_AI;
1345         s->subdev_flags = SDF_READABLE | SDF_CMD_READ |
1346                 ((it->options[opt_diff]) ? SDF_DIFF : SDF_COMMON);
1347         s->n_chan =
1348                 (it->options[opt_diff]) ? boardtype.adchan_di : boardtype.
1349                 adchan_se;
1350         s->insn_read = dt282x_ai_insn_read;
1351         s->do_cmdtest = dt282x_ai_cmdtest;
1352         s->do_cmd = dt282x_ai_cmd;
1353         s->cancel = dt282x_ai_cancel;
1354         s->maxdata = (1 << boardtype.adbits) - 1;
1355         s->len_chanlist = 16;
1356         s->range_table =
1357                 opt_ai_range_lkup(boardtype.ispgl, it->options[opt_ai_range]);
1358         devpriv->ad_2scomp = it->options[opt_ai_twos];
1359
1360         s++;
1361         if ((s->n_chan = boardtype.dachan)) {
1362                 /* ao subsystem */
1363                 s->type = COMEDI_SUBD_AO;
1364                 dev->write_subdev = s;
1365                 s->subdev_flags = SDF_WRITABLE | SDF_CMD_WRITE;
1366                 s->insn_read = dt282x_ao_insn_read;
1367                 s->insn_write = dt282x_ao_insn_write;
1368                 s->do_cmdtest = dt282x_ao_cmdtest;
1369                 s->do_cmd = dt282x_ao_cmd;
1370                 s->cancel = dt282x_ao_cancel;
1371                 s->maxdata = (1 << boardtype.dabits) - 1;
1372                 s->len_chanlist = 2;
1373                 s->range_table_list = devpriv->darangelist;
1374                 devpriv->darangelist[0] =
1375                         opt_ao_range_lkup(it->options[opt_ao0_range]);
1376                 devpriv->darangelist[1] =
1377                         opt_ao_range_lkup(it->options[opt_ao1_range]);
1378                 devpriv->da0_2scomp = it->options[opt_ao0_twos];
1379                 devpriv->da1_2scomp = it->options[opt_ao1_twos];
1380         } else {
1381                 s->type = COMEDI_SUBD_UNUSED;
1382         }
1383
1384         s++;
1385         /* dio subsystem */
1386         s->type = COMEDI_SUBD_DIO;
1387         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1388         s->n_chan = 16;
1389         s->insn_bits = dt282x_dio_insn_bits;
1390         s->insn_config = dt282x_dio_insn_config;
1391         s->maxdata = 1;
1392         s->range_table = &range_digital;
1393
1394         printk("\n");
1395
1396         return 0;
1397 }
1398
1399 static void free_resources(struct comedi_device * dev)
1400 {
1401         if (dev->irq) {
1402                 comedi_free_irq(dev->irq, dev);
1403         }
1404         if (dev->iobase)
1405                 release_region(dev->iobase, DT2821_SIZE);
1406         if (dev->private) {
1407                 if (devpriv->dma[0].chan)
1408                         free_dma(devpriv->dma[0].chan);
1409                 if (devpriv->dma[1].chan)
1410                         free_dma(devpriv->dma[1].chan);
1411                 if (devpriv->dma[0].buf)
1412                         free_page((unsigned long)devpriv->dma[0].buf);
1413                 if (devpriv->dma[1].buf)
1414                         free_page((unsigned long)devpriv->dma[1].buf);
1415         }
1416 }
1417
1418 static int dt282x_detach(struct comedi_device * dev)
1419 {
1420         printk("comedi%d: dt282x: remove\n", dev->minor);
1421
1422         free_resources(dev);
1423
1424         return 0;
1425 }
1426
1427 static int dt282x_grab_dma(struct comedi_device * dev, int dma1, int dma2)
1428 {
1429         int ret;
1430
1431         devpriv->usedma = 0;
1432
1433         if (!dma1 && !dma2) {
1434                 printk(" (no dma)");
1435                 return 0;
1436         }
1437
1438         if (dma1 == dma2 || dma1 < 5 || dma2 < 5 || dma1 > 7 || dma2 > 7)
1439                 return -EINVAL;
1440
1441         if (dma2 < dma1) {
1442                 int i;
1443                 i = dma1;
1444                 dma1 = dma2;
1445                 dma2 = i;
1446         }
1447
1448         ret = request_dma(dma1, "dt282x A");
1449         if (ret)
1450                 return -EBUSY;
1451         devpriv->dma[0].chan = dma1;
1452
1453         ret = request_dma(dma2, "dt282x B");
1454         if (ret)
1455                 return -EBUSY;
1456         devpriv->dma[1].chan = dma2;
1457
1458         devpriv->dma_maxsize = PAGE_SIZE;
1459         devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
1460         devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
1461         if (!devpriv->dma[0].buf || !devpriv->dma[1].buf) {
1462                 printk(" can't get DMA memory");
1463                 return -ENOMEM;
1464         }
1465
1466         printk(" (dma=%d,%d)", dma1, dma2);
1467
1468         devpriv->usedma = 1;
1469
1470         return 0;
1471 }