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