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