2 * comedi/drivers/pcl812.c
4 * Author: Michal Dobes <dobes@tesnet.cz>
6 * hardware driver for Advantech cards
7 * card: PCL-812, PCL-812PG, PCL-813, PCL-813B
8 * driver: pcl812, pcl812pg, pcl813, pcl813b
10 * card: ACL-8112DG, ACL-8112HG, ACL-8112PG, ACL-8113, ACL-8216
11 * driver: acl8112dg, acl8112hg, acl8112pg, acl8113, acl8216
12 * and for ICP DAS cards
13 * card: ISO-813, A-821PGH, A-821PGL, A-821PGL-NDA, A-822PGH, A-822PGL,
14 * driver: iso813, a821pgh, a-821pgl, a-821pglnda, a822pgh, a822pgl,
15 * card: A-823PGH, A-823PGL, A-826PG
16 * driver: a823pgh, a823pgl, a826pg
21 * Description: Advantech PCL-812/PG, PCL-813/B,
22 * ADLink ACL-8112DG/HG/PG, ACL-8113, ACL-8216,
23 * ICP DAS A-821PGH/PGL/PGL-NDA, A-822PGH/PGL, A-823PGH/PGL, A-826PG,
25 * Author: Michal Dobes <dobes@tesnet.cz>
26 * Devices: [Advantech] PCL-812 (pcl812), PCL-812PG (pcl812pg),
27 * PCL-813 (pcl813), PCL-813B (pcl813b), [ADLink] ACL-8112DG (acl8112dg),
28 * ACL-8112HG (acl8112hg), ACL-8113 (acl-8113), ACL-8216 (acl8216),
29 * [ICP] ISO-813 (iso813), A-821PGH (a821pgh), A-821PGL (a821pgl),
30 * A-821PGL-NDA (a821pclnda), A-822PGH (a822pgh), A-822PGL (a822pgl),
31 * A-823PGH (a823pgh), A-823PGL (a823pgl), A-826PG (a826pg)
32 * Updated: Mon, 06 Aug 2007 12:03:15 +0100
33 * Status: works (I hope. My board fire up under my hands
34 * and I cann't test all features.)
36 * This driver supports insn and cmd interfaces. Some boards support only insn
37 * because their hardware don't allow more (PCL-813/B, ACL-8113, ISO-813).
38 * Data transfer over DMA is supported only when you measure only one
39 * channel, this is too hardware limitation of these boards.
41 * Options for PCL-812:
43 * [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7; 10, 11, 12, 14, 15)
44 * [2] - DMA (0=disable, 1, 3)
45 * [3] - 0=trigger source is internal 8253 with 2MHz clock
46 * 1=trigger source is external
47 * [4] - 0=A/D input range is +/-10V
48 * 1=A/D input range is +/-5V
49 * 2=A/D input range is +/-2.5V
50 * 3=A/D input range is +/-1.25V
51 * 4=A/D input range is +/-0.625V
52 * 5=A/D input range is +/-0.3125V
53 * [5] - 0=D/A outputs 0-5V (internal reference -5V)
54 * 1=D/A outputs 0-10V (internal reference -10V)
55 * 2=D/A outputs unknown (external reference)
57 * Options for PCL-812PG, ACL-8112PG:
59 * [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7; 10, 11, 12, 14, 15)
60 * [2] - DMA (0=disable, 1, 3)
61 * [3] - 0=trigger source is internal 8253 with 2MHz clock
62 * 1=trigger source is external
63 * [4] - 0=A/D have max +/-5V input
64 * 1=A/D have max +/-10V input
65 * [5] - 0=D/A outputs 0-5V (internal reference -5V)
66 * 1=D/A outputs 0-10V (internal reference -10V)
67 * 2=D/A outputs unknown (external reference)
69 * Options for ACL-8112DG/HG, A-822PGL/PGH, A-823PGL/PGH, ACL-8216, A-826PG:
71 * [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7; 10, 11, 12, 14, 15)
72 * [2] - DMA (0=disable, 1, 3)
73 * [3] - 0=trigger source is internal 8253 with 2MHz clock
74 * 1=trigger source is external
75 * [4] - 0=A/D channels are S.E.
76 * 1=A/D channels are DIFF
77 * [5] - 0=D/A outputs 0-5V (internal reference -5V)
78 * 1=D/A outputs 0-10V (internal reference -10V)
79 * 2=D/A outputs unknown (external reference)
81 * Options for A-821PGL/PGH:
83 * [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
84 * [2] - 0=A/D channels are S.E.
85 * 1=A/D channels are DIFF
86 * [3] - 0=D/A output 0-5V (internal reference -5V)
87 * 1=D/A output 0-10V (internal reference -10V)
89 * Options for A-821PGL-NDA:
91 * [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
92 * [2] - 0=A/D channels are S.E.
93 * 1=A/D channels are DIFF
95 * Options for PCL-813:
98 * Options for PCL-813B:
100 * [1] - 0= bipolar inputs
103 * Options for ACL-8113, ISO-813:
105 * [1] - 0= 10V bipolar inputs
106 * 1= 10V unipolar inputs
107 * 2= 20V bipolar inputs
108 * 3= 20V unipolar inputs
111 #include <linux/interrupt.h>
112 #include <linux/gfp.h>
113 #include "../comedidev.h"
115 #include <linux/delay.h>
116 #include <linux/ioport.h>
117 #include <linux/io.h>
122 /* if this is defined then a lot of messages is printed */
123 #undef PCL812_EXTDEBUG
125 /* hardware types of the cards */
126 #define boardPCL812PG 0 /* and ACL-8112PG */
127 #define boardPCL813B 1
128 #define boardPCL812 2
129 #define boardPCL813 3
130 #define boardISO813 5
131 #define boardACL8113 6
132 #define boardACL8112 7 /* ACL-8112DG/HG, A-822PGL/PGH, A-823PGL/PGH */
133 #define boardACL8216 8 /* and ICP DAS A-826PG */
134 #define boardA821 9 /* PGH, PGL, PGL/NDA versions */
136 #define PCLx1x_IORANGE 16
138 #define PCL812_CTR0 0
139 #define PCL812_CTR1 1
140 #define PCL812_CTR2 2
141 #define PCL812_CTRCTL 3
142 #define PCL812_AD_LO 4
143 #define PCL812_DA1_LO 4
144 #define PCL812_AD_HI 5
145 #define PCL812_DA1_HI 5
146 #define PCL812_DA2_LO 6
147 #define PCL812_DI_LO 6
148 #define PCL812_DA2_HI 7
149 #define PCL812_DI_HI 7
150 #define PCL812_CLRINT 8
151 #define PCL812_GAIN 9
152 #define PCL812_MUX 10
153 #define PCL812_MODE 11
154 #define PCL812_CNTENABLE 10
155 #define PCL812_SOFTTRIG 12
156 #define PCL812_DO_LO 13
157 #define PCL812_DO_HI 14
159 #define PCL812_DRDY 0x10 /* =0 data ready */
161 #define ACL8216_STATUS 8 /* 5. bit signalize data ready */
163 #define ACL8216_DRDY 0x20 /* =0 data ready */
165 #define MAX_CHANLIST_LEN 256 /* length of scan list */
167 static const struct comedi_lrange range_pcl812pg_ai
= { 5, {
176 static const struct comedi_lrange range_pcl812pg2_ai
= { 5, {
185 static const struct comedi_lrange range812_bipolar1_25
= { 1, {
190 static const struct comedi_lrange range812_bipolar0_625
= { 1, {
196 static const struct comedi_lrange range812_bipolar0_3125
= { 1, {
202 static const struct comedi_lrange range_pcl813b_ai
= { 4, {
210 static const struct comedi_lrange range_pcl813b2_ai
= { 4, {
218 static const struct comedi_lrange range_iso813_1_ai
= { 5, {
227 static const struct comedi_lrange range_iso813_1_2_ai
= { 5, {
236 static const struct comedi_lrange range_iso813_2_ai
= { 4, {
244 static const struct comedi_lrange range_iso813_2_2_ai
= { 4, {
252 static const struct comedi_lrange range_acl8113_1_ai
= { 4, {
260 static const struct comedi_lrange range_acl8113_1_2_ai
= { 4, {
268 static const struct comedi_lrange range_acl8113_2_ai
= { 3, {
275 static const struct comedi_lrange range_acl8113_2_2_ai
= { 3, {
282 static const struct comedi_lrange range_acl8112dg_ai
= { 9, {
295 static const struct comedi_lrange range_acl8112hg_ai
= { 12, {
311 static const struct comedi_lrange range_a821pgh_ai
= { 4, {
319 struct pcl812_board
{
321 const char *name
; /* board name */
322 int board_type
; /* type of this board */
323 int n_aichan
; /* num of AI chans in S.E. */
324 int n_aichan_diff
; /* DIFF num of chans */
325 int n_aochan
; /* num of DA chans */
326 int n_dichan
; /* DI and DO chans */
328 int ai_maxdata
; /* AI resolution */
329 unsigned int ai_ns_min
; /* max sample speed of card v ns */
330 unsigned int i8254_osc_base
; /* clock base */
331 const struct comedi_lrange
*rangelist_ai
; /* rangelist for A/D */
332 const struct comedi_lrange
*rangelist_ao
; /* rangelist for D/A */
333 unsigned int IRQbits
; /* allowed IRQ */
334 unsigned char DMAbits
; /* allowed DMA chans */
335 unsigned char io_range
; /* iorange for this board */
336 unsigned char haveMPC508
; /* 1=board use MPC508A multiplexor */
339 struct pcl812_private
{
341 unsigned char valid
; /* =1 device is OK */
342 unsigned char dma
; /* >0 use dma ( usedDMA channel) */
343 unsigned char use_diff
; /* =1 diff inputs */
344 unsigned char use_MPC
; /* 1=board uses MPC508A multiplexor */
345 unsigned char use_ext_trg
; /* 1=board uses external trigger */
346 unsigned char range_correction
; /* =1 we must add 1 to range number */
347 unsigned char old_chan_reg
; /* lastly used chan/gain pair */
348 unsigned char old_gain_reg
;
349 unsigned char mode_reg_int
; /* there is stored INT number for some card */
350 unsigned char ai_neverending
; /* =1 we do unlimited AI */
351 unsigned char ai_eos
; /* 1=EOS wake up */
352 unsigned char ai_dma
; /* =1 we use DMA */
353 unsigned int ai_poll_ptr
; /* how many sampes transfer poll */
354 unsigned int ai_scans
; /* len of scanlist */
355 unsigned int ai_act_scan
; /* how many scans we finished */
356 unsigned int ai_chanlist
[MAX_CHANLIST_LEN
]; /* our copy of channel/range list */
357 unsigned int ai_n_chan
; /* how many channels is measured */
358 unsigned int ai_flags
; /* flaglist */
359 unsigned int ai_data_len
; /* len of data buffer */
360 short *ai_data
; /* data buffer */
361 unsigned int ai_is16b
; /* =1 we have 16 bit card */
362 unsigned long dmabuf
[2]; /* PTR to DMA buf */
363 unsigned int dmapages
[2]; /* how many pages we have allocated */
364 unsigned int hwdmaptr
[2]; /* HW PTR to DMA buf */
365 unsigned int hwdmasize
[2]; /* DMA buf size in bytes */
366 unsigned int dmabytestomove
[2]; /* how many bytes DMA transfer */
367 int next_dma_buf
; /* which buffer is next to use */
368 unsigned int dma_runs_to_end
; /* how many times we must switch DMA buffers */
369 unsigned int last_dma_run
; /* how many bytes to transfer on last DMA buffer */
370 unsigned int max_812_ai_mode0_rangewait
; /* setling time for gain */
371 unsigned int ao_readback
[2]; /* data for AO readback */
374 #define devpriv ((struct pcl812_private *)dev->private)
377 ==============================================================================
379 static void start_pacer(struct comedi_device
*dev
, int mode
,
380 unsigned int divisor1
, unsigned int divisor2
);
381 static void setup_range_channel(struct comedi_device
*dev
,
382 struct comedi_subdevice
*s
,
383 unsigned int rangechan
, char wait
);
384 static int pcl812_ai_cancel(struct comedi_device
*dev
,
385 struct comedi_subdevice
*s
);
387 ==============================================================================
389 static int pcl812_ai_insn_read(struct comedi_device
*dev
,
390 struct comedi_subdevice
*s
,
391 struct comedi_insn
*insn
, unsigned int *data
)
396 /* select software trigger */
397 outb(devpriv
->mode_reg_int
| 1, dev
->iobase
+ PCL812_MODE
);
398 /* select channel and renge */
399 setup_range_channel(dev
, s
, insn
->chanspec
, 1);
400 for (n
= 0; n
< insn
->n
; n
++) {
401 /* start conversion */
402 outb(255, dev
->iobase
+ PCL812_SOFTTRIG
);
404 timeout
= 50; /* wait max 50us, it must finish under 33us */
406 hi
= inb(dev
->iobase
+ PCL812_AD_HI
);
407 if (!(hi
& PCL812_DRDY
))
412 ("comedi%d: pcl812: (%s at 0x%lx) A/D insn read timeout\n",
413 dev
->minor
, dev
->board_name
, dev
->iobase
);
414 outb(devpriv
->mode_reg_int
| 0, dev
->iobase
+ PCL812_MODE
);
418 data
[n
] = ((hi
& 0xf) << 8) | inb(dev
->iobase
+ PCL812_AD_LO
);
420 outb(devpriv
->mode_reg_int
| 0, dev
->iobase
+ PCL812_MODE
);
425 ==============================================================================
427 static int acl8216_ai_insn_read(struct comedi_device
*dev
,
428 struct comedi_subdevice
*s
,
429 struct comedi_insn
*insn
, unsigned int *data
)
434 /* select software trigger */
435 outb(1, dev
->iobase
+ PCL812_MODE
);
436 /* select channel and renge */
437 setup_range_channel(dev
, s
, insn
->chanspec
, 1);
438 for (n
= 0; n
< insn
->n
; n
++) {
439 /* start conversion */
440 outb(255, dev
->iobase
+ PCL812_SOFTTRIG
);
442 timeout
= 50; /* wait max 50us, it must finish under 33us */
444 if (!(inb(dev
->iobase
+ ACL8216_STATUS
) & ACL8216_DRDY
))
449 ("comedi%d: pcl812: (%s at 0x%lx) A/D insn read timeout\n",
450 dev
->minor
, dev
->board_name
, dev
->iobase
);
451 outb(0, dev
->iobase
+ PCL812_MODE
);
457 PCL812_AD_HI
) << 8) | inb(dev
->iobase
+ PCL812_AD_LO
);
459 outb(0, dev
->iobase
+ PCL812_MODE
);
464 ==============================================================================
466 static int pcl812_ao_insn_write(struct comedi_device
*dev
,
467 struct comedi_subdevice
*s
,
468 struct comedi_insn
*insn
, unsigned int *data
)
470 int chan
= CR_CHAN(insn
->chanspec
);
473 for (i
= 0; i
< insn
->n
; i
++) {
474 outb((data
[i
] & 0xff),
475 dev
->iobase
+ (chan
? PCL812_DA2_LO
: PCL812_DA1_LO
));
476 outb((data
[i
] >> 8) & 0x0f,
477 dev
->iobase
+ (chan
? PCL812_DA2_HI
: PCL812_DA1_HI
));
478 devpriv
->ao_readback
[chan
] = data
[i
];
485 ==============================================================================
487 static int pcl812_ao_insn_read(struct comedi_device
*dev
,
488 struct comedi_subdevice
*s
,
489 struct comedi_insn
*insn
, unsigned int *data
)
491 int chan
= CR_CHAN(insn
->chanspec
);
494 for (i
= 0; i
< insn
->n
; i
++)
495 data
[i
] = devpriv
->ao_readback
[chan
];
501 ==============================================================================
503 static int pcl812_di_insn_bits(struct comedi_device
*dev
,
504 struct comedi_subdevice
*s
,
505 struct comedi_insn
*insn
, unsigned int *data
)
510 data
[1] = inb(dev
->iobase
+ PCL812_DI_LO
);
511 data
[1] |= inb(dev
->iobase
+ PCL812_DI_HI
) << 8;
517 ==============================================================================
519 static int pcl812_do_insn_bits(struct comedi_device
*dev
,
520 struct comedi_subdevice
*s
,
521 struct comedi_insn
*insn
, unsigned int *data
)
527 s
->state
&= ~data
[0];
528 s
->state
|= data
[0] & data
[1];
529 outb(s
->state
& 0xff, dev
->iobase
+ PCL812_DO_LO
);
530 outb((s
->state
>> 8), dev
->iobase
+ PCL812_DO_HI
);
537 #ifdef PCL812_EXTDEBUG
539 ==============================================================================
541 static void pcl812_cmdtest_out(int e
, struct comedi_cmd
*cmd
)
543 printk(KERN_INFO
"pcl812 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e
,
544 cmd
->start_src
, cmd
->scan_begin_src
, cmd
->convert_src
);
545 printk(KERN_INFO
"pcl812 e=%d startarg=%d scanarg=%d convarg=%d\n", e
,
546 cmd
->start_arg
, cmd
->scan_begin_arg
, cmd
->convert_arg
);
547 printk(KERN_INFO
"pcl812 e=%d stopsrc=%x scanend=%x\n", e
,
548 cmd
->stop_src
, cmd
->scan_end_src
);
549 printk(KERN_INFO
"pcl812 e=%d stoparg=%d scanendarg=%d "
550 "chanlistlen=%d\n", e
, cmd
->stop_arg
, cmd
->scan_end_arg
,
556 ==============================================================================
558 static int pcl812_ai_cmdtest(struct comedi_device
*dev
,
559 struct comedi_subdevice
*s
, struct comedi_cmd
*cmd
)
561 const struct pcl812_board
*board
= comedi_board(dev
);
563 int tmp
, divisor1
, divisor2
;
565 #ifdef PCL812_EXTDEBUG
566 printk("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...)\n");
567 pcl812_cmdtest_out(-1, cmd
);
569 /* step 1: make sure trigger sources are trivially valid */
571 tmp
= cmd
->start_src
;
572 cmd
->start_src
&= TRIG_NOW
;
573 if (!cmd
->start_src
|| tmp
!= cmd
->start_src
)
576 tmp
= cmd
->scan_begin_src
;
577 cmd
->scan_begin_src
&= TRIG_FOLLOW
;
578 if (!cmd
->scan_begin_src
|| tmp
!= cmd
->scan_begin_src
)
581 tmp
= cmd
->convert_src
;
582 if (devpriv
->use_ext_trg
)
583 cmd
->convert_src
&= TRIG_EXT
;
585 cmd
->convert_src
&= TRIG_TIMER
;
587 if (!cmd
->convert_src
|| tmp
!= cmd
->convert_src
)
590 tmp
= cmd
->scan_end_src
;
591 cmd
->scan_end_src
&= TRIG_COUNT
;
592 if (!cmd
->scan_end_src
|| tmp
!= cmd
->scan_end_src
)
596 cmd
->stop_src
&= TRIG_COUNT
| TRIG_NONE
;
597 if (!cmd
->stop_src
|| tmp
!= cmd
->stop_src
)
601 #ifdef PCL812_EXTDEBUG
602 pcl812_cmdtest_out(1, cmd
);
604 ("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=1\n",
611 * step 2: make sure trigger sources are
612 * unique and mutually compatible
615 if (cmd
->start_src
!= TRIG_NOW
) {
616 cmd
->start_src
= TRIG_NOW
;
620 if (cmd
->scan_begin_src
!= TRIG_FOLLOW
) {
621 cmd
->scan_begin_src
= TRIG_FOLLOW
;
625 if (devpriv
->use_ext_trg
) {
626 if (cmd
->convert_src
!= TRIG_EXT
) {
627 cmd
->convert_src
= TRIG_EXT
;
631 if (cmd
->convert_src
!= TRIG_TIMER
) {
632 cmd
->convert_src
= TRIG_TIMER
;
637 if (cmd
->scan_end_src
!= TRIG_COUNT
) {
638 cmd
->scan_end_src
= TRIG_COUNT
;
642 if (cmd
->stop_src
!= TRIG_NONE
&& cmd
->stop_src
!= TRIG_COUNT
)
646 #ifdef PCL812_EXTDEBUG
647 pcl812_cmdtest_out(2, cmd
);
649 ("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=2\n",
655 /* step 3: make sure arguments are trivially compatible */
657 if (cmd
->start_arg
!= 0) {
662 if (cmd
->scan_begin_arg
!= 0) {
663 cmd
->scan_begin_arg
= 0;
667 if (cmd
->convert_src
== TRIG_TIMER
) {
668 if (cmd
->convert_arg
< board
->ai_ns_min
) {
669 cmd
->convert_arg
= board
->ai_ns_min
;
672 } else { /* TRIG_EXT */
673 if (cmd
->convert_arg
!= 0) {
674 cmd
->convert_arg
= 0;
679 if (!cmd
->chanlist_len
) {
680 cmd
->chanlist_len
= 1;
683 if (cmd
->chanlist_len
> MAX_CHANLIST_LEN
) {
684 cmd
->chanlist_len
= board
->n_aichan
;
687 if (cmd
->scan_end_arg
!= cmd
->chanlist_len
) {
688 cmd
->scan_end_arg
= cmd
->chanlist_len
;
691 if (cmd
->stop_src
== TRIG_COUNT
) {
692 if (!cmd
->stop_arg
) {
696 } else { /* TRIG_NONE */
697 if (cmd
->stop_arg
!= 0) {
704 #ifdef PCL812_EXTDEBUG
705 pcl812_cmdtest_out(3, cmd
);
707 ("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=3\n",
713 /* step 4: fix up any arguments */
715 if (cmd
->convert_src
== TRIG_TIMER
) {
716 tmp
= cmd
->convert_arg
;
717 i8253_cascade_ns_to_timer(board
->i8254_osc_base
, &divisor1
,
718 &divisor2
, &cmd
->convert_arg
,
719 cmd
->flags
& TRIG_ROUND_MASK
);
720 if (cmd
->convert_arg
< board
->ai_ns_min
)
721 cmd
->convert_arg
= board
->ai_ns_min
;
722 if (tmp
!= cmd
->convert_arg
)
727 #ifdef PCL812_EXTDEBUG
729 ("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=4\n",
739 ==============================================================================
741 static int pcl812_ai_cmd(struct comedi_device
*dev
, struct comedi_subdevice
*s
)
743 const struct pcl812_board
*board
= comedi_board(dev
);
744 unsigned int divisor1
= 0, divisor2
= 0, i
, dma_flags
, bytes
;
745 struct comedi_cmd
*cmd
= &s
->async
->cmd
;
747 #ifdef PCL812_EXTDEBUG
748 printk(KERN_DEBUG
"pcl812 EDBG: BGN: pcl812_ai_cmd(...)\n");
751 if (cmd
->start_src
!= TRIG_NOW
)
753 if (cmd
->scan_begin_src
!= TRIG_FOLLOW
)
755 if (devpriv
->use_ext_trg
) {
756 if (cmd
->convert_src
!= TRIG_EXT
)
759 if (cmd
->convert_src
!= TRIG_TIMER
)
762 if (cmd
->scan_end_src
!= TRIG_COUNT
)
764 if (cmd
->scan_end_arg
!= cmd
->chanlist_len
)
766 if (cmd
->chanlist_len
> MAX_CHANLIST_LEN
)
769 if (cmd
->convert_src
== TRIG_TIMER
) {
770 if (cmd
->convert_arg
< board
->ai_ns_min
)
771 cmd
->convert_arg
= board
->ai_ns_min
;
772 i8253_cascade_ns_to_timer(board
->i8254_osc_base
,
773 &divisor1
, &divisor2
,
775 cmd
->flags
& TRIG_ROUND_MASK
);
778 start_pacer(dev
, -1, 0, 0); /* stop pacer */
780 devpriv
->ai_n_chan
= cmd
->chanlist_len
;
781 memcpy(devpriv
->ai_chanlist
, cmd
->chanlist
,
782 sizeof(unsigned int) * cmd
->scan_end_arg
);
783 /* select first channel and range */
784 setup_range_channel(dev
, s
, devpriv
->ai_chanlist
[0], 1);
786 if (devpriv
->dma
) { /* check if we can use DMA transfer */
788 for (i
= 1; i
< devpriv
->ai_n_chan
; i
++)
789 if (devpriv
->ai_chanlist
[0] != devpriv
->ai_chanlist
[i
]) {
790 /* we cann't use DMA :-( */
797 devpriv
->ai_flags
= cmd
->flags
;
798 devpriv
->ai_data_len
= s
->async
->prealloc_bufsz
;
799 devpriv
->ai_data
= s
->async
->prealloc_buf
;
800 if (cmd
->stop_src
== TRIG_COUNT
) {
801 devpriv
->ai_scans
= cmd
->stop_arg
;
802 devpriv
->ai_neverending
= 0;
804 devpriv
->ai_scans
= 0;
805 devpriv
->ai_neverending
= 1;
808 devpriv
->ai_act_scan
= 0;
809 devpriv
->ai_poll_ptr
= 0;
810 s
->async
->cur_chan
= 0;
812 /* don't we want wake up every scan? */
813 if ((devpriv
->ai_flags
& TRIG_WAKE_EOS
)) {
816 /* DMA is useless for this situation */
817 if (devpriv
->ai_n_chan
== 1)
821 if (devpriv
->ai_dma
) {
822 /* we use EOS, so adapt DMA buffer to one scan */
823 if (devpriv
->ai_eos
) {
824 devpriv
->dmabytestomove
[0] =
825 devpriv
->ai_n_chan
* sizeof(short);
826 devpriv
->dmabytestomove
[1] =
827 devpriv
->ai_n_chan
* sizeof(short);
828 devpriv
->dma_runs_to_end
= 1;
830 devpriv
->dmabytestomove
[0] = devpriv
->hwdmasize
[0];
831 devpriv
->dmabytestomove
[1] = devpriv
->hwdmasize
[1];
832 if (devpriv
->ai_data_len
< devpriv
->hwdmasize
[0])
833 devpriv
->dmabytestomove
[0] =
834 devpriv
->ai_data_len
;
835 if (devpriv
->ai_data_len
< devpriv
->hwdmasize
[1])
836 devpriv
->dmabytestomove
[1] =
837 devpriv
->ai_data_len
;
838 if (devpriv
->ai_neverending
) {
839 devpriv
->dma_runs_to_end
= 1;
841 /* how many samples we must transfer? */
842 bytes
= devpriv
->ai_n_chan
*
843 devpriv
->ai_scans
* sizeof(short);
845 /* how many DMA pages we must fill */
846 devpriv
->dma_runs_to_end
=
847 bytes
/ devpriv
->dmabytestomove
[0];
849 /* on last dma transfer must be moved */
850 devpriv
->last_dma_run
=
851 bytes
% devpriv
->dmabytestomove
[0];
852 if (devpriv
->dma_runs_to_end
== 0)
853 devpriv
->dmabytestomove
[0] =
854 devpriv
->last_dma_run
;
855 devpriv
->dma_runs_to_end
--;
858 if (devpriv
->dmabytestomove
[0] > devpriv
->hwdmasize
[0]) {
859 devpriv
->dmabytestomove
[0] = devpriv
->hwdmasize
[0];
862 if (devpriv
->dmabytestomove
[1] > devpriv
->hwdmasize
[1]) {
863 devpriv
->dmabytestomove
[1] = devpriv
->hwdmasize
[1];
866 devpriv
->next_dma_buf
= 0;
867 set_dma_mode(devpriv
->dma
, DMA_MODE_READ
);
868 dma_flags
= claim_dma_lock();
869 clear_dma_ff(devpriv
->dma
);
870 set_dma_addr(devpriv
->dma
, devpriv
->hwdmaptr
[0]);
871 set_dma_count(devpriv
->dma
, devpriv
->dmabytestomove
[0]);
872 release_dma_lock(dma_flags
);
873 enable_dma(devpriv
->dma
);
874 #ifdef PCL812_EXTDEBUG
876 ("pcl812 EDBG: DMA %d PTR 0x%0x/0x%0x LEN %u/%u EOS %d\n",
877 devpriv
->dma
, devpriv
->hwdmaptr
[0],
878 devpriv
->hwdmaptr
[1], devpriv
->dmabytestomove
[0],
879 devpriv
->dmabytestomove
[1], devpriv
->ai_eos
);
883 switch (cmd
->convert_src
) {
885 start_pacer(dev
, 1, divisor1
, divisor2
);
889 if (devpriv
->ai_dma
) /* let's go! */
890 outb(devpriv
->mode_reg_int
| 2, dev
->iobase
+ PCL812_MODE
);
892 outb(devpriv
->mode_reg_int
| 6, dev
->iobase
+ PCL812_MODE
);
894 #ifdef PCL812_EXTDEBUG
895 printk(KERN_DEBUG
"pcl812 EDBG: END: pcl812_ai_cmd(...)\n");
902 ==============================================================================
904 static irqreturn_t
interrupt_pcl812_ai_int(int irq
, void *d
)
907 unsigned int mask
, timeout
;
908 struct comedi_device
*dev
= d
;
909 struct comedi_subdevice
*s
= dev
->subdevices
+ 0;
910 unsigned int next_chan
;
912 s
->async
->events
= 0;
914 timeout
= 50; /* wait max 50us, it must finish under 33us */
915 if (devpriv
->ai_is16b
) {
918 if (!(inb(dev
->iobase
+ ACL8216_STATUS
) & ACL8216_DRDY
)) {
927 if (!(inb(dev
->iobase
+ PCL812_AD_HI
) & PCL812_DRDY
)) {
937 ("comedi%d: pcl812: (%s at 0x%lx) "
938 "A/D cmd IRQ without DRDY!\n",
939 dev
->minor
, dev
->board_name
, dev
->iobase
);
940 pcl812_ai_cancel(dev
, s
);
941 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
942 comedi_event(dev
, s
);
946 comedi_buf_put(s
->async
,
947 ((inb(dev
->iobase
+ PCL812_AD_HI
) << 8) |
948 inb(dev
->iobase
+ PCL812_AD_LO
)) & mask
);
950 /* Set up next channel. Added by abbotti 2010-01-20, but untested. */
951 next_chan
= s
->async
->cur_chan
+ 1;
952 if (next_chan
>= devpriv
->ai_n_chan
)
954 if (devpriv
->ai_chanlist
[s
->async
->cur_chan
] !=
955 devpriv
->ai_chanlist
[next_chan
])
956 setup_range_channel(dev
, s
, devpriv
->ai_chanlist
[next_chan
], 0);
958 outb(0, dev
->iobase
+ PCL812_CLRINT
); /* clear INT request */
960 s
->async
->cur_chan
= next_chan
;
961 if (next_chan
== 0) { /* one scan done */
962 devpriv
->ai_act_scan
++;
963 if (!(devpriv
->ai_neverending
))
964 /* all data sampled */
965 if (devpriv
->ai_act_scan
>= devpriv
->ai_scans
) {
966 pcl812_ai_cancel(dev
, s
);
967 s
->async
->events
|= COMEDI_CB_EOA
;
971 comedi_event(dev
, s
);
976 ==============================================================================
978 static void transfer_from_dma_buf(struct comedi_device
*dev
,
979 struct comedi_subdevice
*s
, short *ptr
,
980 unsigned int bufptr
, unsigned int len
)
984 s
->async
->events
= 0;
985 for (i
= len
; i
; i
--) {
987 comedi_buf_put(s
->async
, ptr
[bufptr
++]);
989 s
->async
->cur_chan
++;
990 if (s
->async
->cur_chan
>= devpriv
->ai_n_chan
) {
991 s
->async
->cur_chan
= 0;
992 devpriv
->ai_act_scan
++;
993 if (!devpriv
->ai_neverending
)
994 /* all data sampled */
995 if (devpriv
->ai_act_scan
>= devpriv
->ai_scans
) {
996 pcl812_ai_cancel(dev
, s
);
997 s
->async
->events
|= COMEDI_CB_EOA
;
1003 comedi_event(dev
, s
);
1007 ==============================================================================
1009 static irqreturn_t
interrupt_pcl812_ai_dma(int irq
, void *d
)
1011 struct comedi_device
*dev
= d
;
1012 struct comedi_subdevice
*s
= dev
->subdevices
+ 0;
1013 unsigned long dma_flags
;
1017 #ifdef PCL812_EXTDEBUG
1018 printk(KERN_DEBUG
"pcl812 EDBG: BGN: interrupt_pcl812_ai_dma(...)\n");
1020 ptr
= (short *)devpriv
->dmabuf
[devpriv
->next_dma_buf
];
1021 len
= (devpriv
->dmabytestomove
[devpriv
->next_dma_buf
] >> 1) -
1022 devpriv
->ai_poll_ptr
;
1024 devpriv
->next_dma_buf
= 1 - devpriv
->next_dma_buf
;
1025 disable_dma(devpriv
->dma
);
1026 set_dma_mode(devpriv
->dma
, DMA_MODE_READ
);
1027 dma_flags
= claim_dma_lock();
1028 set_dma_addr(devpriv
->dma
, devpriv
->hwdmaptr
[devpriv
->next_dma_buf
]);
1029 if (devpriv
->ai_eos
) {
1030 set_dma_count(devpriv
->dma
,
1031 devpriv
->dmabytestomove
[devpriv
->next_dma_buf
]);
1033 if (devpriv
->dma_runs_to_end
) {
1034 set_dma_count(devpriv
->dma
,
1035 devpriv
->dmabytestomove
[devpriv
->
1038 set_dma_count(devpriv
->dma
, devpriv
->last_dma_run
);
1040 devpriv
->dma_runs_to_end
--;
1042 release_dma_lock(dma_flags
);
1043 enable_dma(devpriv
->dma
);
1045 outb(0, dev
->iobase
+ PCL812_CLRINT
); /* clear INT request */
1047 bufptr
= devpriv
->ai_poll_ptr
;
1048 devpriv
->ai_poll_ptr
= 0;
1050 transfer_from_dma_buf(dev
, s
, ptr
, bufptr
, len
);
1052 #ifdef PCL812_EXTDEBUG
1053 printk(KERN_DEBUG
"pcl812 EDBG: END: interrupt_pcl812_ai_dma(...)\n");
1059 ==============================================================================
1061 static irqreturn_t
interrupt_pcl812(int irq
, void *d
)
1063 struct comedi_device
*dev
= d
;
1065 if (!dev
->attached
) {
1066 comedi_error(dev
, "spurious interrupt");
1069 if (devpriv
->ai_dma
)
1070 return interrupt_pcl812_ai_dma(irq
, d
);
1072 return interrupt_pcl812_ai_int(irq
, d
);
1076 ==============================================================================
1078 static int pcl812_ai_poll(struct comedi_device
*dev
, struct comedi_subdevice
*s
)
1080 unsigned long flags
;
1081 unsigned int top1
, top2
, i
;
1083 if (!devpriv
->ai_dma
)
1084 return 0; /* poll is valid only for DMA transfer */
1086 spin_lock_irqsave(&dev
->spinlock
, flags
);
1088 for (i
= 0; i
< 10; i
++) {
1089 /* where is now DMA */
1090 top1
= get_dma_residue(devpriv
->ai_dma
);
1091 top2
= get_dma_residue(devpriv
->ai_dma
);
1097 spin_unlock_irqrestore(&dev
->spinlock
, flags
);
1100 /* where is now DMA in buffer */
1101 top1
= devpriv
->dmabytestomove
[1 - devpriv
->next_dma_buf
] - top1
;
1102 top1
>>= 1; /* sample position */
1103 top2
= top1
- devpriv
->ai_poll_ptr
;
1104 if (top2
< 1) { /* no new samples */
1105 spin_unlock_irqrestore(&dev
->spinlock
, flags
);
1109 transfer_from_dma_buf(dev
, s
,
1110 (void *)devpriv
->dmabuf
[1 -
1111 devpriv
->next_dma_buf
],
1112 devpriv
->ai_poll_ptr
, top2
);
1114 devpriv
->ai_poll_ptr
= top1
; /* new buffer position */
1116 spin_unlock_irqrestore(&dev
->spinlock
, flags
);
1118 return s
->async
->buf_write_count
- s
->async
->buf_read_count
;
1122 ==============================================================================
1124 static void setup_range_channel(struct comedi_device
*dev
,
1125 struct comedi_subdevice
*s
,
1126 unsigned int rangechan
, char wait
)
1128 unsigned char chan_reg
= CR_CHAN(rangechan
); /* normal board */
1130 unsigned char gain_reg
= CR_RANGE(rangechan
) +
1131 devpriv
->range_correction
;
1133 if ((chan_reg
== devpriv
->old_chan_reg
)
1134 && (gain_reg
== devpriv
->old_gain_reg
))
1135 return; /* we can return, no change */
1137 devpriv
->old_chan_reg
= chan_reg
;
1138 devpriv
->old_gain_reg
= gain_reg
;
1140 if (devpriv
->use_MPC
) {
1141 if (devpriv
->use_diff
) {
1142 chan_reg
= chan_reg
| 0x30; /* DIFF inputs */
1144 if (chan_reg
& 0x80)
1145 /* SE inputs 8-15 */
1146 chan_reg
= chan_reg
| 0x20;
1149 chan_reg
= chan_reg
| 0x10;
1153 outb(chan_reg
, dev
->iobase
+ PCL812_MUX
); /* select channel */
1154 outb(gain_reg
, dev
->iobase
+ PCL812_GAIN
); /* select gain */
1159 * XXX this depends on selected range and can be very long for
1160 * some high gain ranges!
1162 udelay(devpriv
->max_812_ai_mode0_rangewait
);
1166 ==============================================================================
1168 static void start_pacer(struct comedi_device
*dev
, int mode
,
1169 unsigned int divisor1
, unsigned int divisor2
)
1171 #ifdef PCL812_EXTDEBUG
1172 printk(KERN_DEBUG
"pcl812 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode
,
1173 divisor1
, divisor2
);
1175 outb(0xb4, dev
->iobase
+ PCL812_CTRCTL
);
1176 outb(0x74, dev
->iobase
+ PCL812_CTRCTL
);
1180 outb(divisor2
& 0xff, dev
->iobase
+ PCL812_CTR2
);
1181 outb((divisor2
>> 8) & 0xff, dev
->iobase
+ PCL812_CTR2
);
1182 outb(divisor1
& 0xff, dev
->iobase
+ PCL812_CTR1
);
1183 outb((divisor1
>> 8) & 0xff, dev
->iobase
+ PCL812_CTR1
);
1185 #ifdef PCL812_EXTDEBUG
1186 printk(KERN_DEBUG
"pcl812 EDBG: END: start_pacer(...)\n");
1191 ==============================================================================
1193 static void free_resources(struct comedi_device
*dev
)
1195 const struct pcl812_board
*board
= comedi_board(dev
);
1198 if (devpriv
->dmabuf
[0])
1199 free_pages(devpriv
->dmabuf
[0], devpriv
->dmapages
[0]);
1200 if (devpriv
->dmabuf
[1])
1201 free_pages(devpriv
->dmabuf
[1], devpriv
->dmapages
[1]);
1203 free_dma(devpriv
->dma
);
1206 free_irq(dev
->irq
, dev
);
1208 release_region(dev
->iobase
, board
->io_range
);
1212 ==============================================================================
1214 static int pcl812_ai_cancel(struct comedi_device
*dev
,
1215 struct comedi_subdevice
*s
)
1217 #ifdef PCL812_EXTDEBUG
1218 printk(KERN_DEBUG
"pcl812 EDBG: BGN: pcl812_ai_cancel(...)\n");
1220 if (devpriv
->ai_dma
)
1221 disable_dma(devpriv
->dma
);
1222 outb(0, dev
->iobase
+ PCL812_CLRINT
); /* clear INT request */
1224 outb(devpriv
->mode_reg_int
| 0, dev
->iobase
+ PCL812_MODE
);
1225 start_pacer(dev
, -1, 0, 0); /* stop 8254 */
1226 outb(0, dev
->iobase
+ PCL812_CLRINT
); /* clear INT request */
1227 #ifdef PCL812_EXTDEBUG
1228 printk(KERN_DEBUG
"pcl812 EDBG: END: pcl812_ai_cancel(...)\n");
1234 ==============================================================================
1236 static void pcl812_reset(struct comedi_device
*dev
)
1238 const struct pcl812_board
*board
= comedi_board(dev
);
1240 #ifdef PCL812_EXTDEBUG
1241 printk(KERN_DEBUG
"pcl812 EDBG: BGN: pcl812_reset(...)\n");
1243 outb(0, dev
->iobase
+ PCL812_MUX
);
1244 outb(0 + devpriv
->range_correction
, dev
->iobase
+ PCL812_GAIN
);
1245 devpriv
->old_chan_reg
= -1; /* invalidate chain/gain memory */
1246 devpriv
->old_gain_reg
= -1;
1248 switch (board
->board_type
) {
1253 outb(0, dev
->iobase
+ PCL812_DA2_LO
);
1254 outb(0, dev
->iobase
+ PCL812_DA2_HI
);
1256 outb(0, dev
->iobase
+ PCL812_DA1_LO
);
1257 outb(0, dev
->iobase
+ PCL812_DA1_HI
);
1258 start_pacer(dev
, -1, 0, 0); /* stop 8254 */
1259 outb(0, dev
->iobase
+ PCL812_DO_HI
);
1260 outb(0, dev
->iobase
+ PCL812_DO_LO
);
1261 outb(devpriv
->mode_reg_int
| 0, dev
->iobase
+ PCL812_MODE
);
1262 outb(0, dev
->iobase
+ PCL812_CLRINT
);
1272 #ifdef PCL812_EXTDEBUG
1273 printk(KERN_DEBUG
"pcl812 EDBG: END: pcl812_reset(...)\n");
1277 static int pcl812_attach(struct comedi_device
*dev
, struct comedi_devconfig
*it
)
1279 const struct pcl812_board
*board
= comedi_board(dev
);
1281 unsigned long iobase
;
1284 unsigned long pages
;
1285 struct comedi_subdevice
*s
;
1288 iobase
= it
->options
[0];
1289 printk(KERN_INFO
"comedi%d: pcl812: board=%s, ioport=0x%03lx",
1290 dev
->minor
, board
->name
, iobase
);
1292 if (!request_region(iobase
, board
->io_range
, "pcl812")) {
1293 printk("I/O port conflict\n");
1296 dev
->iobase
= iobase
;
1298 ret
= alloc_private(dev
, sizeof(struct pcl812_private
));
1300 free_resources(dev
);
1301 return ret
; /* Can't alloc mem */
1304 dev
->board_name
= board
->name
;
1307 if (board
->IRQbits
!= 0) { /* board support IRQ */
1308 irq
= it
->options
[1];
1309 if (irq
) { /* we want to use IRQ */
1310 if (((1 << irq
) & board
->IRQbits
) == 0) {
1312 (", IRQ %u is out of allowed range, "
1313 "DISABLING IT", irq
);
1314 irq
= 0; /* Bad IRQ */
1317 (irq
, interrupt_pcl812
, 0, "pcl812", dev
)) {
1319 (", unable to allocate IRQ %u, "
1320 "DISABLING IT", irq
);
1321 irq
= 0; /* Can't use IRQ */
1323 printk(KERN_INFO
", irq=%u", irq
);
1334 goto no_dma
; /* if we haven't IRQ, we can't use DMA */
1335 if (board
->DMAbits
!= 0) { /* board support DMA */
1336 dma
= it
->options
[2];
1337 if (((1 << dma
) & board
->DMAbits
) == 0) {
1338 printk(", DMA is out of allowed range, FAIL!\n");
1339 return -EINVAL
; /* Bad DMA */
1341 ret
= request_dma(dma
, "pcl812");
1343 printk(KERN_ERR
", unable to allocate DMA %u, FAIL!\n",
1345 return -EBUSY
; /* DMA isn't free */
1348 printk(KERN_INFO
", dma=%u", dma
);
1349 pages
= 1; /* we want 8KB */
1350 devpriv
->dmabuf
[0] = __get_dma_pages(GFP_KERNEL
, pages
);
1351 if (!devpriv
->dmabuf
[0]) {
1352 printk(", unable to allocate DMA buffer, FAIL!\n");
1354 * maybe experiment with try_to_free_pages()
1357 free_resources(dev
);
1358 return -EBUSY
; /* no buffer :-( */
1360 devpriv
->dmapages
[0] = pages
;
1361 devpriv
->hwdmaptr
[0] = virt_to_bus((void *)devpriv
->dmabuf
[0]);
1362 devpriv
->hwdmasize
[0] = PAGE_SIZE
* (1 << pages
);
1363 devpriv
->dmabuf
[1] = __get_dma_pages(GFP_KERNEL
, pages
);
1364 if (!devpriv
->dmabuf
[1]) {
1365 printk(KERN_ERR
", unable to allocate DMA buffer, FAIL!\n");
1366 free_resources(dev
);
1369 devpriv
->dmapages
[1] = pages
;
1370 devpriv
->hwdmaptr
[1] = virt_to_bus((void *)devpriv
->dmabuf
[1]);
1371 devpriv
->hwdmasize
[1] = PAGE_SIZE
* (1 << pages
);
1376 if (board
->n_aichan
> 0)
1378 if (board
->n_aochan
> 0)
1380 if (board
->n_dichan
> 0)
1382 if (board
->n_dochan
> 0)
1385 ret
= comedi_alloc_subdevices(dev
, n_subdevices
);
1387 free_resources(dev
);
1394 if (board
->n_aichan
> 0) {
1395 s
= dev
->subdevices
+ subdev
;
1396 s
->type
= COMEDI_SUBD_AI
;
1397 s
->subdev_flags
= SDF_READABLE
;
1398 switch (board
->board_type
) {
1400 if (it
->options
[2] == 1) {
1401 s
->n_chan
= board
->n_aichan_diff
;
1402 s
->subdev_flags
|= SDF_DIFF
;
1403 devpriv
->use_diff
= 1;
1405 s
->n_chan
= board
->n_aichan
;
1406 s
->subdev_flags
|= SDF_GROUND
;
1411 if (it
->options
[4] == 1) {
1412 s
->n_chan
= board
->n_aichan_diff
;
1413 s
->subdev_flags
|= SDF_DIFF
;
1414 devpriv
->use_diff
= 1;
1416 s
->n_chan
= board
->n_aichan
;
1417 s
->subdev_flags
|= SDF_GROUND
;
1421 s
->n_chan
= board
->n_aichan
;
1422 s
->subdev_flags
|= SDF_GROUND
;
1425 s
->maxdata
= board
->ai_maxdata
;
1426 s
->len_chanlist
= MAX_CHANLIST_LEN
;
1427 s
->range_table
= board
->rangelist_ai
;
1428 if (board
->board_type
== boardACL8216
)
1429 s
->insn_read
= acl8216_ai_insn_read
;
1431 s
->insn_read
= pcl812_ai_insn_read
;
1433 devpriv
->use_MPC
= board
->haveMPC508
;
1434 s
->cancel
= pcl812_ai_cancel
;
1436 dev
->read_subdev
= s
;
1437 s
->subdev_flags
|= SDF_CMD_READ
;
1438 s
->do_cmdtest
= pcl812_ai_cmdtest
;
1439 s
->do_cmd
= pcl812_ai_cmd
;
1440 s
->poll
= pcl812_ai_poll
;
1442 switch (board
->board_type
) {
1444 if (it
->options
[4] == 1)
1445 s
->range_table
= &range_pcl812pg2_ai
;
1448 switch (it
->options
[4]) {
1450 s
->range_table
= &range_bipolar10
;
1453 s
->range_table
= &range_bipolar5
;
1456 s
->range_table
= &range_bipolar2_5
;
1459 s
->range_table
= &range812_bipolar1_25
;
1462 s
->range_table
= &range812_bipolar0_625
;
1465 s
->range_table
= &range812_bipolar0_3125
;
1468 s
->range_table
= &range_bipolar10
;
1471 (", incorrect range number %d, changing "
1472 "to 0 (+/-10V)", it
->options
[4]);
1478 if (it
->options
[1] == 1)
1479 s
->range_table
= &range_pcl813b2_ai
;
1482 switch (it
->options
[1]) {
1484 s
->range_table
= &range_iso813_1_ai
;
1487 s
->range_table
= &range_iso813_1_2_ai
;
1490 s
->range_table
= &range_iso813_2_ai
;
1491 devpriv
->range_correction
= 1;
1494 s
->range_table
= &range_iso813_2_2_ai
;
1495 devpriv
->range_correction
= 1;
1498 s
->range_table
= &range_iso813_1_ai
;
1501 (", incorrect range number %d, "
1502 "changing to 0 ", it
->options
[1]);
1507 switch (it
->options
[1]) {
1509 s
->range_table
= &range_acl8113_1_ai
;
1512 s
->range_table
= &range_acl8113_1_2_ai
;
1515 s
->range_table
= &range_acl8113_2_ai
;
1516 devpriv
->range_correction
= 1;
1519 s
->range_table
= &range_acl8113_2_2_ai
;
1520 devpriv
->range_correction
= 1;
1523 s
->range_table
= &range_acl8113_1_ai
;
1526 (", incorrect range number %d, "
1527 "changing to 0 ", it
->options
[1]);
1536 if (board
->n_aochan
> 0) {
1537 s
= dev
->subdevices
+ subdev
;
1538 s
->type
= COMEDI_SUBD_AO
;
1539 s
->subdev_flags
= SDF_WRITABLE
| SDF_GROUND
;
1540 s
->n_chan
= board
->n_aochan
;
1542 s
->len_chanlist
= 1;
1543 s
->range_table
= board
->rangelist_ao
;
1544 s
->insn_read
= pcl812_ao_insn_read
;
1545 s
->insn_write
= pcl812_ao_insn_write
;
1546 switch (board
->board_type
) {
1548 if (it
->options
[3] == 1)
1549 s
->range_table
= &range_unipolar10
;
1555 if (it
->options
[5] == 1)
1556 s
->range_table
= &range_unipolar10
;
1557 if (it
->options
[5] == 2)
1558 s
->range_table
= &range_unknown
;
1565 if (board
->n_dichan
> 0) {
1566 s
= dev
->subdevices
+ subdev
;
1567 s
->type
= COMEDI_SUBD_DI
;
1568 s
->subdev_flags
= SDF_READABLE
;
1569 s
->n_chan
= board
->n_dichan
;
1571 s
->len_chanlist
= board
->n_dichan
;
1572 s
->range_table
= &range_digital
;
1573 s
->insn_bits
= pcl812_di_insn_bits
;
1577 /* digital output */
1578 if (board
->n_dochan
> 0) {
1579 s
= dev
->subdevices
+ subdev
;
1580 s
->type
= COMEDI_SUBD_DO
;
1581 s
->subdev_flags
= SDF_WRITABLE
;
1582 s
->n_chan
= board
->n_dochan
;
1584 s
->len_chanlist
= board
->n_dochan
;
1585 s
->range_table
= &range_digital
;
1586 s
->insn_bits
= pcl812_do_insn_bits
;
1590 switch (board
->board_type
) {
1592 devpriv
->ai_is16b
= 1;
1596 devpriv
->max_812_ai_mode0_rangewait
= 1;
1597 if (it
->options
[3] > 0)
1598 /* we use external trigger */
1599 devpriv
->use_ext_trg
= 1;
1601 devpriv
->max_812_ai_mode0_rangewait
= 1;
1602 devpriv
->mode_reg_int
= (irq
<< 4) & 0xf0;
1608 /* maybe there must by greatest timeout */
1609 devpriv
->max_812_ai_mode0_rangewait
= 5;
1613 printk(KERN_INFO
"\n");
1621 static void pcl812_detach(struct comedi_device
*dev
)
1623 free_resources(dev
);
1626 static const struct pcl812_board boardtypes
[] = {
1627 {"pcl812", boardPCL812
, 16, 0, 2, 16, 16, 0x0fff,
1628 33000, 500, &range_bipolar10
, &range_unipolar5
,
1629 0xdcfc, 0x0a, PCLx1x_IORANGE
, 0},
1630 {"pcl812pg", boardPCL812PG
, 16, 0, 2, 16, 16, 0x0fff,
1631 33000, 500, &range_pcl812pg_ai
, &range_unipolar5
,
1632 0xdcfc, 0x0a, PCLx1x_IORANGE
, 0},
1633 {"acl8112pg", boardPCL812PG
, 16, 0, 2, 16, 16, 0x0fff,
1634 10000, 500, &range_pcl812pg_ai
, &range_unipolar5
,
1635 0xdcfc, 0x0a, PCLx1x_IORANGE
, 0},
1636 {"acl8112dg", boardACL8112
, 16, 8, 2, 16, 16, 0x0fff,
1637 10000, 500, &range_acl8112dg_ai
, &range_unipolar5
,
1638 0xdcfc, 0x0a, PCLx1x_IORANGE
, 1},
1639 {"acl8112hg", boardACL8112
, 16, 8, 2, 16, 16, 0x0fff,
1640 10000, 500, &range_acl8112hg_ai
, &range_unipolar5
,
1641 0xdcfc, 0x0a, PCLx1x_IORANGE
, 1},
1642 {"a821pgl", boardA821
, 16, 8, 1, 16, 16, 0x0fff,
1643 10000, 500, &range_pcl813b_ai
, &range_unipolar5
,
1644 0x000c, 0x00, PCLx1x_IORANGE
, 0},
1645 {"a821pglnda", boardA821
, 16, 8, 0, 0, 0, 0x0fff,
1646 10000, 500, &range_pcl813b_ai
, NULL
,
1647 0x000c, 0x00, PCLx1x_IORANGE
, 0},
1648 {"a821pgh", boardA821
, 16, 8, 1, 16, 16, 0x0fff,
1649 10000, 500, &range_a821pgh_ai
, &range_unipolar5
,
1650 0x000c, 0x00, PCLx1x_IORANGE
, 0},
1651 {"a822pgl", boardACL8112
, 16, 8, 2, 16, 16, 0x0fff,
1652 10000, 500, &range_acl8112dg_ai
, &range_unipolar5
,
1653 0xdcfc, 0x0a, PCLx1x_IORANGE
, 0},
1654 {"a822pgh", boardACL8112
, 16, 8, 2, 16, 16, 0x0fff,
1655 10000, 500, &range_acl8112hg_ai
, &range_unipolar5
,
1656 0xdcfc, 0x0a, PCLx1x_IORANGE
, 0},
1657 {"a823pgl", boardACL8112
, 16, 8, 2, 16, 16, 0x0fff,
1658 8000, 500, &range_acl8112dg_ai
, &range_unipolar5
,
1659 0xdcfc, 0x0a, PCLx1x_IORANGE
, 0},
1660 {"a823pgh", boardACL8112
, 16, 8, 2, 16, 16, 0x0fff,
1661 8000, 500, &range_acl8112hg_ai
, &range_unipolar5
,
1662 0xdcfc, 0x0a, PCLx1x_IORANGE
, 0},
1663 {"pcl813", boardPCL813
, 32, 0, 0, 0, 0, 0x0fff,
1664 0, 0, &range_pcl813b_ai
, NULL
,
1665 0x0000, 0x00, PCLx1x_IORANGE
, 0},
1666 {"pcl813b", boardPCL813B
, 32, 0, 0, 0, 0, 0x0fff,
1667 0, 0, &range_pcl813b_ai
, NULL
,
1668 0x0000, 0x00, PCLx1x_IORANGE
, 0},
1669 {"acl8113", boardACL8113
, 32, 0, 0, 0, 0, 0x0fff,
1670 0, 0, &range_acl8113_1_ai
, NULL
,
1671 0x0000, 0x00, PCLx1x_IORANGE
, 0},
1672 {"iso813", boardISO813
, 32, 0, 0, 0, 0, 0x0fff,
1673 0, 0, &range_iso813_1_ai
, NULL
,
1674 0x0000, 0x00, PCLx1x_IORANGE
, 0},
1675 {"acl8216", boardACL8216
, 16, 8, 2, 16, 16, 0xffff,
1676 10000, 500, &range_pcl813b2_ai
, &range_unipolar5
,
1677 0xdcfc, 0x0a, PCLx1x_IORANGE
, 1},
1678 {"a826pg", boardACL8216
, 16, 8, 2, 16, 16, 0xffff,
1679 10000, 500, &range_pcl813b2_ai
, &range_unipolar5
,
1680 0xdcfc, 0x0a, PCLx1x_IORANGE
, 0},
1683 static struct comedi_driver pcl812_driver
= {
1684 .driver_name
= "pcl812",
1685 .module
= THIS_MODULE
,
1686 .attach
= pcl812_attach
,
1687 .detach
= pcl812_detach
,
1688 .board_name
= &boardtypes
[0].name
,
1689 .num_names
= ARRAY_SIZE(boardtypes
),
1690 .offset
= sizeof(struct pcl812_board
),
1692 module_comedi_driver(pcl812_driver
);
1694 MODULE_AUTHOR("Comedi http://www.comedi.org");
1695 MODULE_DESCRIPTION("Comedi low-level driver");
1696 MODULE_LICENSE("GPL");