2 * comedi/drivers/adv_pci1710.c
4 * Author: Michal Dobes <dobes@tesnet.cz>
6 * Thanks to ZhenGang Shang <ZhenGang.Shang@Advantech.com.cn>
7 * for testing and informations.
9 * hardware driver for Advantech cards:
10 * card: PCI-1710, PCI-1710HG, PCI-1711, PCI-1713, PCI-1720, PCI-1731
11 * driver: pci1710, pci1710hg, pci1711, pci1713, pci1720, pci1731
14 * [0] - PCI bus number - if bus number and slot number are 0,
15 * then driver search for first unused card
16 * [1] - PCI slot number
21 Description: Advantech PCI-1710, PCI-1710HG, PCI-1711, PCI-1713,
22 Advantech PCI-1720, PCI-1731
23 Author: Michal Dobes <dobes@tesnet.cz>
24 Devices: [Advantech] PCI-1710 (adv_pci1710), PCI-1710HG (pci1710hg),
25 PCI-1711 (adv_pci1710), PCI-1713, PCI-1720,
29 This driver supports AI, AO, DI and DO subdevices.
30 AI subdevice supports cmd and insn interface,
31 other subdevices support only insn interface.
33 The PCI-1710 and PCI-1710HG have the same PCI device ID, so the
34 driver cannot distinguish between them, as would be normal for a
37 Configuration options:
38 [0] - PCI bus of device (optional)
39 [1] - PCI slot of device (optional)
40 If bus/slot is not specified, the first available PCI
44 #include <linux/module.h>
45 #include <linux/pci.h>
46 #include <linux/interrupt.h>
48 #include "../comedidev.h"
50 #include "comedi_fc.h"
52 #include "amcc_s5933.h"
54 #define PCI171x_AD_DATA 0 /* R: A/D data */
55 #define PCI171x_SOFTTRG 0 /* W: soft trigger for A/D */
56 #define PCI171x_RANGE 2 /* W: A/D gain/range register */
57 #define PCI171x_MUX 4 /* W: A/D multiplexor control */
58 #define PCI171x_STATUS 6 /* R: status register */
59 #define PCI171x_CONTROL 6 /* W: control register */
60 #define PCI171x_CLRINT 8 /* W: clear interrupts request */
61 #define PCI171x_CLRFIFO 9 /* W: clear FIFO */
62 #define PCI171x_DA1 10 /* W: D/A register */
63 #define PCI171x_DA2 12 /* W: D/A register */
64 #define PCI171x_DAREF 14 /* W: D/A reference control */
65 #define PCI171x_DI 16 /* R: digi inputs */
66 #define PCI171x_DO 16 /* R: digi inputs */
68 #define PCI171X_TIMER_BASE 0x18
70 #define PCI171x_CNT0 24 /* R/W: 8254 counter 0 */
71 #define PCI171x_CNT1 26 /* R/W: 8254 counter 1 */
72 #define PCI171x_CNT2 28 /* R/W: 8254 counter 2 */
73 #define PCI171x_CNTCTRL 30 /* W: 8254 counter control */
75 /* upper bits from status register (PCI171x_STATUS) (lower is same with control
77 #define Status_FE 0x0100 /* 1=FIFO is empty */
78 #define Status_FH 0x0200 /* 1=FIFO is half full */
79 #define Status_FF 0x0400 /* 1=FIFO is full, fatal error */
80 #define Status_IRQ 0x0800 /* 1=IRQ occurred */
81 /* bits from control register (PCI171x_CONTROL) */
82 #define Control_CNT0 0x0040 /* 1=CNT0 have external source,
83 * 0=have internal 100kHz source */
84 #define Control_ONEFH 0x0020 /* 1=IRQ on FIFO is half full, 0=every sample */
85 #define Control_IRQEN 0x0010 /* 1=enable IRQ */
86 #define Control_GATE 0x0008 /* 1=enable external trigger GATE (8254?) */
87 #define Control_EXT 0x0004 /* 1=external trigger source */
88 #define Control_PACER 0x0002 /* 1=enable internal 8254 trigger source */
89 #define Control_SW 0x0001 /* 1=enable software trigger source */
90 /* bits from counter control register (PCI171x_CNTCTRL) */
91 #define Counter_BCD 0x0001 /* 0 = binary counter, 1 = BCD counter */
92 #define Counter_M0 0x0002 /* M0-M2 select modes 0-5 */
93 #define Counter_M1 0x0004 /* 000 = mode 0, 010 = mode 2 ... */
94 #define Counter_M2 0x0008
95 #define Counter_RW0 0x0010 /* RW0/RW1 select read/write mode */
96 #define Counter_RW1 0x0020
97 #define Counter_SC0 0x0040 /* Select Counter. Only 00 or 11 may */
98 #define Counter_SC1 0x0080 /* be used, 00 for CNT0,
99 * 11 for read-back command */
101 #define PCI1720_DA0 0 /* W: D/A register 0 */
102 #define PCI1720_DA1 2 /* W: D/A register 1 */
103 #define PCI1720_DA2 4 /* W: D/A register 2 */
104 #define PCI1720_DA3 6 /* W: D/A register 3 */
105 #define PCI1720_RANGE 8 /* R/W: D/A range register */
106 #define PCI1720_SYNCOUT 9 /* W: D/A synchronized output register */
107 #define PCI1720_SYNCONT 15 /* R/W: D/A synchronized control */
109 /* D/A synchronized control (PCI1720_SYNCONT) */
110 #define Syncont_SC0 1 /* set synchronous output mode */
112 static const struct comedi_lrange range_pci1710_3
= {
126 static const char range_codes_pci1710_3
[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
127 0x10, 0x11, 0x12, 0x13 };
129 static const struct comedi_lrange range_pci1710hg
= {
146 static const char range_codes_pci1710hg
[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
147 0x05, 0x06, 0x07, 0x10, 0x11,
150 static const struct comedi_lrange range_pci17x1
= {
160 static const char range_codes_pci17x1
[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
162 static const struct comedi_lrange pci1720_ao_range
= {
171 static const struct comedi_lrange pci171x_ao_range
= {
178 enum pci1710_boardid
{
188 const char *name
; /* board name */
189 int n_aichan
; /* num of A/D chans */
190 const struct comedi_lrange
*rangelist_ai
; /* rangelist for A/D */
191 const char *rangecode_ai
; /* range codes for programming */
192 unsigned int is_pci1713
:1;
193 unsigned int is_pci1720
:1;
194 unsigned int has_irq
:1;
195 unsigned int has_large_fifo
:1; /* 4K or 1K FIFO */
196 unsigned int has_diff_ai
:1;
197 unsigned int has_ao
:1;
198 unsigned int has_di_do
:1;
199 unsigned int has_counter
:1;
202 static const struct boardtype boardtypes
[] = {
206 .rangelist_ai
= &range_pci1710_3
,
207 .rangecode_ai
= range_codes_pci1710_3
,
215 [BOARD_PCI1710HG
] = {
218 .rangelist_ai
= &range_pci1710hg
,
219 .rangecode_ai
= range_codes_pci1710hg
,
230 .rangelist_ai
= &range_pci17x1
,
231 .rangecode_ai
= range_codes_pci17x1
,
240 .rangelist_ai
= &range_pci1710_3
,
241 .rangecode_ai
= range_codes_pci1710_3
,
255 .rangelist_ai
= &range_pci17x1
,
256 .rangecode_ai
= range_codes_pci17x1
,
262 struct pci1710_private
{
263 unsigned int max_samples
;
264 unsigned int CntrlReg
; /* Control register */
266 unsigned int ai_et_CntrlReg
;
267 unsigned int ai_et_MuxVal
;
268 unsigned int next_divisor1
;
269 unsigned int next_divisor2
;
270 unsigned int divisor1
;
271 unsigned int divisor2
;
272 unsigned int act_chanlist
[32]; /* list of scanned channel */
273 unsigned char saved_seglen
; /* len of the non-repeating chanlist */
274 unsigned char da_ranges
; /* copy of D/A outpit range register */
275 unsigned int cnt0_write_wait
; /* after a write, wait for update of the
279 static int pci171x_ai_check_chanlist(struct comedi_device
*dev
,
280 struct comedi_subdevice
*s
,
281 struct comedi_cmd
*cmd
)
283 struct pci1710_private
*devpriv
= dev
->private;
284 unsigned int chan0
= CR_CHAN(cmd
->chanlist
[0]);
285 unsigned int last_aref
= CR_AREF(cmd
->chanlist
[0]);
286 unsigned int next_chan
= (chan0
+ 1) % s
->n_chan
;
287 unsigned int chansegment
[32];
291 if (cmd
->chanlist_len
== 1) {
292 devpriv
->saved_seglen
= cmd
->chanlist_len
;
296 /* first channel is always ok */
297 chansegment
[0] = cmd
->chanlist
[0];
299 for (i
= 1; i
< cmd
->chanlist_len
; i
++) {
300 unsigned int chan
= CR_CHAN(cmd
->chanlist
[i
]);
301 unsigned int aref
= CR_AREF(cmd
->chanlist
[i
]);
303 if (cmd
->chanlist
[0] == cmd
->chanlist
[i
])
304 break; /* we detected a loop, stop */
306 if (aref
== AREF_DIFF
&& (chan
& 1)) {
307 dev_err(dev
->class_dev
,
308 "Odd channel cannot be differential input!\n");
312 if (last_aref
== AREF_DIFF
)
313 next_chan
= (next_chan
+ 1) % s
->n_chan
;
314 if (chan
!= next_chan
) {
315 dev_err(dev
->class_dev
,
316 "channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
317 i
, chan
, next_chan
, chan0
);
321 /* next correct channel in list */
322 chansegment
[i
] = cmd
->chanlist
[i
];
327 for (i
= 0; i
< cmd
->chanlist_len
; i
++) {
328 if (cmd
->chanlist
[i
] != chansegment
[i
% seglen
]) {
329 dev_err(dev
->class_dev
,
330 "bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
331 i
, CR_CHAN(chansegment
[i
]),
332 CR_RANGE(chansegment
[i
]),
333 CR_AREF(chansegment
[i
]),
334 CR_CHAN(cmd
->chanlist
[i
% seglen
]),
335 CR_RANGE(cmd
->chanlist
[i
% seglen
]),
336 CR_AREF(chansegment
[i
% seglen
]));
340 devpriv
->saved_seglen
= seglen
;
345 static void pci171x_ai_setup_chanlist(struct comedi_device
*dev
,
346 struct comedi_subdevice
*s
,
347 unsigned int *chanlist
,
351 const struct boardtype
*board
= dev
->board_ptr
;
352 struct pci1710_private
*devpriv
= dev
->private;
353 unsigned int first_chan
= CR_CHAN(chanlist
[0]);
354 unsigned int last_chan
= CR_CHAN(chanlist
[seglen
- 1]);
357 for (i
= 0; i
< seglen
; i
++) { /* store range list to card */
358 unsigned int chan
= CR_CHAN(chanlist
[i
]);
359 unsigned int range
= CR_RANGE(chanlist
[i
]);
360 unsigned int aref
= CR_AREF(chanlist
[i
]);
361 unsigned int rangeval
;
363 rangeval
= board
->rangecode_ai
[range
];
364 if (aref
== AREF_DIFF
)
367 /* select channel and set range */
368 outw(chan
| (chan
<< 8), dev
->iobase
+ PCI171x_MUX
);
369 outw(rangeval
, dev
->iobase
+ PCI171x_RANGE
);
371 devpriv
->act_chanlist
[i
] = chan
;
373 for ( ; i
< n_chan
; i
++) /* store remainder of channel list */
374 devpriv
->act_chanlist
[i
] = CR_CHAN(chanlist
[i
]);
376 /* select channel interval to scan */
377 devpriv
->ai_et_MuxVal
= first_chan
| (last_chan
<< 8);
378 outw(devpriv
->ai_et_MuxVal
, dev
->iobase
+ PCI171x_MUX
);
381 static int pci171x_ai_eoc(struct comedi_device
*dev
,
382 struct comedi_subdevice
*s
,
383 struct comedi_insn
*insn
,
384 unsigned long context
)
388 status
= inw(dev
->iobase
+ PCI171x_STATUS
);
389 if ((status
& Status_FE
) == 0)
394 static int pci171x_ai_read_sample(struct comedi_device
*dev
,
395 struct comedi_subdevice
*s
,
396 unsigned int cur_chan
,
399 const struct boardtype
*board
= dev
->board_ptr
;
400 struct pci1710_private
*devpriv
= dev
->private;
404 sample
= inw(dev
->iobase
+ PCI171x_AD_DATA
);
405 if (!board
->is_pci1713
) {
407 * The upper 4 bits of the 16-bit sample are the channel number
408 * that the sample was acquired from. Verify that this channel
409 * number matches the expected channel number.
412 if (chan
!= devpriv
->act_chanlist
[cur_chan
]) {
413 dev_err(dev
->class_dev
,
414 "A/D data droput: received from channel %d, expected %d\n",
415 chan
, devpriv
->act_chanlist
[cur_chan
]);
419 *val
= sample
& s
->maxdata
;
423 static int pci171x_ai_insn_read(struct comedi_device
*dev
,
424 struct comedi_subdevice
*s
,
425 struct comedi_insn
*insn
,
428 struct pci1710_private
*devpriv
= dev
->private;
429 unsigned int chan
= CR_CHAN(insn
->chanspec
);
433 devpriv
->CntrlReg
&= Control_CNT0
;
434 devpriv
->CntrlReg
|= Control_SW
; /* set software trigger */
435 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
);
436 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
);
437 outb(0, dev
->iobase
+ PCI171x_CLRINT
);
439 pci171x_ai_setup_chanlist(dev
, s
, &insn
->chanspec
, 1, 1);
441 for (i
= 0; i
< insn
->n
; i
++) {
444 outw(0, dev
->iobase
+ PCI171x_SOFTTRG
); /* start conversion */
446 ret
= comedi_timeout(dev
, s
, insn
, pci171x_ai_eoc
, 0);
450 ret
= pci171x_ai_read_sample(dev
, s
, chan
, &val
);
457 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
);
458 outb(0, dev
->iobase
+ PCI171x_CLRINT
);
460 return ret
? ret
: insn
->n
;
463 static int pci171x_ao_insn_write(struct comedi_device
*dev
,
464 struct comedi_subdevice
*s
,
465 struct comedi_insn
*insn
,
468 struct pci1710_private
*devpriv
= dev
->private;
469 unsigned int chan
= CR_CHAN(insn
->chanspec
);
470 unsigned int range
= CR_RANGE(insn
->chanspec
);
471 unsigned int reg
= chan
? PCI171x_DA2
: PCI171x_DA1
;
472 unsigned int val
= s
->readback
[chan
];
475 devpriv
->da_ranges
&= ~(1 << (chan
<< 1));
476 devpriv
->da_ranges
|= (range
<< (chan
<< 1));
477 outw(devpriv
->da_ranges
, dev
->iobase
+ PCI171x_DAREF
);
479 for (i
= 0; i
< insn
->n
; i
++) {
481 outw(val
, dev
->iobase
+ reg
);
484 s
->readback
[chan
] = val
;
489 static int pci171x_di_insn_bits(struct comedi_device
*dev
,
490 struct comedi_subdevice
*s
,
491 struct comedi_insn
*insn
,
494 data
[1] = inw(dev
->iobase
+ PCI171x_DI
);
499 static int pci171x_do_insn_bits(struct comedi_device
*dev
,
500 struct comedi_subdevice
*s
,
501 struct comedi_insn
*insn
,
504 if (comedi_dio_update_state(s
, data
))
505 outw(s
->state
, dev
->iobase
+ PCI171x_DO
);
512 static void pci171x_start_pacer(struct comedi_device
*dev
,
515 struct pci1710_private
*devpriv
= dev
->private;
516 unsigned long timer_base
= dev
->iobase
+ PCI171X_TIMER_BASE
;
518 i8254_set_mode(timer_base
, 1, 2, I8254_MODE2
| I8254_BINARY
);
519 i8254_set_mode(timer_base
, 1, 1, I8254_MODE2
| I8254_BINARY
);
522 i8254_write(timer_base
, 1, 2, devpriv
->divisor2
);
523 i8254_write(timer_base
, 1, 1, devpriv
->divisor1
);
527 static int pci171x_counter_insn_read(struct comedi_device
*dev
,
528 struct comedi_subdevice
*s
,
529 struct comedi_insn
*insn
,
532 unsigned int msb
, lsb
, ccntrl
;
535 ccntrl
= 0xD2; /* count only */
536 for (i
= 0; i
< insn
->n
; i
++) {
537 outw(ccntrl
, dev
->iobase
+ PCI171x_CNTCTRL
);
539 lsb
= inw(dev
->iobase
+ PCI171x_CNT0
) & 0xFF;
540 msb
= inw(dev
->iobase
+ PCI171x_CNT0
) & 0xFF;
542 data
[0] = lsb
| (msb
<< 8);
548 static int pci171x_counter_insn_write(struct comedi_device
*dev
,
549 struct comedi_subdevice
*s
,
550 struct comedi_insn
*insn
,
553 struct pci1710_private
*devpriv
= dev
->private;
554 uint msb
, lsb
, ccntrl
, status
;
556 lsb
= data
[0] & 0x00FF;
557 msb
= (data
[0] & 0xFF00) >> 8;
559 /* write lsb, then msb */
560 outw(lsb
, dev
->iobase
+ PCI171x_CNT0
);
561 outw(msb
, dev
->iobase
+ PCI171x_CNT0
);
563 if (devpriv
->cnt0_write_wait
) {
564 /* wait for the new count to be loaded */
567 outw(ccntrl
, dev
->iobase
+ PCI171x_CNTCTRL
);
568 status
= inw(dev
->iobase
+ PCI171x_CNT0
) & 0xFF;
569 } while (status
& 0x40);
575 static int pci171x_counter_insn_config(struct comedi_device
*dev
,
576 struct comedi_subdevice
*s
,
577 struct comedi_insn
*insn
,
581 /* This doesn't work like a normal Comedi counter config */
582 struct pci1710_private
*devpriv
= dev
->private;
585 devpriv
->cnt0_write_wait
= data
[0] & 0x20;
587 /* internal or external clock? */
588 if (!(data
[0] & 0x10)) { /* internal */
589 devpriv
->CntrlReg
&= ~Control_CNT0
;
591 devpriv
->CntrlReg
|= Control_CNT0
;
593 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
);
596 ccntrl
|= Counter_M0
;
598 ccntrl
|= Counter_M1
;
600 ccntrl
|= Counter_M2
;
602 ccntrl
|= Counter_BCD
;
603 ccntrl
|= Counter_RW0
; /* set read/write mode */
604 ccntrl
|= Counter_RW1
;
605 outw(ccntrl
, dev
->iobase
+ PCI171x_CNTCTRL
);
611 static int pci1720_ao_insn_write(struct comedi_device
*dev
,
612 struct comedi_subdevice
*s
,
613 struct comedi_insn
*insn
,
616 struct pci1710_private
*devpriv
= dev
->private;
617 unsigned int chan
= CR_CHAN(insn
->chanspec
);
618 unsigned int range
= CR_RANGE(insn
->chanspec
);
622 val
= devpriv
->da_ranges
& (~(0x03 << (chan
<< 1)));
623 val
|= (range
<< (chan
<< 1));
624 if (val
!= devpriv
->da_ranges
) {
625 outb(val
, dev
->iobase
+ PCI1720_RANGE
);
626 devpriv
->da_ranges
= val
;
629 val
= s
->readback
[chan
];
630 for (i
= 0; i
< insn
->n
; i
++) {
632 outw(val
, dev
->iobase
+ PCI1720_DA0
+ (chan
<< 1));
633 outb(0, dev
->iobase
+ PCI1720_SYNCOUT
); /* update outputs */
636 s
->readback
[chan
] = val
;
641 static int pci171x_ai_cancel(struct comedi_device
*dev
,
642 struct comedi_subdevice
*s
)
644 struct pci1710_private
*devpriv
= dev
->private;
646 devpriv
->CntrlReg
&= Control_CNT0
;
647 devpriv
->CntrlReg
|= Control_SW
;
648 /* reset any operations */
649 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
);
650 pci171x_start_pacer(dev
, false);
651 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
);
652 outb(0, dev
->iobase
+ PCI171x_CLRINT
);
657 static void pci1710_handle_every_sample(struct comedi_device
*dev
,
658 struct comedi_subdevice
*s
)
660 struct comedi_cmd
*cmd
= &s
->async
->cmd
;
665 status
= inw(dev
->iobase
+ PCI171x_STATUS
);
666 if (status
& Status_FE
) {
667 dev_dbg(dev
->class_dev
, "A/D FIFO empty (%4x)\n", status
);
668 s
->async
->events
|= COMEDI_CB_ERROR
;
671 if (status
& Status_FF
) {
672 dev_dbg(dev
->class_dev
,
673 "A/D FIFO Full status (Fatal Error!) (%4x)\n", status
);
674 s
->async
->events
|= COMEDI_CB_ERROR
;
678 outb(0, dev
->iobase
+ PCI171x_CLRINT
); /* clear our INT request */
680 for (; !(inw(dev
->iobase
+ PCI171x_STATUS
) & Status_FE
);) {
681 ret
= pci171x_ai_read_sample(dev
, s
, s
->async
->cur_chan
, &val
);
683 s
->async
->events
|= COMEDI_CB_ERROR
;
687 comedi_buf_write_samples(s
, &val
, 1);
689 if (cmd
->stop_src
== TRIG_COUNT
&&
690 s
->async
->scans_done
>= cmd
->stop_arg
) {
691 s
->async
->events
|= COMEDI_CB_EOA
;
696 outb(0, dev
->iobase
+ PCI171x_CLRINT
); /* clear our INT request */
699 static void pci1710_handle_fifo(struct comedi_device
*dev
,
700 struct comedi_subdevice
*s
)
702 struct pci1710_private
*devpriv
= dev
->private;
703 struct comedi_async
*async
= s
->async
;
704 struct comedi_cmd
*cmd
= &async
->cmd
;
708 status
= inw(dev
->iobase
+ PCI171x_STATUS
);
709 if (!(status
& Status_FH
)) {
710 dev_dbg(dev
->class_dev
, "A/D FIFO not half full!\n");
711 async
->events
|= COMEDI_CB_ERROR
;
714 if (status
& Status_FF
) {
715 dev_dbg(dev
->class_dev
,
716 "A/D FIFO Full status (Fatal Error!)\n");
717 async
->events
|= COMEDI_CB_ERROR
;
721 for (i
= 0; i
< devpriv
->max_samples
; i
++) {
725 ret
= pci171x_ai_read_sample(dev
, s
, s
->async
->cur_chan
, &val
);
727 s
->async
->events
|= COMEDI_CB_ERROR
;
731 if (!comedi_buf_write_samples(s
, &val
, 1))
734 if (cmd
->stop_src
== TRIG_COUNT
&&
735 async
->scans_done
>= cmd
->stop_arg
) {
736 async
->events
|= COMEDI_CB_EOA
;
741 outb(0, dev
->iobase
+ PCI171x_CLRINT
); /* clear our INT request */
744 static irqreturn_t
interrupt_service_pci1710(int irq
, void *d
)
746 struct comedi_device
*dev
= d
;
747 struct pci1710_private
*devpriv
= dev
->private;
748 struct comedi_subdevice
*s
;
749 struct comedi_cmd
*cmd
;
751 if (!dev
->attached
) /* is device attached? */
752 return IRQ_NONE
; /* no, exit */
754 s
= dev
->read_subdev
;
755 cmd
= &s
->async
->cmd
;
757 /* is this interrupt from our board? */
758 if (!(inw(dev
->iobase
+ PCI171x_STATUS
) & Status_IRQ
))
759 return IRQ_NONE
; /* no, exit */
761 if (devpriv
->ai_et
) { /* Switch from initial TRIG_EXT to TRIG_xxx. */
763 devpriv
->CntrlReg
&= Control_CNT0
;
764 devpriv
->CntrlReg
|= Control_SW
; /* set software trigger */
765 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
);
766 devpriv
->CntrlReg
= devpriv
->ai_et_CntrlReg
;
767 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
);
768 outb(0, dev
->iobase
+ PCI171x_CLRINT
);
769 outw(devpriv
->ai_et_MuxVal
, dev
->iobase
+ PCI171x_MUX
);
770 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
);
771 pci171x_start_pacer(dev
, true);
775 if (cmd
->flags
& CMDF_WAKE_EOS
)
776 pci1710_handle_every_sample(dev
, s
);
778 pci1710_handle_fifo(dev
, s
);
780 comedi_handle_events(dev
, s
);
785 static int pci171x_ai_cmd(struct comedi_device
*dev
, struct comedi_subdevice
*s
)
787 struct pci1710_private
*devpriv
= dev
->private;
788 struct comedi_cmd
*cmd
= &s
->async
->cmd
;
790 pci171x_start_pacer(dev
, false);
792 pci171x_ai_setup_chanlist(dev
, s
, cmd
->chanlist
, cmd
->chanlist_len
,
793 devpriv
->saved_seglen
);
795 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
);
796 outb(0, dev
->iobase
+ PCI171x_CLRINT
);
798 devpriv
->CntrlReg
&= Control_CNT0
;
799 if ((cmd
->flags
& CMDF_WAKE_EOS
) == 0)
800 devpriv
->CntrlReg
|= Control_ONEFH
;
802 devpriv
->divisor1
= devpriv
->next_divisor1
;
803 devpriv
->divisor2
= devpriv
->next_divisor2
;
805 if (cmd
->convert_src
== TRIG_TIMER
) {
806 devpriv
->CntrlReg
|= Control_PACER
| Control_IRQEN
;
807 if (cmd
->start_src
== TRIG_EXT
) {
808 devpriv
->ai_et_CntrlReg
= devpriv
->CntrlReg
;
810 ~(Control_PACER
| Control_ONEFH
| Control_GATE
);
811 devpriv
->CntrlReg
|= Control_EXT
;
813 } else { /* TRIG_NOW */
816 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
);
818 if (cmd
->start_src
== TRIG_NOW
)
819 pci171x_start_pacer(dev
, true);
820 } else { /* TRIG_EXT */
821 devpriv
->CntrlReg
|= Control_EXT
| Control_IRQEN
;
822 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
);
828 static int pci171x_ai_cmdtest(struct comedi_device
*dev
,
829 struct comedi_subdevice
*s
,
830 struct comedi_cmd
*cmd
)
832 struct pci1710_private
*devpriv
= dev
->private;
836 /* Step 1 : check if triggers are trivially valid */
838 err
|= cfc_check_trigger_src(&cmd
->start_src
, TRIG_NOW
| TRIG_EXT
);
839 err
|= cfc_check_trigger_src(&cmd
->scan_begin_src
, TRIG_FOLLOW
);
840 err
|= cfc_check_trigger_src(&cmd
->convert_src
, TRIG_TIMER
| TRIG_EXT
);
841 err
|= cfc_check_trigger_src(&cmd
->scan_end_src
, TRIG_COUNT
);
842 err
|= cfc_check_trigger_src(&cmd
->stop_src
, TRIG_COUNT
| TRIG_NONE
);
847 /* step 2a: make sure trigger sources are unique */
849 err
|= cfc_check_trigger_is_unique(cmd
->start_src
);
850 err
|= cfc_check_trigger_is_unique(cmd
->convert_src
);
851 err
|= cfc_check_trigger_is_unique(cmd
->stop_src
);
853 /* step 2b: and mutually compatible */
858 /* Step 3: check if arguments are trivially valid */
860 err
|= cfc_check_trigger_arg_is(&cmd
->start_arg
, 0);
861 err
|= cfc_check_trigger_arg_is(&cmd
->scan_begin_arg
, 0);
863 if (cmd
->convert_src
== TRIG_TIMER
)
864 err
|= cfc_check_trigger_arg_min(&cmd
->convert_arg
, 10000);
865 else /* TRIG_FOLLOW */
866 err
|= cfc_check_trigger_arg_is(&cmd
->convert_arg
, 0);
868 err
|= cfc_check_trigger_arg_is(&cmd
->scan_end_arg
, cmd
->chanlist_len
);
870 if (cmd
->stop_src
== TRIG_COUNT
)
871 err
|= cfc_check_trigger_arg_min(&cmd
->stop_arg
, 1);
873 err
|= cfc_check_trigger_arg_is(&cmd
->stop_arg
, 0);
878 /* step 4: fix up any arguments */
880 if (cmd
->convert_src
== TRIG_TIMER
) {
881 arg
= cmd
->convert_arg
;
882 i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ
,
883 &devpriv
->next_divisor1
,
884 &devpriv
->next_divisor2
,
886 err
|= cfc_check_trigger_arg_is(&cmd
->convert_arg
, arg
);
892 /* Step 5: check channel list */
894 err
|= pci171x_ai_check_chanlist(dev
, s
, cmd
);
902 static int pci171x_reset(struct comedi_device
*dev
)
904 const struct boardtype
*board
= dev
->board_ptr
;
905 struct pci1710_private
*devpriv
= dev
->private;
907 outw(0x30, dev
->iobase
+ PCI171x_CNTCTRL
);
908 /* Software trigger, CNT0=external */
909 devpriv
->CntrlReg
= Control_SW
| Control_CNT0
;
910 /* reset any operations */
911 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
);
912 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
); /* clear FIFO */
913 outb(0, dev
->iobase
+ PCI171x_CLRINT
); /* clear INT request */
914 pci171x_start_pacer(dev
, false);
915 devpriv
->da_ranges
= 0;
917 /* set DACs to 0..5V */
918 outb(devpriv
->da_ranges
, dev
->iobase
+ PCI171x_DAREF
);
919 outw(0, dev
->iobase
+ PCI171x_DA1
); /* set DA outputs to 0V */
920 outw(0, dev
->iobase
+ PCI171x_DA2
);
922 outw(0, dev
->iobase
+ PCI171x_DO
); /* digital outputs to 0 */
923 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
); /* clear FIFO */
924 outb(0, dev
->iobase
+ PCI171x_CLRINT
); /* clear INT request */
929 static int pci1720_reset(struct comedi_device
*dev
)
931 struct pci1710_private
*devpriv
= dev
->private;
932 /* set synchronous output mode */
933 outb(Syncont_SC0
, dev
->iobase
+ PCI1720_SYNCONT
);
934 devpriv
->da_ranges
= 0xAA;
935 /* set all ranges to +/-5V */
936 outb(devpriv
->da_ranges
, dev
->iobase
+ PCI1720_RANGE
);
937 outw(0x0800, dev
->iobase
+ PCI1720_DA0
); /* set outputs to 0V */
938 outw(0x0800, dev
->iobase
+ PCI1720_DA1
);
939 outw(0x0800, dev
->iobase
+ PCI1720_DA2
);
940 outw(0x0800, dev
->iobase
+ PCI1720_DA3
);
941 outb(0, dev
->iobase
+ PCI1720_SYNCOUT
); /* update outputs */
946 static int pci1710_reset(struct comedi_device
*dev
)
948 const struct boardtype
*board
= dev
->board_ptr
;
950 if (board
->is_pci1720
)
951 return pci1720_reset(dev
);
953 return pci171x_reset(dev
);
956 static int pci1710_auto_attach(struct comedi_device
*dev
,
957 unsigned long context
)
959 struct pci_dev
*pcidev
= comedi_to_pci_dev(dev
);
960 const struct boardtype
*board
= NULL
;
961 struct pci1710_private
*devpriv
;
962 struct comedi_subdevice
*s
;
963 int ret
, subdev
, n_subdevices
;
965 if (context
< ARRAY_SIZE(boardtypes
))
966 board
= &boardtypes
[context
];
969 dev
->board_ptr
= board
;
970 dev
->board_name
= board
->name
;
972 devpriv
= comedi_alloc_devpriv(dev
, sizeof(*devpriv
));
976 ret
= comedi_pci_enable(dev
);
979 dev
->iobase
= pci_resource_start(pcidev
, 2);
986 if (board
->has_di_do
)
988 if (board
->has_counter
)
991 ret
= comedi_alloc_subdevices(dev
, n_subdevices
);
997 if (board
->has_irq
&& pcidev
->irq
) {
998 ret
= request_irq(pcidev
->irq
, interrupt_service_pci1710
,
999 IRQF_SHARED
, dev
->board_name
, dev
);
1001 dev
->irq
= pcidev
->irq
;
1006 if (board
->n_aichan
) {
1007 s
= &dev
->subdevices
[subdev
];
1008 s
->type
= COMEDI_SUBD_AI
;
1009 s
->subdev_flags
= SDF_READABLE
| SDF_COMMON
| SDF_GROUND
;
1010 if (board
->has_diff_ai
)
1011 s
->subdev_flags
|= SDF_DIFF
;
1012 s
->n_chan
= board
->n_aichan
;
1013 s
->maxdata
= 0x0fff;
1014 s
->range_table
= board
->rangelist_ai
;
1015 s
->insn_read
= pci171x_ai_insn_read
;
1017 dev
->read_subdev
= s
;
1018 s
->subdev_flags
|= SDF_CMD_READ
;
1019 s
->len_chanlist
= s
->n_chan
;
1020 s
->do_cmdtest
= pci171x_ai_cmdtest
;
1021 s
->do_cmd
= pci171x_ai_cmd
;
1022 s
->cancel
= pci171x_ai_cancel
;
1027 if (board
->has_ao
) {
1028 s
= &dev
->subdevices
[subdev
];
1029 s
->type
= COMEDI_SUBD_AO
;
1030 s
->subdev_flags
= SDF_WRITABLE
| SDF_GROUND
| SDF_COMMON
;
1031 s
->maxdata
= 0x0fff;
1032 if (board
->is_pci1720
) {
1034 s
->range_table
= &pci1720_ao_range
;
1035 s
->insn_write
= pci1720_ao_insn_write
;
1038 s
->range_table
= &pci171x_ao_range
;
1039 s
->insn_write
= pci171x_ao_insn_write
;
1042 ret
= comedi_alloc_subdev_readback(s
);
1046 /* initialize the readback values to match the board reset */
1047 if (board
->is_pci1720
) {
1050 for (i
= 0; i
< s
->n_chan
; i
++)
1051 s
->readback
[i
] = 0x0800;
1057 if (board
->has_di_do
) {
1058 s
= &dev
->subdevices
[subdev
];
1059 s
->type
= COMEDI_SUBD_DI
;
1060 s
->subdev_flags
= SDF_READABLE
;
1063 s
->range_table
= &range_digital
;
1064 s
->insn_bits
= pci171x_di_insn_bits
;
1067 s
= &dev
->subdevices
[subdev
];
1068 s
->type
= COMEDI_SUBD_DO
;
1069 s
->subdev_flags
= SDF_WRITABLE
;
1072 s
->range_table
= &range_digital
;
1073 s
->insn_bits
= pci171x_do_insn_bits
;
1077 if (board
->has_counter
) {
1078 s
= &dev
->subdevices
[subdev
];
1079 s
->type
= COMEDI_SUBD_COUNTER
;
1080 s
->subdev_flags
= SDF_READABLE
| SDF_WRITABLE
;
1082 s
->maxdata
= 0xffff;
1083 s
->range_table
= &range_unknown
;
1084 s
->insn_read
= pci171x_counter_insn_read
;
1085 s
->insn_write
= pci171x_counter_insn_write
;
1086 s
->insn_config
= pci171x_counter_insn_config
;
1090 /* max_samples is half the FIFO size (2 bytes/sample) */
1091 devpriv
->max_samples
= (board
->has_large_fifo
) ? 2048 : 512;
1096 static void pci1710_detach(struct comedi_device
*dev
)
1100 comedi_pci_detach(dev
);
1103 static struct comedi_driver adv_pci1710_driver
= {
1104 .driver_name
= "adv_pci1710",
1105 .module
= THIS_MODULE
,
1106 .auto_attach
= pci1710_auto_attach
,
1107 .detach
= pci1710_detach
,
1110 static int adv_pci1710_pci_probe(struct pci_dev
*dev
,
1111 const struct pci_device_id
*id
)
1113 return comedi_pci_auto_config(dev
, &adv_pci1710_driver
,
1117 static const struct pci_device_id adv_pci1710_pci_table
[] = {
1119 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
1120 PCI_VENDOR_ID_PLX
, PCI_DEVICE_ID_PLX_9050
),
1121 .driver_data
= BOARD_PCI1710
,
1123 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
1124 PCI_VENDOR_ID_ADVANTECH
, 0x0000),
1125 .driver_data
= BOARD_PCI1710
,
1127 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
1128 PCI_VENDOR_ID_ADVANTECH
, 0xb100),
1129 .driver_data
= BOARD_PCI1710
,
1131 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
1132 PCI_VENDOR_ID_ADVANTECH
, 0xb200),
1133 .driver_data
= BOARD_PCI1710
,
1135 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
1136 PCI_VENDOR_ID_ADVANTECH
, 0xc100),
1137 .driver_data
= BOARD_PCI1710
,
1139 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
1140 PCI_VENDOR_ID_ADVANTECH
, 0xc200),
1141 .driver_data
= BOARD_PCI1710
,
1143 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710, 0x1000, 0xd100),
1144 .driver_data
= BOARD_PCI1710
,
1146 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
1147 PCI_VENDOR_ID_ADVANTECH
, 0x0002),
1148 .driver_data
= BOARD_PCI1710HG
,
1150 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
1151 PCI_VENDOR_ID_ADVANTECH
, 0xb102),
1152 .driver_data
= BOARD_PCI1710HG
,
1154 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
1155 PCI_VENDOR_ID_ADVANTECH
, 0xb202),
1156 .driver_data
= BOARD_PCI1710HG
,
1158 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
1159 PCI_VENDOR_ID_ADVANTECH
, 0xc102),
1160 .driver_data
= BOARD_PCI1710HG
,
1162 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
1163 PCI_VENDOR_ID_ADVANTECH
, 0xc202),
1164 .driver_data
= BOARD_PCI1710HG
,
1166 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710, 0x1000, 0xd102),
1167 .driver_data
= BOARD_PCI1710HG
,
1169 { PCI_VDEVICE(ADVANTECH
, 0x1711), BOARD_PCI1711
},
1170 { PCI_VDEVICE(ADVANTECH
, 0x1713), BOARD_PCI1713
},
1171 { PCI_VDEVICE(ADVANTECH
, 0x1720), BOARD_PCI1720
},
1172 { PCI_VDEVICE(ADVANTECH
, 0x1731), BOARD_PCI1731
},
1175 MODULE_DEVICE_TABLE(pci
, adv_pci1710_pci_table
);
1177 static struct pci_driver adv_pci1710_pci_driver
= {
1178 .name
= "adv_pci1710",
1179 .id_table
= adv_pci1710_pci_table
,
1180 .probe
= adv_pci1710_pci_probe
,
1181 .remove
= comedi_pci_auto_unconfig
,
1183 module_comedi_pci_driver(adv_pci1710_driver
, adv_pci1710_pci_driver
);
1185 MODULE_AUTHOR("Comedi http://www.comedi.org");
1186 MODULE_DESCRIPTION("Comedi: Advantech PCI-1710 Series Multifunction DAS Cards");
1187 MODULE_LICENSE("GPL");