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