Merge branch 'next/drivers' into HEAD
[deliverable/linux.git] / drivers / staging / comedi / drivers / dt282x.c
CommitLineData
8d3d823c
DS
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/*
24Driver: dt282x
25Description: Data Translation DT2821 series (including DT-EZ)
26Author: ds
27Devices: [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)
34Status: complete
35Updated: Wed, 22 Aug 2001 17:11:34 -0700
36
37Configuration 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],
18e7e78e 48 4=[-2.5,2.5]
8d3d823c 49 [10]- A0 1 jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5],
18e7e78e 50 4=[-2.5,2.5]
8d3d823c
DS
51
52Notes:
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
5a0e3ad6 61#include <linux/gfp.h>
8d3d823c
DS
62#include <linux/ioport.h>
63#include <linux/interrupt.h>
845d131e 64#include <linux/io.h>
8d3d823c
DS
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
18e7e78e
IC
159static 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 }
8d3d823c 166};
0a85b6f0 167
18e7e78e
IC
168static 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 }
8d3d823c 175};
0a85b6f0 176
18e7e78e
IC
177static 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 }
8d3d823c 184};
0a85b6f0 185
18e7e78e
IC
186static 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 }
8d3d823c 193};
0a85b6f0 194
18e7e78e
IC
195static 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 }
8d3d823c 202};
0a85b6f0 203
18e7e78e
IC
204static 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 }
8d3d823c
DS
211};
212
98484c1a 213struct dt282x_board {
8d3d823c
DS
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;
98484c1a 222};
8d3d823c 223
68b08cda 224struct dt282x_private {
8d3d823c
DS
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
9ced1de6 229 const struct comedi_lrange *darangelist[2];
8d3d823c 230
790c5541 231 short ao[2];
8d3d823c
DS
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;
68b08cda 249};
8d3d823c 250
68b08cda 251#define devpriv ((struct dt282x_private *)dev->private)
98484c1a 252#define boardtype (*(const struct dt282x_board *)dev->board_ptr)
8d3d823c
DS
253
254/*
255 * Some useless abstractions
256 */
257#define chan_to_DAC(a) ((a)&1)
8d3d823c
DS
258#define mux_busy() (inw(dev->iobase+DT2821_ADCSR)&DT2821_MUXBUSY)
259#define ad_done() (inw(dev->iobase+DT2821_ADCSR)&DT2821_ADDONE)
8d3d823c
DS
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 */
18e7e78e
IC
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)
8d3d823c 278
da91b269
BP
279static int prep_ai_dma(struct comedi_device *dev, int chan, int size);
280static int prep_ao_dma(struct comedi_device *dev, int chan, int size);
0a85b6f0
MT
281static int dt282x_ai_cancel(struct comedi_device *dev,
282 struct comedi_subdevice *s);
283static int dt282x_ao_cancel(struct comedi_device *dev,
284 struct comedi_subdevice *s);
8d3d823c 285static int dt282x_ns_to_timer(int *nanosec, int round_mode);
da91b269 286static void dt282x_disable_dma(struct comedi_device *dev);
8d3d823c 287
da91b269 288static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2);
8d3d823c 289
da91b269 290static void dt282x_munge(struct comedi_device *dev, short *buf,
0a85b6f0 291 unsigned int nbytes)
8d3d823c
DS
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
18e7e78e 298 if (devpriv->ad_2scomp)
8d3d823c 299 sign = 1 << (boardtype.adbits - 1);
18e7e78e 300 else
8d3d823c 301 sign = 0;
8d3d823c
DS
302
303 if (nbytes % 2)
304 comedi_error(dev, "bug! odd number of bytes from dma xfer");
305 n = nbytes / 2;
18e7e78e 306 for (i = 0; i < n; i++)
8d3d823c 307 buf[i] = (buf[i] & mask) ^ sign;
8d3d823c
DS
308}
309
da91b269 310static void dt282x_ao_dma_interrupt(struct comedi_device *dev)
8d3d823c
DS
311{
312 void *ptr;
313 int size;
314 int i;
e1d7cf9c 315 struct comedi_subdevice *s = &dev->subdevices[1];
8d3d823c 316
d254eb74 317 outw(devpriv->supcsr | DT2821_CLRDMADNE, dev->iobase + DT2821_SUPCSR);
8d3d823c
DS
318
319 if (!s->async->prealloc_buf) {
18e7e78e 320 printk(KERN_ERR "async->data disappeared. dang!\n");
8d3d823c
DS
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) {
18e7e78e 333 printk(KERN_ERR "dt282x: AO underrun\n");
8d3d823c
DS
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
da91b269 342static void dt282x_ai_dma_interrupt(struct comedi_device *dev)
8d3d823c
DS
343{
344 void *ptr;
345 int size;
346 int i;
347 int ret;
e1d7cf9c 348 struct comedi_subdevice *s = &dev->subdevices[0];
8d3d823c 349
d254eb74 350 outw(devpriv->supcsr | DT2821_CLRDMADNE, dev->iobase + DT2821_SUPCSR);
8d3d823c
DS
351
352 if (!s->async->prealloc_buf) {
18e7e78e 353 printk(KERN_ERR "async->data disappeared. dang!\n");
8d3d823c
DS
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) {
18e7e78e 374 printk(KERN_INFO "dt282x: off by one\n");
8d3d823c
DS
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);
d254eb74 387 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR);
8d3d823c
DS
388 }
389#endif
390 /* restart the channel */
391 prep_ai_dma(dev, i, 0);
392}
393
da91b269 394static int prep_ai_dma(struct comedi_device *dev, int dma_index, int n)
8d3d823c
DS
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
da91b269 425static int prep_ao_dma(struct comedi_device *dev, int dma_index, int n)
8d3d823c
DS
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
70265d24 447static irqreturn_t dt282x_interrupt(int irq, void *d)
8d3d823c 448{
71b5f4f1 449 struct comedi_device *dev = d;
34c43922
BP
450 struct comedi_subdevice *s;
451 struct comedi_subdevice *s_ao;
8d3d823c
DS
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
e1d7cf9c
HS
460 s = &dev->subdevices[0];
461 s_ao = &dev->subdevices[1];
8d3d823c
DS
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);
18e7e78e 485 printk(KERN_INFO "disabling irq\n");
8d3d823c
DS
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;
790c5541 496 short data;
8d3d823c 497
0a85b6f0 498 data = (short)inw(dev->iobase + DT2821_ADDAT);
8d3d823c 499 data &= (1 << boardtype.adbits) - 1;
18e7e78e
IC
500
501 if (devpriv->ad_2scomp)
8d3d823c 502 data ^= 1 << (boardtype.adbits - 1);
8d3d823c 503 ret = comedi_buf_put(s->async, data);
18e7e78e
IC
504
505 if (ret == 0)
8d3d823c 506 s->async->events |= COMEDI_CB_OVERFLOW;
8d3d823c
DS
507
508 devpriv->nread--;
509 if (!devpriv->nread) {
510 s->async->events |= COMEDI_CB_EOA;
511 } else {
512 if (supcsr & DT2821_SCDN)
d254eb74
HS
513 outw(devpriv->supcsr | DT2821_STRIG,
514 dev->iobase + DT2821_SUPCSR);
8d3d823c
DS
515 }
516 handled = 1;
517 }
518#endif
519 comedi_event(dev, s);
18e7e78e
IC
520 /* printk("adcsr=0x%02x dacsr-0x%02x supcsr=0x%02x\n",
521 adcsr, dacsr, supcsr); */
8d3d823c
DS
522 return IRQ_RETVAL(handled);
523}
524
da91b269 525static void dt282x_load_changain(struct comedi_device *dev, int n,
0a85b6f0 526 unsigned int *chanlist)
8d3d823c
DS
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]);
d254eb74
HS
535 outw(devpriv->adcsr | (range << 4) | chan,
536 dev->iobase + DT2821_ADCSR);
8d3d823c
DS
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 */
0a85b6f0
MT
547static int dt282x_ai_insn_read(struct comedi_device *dev,
548 struct comedi_subdevice *s,
549 struct comedi_insn *insn, unsigned int *data)
8d3d823c
DS
550{
551 int i;
552
553 /* XXX should we really be enabling the ad clock here? */
554 devpriv->adcsr = DT2821_ADCLK;
d254eb74 555 outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR);
8d3d823c
DS
556
557 dt282x_load_changain(dev, 1, &insn->chanspec);
558
d254eb74 559 outw(devpriv->supcsr | DT2821_PRLD, dev->iobase + DT2821_SUPCSR);
0a85b6f0 560 wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;);
8d3d823c
DS
561
562 for (i = 0; i < insn->n; i++) {
d254eb74
HS
563 outw(devpriv->supcsr | DT2821_STRIG,
564 dev->iobase + DT2821_SUPCSR);
8d3d823c 565 wait_for(ad_done(), comedi_error(dev, "timeout\n");
0a85b6f0 566 return -ETIME;);
8d3d823c
DS
567
568 data[i] =
0a85b6f0 569 inw(dev->iobase +
8d3d823c
DS
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
0a85b6f0
MT
578static int dt282x_ai_cmdtest(struct comedi_device *dev,
579 struct comedi_subdevice *s, struct comedi_cmd *cmd)
8d3d823c 580{
06131969 581 const struct dt282x_board *board = comedi_board(dev);
8d3d823c
DS
582 int err = 0;
583 int tmp;
584
27020ffe 585 /* Step 1 : check if triggers are trivially valid */
8d3d823c 586
27020ffe
HS
587 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
588 err |= cfc_check_trigger_src(&cmd->scan_begin_src,
589 TRIG_FOLLOW | TRIG_EXT);
590 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
591 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
592 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
8d3d823c
DS
593
594 if (err)
595 return 1;
596
27020ffe 597 /* Step 2a : make sure trigger sources are unique */
8d3d823c 598
27020ffe
HS
599 err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
600 err |= cfc_check_trigger_is_unique(cmd->stop_src);
601
602 /* Step 2b : and mutually compatible */
8d3d823c
DS
603
604 if (err)
605 return 2;
606
607 /* step 3: make sure arguments are trivially compatible */
608
609 if (cmd->start_arg != 0) {
610 cmd->start_arg = 0;
611 err++;
612 }
613 if (cmd->scan_begin_src == TRIG_FOLLOW) {
614 /* internal trigger */
615 if (cmd->scan_begin_arg != 0) {
616 cmd->scan_begin_arg = 0;
617 err++;
618 }
619 } else {
620 /* external trigger */
621 /* should be level/edge, hi/lo specification here */
622 if (cmd->scan_begin_arg != 0) {
623 cmd->scan_begin_arg = 0;
624 err++;
625 }
626 }
627 if (cmd->convert_arg < 4000) {
628 /* XXX board dependent */
629 cmd->convert_arg = 4000;
630 err++;
631 }
632#define SLOWEST_TIMER (250*(1<<15)*255)
633 if (cmd->convert_arg > SLOWEST_TIMER) {
634 cmd->convert_arg = SLOWEST_TIMER;
635 err++;
636 }
06131969
HS
637 if (cmd->convert_arg < board->ai_speed) {
638 cmd->convert_arg = board->ai_speed;
8d3d823c
DS
639 err++;
640 }
641 if (cmd->scan_end_arg != cmd->chanlist_len) {
642 cmd->scan_end_arg = cmd->chanlist_len;
643 err++;
644 }
645 if (cmd->stop_src == TRIG_COUNT) {
646 /* any count is allowed */
647 } else {
648 /* TRIG_NONE */
649 if (cmd->stop_arg != 0) {
650 cmd->stop_arg = 0;
651 err++;
652 }
653 }
654
655 if (err)
656 return 3;
657
658 /* step 4: fix up any arguments */
659
660 tmp = cmd->convert_arg;
661 dt282x_ns_to_timer(&cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK);
662 if (tmp != cmd->convert_arg)
663 err++;
664
665 if (err)
666 return 4;
667
668 return 0;
669}
670
da91b269 671static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
8d3d823c 672{
06131969 673 const struct dt282x_board *board = comedi_board(dev);
ea6d0d4c 674 struct comedi_cmd *cmd = &s->async->cmd;
8d3d823c
DS
675 int timer;
676
677 if (devpriv->usedma == 0) {
678 comedi_error(dev,
18e7e78e
IC
679 "driver requires 2 dma channels"
680 " to execute command");
8d3d823c
DS
681 return -EIO;
682 }
683
684 dt282x_disable_dma(dev);
685
06131969
HS
686 if (cmd->convert_arg < board->ai_speed)
687 cmd->convert_arg = board->ai_speed;
8d3d823c
DS
688 timer = dt282x_ns_to_timer(&cmd->convert_arg, TRIG_ROUND_NEAREST);
689 outw(timer, dev->iobase + DT2821_TMRCTR);
690
691 if (cmd->scan_begin_src == TRIG_FOLLOW) {
692 /* internal trigger */
693 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0;
694 } else {
695 /* external trigger */
696 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0 | DT2821_DS1;
697 }
d254eb74
HS
698 outw(devpriv->supcsr | DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_ADCINIT,
699 dev->iobase + DT2821_SUPCSR);
8d3d823c
DS
700
701 devpriv->ntrig = cmd->stop_arg * cmd->scan_end_arg;
702 devpriv->nread = devpriv->ntrig;
703
704 devpriv->dma_dir = DMA_MODE_READ;
705 devpriv->current_dma_index = 0;
706 prep_ai_dma(dev, 0, 0);
707 if (devpriv->ntrig) {
708 prep_ai_dma(dev, 1, 0);
709 devpriv->supcsr |= DT2821_DDMA;
d254eb74 710 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR);
8d3d823c
DS
711 }
712
713 devpriv->adcsr = 0;
714
715 dt282x_load_changain(dev, cmd->chanlist_len, cmd->chanlist);
716
717 devpriv->adcsr = DT2821_ADCLK | DT2821_IADDONE;
d254eb74 718 outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR);
8d3d823c 719
d254eb74 720 outw(devpriv->supcsr | DT2821_PRLD, dev->iobase + DT2821_SUPCSR);
0a85b6f0 721 wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;);
8d3d823c
DS
722
723 if (cmd->scan_begin_src == TRIG_FOLLOW) {
d254eb74
HS
724 outw(devpriv->supcsr | DT2821_STRIG,
725 dev->iobase + DT2821_SUPCSR);
8d3d823c
DS
726 } else {
727 devpriv->supcsr |= DT2821_XTRIG;
d254eb74 728 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR);
8d3d823c
DS
729 }
730
731 return 0;
732}
733
da91b269 734static void dt282x_disable_dma(struct comedi_device *dev)
8d3d823c
DS
735{
736 if (devpriv->usedma) {
737 disable_dma(devpriv->dma[0].chan);
738 disable_dma(devpriv->dma[1].chan);
739 }
740}
741
0a85b6f0
MT
742static int dt282x_ai_cancel(struct comedi_device *dev,
743 struct comedi_subdevice *s)
8d3d823c
DS
744{
745 dt282x_disable_dma(dev);
746
747 devpriv->adcsr = 0;
d254eb74 748 outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR);
8d3d823c
DS
749
750 devpriv->supcsr = 0;
d254eb74 751 outw(devpriv->supcsr | DT2821_ADCINIT, dev->iobase + DT2821_SUPCSR);
8d3d823c
DS
752
753 return 0;
754}
755
756static int dt282x_ns_to_timer(int *nanosec, int round_mode)
757{
758 int prescale, base, divider;
759
760 for (prescale = 0; prescale < 16; prescale++) {
761 if (prescale == 1)
762 continue;
763 base = 250 * (1 << prescale);
764 switch (round_mode) {
765 case TRIG_ROUND_NEAREST:
766 default:
767 divider = (*nanosec + base / 2) / base;
768 break;
769 case TRIG_ROUND_DOWN:
770 divider = (*nanosec) / base;
771 break;
772 case TRIG_ROUND_UP:
773 divider = (*nanosec + base - 1) / base;
774 break;
775 }
776 if (divider < 256) {
777 *nanosec = divider * base;
778 return (prescale << 8) | (255 - divider);
779 }
780 }
781 base = 250 * (1 << 15);
782 divider = 255;
783 *nanosec = divider * base;
784 return (15 << 8) | (255 - divider);
785}
786
787/*
788 * Analog output routine. Selects single channel conversion,
789 * selects correct channel, converts from 2's compliment to
790 * offset binary if necessary, loads the data into the DAC
791 * data register, and performs the conversion.
792 */
0a85b6f0
MT
793static int dt282x_ao_insn_read(struct comedi_device *dev,
794 struct comedi_subdevice *s,
795 struct comedi_insn *insn, unsigned int *data)
8d3d823c
DS
796{
797 data[0] = devpriv->ao[CR_CHAN(insn->chanspec)];
798
799 return 1;
800}
801
0a85b6f0
MT
802static int dt282x_ao_insn_write(struct comedi_device *dev,
803 struct comedi_subdevice *s,
804 struct comedi_insn *insn, unsigned int *data)
8d3d823c 805{
790c5541 806 short d;
8d3d823c
DS
807 unsigned int chan;
808
809 chan = CR_CHAN(insn->chanspec);
810 d = data[0];
811 d &= (1 << boardtype.dabits) - 1;
812 devpriv->ao[chan] = d;
813
814 devpriv->dacsr |= DT2821_SSEL;
815
816 if (chan) {
817 /* select channel */
818 devpriv->dacsr |= DT2821_YSEL;
819 if (devpriv->da0_2scomp)
820 d ^= (1 << (boardtype.dabits - 1));
821 } else {
822 devpriv->dacsr &= ~DT2821_YSEL;
823 if (devpriv->da1_2scomp)
824 d ^= (1 << (boardtype.dabits - 1));
825 }
826
d254eb74 827 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
8d3d823c
DS
828
829 outw(d, dev->iobase + DT2821_DADAT);
830
d254eb74 831 outw(devpriv->supcsr | DT2821_DACON, dev->iobase + DT2821_SUPCSR);
8d3d823c
DS
832
833 return 1;
834}
835
0a85b6f0
MT
836static int dt282x_ao_cmdtest(struct comedi_device *dev,
837 struct comedi_subdevice *s, struct comedi_cmd *cmd)
8d3d823c
DS
838{
839 int err = 0;
840 int tmp;
841
27020ffe 842 /* Step 1 : check if triggers are trivially valid */
8d3d823c 843
27020ffe
HS
844 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT);
845 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
846 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
847 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
848 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
8d3d823c
DS
849
850 if (err)
851 return 1;
852
27020ffe 853 /* Step 2a : make sure trigger sources are unique */
8d3d823c 854
27020ffe
HS
855 err |= cfc_check_trigger_is_unique(cmd->stop_src);
856
857 /* Step 2b : and mutually compatible */
8d3d823c
DS
858
859 if (err)
860 return 2;
861
862 /* step 3: make sure arguments are trivially compatible */
863
864 if (cmd->start_arg != 0) {
865 cmd->start_arg = 0;
866 err++;
867 }
18e7e78e 868 if (cmd->scan_begin_arg < 5000 /* XXX unknown */) {
8d3d823c
DS
869 cmd->scan_begin_arg = 5000;
870 err++;
871 }
872 if (cmd->convert_arg != 0) {
873 cmd->convert_arg = 0;
874 err++;
875 }
876 if (cmd->scan_end_arg > 2) {
877 /* XXX chanlist stuff? */
878 cmd->scan_end_arg = 2;
879 err++;
880 }
881 if (cmd->stop_src == TRIG_COUNT) {
882 /* any count is allowed */
883 } else {
884 /* TRIG_NONE */
885 if (cmd->stop_arg != 0) {
886 cmd->stop_arg = 0;
887 err++;
888 }
889 }
890
891 if (err)
892 return 3;
893
894 /* step 4: fix up any arguments */
895
896 tmp = cmd->scan_begin_arg;
897 dt282x_ns_to_timer(&cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK);
898 if (tmp != cmd->scan_begin_arg)
899 err++;
900
901 if (err)
902 return 4;
903
904 return 0;
905
906}
907
0a85b6f0
MT
908static int dt282x_ao_inttrig(struct comedi_device *dev,
909 struct comedi_subdevice *s, unsigned int x)
8d3d823c
DS
910{
911 int size;
912
913 if (x != 0)
914 return -EINVAL;
915
916 size = cfc_read_array_from_buffer(s, devpriv->dma[0].buf,
0a85b6f0 917 devpriv->dma_maxsize);
8d3d823c 918 if (size == 0) {
18e7e78e 919 printk(KERN_ERR "dt282x: AO underrun\n");
8d3d823c
DS
920 return -EPIPE;
921 }
922 prep_ao_dma(dev, 0, size);
923
924 size = cfc_read_array_from_buffer(s, devpriv->dma[1].buf,
0a85b6f0 925 devpriv->dma_maxsize);
8d3d823c 926 if (size == 0) {
18e7e78e 927 printk(KERN_ERR "dt282x: AO underrun\n");
8d3d823c
DS
928 return -EPIPE;
929 }
930 prep_ao_dma(dev, 1, size);
931
d254eb74 932 outw(devpriv->supcsr | DT2821_STRIG, dev->iobase + DT2821_SUPCSR);
8d3d823c
DS
933 s->async->inttrig = NULL;
934
935 return 1;
936}
937
da91b269 938static int dt282x_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
8d3d823c
DS
939{
940 int timer;
ea6d0d4c 941 struct comedi_cmd *cmd = &s->async->cmd;
8d3d823c
DS
942
943 if (devpriv->usedma == 0) {
944 comedi_error(dev,
18e7e78e
IC
945 "driver requires 2 dma channels"
946 " to execute command");
8d3d823c
DS
947 return -EIO;
948 }
949
950 dt282x_disable_dma(dev);
951
952 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS1 | DT2821_DDMA;
d254eb74
HS
953 outw(devpriv->supcsr | DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_DACINIT,
954 dev->iobase + DT2821_SUPCSR);
8d3d823c
DS
955
956 devpriv->ntrig = cmd->stop_arg * cmd->chanlist_len;
957 devpriv->nread = devpriv->ntrig;
958
959 devpriv->dma_dir = DMA_MODE_WRITE;
960 devpriv->current_dma_index = 0;
961
962 timer = dt282x_ns_to_timer(&cmd->scan_begin_arg, TRIG_ROUND_NEAREST);
963 outw(timer, dev->iobase + DT2821_TMRCTR);
964
965 devpriv->dacsr = DT2821_SSEL | DT2821_DACLK | DT2821_IDARDY;
d254eb74 966 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
8d3d823c
DS
967
968 s->async->inttrig = dt282x_ao_inttrig;
969
970 return 0;
971}
972
0a85b6f0
MT
973static int dt282x_ao_cancel(struct comedi_device *dev,
974 struct comedi_subdevice *s)
8d3d823c
DS
975{
976 dt282x_disable_dma(dev);
977
978 devpriv->dacsr = 0;
d254eb74 979 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
8d3d823c
DS
980
981 devpriv->supcsr = 0;
d254eb74 982 outw(devpriv->supcsr | DT2821_DACINIT, dev->iobase + DT2821_SUPCSR);
8d3d823c
DS
983
984 return 0;
985}
986
0a85b6f0
MT
987static int dt282x_dio_insn_bits(struct comedi_device *dev,
988 struct comedi_subdevice *s,
989 struct comedi_insn *insn, unsigned int *data)
8d3d823c
DS
990{
991 if (data[0]) {
992 s->state &= ~data[0];
993 s->state |= (data[0] & data[1]);
994
995 outw(s->state, dev->iobase + DT2821_DIODAT);
996 }
997 data[1] = inw(dev->iobase + DT2821_DIODAT);
998
a2714e3e 999 return insn->n;
8d3d823c
DS
1000}
1001
0a85b6f0
MT
1002static int dt282x_dio_insn_config(struct comedi_device *dev,
1003 struct comedi_subdevice *s,
1004 struct comedi_insn *insn, unsigned int *data)
8d3d823c
DS
1005{
1006 int mask;
1007
1008 mask = (CR_CHAN(insn->chanspec) < 8) ? 0x00ff : 0xff00;
1009 if (data[0])
1010 s->io_bits |= mask;
1011 else
1012 s->io_bits &= ~mask;
1013
1014 if (s->io_bits & 0x00ff)
1015 devpriv->dacsr |= DT2821_LBOE;
1016 else
1017 devpriv->dacsr &= ~DT2821_LBOE;
1018 if (s->io_bits & 0xff00)
1019 devpriv->dacsr |= DT2821_HBOE;
1020 else
1021 devpriv->dacsr &= ~DT2821_HBOE;
1022
1023 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
1024
1025 return 1;
1026}
1027
9ced1de6 1028static const struct comedi_lrange *const ai_range_table[] = {
8d3d823c
DS
1029 &range_dt282x_ai_lo_bipolar,
1030 &range_dt282x_ai_lo_unipolar,
1031 &range_dt282x_ai_5_bipolar,
1032 &range_dt282x_ai_5_unipolar
1033};
0a85b6f0 1034
9ced1de6 1035static const struct comedi_lrange *const ai_range_pgl_table[] = {
8d3d823c
DS
1036 &range_dt282x_ai_hi_bipolar,
1037 &range_dt282x_ai_hi_unipolar
1038};
0a85b6f0 1039
9ced1de6 1040static const struct comedi_lrange *opt_ai_range_lkup(int ispgl, int x)
8d3d823c
DS
1041{
1042 if (ispgl) {
1043 if (x < 0 || x >= 2)
1044 x = 0;
1045 return ai_range_pgl_table[x];
1046 } else {
1047 if (x < 0 || x >= 4)
1048 x = 0;
1049 return ai_range_table[x];
1050 }
1051}
0a85b6f0 1052
9ced1de6 1053static const struct comedi_lrange *const ao_range_table[] = {
8d3d823c
DS
1054 &range_bipolar10,
1055 &range_unipolar10,
1056 &range_bipolar5,
1057 &range_unipolar5,
1058 &range_bipolar2_5
1059};
0a85b6f0 1060
9ced1de6 1061static const struct comedi_lrange *opt_ao_range_lkup(int x)
8d3d823c
DS
1062{
1063 if (x < 0 || x >= 5)
1064 x = 0;
1065 return ao_range_table[x];
1066}
1067
18e7e78e
IC
1068enum { /* i/o base, irq, dma channels */
1069 opt_iobase = 0, opt_irq, opt_dma1, opt_dma2,
8d3d823c
DS
1070 opt_diff, /* differential */
1071 opt_ai_twos, opt_ao0_twos, opt_ao1_twos, /* twos comp */
1072 opt_ai_range, opt_ao0_range, opt_ao1_range, /* range */
1073};
1074
e0eaa10d
HS
1075static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2)
1076{
1077 int ret;
1078
1079 devpriv->usedma = 0;
1080
1081 if (!dma1 && !dma2) {
1082 printk(KERN_ERR " (no dma)");
1083 return 0;
1084 }
1085
1086 if (dma1 == dma2 || dma1 < 5 || dma2 < 5 || dma1 > 7 || dma2 > 7)
1087 return -EINVAL;
1088
1089 if (dma2 < dma1) {
1090 int i;
1091 i = dma1;
1092 dma1 = dma2;
1093 dma2 = i;
1094 }
1095
1096 ret = request_dma(dma1, "dt282x A");
1097 if (ret)
1098 return -EBUSY;
1099 devpriv->dma[0].chan = dma1;
1100
1101 ret = request_dma(dma2, "dt282x B");
1102 if (ret)
1103 return -EBUSY;
1104 devpriv->dma[1].chan = dma2;
1105
1106 devpriv->dma_maxsize = PAGE_SIZE;
1107 devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
1108 devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
1109 if (!devpriv->dma[0].buf || !devpriv->dma[1].buf) {
1110 printk(KERN_ERR " can't get DMA memory");
1111 return -ENOMEM;
1112 }
1113
1114 printk(KERN_INFO " (dma=%d,%d)", dma1, dma2);
1115
1116 devpriv->usedma = 1;
1117
1118 return 0;
1119}
1120
8d3d823c
DS
1121/*
1122 options:
1123 0 i/o base
1124 1 irq
1125 2 dma1
1126 3 dma2
1127 4 0=single ended, 1=differential
1128 5 ai 0=straight binary, 1=2's comp
1129 6 ao0 0=straight binary, 1=2's comp
1130 7 ao1 0=straight binary, 1=2's comp
1131 8 ai 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V
1132 9 ao0 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1133 10 ao1 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1134 */
da91b269 1135static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
8d3d823c 1136{
06131969 1137 const struct dt282x_board *board = comedi_board(dev);
8d3d823c
DS
1138 int i, irq;
1139 int ret;
34c43922 1140 struct comedi_subdevice *s;
8d3d823c
DS
1141 unsigned long iobase;
1142
06131969 1143 dev->board_name = board->name;
8d3d823c
DS
1144
1145 iobase = it->options[opt_iobase];
1146 if (!iobase)
1147 iobase = 0x240;
1148
18e7e78e 1149 printk(KERN_INFO "comedi%d: dt282x: 0x%04lx", dev->minor, iobase);
8d3d823c 1150 if (!request_region(iobase, DT2821_SIZE, "dt282x")) {
18e7e78e 1151 printk(KERN_INFO " I/O port conflict\n");
8d3d823c
DS
1152 return -EBUSY;
1153 }
1154 dev->iobase = iobase;
1155
1156 outw(DT2821_BDINIT, dev->iobase + DT2821_SUPCSR);
1157 i = inw(dev->iobase + DT2821_ADCSR);
1158#ifdef DEBUG
18e7e78e 1159 printk(KERN_DEBUG " fingerprint=%x,%x,%x,%x,%x",
0a85b6f0
MT
1160 inw(dev->iobase + DT2821_ADCSR),
1161 inw(dev->iobase + DT2821_CHANCSR),
1162 inw(dev->iobase + DT2821_DACSR),
1163 inw(dev->iobase + DT2821_SUPCSR),
1164 inw(dev->iobase + DT2821_TMRCTR));
8d3d823c
DS
1165#endif
1166
1167 if (((inw(dev->iobase + DT2821_ADCSR) & DT2821_ADCSR_MASK)
0a85b6f0
MT
1168 != DT2821_ADCSR_VAL) ||
1169 ((inw(dev->iobase + DT2821_CHANCSR) & DT2821_CHANCSR_MASK)
1170 != DT2821_CHANCSR_VAL) ||
1171 ((inw(dev->iobase + DT2821_DACSR) & DT2821_DACSR_MASK)
1172 != DT2821_DACSR_VAL) ||
1173 ((inw(dev->iobase + DT2821_SUPCSR) & DT2821_SUPCSR_MASK)
1174 != DT2821_SUPCSR_VAL) ||
1175 ((inw(dev->iobase + DT2821_TMRCTR) & DT2821_TMRCTR_MASK)
1176 != DT2821_TMRCTR_VAL)) {
18e7e78e 1177 printk(KERN_ERR " board not found");
8d3d823c
DS
1178 return -EIO;
1179 }
1180 /* should do board test */
1181
1182 irq = it->options[opt_irq];
1183#if 0
1184 if (irq < 0) {
1185 unsigned long flags;
1186 int irqs;
1187
1188 save_flags(flags);
1189 sti();
1190 irqs = probe_irq_on();
1191
1192 /* trigger interrupt */
1193
5f74ea14 1194 udelay(100);
8d3d823c
DS
1195
1196 irq = probe_irq_off(irqs);
1197 restore_flags(flags);
18e7e78e
IC
1198 if (0 /* error */)
1199 printk(KERN_ERR " error probing irq (bad)");
8d3d823c
DS
1200 }
1201#endif
1202 if (irq > 0) {
18e7e78e 1203 printk(KERN_INFO " ( irq = %d )", irq);
5f74ea14 1204 ret = request_irq(irq, dt282x_interrupt, 0, "dt282x", dev);
8d3d823c 1205 if (ret < 0) {
18e7e78e 1206 printk(KERN_ERR " failed to get irq\n");
8d3d823c
DS
1207 return -EIO;
1208 }
1209 dev->irq = irq;
1210 } else if (irq == 0) {
18e7e78e 1211 printk(KERN_INFO " (no irq)");
8d3d823c
DS
1212 } else {
1213#if 0
18e7e78e 1214 printk(KERN_INFO " (probe returned multiple irqs--bad)");
8d3d823c 1215#else
18e7e78e 1216 printk(KERN_INFO " (irq probe not implemented)");
8d3d823c
DS
1217#endif
1218 }
1219
c3744138
BP
1220 ret = alloc_private(dev, sizeof(struct dt282x_private));
1221 if (ret < 0)
8d3d823c
DS
1222 return ret;
1223
1224 ret = dt282x_grab_dma(dev, it->options[opt_dma1],
0a85b6f0 1225 it->options[opt_dma2]);
8d3d823c
DS
1226 if (ret < 0)
1227 return ret;
1228
2f0b9d08 1229 ret = comedi_alloc_subdevices(dev, 3);
8b6c5694 1230 if (ret)
8d3d823c
DS
1231 return ret;
1232
e1d7cf9c 1233 s = &dev->subdevices[0];
8d3d823c
DS
1234
1235 dev->read_subdev = s;
1236 /* ai subdevice */
1237 s->type = COMEDI_SUBD_AI;
1238 s->subdev_flags = SDF_READABLE | SDF_CMD_READ |
0a85b6f0 1239 ((it->options[opt_diff]) ? SDF_DIFF : SDF_COMMON);
8d3d823c 1240 s->n_chan =
0a85b6f0 1241 (it->options[opt_diff]) ? boardtype.adchan_di : boardtype.adchan_se;
8d3d823c
DS
1242 s->insn_read = dt282x_ai_insn_read;
1243 s->do_cmdtest = dt282x_ai_cmdtest;
1244 s->do_cmd = dt282x_ai_cmd;
1245 s->cancel = dt282x_ai_cancel;
1246 s->maxdata = (1 << boardtype.adbits) - 1;
1247 s->len_chanlist = 16;
1248 s->range_table =
0a85b6f0 1249 opt_ai_range_lkup(boardtype.ispgl, it->options[opt_ai_range]);
8d3d823c
DS
1250 devpriv->ad_2scomp = it->options[opt_ai_twos];
1251
e1d7cf9c 1252 s = &dev->subdevices[1];
c3744138
BP
1253
1254 s->n_chan = boardtype.dachan;
1255 if (s->n_chan) {
8d3d823c
DS
1256 /* ao subsystem */
1257 s->type = COMEDI_SUBD_AO;
1258 dev->write_subdev = s;
1259 s->subdev_flags = SDF_WRITABLE | SDF_CMD_WRITE;
1260 s->insn_read = dt282x_ao_insn_read;
1261 s->insn_write = dt282x_ao_insn_write;
1262 s->do_cmdtest = dt282x_ao_cmdtest;
1263 s->do_cmd = dt282x_ao_cmd;
1264 s->cancel = dt282x_ao_cancel;
1265 s->maxdata = (1 << boardtype.dabits) - 1;
1266 s->len_chanlist = 2;
1267 s->range_table_list = devpriv->darangelist;
1268 devpriv->darangelist[0] =
0a85b6f0 1269 opt_ao_range_lkup(it->options[opt_ao0_range]);
8d3d823c 1270 devpriv->darangelist[1] =
0a85b6f0 1271 opt_ao_range_lkup(it->options[opt_ao1_range]);
8d3d823c
DS
1272 devpriv->da0_2scomp = it->options[opt_ao0_twos];
1273 devpriv->da1_2scomp = it->options[opt_ao1_twos];
1274 } else {
1275 s->type = COMEDI_SUBD_UNUSED;
1276 }
1277
e1d7cf9c 1278 s = &dev->subdevices[2];
8d3d823c
DS
1279 /* dio subsystem */
1280 s->type = COMEDI_SUBD_DIO;
1281 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1282 s->n_chan = 16;
1283 s->insn_bits = dt282x_dio_insn_bits;
1284 s->insn_config = dt282x_dio_insn_config;
1285 s->maxdata = 1;
1286 s->range_table = &range_digital;
1287
18e7e78e 1288 printk(KERN_INFO "\n");
8d3d823c
DS
1289
1290 return 0;
1291}
1292
484ecc95 1293static void dt282x_detach(struct comedi_device *dev)
8d3d823c 1294{
18e7e78e 1295 if (dev->irq)
5f74ea14 1296 free_irq(dev->irq, dev);
8d3d823c
DS
1297 if (dev->iobase)
1298 release_region(dev->iobase, DT2821_SIZE);
1299 if (dev->private) {
1300 if (devpriv->dma[0].chan)
1301 free_dma(devpriv->dma[0].chan);
1302 if (devpriv->dma[1].chan)
1303 free_dma(devpriv->dma[1].chan);
1304 if (devpriv->dma[0].buf)
1305 free_page((unsigned long)devpriv->dma[0].buf);
1306 if (devpriv->dma[1].buf)
1307 free_page((unsigned long)devpriv->dma[1].buf);
1308 }
1309}
1310
e0eaa10d
HS
1311static const struct dt282x_board boardtypes[] = {
1312 {
1313 .name = "dt2821",
1314 .adbits = 12,
1315 .adchan_se = 16,
1316 .adchan_di = 8,
1317 .ai_speed = 20000,
1318 .ispgl = 0,
1319 .dachan = 2,
1320 .dabits = 12,
1321 }, {
1322 .name = "dt2821-f",
1323 .adbits = 12,
1324 .adchan_se = 16,
1325 .adchan_di = 8,
1326 .ai_speed = 6500,
1327 .ispgl = 0,
1328 .dachan = 2,
1329 .dabits = 12,
1330 }, {
1331 .name = "dt2821-g",
1332 .adbits = 12,
1333 .adchan_se = 16,
1334 .adchan_di = 8,
1335 .ai_speed = 4000,
1336 .ispgl = 0,
1337 .dachan = 2,
1338 .dabits = 12,
1339 }, {
1340 .name = "dt2823",
1341 .adbits = 16,
1342 .adchan_se = 0,
1343 .adchan_di = 4,
1344 .ai_speed = 10000,
1345 .ispgl = 0,
1346 .dachan = 2,
1347 .dabits = 16,
1348 }, {
1349 .name = "dt2824-pgh",
1350 .adbits = 12,
1351 .adchan_se = 16,
1352 .adchan_di = 8,
1353 .ai_speed = 20000,
1354 .ispgl = 0,
1355 .dachan = 0,
1356 .dabits = 0,
1357 }, {
1358 .name = "dt2824-pgl",
1359 .adbits = 12,
1360 .adchan_se = 16,
1361 .adchan_di = 8,
1362 .ai_speed = 20000,
1363 .ispgl = 1,
1364 .dachan = 0,
1365 .dabits = 0,
1366 }, {
1367 .name = "dt2825",
1368 .adbits = 12,
1369 .adchan_se = 16,
1370 .adchan_di = 8,
1371 .ai_speed = 20000,
1372 .ispgl = 1,
1373 .dachan = 2,
1374 .dabits = 12,
1375 }, {
1376 .name = "dt2827",
1377 .adbits = 16,
1378 .adchan_se = 0,
1379 .adchan_di = 4,
1380 .ai_speed = 10000,
1381 .ispgl = 0,
1382 .dachan = 2,
1383 .dabits = 12,
1384 }, {
1385 .name = "dt2828",
1386 .adbits = 12,
1387 .adchan_se = 4,
1388 .adchan_di = 0,
1389 .ai_speed = 10000,
1390 .ispgl = 0,
1391 .dachan = 2,
1392 .dabits = 12,
1393 }, {
1394 .name = "dt2829",
1395 .adbits = 16,
1396 .adchan_se = 8,
1397 .adchan_di = 0,
1398 .ai_speed = 33250,
1399 .ispgl = 0,
1400 .dachan = 2,
1401 .dabits = 16,
1402 }, {
1403 .name = "dt21-ez",
1404 .adbits = 12,
1405 .adchan_se = 16,
1406 .adchan_di = 8,
1407 .ai_speed = 10000,
1408 .ispgl = 0,
1409 .dachan = 2,
1410 .dabits = 12,
1411 }, {
1412 .name = "dt23-ez",
1413 .adbits = 16,
1414 .adchan_se = 16,
1415 .adchan_di = 8,
1416 .ai_speed = 10000,
1417 .ispgl = 0,
1418 .dachan = 0,
1419 .dabits = 0,
1420 }, {
1421 .name = "dt24-ez",
1422 .adbits = 12,
1423 .adchan_se = 16,
1424 .adchan_di = 8,
1425 .ai_speed = 10000,
1426 .ispgl = 0,
1427 .dachan = 0,
1428 .dabits = 0,
1429 }, {
1430 .name = "dt24-ez-pgl",
1431 .adbits = 12,
1432 .adchan_se = 16,
1433 .adchan_di = 8,
1434 .ai_speed = 10000,
1435 .ispgl = 1,
1436 .dachan = 0,
1437 .dabits = 0,
1438 },
1439};
8d3d823c 1440
e0eaa10d
HS
1441static struct comedi_driver dt282x_driver = {
1442 .driver_name = "dt282x",
1443 .module = THIS_MODULE,
1444 .attach = dt282x_attach,
1445 .detach = dt282x_detach,
1446 .board_name = &boardtypes[0].name,
1447 .num_names = ARRAY_SIZE(boardtypes),
1448 .offset = sizeof(struct dt282x_board),
1449};
1450module_comedi_driver(dt282x_driver);
90f703d3
AT
1451
1452MODULE_AUTHOR("Comedi http://www.comedi.org");
1453MODULE_DESCRIPTION("Comedi low-level driver");
1454MODULE_LICENSE("GPL");
This page took 0.455319 seconds and 5 git commands to generate.