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