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