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