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