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;
432 devpriv->CntrlReg &= Control_CNT0;
433 devpriv->CntrlReg |= Control_SW; /* set software trigger */
434 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
435 outb(0, dev->iobase + PCI171x_CLRFIFO);
436 outb(0, dev->iobase + PCI171x_CLRINT);
438 pci171x_ai_setup_chanlist(dev, s, &insn->chanspec, 1, 1);
440 for (i = 0; i < insn->n; i++) {
443 outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */
445 ret = comedi_timeout(dev, s, insn, pci171x_ai_eoc, 0);
449 ret = pci171x_ai_read_sample(dev, s, 0, &val);
456 outb(0, dev->iobase + PCI171x_CLRFIFO);
457 outb(0, dev->iobase + PCI171x_CLRINT);
459 return ret ? ret : insn->n;
462 static int pci171x_ao_insn_write(struct comedi_device *dev,
463 struct comedi_subdevice *s,
464 struct comedi_insn *insn,
467 struct pci1710_private *devpriv = dev->private;
468 unsigned int chan = CR_CHAN(insn->chanspec);
469 unsigned int range = CR_RANGE(insn->chanspec);
470 unsigned int reg = chan ? PCI171x_DA2 : PCI171x_DA1;
471 unsigned int val = s->readback[chan];
474 devpriv->da_ranges &= ~(1 << (chan << 1));
475 devpriv->da_ranges |= (range << (chan << 1));
476 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
478 for (i = 0; i < insn->n; i++) {
480 outw(val, dev->iobase + reg);
483 s->readback[chan] = val;
488 static int pci171x_di_insn_bits(struct comedi_device *dev,
489 struct comedi_subdevice *s,
490 struct comedi_insn *insn,
493 data[1] = inw(dev->iobase + PCI171x_DI);
498 static int pci171x_do_insn_bits(struct comedi_device *dev,
499 struct comedi_subdevice *s,
500 struct comedi_insn *insn,
503 if (comedi_dio_update_state(s, data))
504 outw(s->state, dev->iobase + PCI171x_DO);
511 static void pci171x_start_pacer(struct comedi_device *dev,
514 struct pci1710_private *devpriv = dev->private;
515 unsigned long timer_base = dev->iobase + PCI171X_TIMER_BASE;
517 i8254_set_mode(timer_base, 1, 2, I8254_MODE2 | I8254_BINARY);
518 i8254_set_mode(timer_base, 1, 1, I8254_MODE2 | I8254_BINARY);
521 i8254_write(timer_base, 1, 2, devpriv->divisor2);
522 i8254_write(timer_base, 1, 1, devpriv->divisor1);
526 static int pci171x_counter_insn_read(struct comedi_device *dev,
527 struct comedi_subdevice *s,
528 struct comedi_insn *insn,
531 unsigned int msb, lsb, ccntrl;
534 ccntrl = 0xD2; /* count only */
535 for (i = 0; i < insn->n; i++) {
536 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
538 lsb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
539 msb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
541 data[0] = lsb | (msb << 8);
547 static int pci171x_counter_insn_write(struct comedi_device *dev,
548 struct comedi_subdevice *s,
549 struct comedi_insn *insn,
552 struct pci1710_private *devpriv = dev->private;
553 uint msb, lsb, ccntrl, status;
555 lsb = data[0] & 0x00FF;
556 msb = (data[0] & 0xFF00) >> 8;
558 /* write lsb, then msb */
559 outw(lsb, dev->iobase + PCI171x_CNT0);
560 outw(msb, dev->iobase + PCI171x_CNT0);
562 if (devpriv->cnt0_write_wait) {
563 /* wait for the new count to be loaded */
566 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
567 status = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
568 } while (status & 0x40);
574 static int pci171x_counter_insn_config(struct comedi_device *dev,
575 struct comedi_subdevice *s,
576 struct comedi_insn *insn,
580 /* This doesn't work like a normal Comedi counter config */
581 struct pci1710_private *devpriv = dev->private;
584 devpriv->cnt0_write_wait = data[0] & 0x20;
586 /* internal or external clock? */
587 if (!(data[0] & 0x10)) { /* internal */
588 devpriv->CntrlReg &= ~Control_CNT0;
590 devpriv->CntrlReg |= Control_CNT0;
592 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
595 ccntrl |= Counter_M0;
597 ccntrl |= Counter_M1;
599 ccntrl |= Counter_M2;
601 ccntrl |= Counter_BCD;
602 ccntrl |= Counter_RW0; /* set read/write mode */
603 ccntrl |= Counter_RW1;
604 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
610 static int pci1720_ao_insn_write(struct comedi_device *dev,
611 struct comedi_subdevice *s,
612 struct comedi_insn *insn,
615 struct pci1710_private *devpriv = dev->private;
616 unsigned int chan = CR_CHAN(insn->chanspec);
617 unsigned int range = CR_RANGE(insn->chanspec);
621 val = devpriv->da_ranges & (~(0x03 << (chan << 1)));
622 val |= (range << (chan << 1));
623 if (val != devpriv->da_ranges) {
624 outb(val, dev->iobase + PCI1720_RANGE);
625 devpriv->da_ranges = val;
628 val = s->readback[chan];
629 for (i = 0; i < insn->n; i++) {
631 outw(val, dev->iobase + PCI1720_DA0 + (chan << 1));
632 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
635 s->readback[chan] = val;
640 static int pci171x_ai_cancel(struct comedi_device *dev,
641 struct comedi_subdevice *s)
643 struct pci1710_private *devpriv = dev->private;
645 devpriv->CntrlReg &= Control_CNT0;
646 devpriv->CntrlReg |= Control_SW;
647 /* reset any operations */
648 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
649 pci171x_start_pacer(dev, false);
650 outb(0, dev->iobase + PCI171x_CLRFIFO);
651 outb(0, dev->iobase + PCI171x_CLRINT);
656 static void pci1710_handle_every_sample(struct comedi_device *dev,
657 struct comedi_subdevice *s)
659 struct comedi_cmd *cmd = &s->async->cmd;
664 status = inw(dev->iobase + PCI171x_STATUS);
665 if (status & Status_FE) {
666 dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", status);
667 s->async->events |= COMEDI_CB_ERROR;
670 if (status & Status_FF) {
671 dev_dbg(dev->class_dev,
672 "A/D FIFO Full status (Fatal Error!) (%4x)\n", status);
673 s->async->events |= COMEDI_CB_ERROR;
677 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
679 for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
680 ret = pci171x_ai_read_sample(dev, s, s->async->cur_chan, &val);
682 s->async->events |= COMEDI_CB_ERROR;
686 comedi_buf_write_samples(s, &val, 1);
688 if (cmd->stop_src == TRIG_COUNT &&
689 s->async->scans_done >= cmd->stop_arg) {
690 s->async->events |= COMEDI_CB_EOA;
695 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
698 static void pci1710_handle_fifo(struct comedi_device *dev,
699 struct comedi_subdevice *s)
701 struct pci1710_private *devpriv = dev->private;
702 struct comedi_async *async = s->async;
703 struct comedi_cmd *cmd = &async->cmd;
707 status = inw(dev->iobase + PCI171x_STATUS);
708 if (!(status & Status_FH)) {
709 dev_dbg(dev->class_dev, "A/D FIFO not half full!\n");
710 async->events |= COMEDI_CB_ERROR;
713 if (status & Status_FF) {
714 dev_dbg(dev->class_dev,
715 "A/D FIFO Full status (Fatal Error!)\n");
716 async->events |= COMEDI_CB_ERROR;
720 for (i = 0; i < devpriv->max_samples; i++) {
724 ret = pci171x_ai_read_sample(dev, s, s->async->cur_chan, &val);
726 s->async->events |= COMEDI_CB_ERROR;
730 if (!comedi_buf_write_samples(s, &val, 1))
733 if (cmd->stop_src == TRIG_COUNT &&
734 async->scans_done >= cmd->stop_arg) {
735 async->events |= COMEDI_CB_EOA;
740 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
743 static irqreturn_t interrupt_service_pci1710(int irq, void *d)
745 struct comedi_device *dev = d;
746 struct pci1710_private *devpriv = dev->private;
747 struct comedi_subdevice *s;
748 struct comedi_cmd *cmd;
750 if (!dev->attached) /* is device attached? */
751 return IRQ_NONE; /* no, exit */
753 s = dev->read_subdev;
754 cmd = &s->async->cmd;
756 /* is this interrupt from our board? */
757 if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))
758 return IRQ_NONE; /* no, exit */
760 if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */
762 devpriv->CntrlReg &= Control_CNT0;
763 devpriv->CntrlReg |= Control_SW; /* set software trigger */
764 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
765 devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
766 outb(0, dev->iobase + PCI171x_CLRFIFO);
767 outb(0, dev->iobase + PCI171x_CLRINT);
768 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
769 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
770 pci171x_start_pacer(dev, true);
774 if (cmd->flags & CMDF_WAKE_EOS)
775 pci1710_handle_every_sample(dev, s);
777 pci1710_handle_fifo(dev, s);
779 comedi_handle_events(dev, s);
784 static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
786 struct pci1710_private *devpriv = dev->private;
787 struct comedi_cmd *cmd = &s->async->cmd;
789 pci171x_start_pacer(dev, false);
791 pci171x_ai_setup_chanlist(dev, s, cmd->chanlist, cmd->chanlist_len,
792 devpriv->saved_seglen);
794 outb(0, dev->iobase + PCI171x_CLRFIFO);
795 outb(0, dev->iobase + PCI171x_CLRINT);
797 devpriv->CntrlReg &= Control_CNT0;
798 if ((cmd->flags & CMDF_WAKE_EOS) == 0)
799 devpriv->CntrlReg |= Control_ONEFH;
801 devpriv->divisor1 = devpriv->next_divisor1;
802 devpriv->divisor2 = devpriv->next_divisor2;
804 if (cmd->convert_src == TRIG_TIMER) {
805 devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
806 if (cmd->start_src == TRIG_EXT) {
807 devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
809 ~(Control_PACER | Control_ONEFH | Control_GATE);
810 devpriv->CntrlReg |= Control_EXT;
812 } else { /* TRIG_NOW */
815 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
817 if (cmd->start_src == TRIG_NOW)
818 pci171x_start_pacer(dev, true);
819 } else { /* TRIG_EXT */
820 devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
821 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
827 static int pci171x_ai_cmdtest(struct comedi_device *dev,
828 struct comedi_subdevice *s,
829 struct comedi_cmd *cmd)
831 struct pci1710_private *devpriv = dev->private;
835 /* Step 1 : check if triggers are trivially valid */
837 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
838 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
839 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
840 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
841 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
846 /* step 2a: make sure trigger sources are unique */
848 err |= cfc_check_trigger_is_unique(cmd->start_src);
849 err |= cfc_check_trigger_is_unique(cmd->convert_src);
850 err |= cfc_check_trigger_is_unique(cmd->stop_src);
852 /* step 2b: and mutually compatible */
857 /* Step 3: check if arguments are trivially valid */
859 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
860 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
862 if (cmd->convert_src == TRIG_TIMER)
863 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000);
864 else /* TRIG_FOLLOW */
865 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
867 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
869 if (cmd->stop_src == TRIG_COUNT)
870 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
872 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
877 /* step 4: fix up any arguments */
879 if (cmd->convert_src == TRIG_TIMER) {
880 arg = cmd->convert_arg;
881 i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
882 &devpriv->next_divisor1,
883 &devpriv->next_divisor2,
885 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
891 /* Step 5: check channel list */
893 err |= pci171x_ai_check_chanlist(dev, s, cmd);
901 static int pci171x_reset(struct comedi_device *dev)
903 const struct boardtype *board = dev->board_ptr;
904 struct pci1710_private *devpriv = dev->private;
906 outw(0x30, dev->iobase + PCI171x_CNTCTRL);
907 /* Software trigger, CNT0=external */
908 devpriv->CntrlReg = Control_SW | Control_CNT0;
909 /* reset any operations */
910 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
911 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
912 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
913 pci171x_start_pacer(dev, false);
914 devpriv->da_ranges = 0;
916 /* set DACs to 0..5V */
917 outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
918 outw(0, dev->iobase + PCI171x_DA1); /* set DA outputs to 0V */
919 outw(0, dev->iobase + PCI171x_DA2);
921 outw(0, dev->iobase + PCI171x_DO); /* digital outputs to 0 */
922 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
923 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
928 static int pci1720_reset(struct comedi_device *dev)
930 struct pci1710_private *devpriv = dev->private;
931 /* set synchronous output mode */
932 outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT);
933 devpriv->da_ranges = 0xAA;
934 /* set all ranges to +/-5V */
935 outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE);
936 outw(0x0800, dev->iobase + PCI1720_DA0); /* set outputs to 0V */
937 outw(0x0800, dev->iobase + PCI1720_DA1);
938 outw(0x0800, dev->iobase + PCI1720_DA2);
939 outw(0x0800, dev->iobase + PCI1720_DA3);
940 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
945 static int pci1710_reset(struct comedi_device *dev)
947 const struct boardtype *board = dev->board_ptr;
949 if (board->is_pci1720)
950 return pci1720_reset(dev);
952 return pci171x_reset(dev);
955 static int pci1710_auto_attach(struct comedi_device *dev,
956 unsigned long context)
958 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
959 const struct boardtype *board = NULL;
960 struct pci1710_private *devpriv;
961 struct comedi_subdevice *s;
962 int ret, subdev, n_subdevices;
964 if (context < ARRAY_SIZE(boardtypes))
965 board = &boardtypes[context];
968 dev->board_ptr = board;
969 dev->board_name = board->name;
971 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
975 ret = comedi_pci_enable(dev);
978 dev->iobase = pci_resource_start(pcidev, 2);
985 if (board->has_di_do)
987 if (board->has_counter)
990 ret = comedi_alloc_subdevices(dev, n_subdevices);
996 if (board->has_irq && pcidev->irq) {
997 ret = request_irq(pcidev->irq, interrupt_service_pci1710,
998 IRQF_SHARED, dev->board_name, dev);
1000 dev->irq = pcidev->irq;
1005 if (board->n_aichan) {
1006 s = &dev->subdevices[subdev];
1007 s->type = COMEDI_SUBD_AI;
1008 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
1009 if (board->has_diff_ai)
1010 s->subdev_flags |= SDF_DIFF;
1011 s->n_chan = board->n_aichan;
1012 s->maxdata = 0x0fff;
1013 s->range_table = board->rangelist_ai;
1014 s->insn_read = pci171x_ai_insn_read;
1016 dev->read_subdev = s;
1017 s->subdev_flags |= SDF_CMD_READ;
1018 s->len_chanlist = s->n_chan;
1019 s->do_cmdtest = pci171x_ai_cmdtest;
1020 s->do_cmd = pci171x_ai_cmd;
1021 s->cancel = pci171x_ai_cancel;
1026 if (board->has_ao) {
1027 s = &dev->subdevices[subdev];
1028 s->type = COMEDI_SUBD_AO;
1029 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1030 s->maxdata = 0x0fff;
1031 if (board->is_pci1720) {
1033 s->range_table = &pci1720_ao_range;
1034 s->insn_write = pci1720_ao_insn_write;
1037 s->range_table = &pci171x_ao_range;
1038 s->insn_write = pci171x_ao_insn_write;
1041 ret = comedi_alloc_subdev_readback(s);
1045 /* initialize the readback values to match the board reset */
1046 if (board->is_pci1720) {
1049 for (i = 0; i < s->n_chan; i++)
1050 s->readback[i] = 0x0800;
1056 if (board->has_di_do) {
1057 s = &dev->subdevices[subdev];
1058 s->type = COMEDI_SUBD_DI;
1059 s->subdev_flags = SDF_READABLE;
1062 s->range_table = &range_digital;
1063 s->insn_bits = pci171x_di_insn_bits;
1066 s = &dev->subdevices[subdev];
1067 s->type = COMEDI_SUBD_DO;
1068 s->subdev_flags = SDF_WRITABLE;
1071 s->range_table = &range_digital;
1072 s->insn_bits = pci171x_do_insn_bits;
1076 if (board->has_counter) {
1077 s = &dev->subdevices[subdev];
1078 s->type = COMEDI_SUBD_COUNTER;
1079 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1081 s->maxdata = 0xffff;
1082 s->range_table = &range_unknown;
1083 s->insn_read = pci171x_counter_insn_read;
1084 s->insn_write = pci171x_counter_insn_write;
1085 s->insn_config = pci171x_counter_insn_config;
1089 /* max_samples is half the FIFO size (2 bytes/sample) */
1090 devpriv->max_samples = (board->has_large_fifo) ? 2048 : 512;
1095 static void pci1710_detach(struct comedi_device *dev)
1099 comedi_pci_detach(dev);
1102 static struct comedi_driver adv_pci1710_driver = {
1103 .driver_name = "adv_pci1710",
1104 .module = THIS_MODULE,
1105 .auto_attach = pci1710_auto_attach,
1106 .detach = pci1710_detach,
1109 static int adv_pci1710_pci_probe(struct pci_dev *dev,
1110 const struct pci_device_id *id)
1112 return comedi_pci_auto_config(dev, &adv_pci1710_driver,
1116 static const struct pci_device_id adv_pci1710_pci_table[] = {
1118 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1119 PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050),
1120 .driver_data = BOARD_PCI1710,
1122 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1123 PCI_VENDOR_ID_ADVANTECH, 0x0000),
1124 .driver_data = BOARD_PCI1710,
1126 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1127 PCI_VENDOR_ID_ADVANTECH, 0xb100),
1128 .driver_data = BOARD_PCI1710,
1130 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1131 PCI_VENDOR_ID_ADVANTECH, 0xb200),
1132 .driver_data = BOARD_PCI1710,
1134 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1135 PCI_VENDOR_ID_ADVANTECH, 0xc100),
1136 .driver_data = BOARD_PCI1710,
1138 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1139 PCI_VENDOR_ID_ADVANTECH, 0xc200),
1140 .driver_data = BOARD_PCI1710,
1142 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd100),
1143 .driver_data = BOARD_PCI1710,
1145 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1146 PCI_VENDOR_ID_ADVANTECH, 0x0002),
1147 .driver_data = BOARD_PCI1710HG,
1149 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1150 PCI_VENDOR_ID_ADVANTECH, 0xb102),
1151 .driver_data = BOARD_PCI1710HG,
1153 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1154 PCI_VENDOR_ID_ADVANTECH, 0xb202),
1155 .driver_data = BOARD_PCI1710HG,
1157 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1158 PCI_VENDOR_ID_ADVANTECH, 0xc102),
1159 .driver_data = BOARD_PCI1710HG,
1161 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1162 PCI_VENDOR_ID_ADVANTECH, 0xc202),
1163 .driver_data = BOARD_PCI1710HG,
1165 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd102),
1166 .driver_data = BOARD_PCI1710HG,
1168 { PCI_VDEVICE(ADVANTECH, 0x1711), BOARD_PCI1711 },
1169 { PCI_VDEVICE(ADVANTECH, 0x1713), BOARD_PCI1713 },
1170 { PCI_VDEVICE(ADVANTECH, 0x1720), BOARD_PCI1720 },
1171 { PCI_VDEVICE(ADVANTECH, 0x1731), BOARD_PCI1731 },
1174 MODULE_DEVICE_TABLE(pci, adv_pci1710_pci_table);
1176 static struct pci_driver adv_pci1710_pci_driver = {
1177 .name = "adv_pci1710",
1178 .id_table = adv_pci1710_pci_table,
1179 .probe = adv_pci1710_pci_probe,
1180 .remove = comedi_pci_auto_unconfig,
1182 module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver);
1184 MODULE_AUTHOR("Comedi http://www.comedi.org");
1185 MODULE_DESCRIPTION("Comedi: Advantech PCI-1710 Series Multifunction DAS Cards");
1186 MODULE_LICENSE("GPL");