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