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