Merge branch 'for-linus' of git://github.com/schandinat/linux-2.6
[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 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");