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");