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