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