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