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