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