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