staging: comedi: dt282x: rewrite "Devices:" line
[firefly-linux-kernel-4.4.55.git] / drivers / staging / comedi / drivers / dt282x.c
1 /*
2  * dt282x.c
3  * Comedi 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 /*
20  * Driver: dt282x
21  * Description: Data Translation DT2821 series (including DT-EZ)
22  * Author: ds
23  * Devices: [Data Translation] DT2821 (dt2821), DT2821-F-16SE (dt2821-f),
24  *   DT2821-F-8DI (dt2821-f), DT2821-G-16SE (dt2821-g),
25  *   DT2821-G-8DI (dt2821-g), DT2823 (dt2823), DT2824-PGH (dt2824-pgh),
26  *   DT2824-PGL (dt2824-pgl), DT2825 (dt2825), DT2827 (dt2827),
27  *   DT2828 (dt2828), DT2928 (dt2829), 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 (optional, required for async command support)
35  *   [2] - DMA 1 (optional, required for async command support)
36  *   [3] - DMA 2 (optional, required for async command support)
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 data format (deprecated, see below)
40  *   [7] - AO 1 data format (deprecated, see below)
41  *   [8] - AI jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5]
42  *   [9] - AO channel 0 range (deprecated, see below)
43  *   [10]- AO channel 1 range (deprecated, see below)
44  *
45  * Notes:
46  *   - AO commands might be broken.
47  *   - If you try to run a command on both the AI and AO subdevices
48  *     simultaneously, bad things will happen.  The driver needs to
49  *     be fixed to check for this situation and return an error.
50  *   - AO range is not programmable. The AO subdevice has a range_table
51  *     containing all the possible analog output ranges. Use the range
52  *     that matches your board configuration to convert between data
53  *     values and physical units. The format of the data written to the
54  *     board is handled automatically based on the unipolar/bipolar
55  *     range that is selected.
56  */
57
58 #include <linux/module.h>
59 #include "../comedidev.h"
60
61 #include <linux/delay.h>
62 #include <linux/gfp.h>
63 #include <linux/interrupt.h>
64 #include <linux/io.h>
65
66 #include <asm/dma.h>
67
68 #include "comedi_fc.h"
69
70 /*
71  * Register map
72  */
73 #define DT2821_ADCSR_REG                0x00
74 #define DT2821_ADCSR_ADERR              (1 << 15)
75 #define DT2821_ADCSR_ADCLK              (1 << 9)
76 #define DT2821_ADCSR_MUXBUSY            (1 << 8)
77 #define DT2821_ADCSR_ADDONE             (1 << 7)
78 #define DT2821_ADCSR_IADDONE            (1 << 6)
79 #define DT2821_ADCSR_GS(x)              (((x) & 0x3) << 4)
80 #define DT2821_ADCSR_CHAN(x)            (((x) & 0xf) << 0)
81 #define DT2821_CHANCSR_REG              0x02
82 #define DT2821_CHANCSR_LLE              (1 << 15)
83 #define DT2821_CHANCSR_PRESLA(x)        (((x) & 0xf) >> 8)
84 #define DT2821_CHANCSR_NUMB(x)          ((((x) - 1) & 0xf) << 0)
85 #define DT2821_ADDAT_REG                0x04
86 #define DT2821_DACSR_REG                0x06
87 #define DT2821_DACSR_DAERR              (1 << 15)
88 #define DT2821_DACSR_YSEL(x)            ((x) << 9)
89 #define DT2821_DACSR_SSEL               (1 << 8)
90 #define DT2821_DACSR_DACRDY             (1 << 7)
91 #define DT2821_DACSR_IDARDY             (1 << 6)
92 #define DT2821_DACSR_DACLK              (1 << 5)
93 #define DT2821_DACSR_HBOE               (1 << 1)
94 #define DT2821_DACSR_LBOE               (1 << 0)
95 #define DT2821_DADAT_REG                0x08
96 #define DT2821_DIODAT_REG               0x0a
97 #define DT2821_SUPCSR_REG               0x0c
98 #define DT2821_SUPCSR_DMAD              (1 << 15)
99 #define DT2821_SUPCSR_ERRINTEN          (1 << 14)
100 #define DT2821_SUPCSR_CLRDMADNE         (1 << 13)
101 #define DT2821_SUPCSR_DDMA              (1 << 12)
102 #define DT2821_SUPCSR_DS_PIO            (0 << 10)
103 #define DT2821_SUPCSR_DS_AD_CLK         (1 << 10)
104 #define DT2821_SUPCSR_DS_DA_CLK         (2 << 10)
105 #define DT2821_SUPCSR_DS_AD_TRIG        (3 << 10)
106 #define DT2821_SUPCSR_BUFFB             (1 << 9)
107 #define DT2821_SUPCSR_SCDN              (1 << 8)
108 #define DT2821_SUPCSR_DACON             (1 << 7)
109 #define DT2821_SUPCSR_ADCINIT           (1 << 6)
110 #define DT2821_SUPCSR_DACINIT           (1 << 5)
111 #define DT2821_SUPCSR_PRLD              (1 << 4)
112 #define DT2821_SUPCSR_STRIG             (1 << 3)
113 #define DT2821_SUPCSR_XTRIG             (1 << 2)
114 #define DT2821_SUPCSR_XCLK              (1 << 1)
115 #define DT2821_SUPCSR_BDINIT            (1 << 0)
116 #define DT2821_TMRCTR_REG               0x0e
117
118 static const struct comedi_lrange range_dt282x_ai_lo_bipolar = {
119         4, {
120                 BIP_RANGE(10),
121                 BIP_RANGE(5),
122                 BIP_RANGE(2.5),
123                 BIP_RANGE(1.25)
124         }
125 };
126
127 static const struct comedi_lrange range_dt282x_ai_lo_unipolar = {
128         4, {
129                 UNI_RANGE(10),
130                 UNI_RANGE(5),
131                 UNI_RANGE(2.5),
132                 UNI_RANGE(1.25)
133         }
134 };
135
136 static const struct comedi_lrange range_dt282x_ai_5_bipolar = {
137         4, {
138                 BIP_RANGE(5),
139                 BIP_RANGE(2.5),
140                 BIP_RANGE(1.25),
141                 BIP_RANGE(0.625)
142         }
143 };
144
145 static const struct comedi_lrange range_dt282x_ai_5_unipolar = {
146         4, {
147                 UNI_RANGE(5),
148                 UNI_RANGE(2.5),
149                 UNI_RANGE(1.25),
150                 UNI_RANGE(0.625)
151         }
152 };
153
154 static const struct comedi_lrange range_dt282x_ai_hi_bipolar = {
155         4, {
156                 BIP_RANGE(10),
157                 BIP_RANGE(1),
158                 BIP_RANGE(0.1),
159                 BIP_RANGE(0.02)
160         }
161 };
162
163 static const struct comedi_lrange range_dt282x_ai_hi_unipolar = {
164         4, {
165                 UNI_RANGE(10),
166                 UNI_RANGE(1),
167                 UNI_RANGE(0.1),
168                 UNI_RANGE(0.02)
169         }
170 };
171
172 /*
173  * The Analog Output range is set per-channel using jumpers on the board.
174  * All of these ranges may not be available on some DT2821 series boards.
175  * The default jumper setting has both channels set for +/-10V output.
176  */
177 static const struct comedi_lrange dt282x_ao_range = {
178         5, {
179                 BIP_RANGE(10),
180                 BIP_RANGE(5),
181                 BIP_RANGE(2.5),
182                 UNI_RANGE(10),
183                 UNI_RANGE(5),
184         }
185 };
186
187 struct dt282x_board {
188         const char *name;
189         unsigned int ai_maxdata;
190         int adchan_se;
191         int adchan_di;
192         int ai_speed;
193         int ispgl;
194         int dachan;
195         unsigned int ao_maxdata;
196 };
197
198 static const struct dt282x_board boardtypes[] = {
199         {
200                 .name           = "dt2821",
201                 .ai_maxdata     = 0x0fff,
202                 .adchan_se      = 16,
203                 .adchan_di      = 8,
204                 .ai_speed       = 20000,
205                 .dachan         = 2,
206                 .ao_maxdata     = 0x0fff,
207         }, {
208                 .name           = "dt2821-f",
209                 .ai_maxdata     = 0x0fff,
210                 .adchan_se      = 16,
211                 .adchan_di      = 8,
212                 .ai_speed       = 6500,
213                 .dachan         = 2,
214                 .ao_maxdata     = 0x0fff,
215         }, {
216                 .name           = "dt2821-g",
217                 .ai_maxdata     = 0x0fff,
218                 .adchan_se      = 16,
219                 .adchan_di      = 8,
220                 .ai_speed       = 4000,
221                 .dachan         = 2,
222                 .ao_maxdata     = 0x0fff,
223         }, {
224                 .name           = "dt2823",
225                 .ai_maxdata     = 0xffff,
226                 .adchan_di      = 4,
227                 .ai_speed       = 10000,
228                 .dachan         = 2,
229                 .ao_maxdata     = 0xffff,
230         }, {
231                 .name           = "dt2824-pgh",
232                 .ai_maxdata     = 0x0fff,
233                 .adchan_se      = 16,
234                 .adchan_di      = 8,
235                 .ai_speed       = 20000,
236         }, {
237                 .name           = "dt2824-pgl",
238                 .ai_maxdata     = 0x0fff,
239                 .adchan_se      = 16,
240                 .adchan_di      = 8,
241                 .ai_speed       = 20000,
242                 .ispgl          = 1,
243         }, {
244                 .name           = "dt2825",
245                 .ai_maxdata     = 0x0fff,
246                 .adchan_se      = 16,
247                 .adchan_di      = 8,
248                 .ai_speed       = 20000,
249                 .ispgl          = 1,
250                 .dachan         = 2,
251                 .ao_maxdata     = 0x0fff,
252         }, {
253                 .name           = "dt2827",
254                 .ai_maxdata     = 0xffff,
255                 .adchan_di      = 4,
256                 .ai_speed       = 10000,
257                 .dachan         = 2,
258                 .ao_maxdata     = 0x0fff,
259         }, {
260                 .name           = "dt2828",
261                 .ai_maxdata     = 0x0fff,
262                 .adchan_se      = 4,
263                 .ai_speed       = 10000,
264                 .dachan         = 2,
265                 .ao_maxdata     = 0x0fff,
266         }, {
267                 .name           = "dt2829",
268                 .ai_maxdata     = 0xffff,
269                 .adchan_se      = 8,
270                 .ai_speed       = 33250,
271                 .dachan         = 2,
272                 .ao_maxdata     = 0xffff,
273         }, {
274                 .name           = "dt21-ez",
275                 .ai_maxdata     = 0x0fff,
276                 .adchan_se      = 16,
277                 .adchan_di      = 8,
278                 .ai_speed       = 10000,
279                 .dachan         = 2,
280                 .ao_maxdata     = 0x0fff,
281         }, {
282                 .name           = "dt23-ez",
283                 .ai_maxdata     = 0xffff,
284                 .adchan_se      = 16,
285                 .adchan_di      = 8,
286                 .ai_speed       = 10000,
287         }, {
288                 .name           = "dt24-ez",
289                 .ai_maxdata     = 0x0fff,
290                 .adchan_se      = 16,
291                 .adchan_di      = 8,
292                 .ai_speed       = 10000,
293         }, {
294                 .name           = "dt24-ez-pgl",
295                 .ai_maxdata     = 0x0fff,
296                 .adchan_se      = 16,
297                 .adchan_di      = 8,
298                 .ai_speed       = 10000,
299                 .ispgl          = 1,
300         },
301 };
302
303 struct dt282x_private {
304         unsigned int ad_2scomp:1;
305
306         unsigned int divisor;
307
308         int dacsr;      /* software copies of registers */
309         int adcsr;
310         int supcsr;
311
312         int ntrig;
313         int nread;
314
315         struct {
316                 int chan;
317                 unsigned short *buf;    /* DMA buffer */
318                 int size;       /* size of current transfer */
319         } dma[2];
320         int dma_maxsize;        /* max size of DMA transfer (in bytes) */
321         int current_dma_index;
322         int dma_dir;
323 };
324
325 static int dt282x_prep_ai_dma(struct comedi_device *dev, int dma_index, int n)
326 {
327         struct dt282x_private *devpriv = dev->private;
328         int dma_chan;
329         unsigned long dma_ptr;
330         unsigned long flags;
331
332         if (!devpriv->ntrig)
333                 return 0;
334
335         if (n == 0)
336                 n = devpriv->dma_maxsize;
337         if (n > devpriv->ntrig * 2)
338                 n = devpriv->ntrig * 2;
339         devpriv->ntrig -= n / 2;
340
341         devpriv->dma[dma_index].size = n;
342         dma_chan = devpriv->dma[dma_index].chan;
343         dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
344
345         set_dma_mode(dma_chan, DMA_MODE_READ);
346         flags = claim_dma_lock();
347         clear_dma_ff(dma_chan);
348         set_dma_addr(dma_chan, dma_ptr);
349         set_dma_count(dma_chan, n);
350         release_dma_lock(flags);
351
352         enable_dma(dma_chan);
353
354         return n;
355 }
356
357 static int dt282x_prep_ao_dma(struct comedi_device *dev, int dma_index, int n)
358 {
359         struct dt282x_private *devpriv = dev->private;
360         int dma_chan;
361         unsigned long dma_ptr;
362         unsigned long flags;
363
364         devpriv->dma[dma_index].size = n;
365         dma_chan = devpriv->dma[dma_index].chan;
366         dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
367
368         set_dma_mode(dma_chan, DMA_MODE_WRITE);
369         flags = claim_dma_lock();
370         clear_dma_ff(dma_chan);
371         set_dma_addr(dma_chan, dma_ptr);
372         set_dma_count(dma_chan, n);
373         release_dma_lock(flags);
374
375         enable_dma(dma_chan);
376
377         return n;
378 }
379
380 static void dt282x_disable_dma(struct comedi_device *dev)
381 {
382         struct dt282x_private *devpriv = dev->private;
383
384         disable_dma(devpriv->dma[0].chan);
385         disable_dma(devpriv->dma[1].chan);
386 }
387
388 static unsigned int dt282x_ns_to_timer(unsigned int *ns, unsigned int flags)
389 {
390         unsigned int prescale, base, divider;
391
392         for (prescale = 0; prescale < 16; prescale++) {
393                 if (prescale == 1)
394                         continue;
395                 base = 250 * (1 << prescale);
396                 switch (flags & CMDF_ROUND_MASK) {
397                 case CMDF_ROUND_NEAREST:
398                 default:
399                         divider = (*ns + base / 2) / base;
400                         break;
401                 case CMDF_ROUND_DOWN:
402                         divider = (*ns) / base;
403                         break;
404                 case CMDF_ROUND_UP:
405                         divider = (*ns + base - 1) / base;
406                         break;
407                 }
408                 if (divider < 256) {
409                         *ns = divider * base;
410                         return (prescale << 8) | (255 - divider);
411                 }
412         }
413         base = 250 * (1 << 15);
414         divider = 255;
415         *ns = divider * base;
416         return (15 << 8) | (255 - divider);
417 }
418
419 static void dt282x_munge(struct comedi_device *dev,
420                          struct comedi_subdevice *s,
421                          unsigned short *buf,
422                          unsigned int nbytes)
423 {
424         struct dt282x_private *devpriv = dev->private;
425         unsigned int val;
426         int i;
427
428         if (nbytes % 2)
429                 dev_err(dev->class_dev,
430                         "bug! odd number of bytes from dma xfer\n");
431
432         for (i = 0; i < nbytes / 2; i++) {
433                 val = buf[i];
434                 val &= s->maxdata;
435                 if (devpriv->ad_2scomp)
436                         val = comedi_offset_munge(s, val);
437
438                 buf[i] = val;
439         }
440 }
441
442 static unsigned int dt282x_ao_setup_dma(struct comedi_device *dev,
443                                         struct comedi_subdevice *s,
444                                         int cur_dma)
445 {
446         struct dt282x_private *devpriv = dev->private;
447         void *ptr = devpriv->dma[cur_dma].buf;
448         unsigned int nsamples = comedi_bytes_to_samples(s, devpriv->dma_maxsize);
449         unsigned int nbytes;
450
451         nbytes = comedi_buf_read_samples(s, ptr, nsamples);
452         if (nbytes)
453                 dt282x_prep_ao_dma(dev, cur_dma, nbytes);
454         else
455                 dev_err(dev->class_dev, "AO underrun\n");
456
457         return nbytes;
458 }
459
460 static void dt282x_ao_dma_interrupt(struct comedi_device *dev,
461                                     struct comedi_subdevice *s)
462 {
463         struct dt282x_private *devpriv = dev->private;
464         int cur_dma = devpriv->current_dma_index;
465
466         outw(devpriv->supcsr | DT2821_SUPCSR_CLRDMADNE,
467              dev->iobase + DT2821_SUPCSR_REG);
468
469         disable_dma(devpriv->dma[cur_dma].chan);
470
471         devpriv->current_dma_index = 1 - cur_dma;
472
473         if (!dt282x_ao_setup_dma(dev, s, cur_dma))
474                 s->async->events |= COMEDI_CB_OVERFLOW;
475 }
476
477 static void dt282x_ai_dma_interrupt(struct comedi_device *dev,
478                                     struct comedi_subdevice *s)
479 {
480         struct dt282x_private *devpriv = dev->private;
481         int cur_dma = devpriv->current_dma_index;
482         void *ptr = devpriv->dma[cur_dma].buf;
483         int size = devpriv->dma[cur_dma].size;
484         unsigned int nsamples = comedi_bytes_to_samples(s, size);
485         int ret;
486
487         outw(devpriv->supcsr | DT2821_SUPCSR_CLRDMADNE,
488              dev->iobase + DT2821_SUPCSR_REG);
489
490         disable_dma(devpriv->dma[cur_dma].chan);
491
492         devpriv->current_dma_index = 1 - cur_dma;
493
494         dt282x_munge(dev, s, ptr, size);
495         ret = comedi_buf_write_samples(s, ptr, nsamples);
496         if (ret != size)
497                 return;
498
499         devpriv->nread -= nsamples;
500         if (devpriv->nread < 0) {
501                 dev_info(dev->class_dev, "nread off by one\n");
502                 devpriv->nread = 0;
503         }
504         if (!devpriv->nread) {
505                 s->async->events |= COMEDI_CB_EOA;
506                 return;
507         }
508 #if 0
509         /* clear the dual dma flag, making this the last dma segment */
510         /* XXX probably wrong */
511         if (!devpriv->ntrig) {
512                 devpriv->supcsr &= ~DT2821_SUPCSR_DDMA;
513                 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR_REG);
514         }
515 #endif
516         /* restart the channel */
517         dt282x_prep_ai_dma(dev, cur_dma, 0);
518 }
519
520 static irqreturn_t dt282x_interrupt(int irq, void *d)
521 {
522         struct comedi_device *dev = d;
523         struct dt282x_private *devpriv = dev->private;
524         struct comedi_subdevice *s = dev->read_subdev;
525         struct comedi_subdevice *s_ao = dev->write_subdev;
526         unsigned int supcsr, adcsr, dacsr;
527         int handled = 0;
528
529         if (!dev->attached) {
530                 dev_err(dev->class_dev, "spurious interrupt\n");
531                 return IRQ_HANDLED;
532         }
533
534         adcsr = inw(dev->iobase + DT2821_ADCSR_REG);
535         dacsr = inw(dev->iobase + DT2821_DACSR_REG);
536         supcsr = inw(dev->iobase + DT2821_SUPCSR_REG);
537         if (supcsr & DT2821_SUPCSR_DMAD) {
538                 if (devpriv->dma_dir == DMA_MODE_READ)
539                         dt282x_ai_dma_interrupt(dev, s);
540                 else
541                         dt282x_ao_dma_interrupt(dev, s_ao);
542                 handled = 1;
543         }
544         if (adcsr & DT2821_ADCSR_ADERR) {
545                 if (devpriv->nread != 0) {
546                         dev_err(dev->class_dev, "A/D error\n");
547                         s->async->events |= COMEDI_CB_ERROR;
548                 }
549                 handled = 1;
550         }
551         if (dacsr & DT2821_DACSR_DAERR) {
552                 dev_err(dev->class_dev, "D/A error\n");
553                 s_ao->async->events |= COMEDI_CB_ERROR;
554                 handled = 1;
555         }
556 #if 0
557         if (adcsr & DT2821_ADCSR_ADDONE) {
558                 unsigned short data;
559
560                 data = inw(dev->iobase + DT2821_ADDAT_REG);
561                 data &= s->maxdata;
562                 if (devpriv->ad_2scomp)
563                         data = comedi_offset_munge(s, data);
564
565                 comedi_buf_write_samples(s, &data, 1);
566
567                 devpriv->nread--;
568                 if (!devpriv->nread) {
569                         s->async->events |= COMEDI_CB_EOA;
570                 } else {
571                         if (supcsr & DT2821_SUPCSR_SCDN)
572                                 outw(devpriv->supcsr | DT2821_SUPCSR_STRIG,
573                                      dev->iobase + DT2821_SUPCSR_REG);
574                 }
575                 handled = 1;
576         }
577 #endif
578         comedi_handle_events(dev, s);
579         comedi_handle_events(dev, s_ao);
580
581         return IRQ_RETVAL(handled);
582 }
583
584 static void dt282x_load_changain(struct comedi_device *dev, int n,
585                                  unsigned int *chanlist)
586 {
587         struct dt282x_private *devpriv = dev->private;
588         int i;
589
590         outw(DT2821_CHANCSR_LLE | DT2821_CHANCSR_NUMB(n),
591              dev->iobase + DT2821_CHANCSR_REG);
592         for (i = 0; i < n; i++) {
593                 unsigned int chan = CR_CHAN(chanlist[i]);
594                 unsigned int range = CR_RANGE(chanlist[i]);
595
596                 outw(devpriv->adcsr |
597                      DT2821_ADCSR_GS(range) |
598                      DT2821_ADCSR_CHAN(chan),
599                      dev->iobase + DT2821_ADCSR_REG);
600         }
601         outw(DT2821_CHANCSR_NUMB(n), dev->iobase + DT2821_CHANCSR_REG);
602 }
603
604 static int dt282x_ai_timeout(struct comedi_device *dev,
605                              struct comedi_subdevice *s,
606                              struct comedi_insn *insn,
607                              unsigned long context)
608 {
609         unsigned int status;
610
611         status = inw(dev->iobase + DT2821_ADCSR_REG);
612         switch (context) {
613         case DT2821_ADCSR_MUXBUSY:
614                 if ((status & DT2821_ADCSR_MUXBUSY) == 0)
615                         return 0;
616                 break;
617         case DT2821_ADCSR_ADDONE:
618                 if (status & DT2821_ADCSR_ADDONE)
619                         return 0;
620                 break;
621         default:
622                 return -EINVAL;
623         }
624         return -EBUSY;
625 }
626
627 /*
628  *    Performs a single A/D conversion.
629  *      - Put channel/gain into channel-gain list
630  *      - preload multiplexer
631  *      - trigger conversion and wait for it to finish
632  */
633 static int dt282x_ai_insn_read(struct comedi_device *dev,
634                                struct comedi_subdevice *s,
635                                struct comedi_insn *insn,
636                                unsigned int *data)
637 {
638         struct dt282x_private *devpriv = dev->private;
639         unsigned int val;
640         int ret;
641         int i;
642
643         /* XXX should we really be enabling the ad clock here? */
644         devpriv->adcsr = DT2821_ADCSR_ADCLK;
645         outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR_REG);
646
647         dt282x_load_changain(dev, 1, &insn->chanspec);
648
649         outw(devpriv->supcsr | DT2821_SUPCSR_PRLD,
650              dev->iobase + DT2821_SUPCSR_REG);
651         ret = comedi_timeout(dev, s, insn,
652                              dt282x_ai_timeout, DT2821_ADCSR_MUXBUSY);
653         if (ret)
654                 return ret;
655
656         for (i = 0; i < insn->n; i++) {
657                 outw(devpriv->supcsr | DT2821_SUPCSR_STRIG,
658                      dev->iobase + DT2821_SUPCSR_REG);
659
660                 ret = comedi_timeout(dev, s, insn,
661                                      dt282x_ai_timeout, DT2821_ADCSR_ADDONE);
662                 if (ret)
663                         return ret;
664
665                 val = inw(dev->iobase + DT2821_ADDAT_REG);
666                 val &= s->maxdata;
667                 if (devpriv->ad_2scomp)
668                         val = comedi_offset_munge(s, val);
669
670                 data[i] = val;
671         }
672
673         return i;
674 }
675
676 static int dt282x_ai_cmdtest(struct comedi_device *dev,
677                              struct comedi_subdevice *s,
678                              struct comedi_cmd *cmd)
679 {
680         const struct dt282x_board *board = dev->board_ptr;
681         struct dt282x_private *devpriv = dev->private;
682         int err = 0;
683         unsigned int arg;
684
685         /* Step 1 : check if triggers are trivially valid */
686
687         err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
688         err |= cfc_check_trigger_src(&cmd->scan_begin_src,
689                                         TRIG_FOLLOW | TRIG_EXT);
690         err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
691         err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
692         err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
693
694         if (err)
695                 return 1;
696
697         /* Step 2a : make sure trigger sources are unique */
698
699         err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
700         err |= cfc_check_trigger_is_unique(cmd->stop_src);
701
702         /* Step 2b : and mutually compatible */
703
704         if (err)
705                 return 2;
706
707         /* Step 3: check if arguments are trivially valid */
708
709         err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
710
711         if (cmd->scan_begin_src == TRIG_FOLLOW) {
712                 /* internal trigger */
713                 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
714         } else {
715                 /* external trigger */
716                 /* should be level/edge, hi/lo specification here */
717                 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
718         }
719
720         err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 4000);
721
722 #define SLOWEST_TIMER   (250*(1<<15)*255)
723         err |= cfc_check_trigger_arg_max(&cmd->convert_arg, SLOWEST_TIMER);
724         err |= cfc_check_trigger_arg_min(&cmd->convert_arg, board->ai_speed);
725         err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
726
727         if (cmd->stop_src == TRIG_COUNT)
728                 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
729         else    /* TRIG_EXT | TRIG_NONE */
730                 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
731
732         if (err)
733                 return 3;
734
735         /* step 4: fix up any arguments */
736
737         arg = cmd->convert_arg;
738         devpriv->divisor = dt282x_ns_to_timer(&arg, cmd->flags);
739         err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
740
741         if (err)
742                 return 4;
743
744         return 0;
745 }
746
747 static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
748 {
749         struct dt282x_private *devpriv = dev->private;
750         struct comedi_cmd *cmd = &s->async->cmd;
751         int ret;
752
753         dt282x_disable_dma(dev);
754
755         outw(devpriv->divisor, dev->iobase + DT2821_TMRCTR_REG);
756
757         devpriv->supcsr = DT2821_SUPCSR_ERRINTEN;
758         if (cmd->scan_begin_src == TRIG_FOLLOW)
759                 devpriv->supcsr = DT2821_SUPCSR_DS_AD_CLK;
760         else
761                 devpriv->supcsr = DT2821_SUPCSR_DS_AD_TRIG;
762         outw(devpriv->supcsr |
763              DT2821_SUPCSR_CLRDMADNE |
764              DT2821_SUPCSR_BUFFB |
765              DT2821_SUPCSR_ADCINIT,
766              dev->iobase + DT2821_SUPCSR_REG);
767
768         devpriv->ntrig = cmd->stop_arg * cmd->scan_end_arg;
769         devpriv->nread = devpriv->ntrig;
770
771         devpriv->dma_dir = DMA_MODE_READ;
772         devpriv->current_dma_index = 0;
773         dt282x_prep_ai_dma(dev, 0, 0);
774         if (devpriv->ntrig) {
775                 dt282x_prep_ai_dma(dev, 1, 0);
776                 devpriv->supcsr |= DT2821_SUPCSR_DDMA;
777                 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR_REG);
778         }
779
780         devpriv->adcsr = 0;
781
782         dt282x_load_changain(dev, cmd->chanlist_len, cmd->chanlist);
783
784         devpriv->adcsr = DT2821_ADCSR_ADCLK | DT2821_ADCSR_IADDONE;
785         outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR_REG);
786
787         outw(devpriv->supcsr | DT2821_SUPCSR_PRLD,
788              dev->iobase + DT2821_SUPCSR_REG);
789         ret = comedi_timeout(dev, s, NULL,
790                              dt282x_ai_timeout, DT2821_ADCSR_MUXBUSY);
791         if (ret)
792                 return ret;
793
794         if (cmd->scan_begin_src == TRIG_FOLLOW) {
795                 outw(devpriv->supcsr | DT2821_SUPCSR_STRIG,
796                         dev->iobase + DT2821_SUPCSR_REG);
797         } else {
798                 devpriv->supcsr |= DT2821_SUPCSR_XTRIG;
799                 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR_REG);
800         }
801
802         return 0;
803 }
804
805 static int dt282x_ai_cancel(struct comedi_device *dev,
806                             struct comedi_subdevice *s)
807 {
808         struct dt282x_private *devpriv = dev->private;
809
810         dt282x_disable_dma(dev);
811
812         devpriv->adcsr = 0;
813         outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR_REG);
814
815         devpriv->supcsr = 0;
816         outw(devpriv->supcsr | DT2821_SUPCSR_ADCINIT,
817              dev->iobase + DT2821_SUPCSR_REG);
818
819         return 0;
820 }
821
822 static int dt282x_ao_insn_write(struct comedi_device *dev,
823                                 struct comedi_subdevice *s,
824                                 struct comedi_insn *insn,
825                                 unsigned int *data)
826 {
827         struct dt282x_private *devpriv = dev->private;
828         unsigned int chan = CR_CHAN(insn->chanspec);
829         unsigned int range = CR_RANGE(insn->chanspec);
830         int i;
831
832         devpriv->dacsr |= DT2821_DACSR_SSEL | DT2821_DACSR_YSEL(chan);
833
834         for (i = 0; i < insn->n; i++) {
835                 unsigned int val = data[i];
836
837                 s->readback[chan] = val;
838
839                 if (comedi_range_is_bipolar(s, range))
840                         val = comedi_offset_munge(s, val);
841
842                 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR_REG);
843
844                 outw(val, dev->iobase + DT2821_DADAT_REG);
845
846                 outw(devpriv->supcsr | DT2821_SUPCSR_DACON,
847                      dev->iobase + DT2821_SUPCSR_REG);
848         }
849
850         return insn->n;
851 }
852
853 static int dt282x_ao_cmdtest(struct comedi_device *dev,
854                              struct comedi_subdevice *s,
855                              struct comedi_cmd *cmd)
856 {
857         struct dt282x_private *devpriv = dev->private;
858         int err = 0;
859         unsigned int arg;
860
861         /* Step 1 : check if triggers are trivially valid */
862
863         err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT);
864         err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
865         err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
866         err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
867         err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
868
869         if (err)
870                 return 1;
871
872         /* Step 2a : make sure trigger sources are unique */
873
874         err |= cfc_check_trigger_is_unique(cmd->stop_src);
875
876         /* Step 2b : and mutually compatible */
877
878         if (err)
879                 return 2;
880
881         /* Step 3: check if arguments are trivially valid */
882
883         err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
884         err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, 5000);
885         err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
886         err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
887
888         if (cmd->stop_src == TRIG_COUNT)
889                 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
890         else    /* TRIG_EXT | TRIG_NONE */
891                 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
892
893         if (err)
894                 return 3;
895
896         /* step 4: fix up any arguments */
897
898         arg = cmd->scan_begin_arg;
899         devpriv->divisor = dt282x_ns_to_timer(&arg, cmd->flags);
900         err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
901
902         if (err)
903                 return 4;
904
905         return 0;
906
907 }
908
909 static int dt282x_ao_inttrig(struct comedi_device *dev,
910                              struct comedi_subdevice *s,
911                              unsigned int trig_num)
912 {
913         struct dt282x_private *devpriv = dev->private;
914         struct comedi_cmd *cmd = &s->async->cmd;
915
916         if (trig_num != cmd->start_src)
917                 return -EINVAL;
918
919         if (!dt282x_ao_setup_dma(dev, s, 0))
920                 return -EPIPE;
921
922         if (!dt282x_ao_setup_dma(dev, s, 1))
923                 return -EPIPE;
924
925         outw(devpriv->supcsr | DT2821_SUPCSR_STRIG,
926              dev->iobase + DT2821_SUPCSR_REG);
927         s->async->inttrig = NULL;
928
929         return 1;
930 }
931
932 static int dt282x_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
933 {
934         struct dt282x_private *devpriv = dev->private;
935         struct comedi_cmd *cmd = &s->async->cmd;
936
937         dt282x_disable_dma(dev);
938
939         devpriv->supcsr = DT2821_SUPCSR_ERRINTEN |
940                           DT2821_SUPCSR_DS_DA_CLK |
941                           DT2821_SUPCSR_DDMA;
942         outw(devpriv->supcsr |
943              DT2821_SUPCSR_CLRDMADNE |
944              DT2821_SUPCSR_BUFFB |
945              DT2821_SUPCSR_DACINIT,
946              dev->iobase + DT2821_SUPCSR_REG);
947
948         devpriv->ntrig = cmd->stop_arg * cmd->chanlist_len;
949         devpriv->nread = devpriv->ntrig;
950
951         devpriv->dma_dir = DMA_MODE_WRITE;
952         devpriv->current_dma_index = 0;
953
954         outw(devpriv->divisor, dev->iobase + DT2821_TMRCTR_REG);
955
956         /* clear all bits but the DIO direction bits */
957         devpriv->dacsr &= (DT2821_DACSR_LBOE | DT2821_DACSR_HBOE);
958
959         devpriv->dacsr |= (DT2821_DACSR_SSEL |
960                            DT2821_DACSR_DACLK |
961                            DT2821_DACSR_IDARDY);
962         outw(devpriv->dacsr, dev->iobase + DT2821_DACSR_REG);
963
964         s->async->inttrig = dt282x_ao_inttrig;
965
966         return 0;
967 }
968
969 static int dt282x_ao_cancel(struct comedi_device *dev,
970                             struct comedi_subdevice *s)
971 {
972         struct dt282x_private *devpriv = dev->private;
973
974         dt282x_disable_dma(dev);
975
976         /* clear all bits but the DIO direction bits */
977         devpriv->dacsr &= (DT2821_DACSR_LBOE | DT2821_DACSR_HBOE);
978
979         outw(devpriv->dacsr, dev->iobase + DT2821_DACSR_REG);
980
981         devpriv->supcsr = 0;
982         outw(devpriv->supcsr | DT2821_SUPCSR_DACINIT,
983              dev->iobase + DT2821_SUPCSR_REG);
984
985         return 0;
986 }
987
988 static int dt282x_dio_insn_bits(struct comedi_device *dev,
989                                 struct comedi_subdevice *s,
990                                 struct comedi_insn *insn,
991                                 unsigned int *data)
992 {
993         if (comedi_dio_update_state(s, data))
994                 outw(s->state, dev->iobase + DT2821_DIODAT_REG);
995
996         data[1] = inw(dev->iobase + DT2821_DIODAT_REG);
997
998         return insn->n;
999 }
1000
1001 static int dt282x_dio_insn_config(struct comedi_device *dev,
1002                                   struct comedi_subdevice *s,
1003                                   struct comedi_insn *insn,
1004                                   unsigned int *data)
1005 {
1006         struct dt282x_private *devpriv = dev->private;
1007         unsigned int chan = CR_CHAN(insn->chanspec);
1008         unsigned int mask;
1009         int ret;
1010
1011         if (chan < 8)
1012                 mask = 0x00ff;
1013         else
1014                 mask = 0xff00;
1015
1016         ret = comedi_dio_insn_config(dev, s, insn, data, mask);
1017         if (ret)
1018                 return ret;
1019
1020         devpriv->dacsr &= ~(DT2821_DACSR_LBOE | DT2821_DACSR_HBOE);
1021         if (s->io_bits & 0x00ff)
1022                 devpriv->dacsr |= DT2821_DACSR_LBOE;
1023         if (s->io_bits & 0xff00)
1024                 devpriv->dacsr |= DT2821_DACSR_HBOE;
1025
1026         outw(devpriv->dacsr, dev->iobase + DT2821_DACSR_REG);
1027
1028         return insn->n;
1029 }
1030
1031 static const struct comedi_lrange *const ai_range_table[] = {
1032         &range_dt282x_ai_lo_bipolar,
1033         &range_dt282x_ai_lo_unipolar,
1034         &range_dt282x_ai_5_bipolar,
1035         &range_dt282x_ai_5_unipolar
1036 };
1037
1038 static const struct comedi_lrange *const ai_range_pgl_table[] = {
1039         &range_dt282x_ai_hi_bipolar,
1040         &range_dt282x_ai_hi_unipolar
1041 };
1042
1043 static const struct comedi_lrange *opt_ai_range_lkup(int ispgl, int x)
1044 {
1045         if (ispgl) {
1046                 if (x < 0 || x >= 2)
1047                         x = 0;
1048                 return ai_range_pgl_table[x];
1049         }
1050
1051         if (x < 0 || x >= 4)
1052                 x = 0;
1053         return ai_range_table[x];
1054 }
1055
1056 static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2)
1057 {
1058         struct dt282x_private *devpriv = dev->private;
1059         int ret;
1060
1061         ret = request_dma(dma1, "dt282x A");
1062         if (ret)
1063                 return -EBUSY;
1064         devpriv->dma[0].chan = dma1;
1065
1066         ret = request_dma(dma2, "dt282x B");
1067         if (ret)
1068                 return -EBUSY;
1069         devpriv->dma[1].chan = dma2;
1070
1071         devpriv->dma_maxsize = PAGE_SIZE;
1072         devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
1073         devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
1074         if (!devpriv->dma[0].buf || !devpriv->dma[1].buf)
1075                 return -ENOMEM;
1076
1077         return 0;
1078 }
1079
1080 static void dt282x_free_dma(struct comedi_device *dev)
1081 {
1082         struct dt282x_private *devpriv = dev->private;
1083         int i;
1084
1085         if (!devpriv)
1086                 return;
1087
1088         for (i = 0; i < 2; i++) {
1089                 if (devpriv->dma[i].chan)
1090                         free_dma(devpriv->dma[i].chan);
1091                 if (devpriv->dma[i].buf)
1092                         free_page((unsigned long)devpriv->dma[i].buf);
1093                 devpriv->dma[i].chan = 0;
1094                 devpriv->dma[i].buf = NULL;
1095         }
1096 }
1097
1098 static int dt282x_initialize(struct comedi_device *dev)
1099 {
1100         /* Initialize board */
1101         outw(DT2821_SUPCSR_BDINIT, dev->iobase + DT2821_SUPCSR_REG);
1102         inw(dev->iobase + DT2821_ADCSR_REG);
1103
1104         /*
1105          * At power up, some registers are in a well-known state.
1106          * Check them to see if a DT2821 series board is present.
1107          */
1108         if (((inw(dev->iobase + DT2821_ADCSR_REG) & 0xfff0) != 0x7c00) ||
1109             ((inw(dev->iobase + DT2821_CHANCSR_REG) & 0xf0f0) != 0x70f0) ||
1110             ((inw(dev->iobase + DT2821_DACSR_REG) & 0x7c93) != 0x7c90) ||
1111             ((inw(dev->iobase + DT2821_SUPCSR_REG) & 0xf8ff) != 0x0000) ||
1112             ((inw(dev->iobase + DT2821_TMRCTR_REG) & 0xff00) != 0xf000)) {
1113                 dev_err(dev->class_dev, "board not found\n");
1114                 return -EIO;
1115         }
1116         return 0;
1117 }
1118
1119 /*
1120    options:
1121    0    i/o base
1122    1    irq
1123    2    dma1
1124    3    dma2
1125    4    0=single ended, 1=differential
1126    5    ai 0=straight binary, 1=2's comp
1127    6    ao0 0=straight binary, 1=2's comp
1128    7    ao1 0=straight binary, 1=2's comp
1129    8    ai 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V
1130    9    ao0 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1131    10   ao1 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1132  */
1133 static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1134 {
1135         const struct dt282x_board *board = dev->board_ptr;
1136         struct dt282x_private *devpriv;
1137         struct comedi_subdevice *s;
1138         int ret;
1139
1140         ret = comedi_request_region(dev, it->options[0], 0x10);
1141         if (ret)
1142                 return ret;
1143
1144         ret = dt282x_initialize(dev);
1145         if (ret)
1146                 return ret;
1147
1148         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1149         if (!devpriv)
1150                 return -ENOMEM;
1151
1152         /* an IRQ and 2 DMA channels are required for async command support */
1153         if (it->options[1] && it->options[2] && it->options[3]) {
1154                 unsigned int irq = it->options[1];
1155                 unsigned int dma1 = it->options[2];
1156                 unsigned int dma2 = it->options[3];
1157
1158                 if (dma2 < dma1) {
1159                         unsigned int swap;
1160
1161                         swap = dma1;
1162                         dma1 = dma2;
1163                         dma2 = swap;
1164                 }
1165
1166                 if (dma1 != dma2 &&
1167                     dma1 >= 5 && dma1 <= 7 &&
1168                     dma2 >= 5 && dma2 <= 7) {
1169                         ret = request_irq(irq, dt282x_interrupt, 0,
1170                                           dev->board_name, dev);
1171                         if (ret == 0) {
1172                                 dev->irq = irq;
1173
1174                                 ret = dt282x_grab_dma(dev, dma1, dma2);
1175                                 if (ret < 0) {
1176                                         dt282x_free_dma(dev);
1177                                         free_irq(dev->irq, dev);
1178                                         dev->irq = 0;
1179                                 }
1180                         }
1181                 }
1182         }
1183
1184         ret = comedi_alloc_subdevices(dev, 3);
1185         if (ret)
1186                 return ret;
1187
1188         /* Analog Input subdevice */
1189         s = &dev->subdevices[0];
1190         s->type         = COMEDI_SUBD_AI;
1191         s->subdev_flags = SDF_READABLE;
1192         if ((it->options[4] && board->adchan_di) || board->adchan_se == 0) {
1193                 s->subdev_flags |= SDF_DIFF;
1194                 s->n_chan       = board->adchan_di;
1195         } else {
1196                 s->subdev_flags |= SDF_COMMON;
1197                 s->n_chan       = board->adchan_se;
1198         }
1199         s->maxdata      = board->ai_maxdata;
1200
1201         s->range_table = opt_ai_range_lkup(board->ispgl, it->options[8]);
1202         devpriv->ad_2scomp = it->options[5] ? 1 : 0;
1203
1204         s->insn_read    = dt282x_ai_insn_read;
1205         if (dev->irq) {
1206                 dev->read_subdev = s;
1207                 s->subdev_flags |= SDF_CMD_READ;
1208                 s->len_chanlist = s->n_chan;
1209                 s->do_cmdtest   = dt282x_ai_cmdtest;
1210                 s->do_cmd       = dt282x_ai_cmd;
1211                 s->cancel       = dt282x_ai_cancel;
1212         }
1213
1214         /* Analog Output subdevice */
1215         s = &dev->subdevices[1];
1216         if (board->dachan) {
1217                 s->type         = COMEDI_SUBD_AO;
1218                 s->subdev_flags = SDF_WRITABLE;
1219                 s->n_chan       = board->dachan;
1220                 s->maxdata      = board->ao_maxdata;
1221                 /* ranges are per-channel, set by jumpers on the board */
1222                 s->range_table  = &dt282x_ao_range;
1223                 s->insn_write   = dt282x_ao_insn_write;
1224                 if (dev->irq) {
1225                         dev->write_subdev = s;
1226                         s->subdev_flags |= SDF_CMD_WRITE;
1227                         s->len_chanlist = s->n_chan;
1228                         s->do_cmdtest   = dt282x_ao_cmdtest;
1229                         s->do_cmd       = dt282x_ao_cmd;
1230                         s->cancel       = dt282x_ao_cancel;
1231                 }
1232
1233                 ret = comedi_alloc_subdev_readback(s);
1234                 if (ret)
1235                         return ret;
1236         } else {
1237                 s->type         = COMEDI_SUBD_UNUSED;
1238         }
1239
1240         /* Digital I/O subdevice */
1241         s = &dev->subdevices[2];
1242         s->type         = COMEDI_SUBD_DIO;
1243         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1244         s->n_chan       = 16;
1245         s->maxdata      = 1;
1246         s->range_table  = &range_digital;
1247         s->insn_bits    = dt282x_dio_insn_bits;
1248         s->insn_config  = dt282x_dio_insn_config;
1249
1250         return 0;
1251 }
1252
1253 static void dt282x_detach(struct comedi_device *dev)
1254 {
1255         dt282x_free_dma(dev);
1256         comedi_legacy_detach(dev);
1257 }
1258
1259 static struct comedi_driver dt282x_driver = {
1260         .driver_name    = "dt282x",
1261         .module         = THIS_MODULE,
1262         .attach         = dt282x_attach,
1263         .detach         = dt282x_detach,
1264         .board_name     = &boardtypes[0].name,
1265         .num_names      = ARRAY_SIZE(boardtypes),
1266         .offset         = sizeof(struct dt282x_board),
1267 };
1268 module_comedi_driver(dt282x_driver);
1269
1270 MODULE_AUTHOR("Comedi http://www.comedi.org");
1271 MODULE_DESCRIPTION("Comedi driver for Data Translation DT2821 series");
1272 MODULE_LICENSE("GPL");