Merge tag 'edac_fixes_for_3.10' of git://git.kernel.org/pub/scm/linux/kernel/git...
[firefly-linux-kernel-4.4.55.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 /*
252  *    Some useless abstractions
253  */
254 #define chan_to_DAC(a)  ((a)&1)
255 #define mux_busy() (inw(dev->iobase+DT2821_ADCSR)&DT2821_MUXBUSY)
256 #define ad_done() (inw(dev->iobase+DT2821_ADCSR)&DT2821_ADDONE)
257
258 /*
259  *    danger! macro abuse... a is the expression to wait on, and b is
260  *      the statement(s) to execute if it doesn't happen.
261  */
262 #define wait_for(a, b)                                          \
263         do {                                                    \
264                 int _i;                                         \
265                 for (_i = 0; _i < DT2821_TIMEOUT; _i++) {       \
266                         if (a) {                                \
267                                 _i = 0;                         \
268                                 break;                          \
269                         }                                       \
270                         udelay(5);                              \
271                 }                                               \
272                 if (_i)                                         \
273                         b                                       \
274         } while (0)
275
276 static int prep_ai_dma(struct comedi_device *dev, int chan, int size);
277 static int prep_ao_dma(struct comedi_device *dev, int chan, int size);
278 static int dt282x_ai_cancel(struct comedi_device *dev,
279                             struct comedi_subdevice *s);
280 static int dt282x_ao_cancel(struct comedi_device *dev,
281                             struct comedi_subdevice *s);
282 static int dt282x_ns_to_timer(int *nanosec, int round_mode);
283 static void dt282x_disable_dma(struct comedi_device *dev);
284
285 static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2);
286
287 static void dt282x_munge(struct comedi_device *dev, short *buf,
288                          unsigned int nbytes)
289 {
290         const struct dt282x_board *board = comedi_board(dev);
291         struct dt282x_private *devpriv = dev->private;
292         unsigned int i;
293         unsigned short mask = (1 << board->adbits) - 1;
294         unsigned short sign = 1 << (board->adbits - 1);
295         int n;
296
297         if (devpriv->ad_2scomp)
298                 sign = 1 << (board->adbits - 1);
299         else
300                 sign = 0;
301
302         if (nbytes % 2)
303                 comedi_error(dev, "bug! odd number of bytes from dma xfer");
304         n = nbytes / 2;
305         for (i = 0; i < n; i++)
306                 buf[i] = (buf[i] & mask) ^ sign;
307 }
308
309 static void dt282x_ao_dma_interrupt(struct comedi_device *dev)
310 {
311         struct dt282x_private *devpriv = dev->private;
312         void *ptr;
313         int size;
314         int i;
315         struct comedi_subdevice *s = &dev->subdevices[1];
316
317         outw(devpriv->supcsr | DT2821_CLRDMADNE, dev->iobase + DT2821_SUPCSR);
318
319         if (!s->async->prealloc_buf) {
320                 printk(KERN_ERR "async->data disappeared.  dang!\n");
321                 return;
322         }
323
324         i = devpriv->current_dma_index;
325         ptr = devpriv->dma[i].buf;
326
327         disable_dma(devpriv->dma[i].chan);
328
329         devpriv->current_dma_index = 1 - i;
330
331         size = cfc_read_array_from_buffer(s, ptr, devpriv->dma_maxsize);
332         if (size == 0) {
333                 printk(KERN_ERR "dt282x: AO underrun\n");
334                 dt282x_ao_cancel(dev, s);
335                 s->async->events |= COMEDI_CB_OVERFLOW;
336                 return;
337         }
338         prep_ao_dma(dev, i, size);
339         return;
340 }
341
342 static void dt282x_ai_dma_interrupt(struct comedi_device *dev)
343 {
344         struct dt282x_private *devpriv = dev->private;
345         void *ptr;
346         int size;
347         int i;
348         int ret;
349         struct comedi_subdevice *s = &dev->subdevices[0];
350
351         outw(devpriv->supcsr | DT2821_CLRDMADNE, dev->iobase + DT2821_SUPCSR);
352
353         if (!s->async->prealloc_buf) {
354                 printk(KERN_ERR "async->data disappeared.  dang!\n");
355                 return;
356         }
357
358         i = devpriv->current_dma_index;
359         ptr = devpriv->dma[i].buf;
360         size = devpriv->dma[i].size;
361
362         disable_dma(devpriv->dma[i].chan);
363
364         devpriv->current_dma_index = 1 - i;
365
366         dt282x_munge(dev, ptr, size);
367         ret = cfc_write_array_to_buffer(s, ptr, size);
368         if (ret != size) {
369                 dt282x_ai_cancel(dev, s);
370                 return;
371         }
372         devpriv->nread -= size / 2;
373
374         if (devpriv->nread < 0) {
375                 printk(KERN_INFO "dt282x: off by one\n");
376                 devpriv->nread = 0;
377         }
378         if (!devpriv->nread) {
379                 dt282x_ai_cancel(dev, s);
380                 s->async->events |= COMEDI_CB_EOA;
381                 return;
382         }
383 #if 0
384         /* clear the dual dma flag, making this the last dma segment */
385         /* XXX probably wrong */
386         if (!devpriv->ntrig) {
387                 devpriv->supcsr &= ~(DT2821_DDMA);
388                 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR);
389         }
390 #endif
391         /* restart the channel */
392         prep_ai_dma(dev, i, 0);
393 }
394
395 static int prep_ai_dma(struct comedi_device *dev, int dma_index, int n)
396 {
397         struct dt282x_private *devpriv = dev->private;
398         int dma_chan;
399         unsigned long dma_ptr;
400         unsigned long flags;
401
402         if (!devpriv->ntrig)
403                 return 0;
404
405         if (n == 0)
406                 n = devpriv->dma_maxsize;
407         if (n > devpriv->ntrig * 2)
408                 n = devpriv->ntrig * 2;
409         devpriv->ntrig -= n / 2;
410
411         devpriv->dma[dma_index].size = n;
412         dma_chan = devpriv->dma[dma_index].chan;
413         dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
414
415         set_dma_mode(dma_chan, DMA_MODE_READ);
416         flags = claim_dma_lock();
417         clear_dma_ff(dma_chan);
418         set_dma_addr(dma_chan, dma_ptr);
419         set_dma_count(dma_chan, n);
420         release_dma_lock(flags);
421
422         enable_dma(dma_chan);
423
424         return n;
425 }
426
427 static int prep_ao_dma(struct comedi_device *dev, int dma_index, int n)
428 {
429         struct dt282x_private *devpriv = dev->private;
430         int dma_chan;
431         unsigned long dma_ptr;
432         unsigned long flags;
433
434         devpriv->dma[dma_index].size = n;
435         dma_chan = devpriv->dma[dma_index].chan;
436         dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
437
438         set_dma_mode(dma_chan, DMA_MODE_WRITE);
439         flags = claim_dma_lock();
440         clear_dma_ff(dma_chan);
441         set_dma_addr(dma_chan, dma_ptr);
442         set_dma_count(dma_chan, n);
443         release_dma_lock(flags);
444
445         enable_dma(dma_chan);
446
447         return n;
448 }
449
450 static irqreturn_t dt282x_interrupt(int irq, void *d)
451 {
452         struct comedi_device *dev = d;
453         struct dt282x_private *devpriv = dev->private;
454         struct comedi_subdevice *s;
455         struct comedi_subdevice *s_ao;
456         unsigned int supcsr, adcsr, dacsr;
457         int handled = 0;
458
459         if (!dev->attached) {
460                 comedi_error(dev, "spurious interrupt");
461                 return IRQ_HANDLED;
462         }
463
464         s = &dev->subdevices[0];
465         s_ao = &dev->subdevices[1];
466         adcsr = inw(dev->iobase + DT2821_ADCSR);
467         dacsr = inw(dev->iobase + DT2821_DACSR);
468         supcsr = inw(dev->iobase + DT2821_SUPCSR);
469         if (supcsr & DT2821_DMAD) {
470                 if (devpriv->dma_dir == DMA_MODE_READ)
471                         dt282x_ai_dma_interrupt(dev);
472                 else
473                         dt282x_ao_dma_interrupt(dev);
474                 handled = 1;
475         }
476         if (adcsr & DT2821_ADERR) {
477                 if (devpriv->nread != 0) {
478                         comedi_error(dev, "A/D error");
479                         dt282x_ai_cancel(dev, s);
480                         s->async->events |= COMEDI_CB_ERROR;
481                 }
482                 handled = 1;
483         }
484         if (dacsr & DT2821_DAERR) {
485 #if 0
486                 static int warn = 5;
487                 if (--warn <= 0) {
488                         disable_irq(dev->irq);
489                         printk(KERN_INFO "disabling irq\n");
490                 }
491 #endif
492                 comedi_error(dev, "D/A error");
493                 dt282x_ao_cancel(dev, s_ao);
494                 s->async->events |= COMEDI_CB_ERROR;
495                 handled = 1;
496         }
497 #if 0
498         if (adcsr & DT2821_ADDONE) {
499                 int ret;
500                 short data;
501
502                 data = (short)inw(dev->iobase + DT2821_ADDAT);
503                 data &= (1 << board->adbits) - 1;
504
505                 if (devpriv->ad_2scomp)
506                         data ^= 1 << (board->adbits - 1);
507                 ret = comedi_buf_put(s->async, data);
508
509                 if (ret == 0)
510                         s->async->events |= COMEDI_CB_OVERFLOW;
511
512                 devpriv->nread--;
513                 if (!devpriv->nread) {
514                         s->async->events |= COMEDI_CB_EOA;
515                 } else {
516                         if (supcsr & DT2821_SCDN)
517                                 outw(devpriv->supcsr | DT2821_STRIG,
518                                         dev->iobase + DT2821_SUPCSR);
519                 }
520                 handled = 1;
521         }
522 #endif
523         comedi_event(dev, s);
524         /* printk("adcsr=0x%02x dacsr-0x%02x supcsr=0x%02x\n",
525                 adcsr, dacsr, supcsr); */
526         return IRQ_RETVAL(handled);
527 }
528
529 static void dt282x_load_changain(struct comedi_device *dev, int n,
530                                  unsigned int *chanlist)
531 {
532         struct dt282x_private *devpriv = dev->private;
533         unsigned int i;
534         unsigned int chan, range;
535
536         outw(DT2821_LLE | (n - 1), dev->iobase + DT2821_CHANCSR);
537         for (i = 0; i < n; i++) {
538                 chan = CR_CHAN(chanlist[i]);
539                 range = CR_RANGE(chanlist[i]);
540                 outw(devpriv->adcsr | (range << 4) | chan,
541                         dev->iobase + DT2821_ADCSR);
542         }
543         outw(n - 1, dev->iobase + DT2821_CHANCSR);
544 }
545
546 /*
547  *    Performs a single A/D conversion.
548  *      - Put channel/gain into channel-gain list
549  *      - preload multiplexer
550  *      - trigger conversion and wait for it to finish
551  */
552 static int dt282x_ai_insn_read(struct comedi_device *dev,
553                                struct comedi_subdevice *s,
554                                struct comedi_insn *insn, unsigned int *data)
555 {
556         const struct dt282x_board *board = comedi_board(dev);
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 << board->adbits) - 1);
578                 if (devpriv->ad_2scomp)
579                         data[i] ^= (1 << (board->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         const struct dt282x_board *board = comedi_board(dev);
799         struct dt282x_private *devpriv = dev->private;
800         short d;
801         unsigned int chan;
802
803         chan = CR_CHAN(insn->chanspec);
804         d = data[0];
805         d &= (1 << board->dabits) - 1;
806         devpriv->ao[chan] = d;
807
808         devpriv->dacsr |= DT2821_SSEL;
809
810         if (chan) {
811                 /* select channel */
812                 devpriv->dacsr |= DT2821_YSEL;
813                 if (devpriv->da0_2scomp)
814                         d ^= (1 << (board->dabits - 1));
815         } else {
816                 devpriv->dacsr &= ~DT2821_YSEL;
817                 if (devpriv->da1_2scomp)
818                         d ^= (1 << (board->dabits - 1));
819         }
820
821         outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
822
823         outw(d, dev->iobase + DT2821_DADAT);
824
825         outw(devpriv->supcsr | DT2821_DACON, dev->iobase + DT2821_SUPCSR);
826
827         return 1;
828 }
829
830 static int dt282x_ao_cmdtest(struct comedi_device *dev,
831                              struct comedi_subdevice *s, struct comedi_cmd *cmd)
832 {
833         int err = 0;
834         int tmp;
835
836         /* Step 1 : check if triggers are trivially valid */
837
838         err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT);
839         err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
840         err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
841         err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
842         err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
843
844         if (err)
845                 return 1;
846
847         /* Step 2a : make sure trigger sources are unique */
848
849         err |= cfc_check_trigger_is_unique(cmd->stop_src);
850
851         /* Step 2b : and mutually compatible */
852
853         if (err)
854                 return 2;
855
856         /* Step 3: check if arguments are trivially valid */
857
858         err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
859         err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, 5000);
860         err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
861         err |= cfc_check_trigger_arg_max(&cmd->scan_end_arg, 2);
862
863         if (cmd->stop_src == TRIG_COUNT) {
864                 /* any count is allowed */
865         } else {        /* TRIG_NONE */
866                 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
867         }
868
869         if (err)
870                 return 3;
871
872         /* step 4: fix up any arguments */
873
874         tmp = cmd->scan_begin_arg;
875         dt282x_ns_to_timer(&cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK);
876         if (tmp != cmd->scan_begin_arg)
877                 err++;
878
879         if (err)
880                 return 4;
881
882         return 0;
883
884 }
885
886 static int dt282x_ao_inttrig(struct comedi_device *dev,
887                              struct comedi_subdevice *s, unsigned int x)
888 {
889         struct dt282x_private *devpriv = dev->private;
890         int size;
891
892         if (x != 0)
893                 return -EINVAL;
894
895         size = cfc_read_array_from_buffer(s, devpriv->dma[0].buf,
896                                           devpriv->dma_maxsize);
897         if (size == 0) {
898                 printk(KERN_ERR "dt282x: AO underrun\n");
899                 return -EPIPE;
900         }
901         prep_ao_dma(dev, 0, size);
902
903         size = cfc_read_array_from_buffer(s, devpriv->dma[1].buf,
904                                           devpriv->dma_maxsize);
905         if (size == 0) {
906                 printk(KERN_ERR "dt282x: AO underrun\n");
907                 return -EPIPE;
908         }
909         prep_ao_dma(dev, 1, size);
910
911         outw(devpriv->supcsr | DT2821_STRIG, dev->iobase + DT2821_SUPCSR);
912         s->async->inttrig = NULL;
913
914         return 1;
915 }
916
917 static int dt282x_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
918 {
919         struct dt282x_private *devpriv = dev->private;
920         int timer;
921         struct comedi_cmd *cmd = &s->async->cmd;
922
923         if (devpriv->usedma == 0) {
924                 comedi_error(dev,
925                              "driver requires 2 dma channels"
926                                                 " to execute command");
927                 return -EIO;
928         }
929
930         dt282x_disable_dma(dev);
931
932         devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS1 | DT2821_DDMA;
933         outw(devpriv->supcsr | DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_DACINIT,
934                 dev->iobase + DT2821_SUPCSR);
935
936         devpriv->ntrig = cmd->stop_arg * cmd->chanlist_len;
937         devpriv->nread = devpriv->ntrig;
938
939         devpriv->dma_dir = DMA_MODE_WRITE;
940         devpriv->current_dma_index = 0;
941
942         timer = dt282x_ns_to_timer(&cmd->scan_begin_arg, TRIG_ROUND_NEAREST);
943         outw(timer, dev->iobase + DT2821_TMRCTR);
944
945         devpriv->dacsr = DT2821_SSEL | DT2821_DACLK | DT2821_IDARDY;
946         outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
947
948         s->async->inttrig = dt282x_ao_inttrig;
949
950         return 0;
951 }
952
953 static int dt282x_ao_cancel(struct comedi_device *dev,
954                             struct comedi_subdevice *s)
955 {
956         struct dt282x_private *devpriv = dev->private;
957
958         dt282x_disable_dma(dev);
959
960         devpriv->dacsr = 0;
961         outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
962
963         devpriv->supcsr = 0;
964         outw(devpriv->supcsr | DT2821_DACINIT, dev->iobase + DT2821_SUPCSR);
965
966         return 0;
967 }
968
969 static int dt282x_dio_insn_bits(struct comedi_device *dev,
970                                 struct comedi_subdevice *s,
971                                 struct comedi_insn *insn, unsigned int *data)
972 {
973         if (data[0]) {
974                 s->state &= ~data[0];
975                 s->state |= (data[0] & data[1]);
976
977                 outw(s->state, dev->iobase + DT2821_DIODAT);
978         }
979         data[1] = inw(dev->iobase + DT2821_DIODAT);
980
981         return insn->n;
982 }
983
984 static int dt282x_dio_insn_config(struct comedi_device *dev,
985                                   struct comedi_subdevice *s,
986                                   struct comedi_insn *insn, unsigned int *data)
987 {
988         struct dt282x_private *devpriv = dev->private;
989         int mask;
990
991         mask = (CR_CHAN(insn->chanspec) < 8) ? 0x00ff : 0xff00;
992         if (data[0])
993                 s->io_bits |= mask;
994         else
995                 s->io_bits &= ~mask;
996
997         if (s->io_bits & 0x00ff)
998                 devpriv->dacsr |= DT2821_LBOE;
999         else
1000                 devpriv->dacsr &= ~DT2821_LBOE;
1001         if (s->io_bits & 0xff00)
1002                 devpriv->dacsr |= DT2821_HBOE;
1003         else
1004                 devpriv->dacsr &= ~DT2821_HBOE;
1005
1006         outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
1007
1008         return 1;
1009 }
1010
1011 static const struct comedi_lrange *const ai_range_table[] = {
1012         &range_dt282x_ai_lo_bipolar,
1013         &range_dt282x_ai_lo_unipolar,
1014         &range_dt282x_ai_5_bipolar,
1015         &range_dt282x_ai_5_unipolar
1016 };
1017
1018 static const struct comedi_lrange *const ai_range_pgl_table[] = {
1019         &range_dt282x_ai_hi_bipolar,
1020         &range_dt282x_ai_hi_unipolar
1021 };
1022
1023 static const struct comedi_lrange *opt_ai_range_lkup(int ispgl, int x)
1024 {
1025         if (ispgl) {
1026                 if (x < 0 || x >= 2)
1027                         x = 0;
1028                 return ai_range_pgl_table[x];
1029         } else {
1030                 if (x < 0 || x >= 4)
1031                         x = 0;
1032                 return ai_range_table[x];
1033         }
1034 }
1035
1036 static const struct comedi_lrange *const ao_range_table[] = {
1037         &range_bipolar10,
1038         &range_unipolar10,
1039         &range_bipolar5,
1040         &range_unipolar5,
1041         &range_bipolar2_5
1042 };
1043
1044 static const struct comedi_lrange *opt_ao_range_lkup(int x)
1045 {
1046         if (x < 0 || x >= 5)
1047                 x = 0;
1048         return ao_range_table[x];
1049 }
1050
1051 enum {  /* i/o base, irq, dma channels */
1052         opt_iobase = 0, opt_irq, opt_dma1, opt_dma2,
1053         opt_diff,               /* differential */
1054         opt_ai_twos, opt_ao0_twos, opt_ao1_twos,        /* twos comp */
1055         opt_ai_range, opt_ao0_range, opt_ao1_range,     /* range */
1056 };
1057
1058 static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2)
1059 {
1060         struct dt282x_private *devpriv = dev->private;
1061         int ret;
1062
1063         devpriv->usedma = 0;
1064
1065         if (!dma1 && !dma2) {
1066                 printk(KERN_ERR " (no dma)");
1067                 return 0;
1068         }
1069
1070         if (dma1 == dma2 || dma1 < 5 || dma2 < 5 || dma1 > 7 || dma2 > 7)
1071                 return -EINVAL;
1072
1073         if (dma2 < dma1) {
1074                 int i;
1075                 i = dma1;
1076                 dma1 = dma2;
1077                 dma2 = i;
1078         }
1079
1080         ret = request_dma(dma1, "dt282x A");
1081         if (ret)
1082                 return -EBUSY;
1083         devpriv->dma[0].chan = dma1;
1084
1085         ret = request_dma(dma2, "dt282x B");
1086         if (ret)
1087                 return -EBUSY;
1088         devpriv->dma[1].chan = dma2;
1089
1090         devpriv->dma_maxsize = PAGE_SIZE;
1091         devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
1092         devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
1093         if (!devpriv->dma[0].buf || !devpriv->dma[1].buf) {
1094                 printk(KERN_ERR " can't get DMA memory");
1095                 return -ENOMEM;
1096         }
1097
1098         printk(KERN_INFO " (dma=%d,%d)", dma1, dma2);
1099
1100         devpriv->usedma = 1;
1101
1102         return 0;
1103 }
1104
1105 /*
1106    options:
1107    0    i/o base
1108    1    irq
1109    2    dma1
1110    3    dma2
1111    4    0=single ended, 1=differential
1112    5    ai 0=straight binary, 1=2's comp
1113    6    ao0 0=straight binary, 1=2's comp
1114    7    ao1 0=straight binary, 1=2's comp
1115    8    ai 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V
1116    9    ao0 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1117    10   ao1 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1118  */
1119 static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1120 {
1121         const struct dt282x_board *board = comedi_board(dev);
1122         struct dt282x_private *devpriv;
1123         int i, irq;
1124         int ret;
1125         struct comedi_subdevice *s;
1126
1127         ret = comedi_request_region(dev, it->options[0], DT2821_SIZE);
1128         if (ret)
1129                 return ret;
1130
1131         outw(DT2821_BDINIT, dev->iobase + DT2821_SUPCSR);
1132         i = inw(dev->iobase + DT2821_ADCSR);
1133 #ifdef DEBUG
1134         printk(KERN_DEBUG " fingerprint=%x,%x,%x,%x,%x",
1135                inw(dev->iobase + DT2821_ADCSR),
1136                inw(dev->iobase + DT2821_CHANCSR),
1137                inw(dev->iobase + DT2821_DACSR),
1138                inw(dev->iobase + DT2821_SUPCSR),
1139                inw(dev->iobase + DT2821_TMRCTR));
1140 #endif
1141
1142         if (((inw(dev->iobase + DT2821_ADCSR) & DT2821_ADCSR_MASK)
1143              != DT2821_ADCSR_VAL) ||
1144             ((inw(dev->iobase + DT2821_CHANCSR) & DT2821_CHANCSR_MASK)
1145              != DT2821_CHANCSR_VAL) ||
1146             ((inw(dev->iobase + DT2821_DACSR) & DT2821_DACSR_MASK)
1147              != DT2821_DACSR_VAL) ||
1148             ((inw(dev->iobase + DT2821_SUPCSR) & DT2821_SUPCSR_MASK)
1149              != DT2821_SUPCSR_VAL) ||
1150             ((inw(dev->iobase + DT2821_TMRCTR) & DT2821_TMRCTR_MASK)
1151              != DT2821_TMRCTR_VAL)) {
1152                 printk(KERN_ERR " board not found");
1153                 return -EIO;
1154         }
1155         /* should do board test */
1156
1157         irq = it->options[opt_irq];
1158 #if 0
1159         if (irq < 0) {
1160                 unsigned long flags;
1161                 int irqs;
1162
1163                 save_flags(flags);
1164                 sti();
1165                 irqs = probe_irq_on();
1166
1167                 /* trigger interrupt */
1168
1169                 udelay(100);
1170
1171                 irq = probe_irq_off(irqs);
1172                 restore_flags(flags);
1173                 if (0 /* error */)
1174                         printk(KERN_ERR " error probing irq (bad)");
1175         }
1176 #endif
1177         if (irq > 0) {
1178                 printk(KERN_INFO " ( irq = %d )", irq);
1179                 ret = request_irq(irq, dt282x_interrupt, 0,
1180                                   dev->board_name, dev);
1181                 if (ret < 0) {
1182                         printk(KERN_ERR " failed to get irq\n");
1183                         return -EIO;
1184                 }
1185                 dev->irq = irq;
1186         } else if (irq == 0) {
1187                 printk(KERN_INFO " (no irq)");
1188         } else {
1189 #if 0
1190                 printk(KERN_INFO " (probe returned multiple irqs--bad)");
1191 #else
1192                 printk(KERN_INFO " (irq probe not implemented)");
1193 #endif
1194         }
1195
1196         devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
1197         if (!devpriv)
1198                 return -ENOMEM;
1199         dev->private = devpriv;
1200
1201         ret = dt282x_grab_dma(dev, it->options[opt_dma1],
1202                               it->options[opt_dma2]);
1203         if (ret < 0)
1204                 return ret;
1205
1206         ret = comedi_alloc_subdevices(dev, 3);
1207         if (ret)
1208                 return ret;
1209
1210         s = &dev->subdevices[0];
1211
1212         dev->read_subdev = s;
1213         /* ai subdevice */
1214         s->type = COMEDI_SUBD_AI;
1215         s->subdev_flags = SDF_READABLE | SDF_CMD_READ |
1216             ((it->options[opt_diff]) ? SDF_DIFF : SDF_COMMON);
1217         s->n_chan =
1218             (it->options[opt_diff]) ? board->adchan_di : board->adchan_se;
1219         s->insn_read = dt282x_ai_insn_read;
1220         s->do_cmdtest = dt282x_ai_cmdtest;
1221         s->do_cmd = dt282x_ai_cmd;
1222         s->cancel = dt282x_ai_cancel;
1223         s->maxdata = (1 << board->adbits) - 1;
1224         s->len_chanlist = 16;
1225         s->range_table =
1226             opt_ai_range_lkup(board->ispgl, it->options[opt_ai_range]);
1227         devpriv->ad_2scomp = it->options[opt_ai_twos];
1228
1229         s = &dev->subdevices[1];
1230
1231         s->n_chan = board->dachan;
1232         if (s->n_chan) {
1233                 /* ao subsystem */
1234                 s->type = COMEDI_SUBD_AO;
1235                 dev->write_subdev = s;
1236                 s->subdev_flags = SDF_WRITABLE | SDF_CMD_WRITE;
1237                 s->insn_read = dt282x_ao_insn_read;
1238                 s->insn_write = dt282x_ao_insn_write;
1239                 s->do_cmdtest = dt282x_ao_cmdtest;
1240                 s->do_cmd = dt282x_ao_cmd;
1241                 s->cancel = dt282x_ao_cancel;
1242                 s->maxdata = (1 << board->dabits) - 1;
1243                 s->len_chanlist = 2;
1244                 s->range_table_list = devpriv->darangelist;
1245                 devpriv->darangelist[0] =
1246                     opt_ao_range_lkup(it->options[opt_ao0_range]);
1247                 devpriv->darangelist[1] =
1248                     opt_ao_range_lkup(it->options[opt_ao1_range]);
1249                 devpriv->da0_2scomp = it->options[opt_ao0_twos];
1250                 devpriv->da1_2scomp = it->options[opt_ao1_twos];
1251         } else {
1252                 s->type = COMEDI_SUBD_UNUSED;
1253         }
1254
1255         s = &dev->subdevices[2];
1256         /* dio subsystem */
1257         s->type = COMEDI_SUBD_DIO;
1258         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1259         s->n_chan = 16;
1260         s->insn_bits = dt282x_dio_insn_bits;
1261         s->insn_config = dt282x_dio_insn_config;
1262         s->maxdata = 1;
1263         s->range_table = &range_digital;
1264
1265         printk(KERN_INFO "\n");
1266
1267         return 0;
1268 }
1269
1270 static void dt282x_detach(struct comedi_device *dev)
1271 {
1272         struct dt282x_private *devpriv = dev->private;
1273
1274         if (dev->private) {
1275                 if (devpriv->dma[0].chan)
1276                         free_dma(devpriv->dma[0].chan);
1277                 if (devpriv->dma[1].chan)
1278                         free_dma(devpriv->dma[1].chan);
1279                 if (devpriv->dma[0].buf)
1280                         free_page((unsigned long)devpriv->dma[0].buf);
1281                 if (devpriv->dma[1].buf)
1282                         free_page((unsigned long)devpriv->dma[1].buf);
1283         }
1284         comedi_legacy_detach(dev);
1285 }
1286
1287 static const struct dt282x_board boardtypes[] = {
1288         {
1289                 .name           = "dt2821",
1290                 .adbits         = 12,
1291                 .adchan_se      = 16,
1292                 .adchan_di      = 8,
1293                 .ai_speed       = 20000,
1294                 .ispgl          = 0,
1295                 .dachan         = 2,
1296                 .dabits         = 12,
1297         }, {
1298                 .name           = "dt2821-f",
1299                 .adbits         = 12,
1300                 .adchan_se      = 16,
1301                 .adchan_di      = 8,
1302                 .ai_speed       = 6500,
1303                 .ispgl          = 0,
1304                 .dachan         = 2,
1305                 .dabits         = 12,
1306         }, {
1307                 .name           = "dt2821-g",
1308                 .adbits         = 12,
1309                 .adchan_se      = 16,
1310                 .adchan_di      = 8,
1311                 .ai_speed       = 4000,
1312                 .ispgl          = 0,
1313                 .dachan         = 2,
1314                 .dabits         = 12,
1315         }, {
1316                 .name           = "dt2823",
1317                 .adbits         = 16,
1318                 .adchan_se      = 0,
1319                 .adchan_di      = 4,
1320                 .ai_speed       = 10000,
1321                 .ispgl          = 0,
1322                 .dachan         = 2,
1323                 .dabits         = 16,
1324         }, {
1325                 .name           = "dt2824-pgh",
1326                 .adbits         = 12,
1327                 .adchan_se      = 16,
1328                 .adchan_di      = 8,
1329                 .ai_speed       = 20000,
1330                 .ispgl          = 0,
1331                 .dachan         = 0,
1332                 .dabits         = 0,
1333         }, {
1334                 .name           = "dt2824-pgl",
1335                 .adbits         = 12,
1336                 .adchan_se      = 16,
1337                 .adchan_di      = 8,
1338                 .ai_speed       = 20000,
1339                 .ispgl          = 1,
1340                 .dachan         = 0,
1341                 .dabits         = 0,
1342         }, {
1343                 .name           = "dt2825",
1344                 .adbits         = 12,
1345                 .adchan_se      = 16,
1346                 .adchan_di      = 8,
1347                 .ai_speed       = 20000,
1348                 .ispgl          = 1,
1349                 .dachan         = 2,
1350                 .dabits         = 12,
1351         }, {
1352                 .name           = "dt2827",
1353                 .adbits         = 16,
1354                 .adchan_se      = 0,
1355                 .adchan_di      = 4,
1356                 .ai_speed       = 10000,
1357                 .ispgl          = 0,
1358                 .dachan         = 2,
1359                 .dabits         = 12,
1360         }, {
1361                 .name           = "dt2828",
1362                 .adbits         = 12,
1363                 .adchan_se      = 4,
1364                 .adchan_di      = 0,
1365                 .ai_speed       = 10000,
1366                 .ispgl          = 0,
1367                 .dachan         = 2,
1368                 .dabits         = 12,
1369         }, {
1370                 .name           = "dt2829",
1371                 .adbits         = 16,
1372                 .adchan_se      = 8,
1373                 .adchan_di      = 0,
1374                 .ai_speed       = 33250,
1375                 .ispgl          = 0,
1376                 .dachan         = 2,
1377                 .dabits         = 16,
1378         }, {
1379                 .name           = "dt21-ez",
1380                 .adbits         = 12,
1381                 .adchan_se      = 16,
1382                 .adchan_di      = 8,
1383                 .ai_speed       = 10000,
1384                 .ispgl          = 0,
1385                 .dachan         = 2,
1386                 .dabits         = 12,
1387         }, {
1388                 .name           = "dt23-ez",
1389                 .adbits         = 16,
1390                 .adchan_se      = 16,
1391                 .adchan_di      = 8,
1392                 .ai_speed       = 10000,
1393                 .ispgl          = 0,
1394                 .dachan         = 0,
1395                 .dabits         = 0,
1396         }, {
1397                 .name           = "dt24-ez",
1398                 .adbits         = 12,
1399                 .adchan_se      = 16,
1400                 .adchan_di      = 8,
1401                 .ai_speed       = 10000,
1402                 .ispgl          = 0,
1403                 .dachan         = 0,
1404                 .dabits         = 0,
1405         }, {
1406                 .name           = "dt24-ez-pgl",
1407                 .adbits         = 12,
1408                 .adchan_se      = 16,
1409                 .adchan_di      = 8,
1410                 .ai_speed       = 10000,
1411                 .ispgl          = 1,
1412                 .dachan         = 0,
1413                 .dabits         = 0,
1414         },
1415 };
1416
1417 static struct comedi_driver dt282x_driver = {
1418         .driver_name    = "dt282x",
1419         .module         = THIS_MODULE,
1420         .attach         = dt282x_attach,
1421         .detach         = dt282x_detach,
1422         .board_name     = &boardtypes[0].name,
1423         .num_names      = ARRAY_SIZE(boardtypes),
1424         .offset         = sizeof(struct dt282x_board),
1425 };
1426 module_comedi_driver(dt282x_driver);
1427
1428 MODULE_AUTHOR("Comedi http://www.comedi.org");
1429 MODULE_DESCRIPTION("Comedi low-level driver");
1430 MODULE_LICENSE("GPL");