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