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