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