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