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