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 /* hardware types of the cards */
55 #define TYPE_PCI171X 0
56 #define TYPE_PCI1713 2
57 #define TYPE_PCI1720 3
59 #define PCI171x_AD_DATA 0 /* R: A/D data */
60 #define PCI171x_SOFTTRG 0 /* W: soft trigger for A/D */
61 #define PCI171x_RANGE 2 /* W: A/D gain/range register */
62 #define PCI171x_MUX 4 /* W: A/D multiplexor control */
63 #define PCI171x_STATUS 6 /* R: status register */
64 #define PCI171x_CONTROL 6 /* W: control register */
65 #define PCI171x_CLRINT 8 /* W: clear interrupts request */
66 #define PCI171x_CLRFIFO 9 /* W: clear FIFO */
67 #define PCI171x_DA1 10 /* W: D/A register */
68 #define PCI171x_DA2 12 /* W: D/A register */
69 #define PCI171x_DAREF 14 /* W: D/A reference control */
70 #define PCI171x_DI 16 /* R: digi inputs */
71 #define PCI171x_DO 16 /* R: digi inputs */
73 #define PCI171X_TIMER_BASE 0x18
75 #define PCI171x_CNT0 24 /* R/W: 8254 counter 0 */
76 #define PCI171x_CNT1 26 /* R/W: 8254 counter 1 */
77 #define PCI171x_CNT2 28 /* R/W: 8254 counter 2 */
78 #define PCI171x_CNTCTRL 30 /* W: 8254 counter control */
80 /* upper bits from status register (PCI171x_STATUS) (lower is same with control
82 #define Status_FE 0x0100 /* 1=FIFO is empty */
83 #define Status_FH 0x0200 /* 1=FIFO is half full */
84 #define Status_FF 0x0400 /* 1=FIFO is full, fatal error */
85 #define Status_IRQ 0x0800 /* 1=IRQ occurred */
86 /* bits from control register (PCI171x_CONTROL) */
87 #define Control_CNT0 0x0040 /* 1=CNT0 have external source,
88 * 0=have internal 100kHz source */
89 #define Control_ONEFH 0x0020 /* 1=IRQ on FIFO is half full, 0=every sample */
90 #define Control_IRQEN 0x0010 /* 1=enable IRQ */
91 #define Control_GATE 0x0008 /* 1=enable external trigger GATE (8254?) */
92 #define Control_EXT 0x0004 /* 1=external trigger source */
93 #define Control_PACER 0x0002 /* 1=enable internal 8254 trigger source */
94 #define Control_SW 0x0001 /* 1=enable software trigger source */
95 /* bits from counter control register (PCI171x_CNTCTRL) */
96 #define Counter_BCD 0x0001 /* 0 = binary counter, 1 = BCD counter */
97 #define Counter_M0 0x0002 /* M0-M2 select modes 0-5 */
98 #define Counter_M1 0x0004 /* 000 = mode 0, 010 = mode 2 ... */
99 #define Counter_M2 0x0008
100 #define Counter_RW0 0x0010 /* RW0/RW1 select read/write mode */
101 #define Counter_RW1 0x0020
102 #define Counter_SC0 0x0040 /* Select Counter. Only 00 or 11 may */
103 #define Counter_SC1 0x0080 /* be used, 00 for CNT0,
104 * 11 for read-back command */
106 #define PCI1720_DA0 0 /* W: D/A register 0 */
107 #define PCI1720_DA1 2 /* W: D/A register 1 */
108 #define PCI1720_DA2 4 /* W: D/A register 2 */
109 #define PCI1720_DA3 6 /* W: D/A register 3 */
110 #define PCI1720_RANGE 8 /* R/W: D/A range register */
111 #define PCI1720_SYNCOUT 9 /* W: D/A synchronized output register */
112 #define PCI1720_SYNCONT 15 /* R/W: D/A synchronized control */
114 /* D/A synchronized control (PCI1720_SYNCONT) */
115 #define Syncont_SC0 1 /* set synchronous output mode */
117 static const struct comedi_lrange range_pci1710_3 = {
131 static const char range_codes_pci1710_3[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
132 0x10, 0x11, 0x12, 0x13 };
134 static const struct comedi_lrange range_pci1710hg = {
151 static const char range_codes_pci1710hg[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
152 0x05, 0x06, 0x07, 0x10, 0x11,
155 static const struct comedi_lrange range_pci17x1 = {
165 static const char range_codes_pci17x1[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
167 static const struct comedi_lrange range_pci1720 = {
176 static const struct comedi_lrange range_pci171x_da = {
183 enum pci1710_boardid {
193 const char *name; /* board name */
194 char cardtype; /* 0=1710& co. 2=1713, ... */
195 int n_aichan; /* num of A/D chans */
196 const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */
197 const char *rangecode_ai; /* range codes for programming */
198 const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */
199 unsigned int has_irq:1;
200 unsigned int has_large_fifo:1; /* 4K or 1K FIFO */
201 unsigned int has_diff_ai:1;
202 unsigned int has_ao:1;
203 unsigned int has_di_do:1;
204 unsigned int has_counter:1;
207 static const struct boardtype boardtypes[] = {
210 .cardtype = TYPE_PCI171X,
212 .rangelist_ai = &range_pci1710_3,
213 .rangecode_ai = range_codes_pci1710_3,
214 .rangelist_ao = &range_pci171x_da,
222 [BOARD_PCI1710HG] = {
224 .cardtype = TYPE_PCI171X,
226 .rangelist_ai = &range_pci1710hg,
227 .rangecode_ai = range_codes_pci1710hg,
228 .rangelist_ao = &range_pci171x_da,
238 .cardtype = TYPE_PCI171X,
240 .rangelist_ai = &range_pci17x1,
241 .rangecode_ai = range_codes_pci17x1,
242 .rangelist_ao = &range_pci171x_da,
250 .cardtype = TYPE_PCI1713,
252 .rangelist_ai = &range_pci1710_3,
253 .rangecode_ai = range_codes_pci1710_3,
260 .cardtype = TYPE_PCI1720,
261 .rangelist_ao = &range_pci1720,
266 .cardtype = TYPE_PCI171X,
268 .rangelist_ai = &range_pci17x1,
269 .rangecode_ai = range_codes_pci17x1,
275 struct pci1710_private {
276 unsigned int max_samples;
277 unsigned int CntrlReg; /* Control register */
279 unsigned int ai_et_CntrlReg;
280 unsigned int ai_et_MuxVal;
281 unsigned int next_divisor1;
282 unsigned int next_divisor2;
283 unsigned int divisor1;
284 unsigned int divisor2;
285 unsigned int act_chanlist[32]; /* list of scanned channel */
286 unsigned char saved_seglen; /* len of the non-repeating chanlist */
287 unsigned char da_ranges; /* copy of D/A outpit range register */
288 unsigned int cnt0_write_wait; /* after a write, wait for update of the
292 /* used for gain list programming */
293 static const unsigned int muxonechan[] = {
294 0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707,
295 0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f,
296 0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717,
297 0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f
300 static int pci171x_ai_dropout(struct comedi_device *dev,
301 struct comedi_subdevice *s,
305 const struct boardtype *board = dev->board_ptr;
306 struct pci1710_private *devpriv = dev->private;
308 if (board->cardtype != TYPE_PCI1713) {
309 if ((val & 0xf000) != devpriv->act_chanlist[chan]) {
310 dev_err(dev->class_dev,
311 "A/D data droput: received from channel %d, expected %d\n",
313 (devpriv->act_chanlist[chan] >> 12) & 0xf);
320 static int pci171x_ai_check_chanlist(struct comedi_device *dev,
321 struct comedi_subdevice *s,
322 struct comedi_cmd *cmd)
324 struct pci1710_private *devpriv = dev->private;
325 unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
326 unsigned int last_aref = CR_AREF(cmd->chanlist[0]);
327 unsigned int next_chan = (chan0 + 1) % s->n_chan;
328 unsigned int chansegment[32];
332 if (cmd->chanlist_len == 1) {
333 devpriv->saved_seglen = cmd->chanlist_len;
337 /* first channel is always ok */
338 chansegment[0] = cmd->chanlist[0];
340 for (i = 1; i < cmd->chanlist_len; i++) {
341 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
342 unsigned int aref = CR_AREF(cmd->chanlist[i]);
344 if (cmd->chanlist[0] == cmd->chanlist[i])
345 break; /* we detected a loop, stop */
347 if (aref == AREF_DIFF && (chan & 1)) {
348 dev_err(dev->class_dev,
349 "Odd channel cannot be differential input!\n");
353 if (last_aref == AREF_DIFF)
354 next_chan = (next_chan + 1) % s->n_chan;
355 if (chan != next_chan) {
356 dev_err(dev->class_dev,
357 "channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
358 i, chan, next_chan, chan0);
362 /* next correct channel in list */
363 chansegment[i] = cmd->chanlist[i];
368 for (i = 0; i < cmd->chanlist_len; i++) {
369 if (cmd->chanlist[i] != chansegment[i % seglen]) {
370 dev_err(dev->class_dev,
371 "bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
372 i, CR_CHAN(chansegment[i]),
373 CR_RANGE(chansegment[i]),
374 CR_AREF(chansegment[i]),
375 CR_CHAN(cmd->chanlist[i % seglen]),
376 CR_RANGE(cmd->chanlist[i % seglen]),
377 CR_AREF(chansegment[i % seglen]));
381 devpriv->saved_seglen = seglen;
386 static void setup_channel_list(struct comedi_device *dev,
387 struct comedi_subdevice *s,
388 unsigned int *chanlist, unsigned int n_chan,
391 const struct boardtype *board = dev->board_ptr;
392 struct pci1710_private *devpriv = dev->private;
393 unsigned int i, range, chanprog;
395 for (i = 0; i < seglen; i++) { /* store range list to card */
396 chanprog = muxonechan[CR_CHAN(chanlist[i])];
397 outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */
398 range = board->rangecode_ai[CR_RANGE(chanlist[i])];
399 if (CR_AREF(chanlist[i]) == AREF_DIFF)
401 outw(range, dev->iobase + PCI171x_RANGE); /* select gain */
402 devpriv->act_chanlist[i] =
403 (CR_CHAN(chanlist[i]) << 12) & 0xf000;
405 for ( ; i < n_chan; i++) { /* store remainder of channel list */
406 devpriv->act_chanlist[i] =
407 (CR_CHAN(chanlist[i]) << 12) & 0xf000;
410 devpriv->ai_et_MuxVal =
411 CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
412 /* select channel interval to scan */
413 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
416 static int pci171x_ai_eoc(struct comedi_device *dev,
417 struct comedi_subdevice *s,
418 struct comedi_insn *insn,
419 unsigned long context)
423 status = inw(dev->iobase + PCI171x_STATUS);
424 if ((status & Status_FE) == 0)
429 static int pci171x_ai_insn_read(struct comedi_device *dev,
430 struct comedi_subdevice *s,
431 struct comedi_insn *insn,
434 struct pci1710_private *devpriv = dev->private;
435 unsigned int chan = CR_CHAN(insn->chanspec);
439 devpriv->CntrlReg &= Control_CNT0;
440 devpriv->CntrlReg |= Control_SW; /* set software trigger */
441 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
442 outb(0, dev->iobase + PCI171x_CLRFIFO);
443 outb(0, dev->iobase + PCI171x_CLRINT);
445 setup_channel_list(dev, s, &insn->chanspec, 1, 1);
447 for (i = 0; i < insn->n; i++) {
450 outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */
452 ret = comedi_timeout(dev, s, insn, pci171x_ai_eoc, 0);
456 val = inw(dev->iobase + PCI171x_AD_DATA);
457 ret = pci171x_ai_dropout(dev, s, chan, val);
461 data[i] = val & s->maxdata;
464 outb(0, dev->iobase + PCI171x_CLRFIFO);
465 outb(0, dev->iobase + PCI171x_CLRINT);
467 return ret ? ret : insn->n;
470 static int pci171x_ao_insn_write(struct comedi_device *dev,
471 struct comedi_subdevice *s,
472 struct comedi_insn *insn,
475 struct pci1710_private *devpriv = dev->private;
476 unsigned int chan = CR_CHAN(insn->chanspec);
477 unsigned int range = CR_RANGE(insn->chanspec);
478 unsigned int reg = chan ? PCI171x_DA2 : PCI171x_DA1;
479 unsigned int val = s->readback[chan];
482 devpriv->da_ranges &= ~(1 << (chan << 1));
483 devpriv->da_ranges |= (range << (chan << 1));
484 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
486 for (i = 0; i < insn->n; i++) {
488 outw(val, dev->iobase + reg);
491 s->readback[chan] = val;
496 static int pci171x_di_insn_bits(struct comedi_device *dev,
497 struct comedi_subdevice *s,
498 struct comedi_insn *insn,
501 data[1] = inw(dev->iobase + PCI171x_DI);
506 static int pci171x_do_insn_bits(struct comedi_device *dev,
507 struct comedi_subdevice *s,
508 struct comedi_insn *insn,
511 if (comedi_dio_update_state(s, data))
512 outw(s->state, dev->iobase + PCI171x_DO);
519 static void pci171x_start_pacer(struct comedi_device *dev,
522 struct pci1710_private *devpriv = dev->private;
523 unsigned long timer_base = dev->iobase + PCI171X_TIMER_BASE;
525 i8254_set_mode(timer_base, 1, 2, I8254_MODE2 | I8254_BINARY);
526 i8254_set_mode(timer_base, 1, 1, I8254_MODE2 | I8254_BINARY);
529 i8254_write(timer_base, 1, 2, devpriv->divisor2);
530 i8254_write(timer_base, 1, 1, devpriv->divisor1);
534 static int pci171x_counter_insn_read(struct comedi_device *dev,
535 struct comedi_subdevice *s,
536 struct comedi_insn *insn,
539 unsigned int msb, lsb, ccntrl;
542 ccntrl = 0xD2; /* count only */
543 for (i = 0; i < insn->n; i++) {
544 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
546 lsb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
547 msb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
549 data[0] = lsb | (msb << 8);
555 static int pci171x_counter_insn_write(struct comedi_device *dev,
556 struct comedi_subdevice *s,
557 struct comedi_insn *insn,
560 struct pci1710_private *devpriv = dev->private;
561 uint msb, lsb, ccntrl, status;
563 lsb = data[0] & 0x00FF;
564 msb = (data[0] & 0xFF00) >> 8;
566 /* write lsb, then msb */
567 outw(lsb, dev->iobase + PCI171x_CNT0);
568 outw(msb, dev->iobase + PCI171x_CNT0);
570 if (devpriv->cnt0_write_wait) {
571 /* wait for the new count to be loaded */
574 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
575 status = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
576 } while (status & 0x40);
582 static int pci171x_counter_insn_config(struct comedi_device *dev,
583 struct comedi_subdevice *s,
584 struct comedi_insn *insn,
588 /* This doesn't work like a normal Comedi counter config */
589 struct pci1710_private *devpriv = dev->private;
592 devpriv->cnt0_write_wait = data[0] & 0x20;
594 /* internal or external clock? */
595 if (!(data[0] & 0x10)) { /* internal */
596 devpriv->CntrlReg &= ~Control_CNT0;
598 devpriv->CntrlReg |= Control_CNT0;
600 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
603 ccntrl |= Counter_M0;
605 ccntrl |= Counter_M1;
607 ccntrl |= Counter_M2;
609 ccntrl |= Counter_BCD;
610 ccntrl |= Counter_RW0; /* set read/write mode */
611 ccntrl |= Counter_RW1;
612 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
618 static int pci1720_ao_insn_write(struct comedi_device *dev,
619 struct comedi_subdevice *s,
620 struct comedi_insn *insn,
623 struct pci1710_private *devpriv = dev->private;
624 unsigned int chan = CR_CHAN(insn->chanspec);
625 unsigned int range = CR_RANGE(insn->chanspec);
629 val = devpriv->da_ranges & (~(0x03 << (chan << 1)));
630 val |= (range << (chan << 1));
631 if (val != devpriv->da_ranges) {
632 outb(val, dev->iobase + PCI1720_RANGE);
633 devpriv->da_ranges = val;
636 val = s->readback[chan];
637 for (i = 0; i < insn->n; i++) {
639 outw(val, dev->iobase + PCI1720_DA0 + (chan << 1));
640 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
643 s->readback[chan] = val;
648 static int pci171x_ai_cancel(struct comedi_device *dev,
649 struct comedi_subdevice *s)
651 const struct boardtype *board = dev->board_ptr;
652 struct pci1710_private *devpriv = dev->private;
654 switch (board->cardtype) {
656 devpriv->CntrlReg &= Control_CNT0;
657 devpriv->CntrlReg |= Control_SW;
658 /* reset any operations */
659 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
660 pci171x_start_pacer(dev, false);
661 outb(0, dev->iobase + PCI171x_CLRFIFO);
662 outb(0, dev->iobase + PCI171x_CLRINT);
669 static void pci1710_handle_every_sample(struct comedi_device *dev,
670 struct comedi_subdevice *s)
672 struct comedi_cmd *cmd = &s->async->cmd;
677 status = inw(dev->iobase + PCI171x_STATUS);
678 if (status & Status_FE) {
679 dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", status);
680 s->async->events |= COMEDI_CB_ERROR;
681 comedi_handle_events(dev, s);
684 if (status & Status_FF) {
685 dev_dbg(dev->class_dev,
686 "A/D FIFO Full status (Fatal Error!) (%4x)\n", status);
687 s->async->events |= COMEDI_CB_ERROR;
688 comedi_handle_events(dev, s);
692 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
694 for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
695 val = inw(dev->iobase + PCI171x_AD_DATA);
696 ret = pci171x_ai_dropout(dev, s, s->async->cur_chan, val);
698 s->async->events |= COMEDI_CB_ERROR;
703 comedi_buf_write_samples(s, &val, 1);
705 if (cmd->stop_src == TRIG_COUNT &&
706 s->async->scans_done >= cmd->stop_arg) {
707 s->async->events |= COMEDI_CB_EOA;
712 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
714 comedi_handle_events(dev, s);
717 static int move_block_from_fifo(struct comedi_device *dev,
718 struct comedi_subdevice *s, int n, int turn)
724 for (i = 0; i < n; i++) {
725 val = inw(dev->iobase + PCI171x_AD_DATA);
727 ret = pci171x_ai_dropout(dev, s, s->async->cur_chan, val);
729 s->async->events |= COMEDI_CB_ERROR;
734 comedi_buf_write_samples(s, &val, 1);
739 static void pci1710_handle_fifo(struct comedi_device *dev,
740 struct comedi_subdevice *s)
742 struct pci1710_private *devpriv = dev->private;
743 struct comedi_cmd *cmd = &s->async->cmd;
744 unsigned int nsamples;
747 m = inw(dev->iobase + PCI171x_STATUS);
748 if (!(m & Status_FH)) {
749 dev_dbg(dev->class_dev, "A/D FIFO not half full! (%4x)\n", m);
750 s->async->events |= COMEDI_CB_ERROR;
751 comedi_handle_events(dev, s);
755 dev_dbg(dev->class_dev,
756 "A/D FIFO Full status (Fatal Error!) (%4x)\n", m);
757 s->async->events |= COMEDI_CB_ERROR;
758 comedi_handle_events(dev, s);
762 nsamples = devpriv->max_samples;
763 if (comedi_samples_to_bytes(s, nsamples) >= s->async->prealloc_bufsz) {
764 m = comedi_bytes_to_samples(s, s->async->prealloc_bufsz);
765 if (move_block_from_fifo(dev, s, m, 0))
771 if (move_block_from_fifo(dev, s, nsamples, 1))
775 if (cmd->stop_src == TRIG_COUNT &&
776 s->async->scans_done >= cmd->stop_arg) {
777 s->async->events |= COMEDI_CB_EOA;
778 comedi_handle_events(dev, s);
781 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
783 comedi_handle_events(dev, s);
786 static irqreturn_t interrupt_service_pci1710(int irq, void *d)
788 struct comedi_device *dev = d;
789 struct pci1710_private *devpriv = dev->private;
790 struct comedi_subdevice *s;
791 struct comedi_cmd *cmd;
793 if (!dev->attached) /* is device attached? */
794 return IRQ_NONE; /* no, exit */
796 s = dev->read_subdev;
797 cmd = &s->async->cmd;
799 /* is this interrupt from our board? */
800 if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))
801 return IRQ_NONE; /* no, exit */
803 if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */
805 devpriv->CntrlReg &= Control_CNT0;
806 devpriv->CntrlReg |= Control_SW; /* set software trigger */
807 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
808 devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
809 outb(0, dev->iobase + PCI171x_CLRFIFO);
810 outb(0, dev->iobase + PCI171x_CLRINT);
811 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
812 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
813 pci171x_start_pacer(dev, true);
817 if (cmd->flags & CMDF_WAKE_EOS)
818 pci1710_handle_every_sample(dev, s);
820 pci1710_handle_fifo(dev, s);
825 static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
827 struct pci1710_private *devpriv = dev->private;
828 struct comedi_cmd *cmd = &s->async->cmd;
830 pci171x_start_pacer(dev, false);
832 setup_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len,
833 devpriv->saved_seglen);
835 outb(0, dev->iobase + PCI171x_CLRFIFO);
836 outb(0, dev->iobase + PCI171x_CLRINT);
838 devpriv->CntrlReg &= Control_CNT0;
839 if ((cmd->flags & CMDF_WAKE_EOS) == 0)
840 devpriv->CntrlReg |= Control_ONEFH;
842 devpriv->divisor1 = devpriv->next_divisor1;
843 devpriv->divisor2 = devpriv->next_divisor2;
845 if (cmd->convert_src == TRIG_TIMER) {
846 devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
847 if (cmd->start_src == TRIG_EXT) {
848 devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
850 ~(Control_PACER | Control_ONEFH | Control_GATE);
851 devpriv->CntrlReg |= Control_EXT;
853 } else { /* TRIG_NOW */
856 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
858 if (cmd->start_src == TRIG_NOW)
859 pci171x_start_pacer(dev, true);
860 } else { /* TRIG_EXT */
861 devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
862 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
868 static int pci171x_ai_cmdtest(struct comedi_device *dev,
869 struct comedi_subdevice *s,
870 struct comedi_cmd *cmd)
872 struct pci1710_private *devpriv = dev->private;
876 /* Step 1 : check if triggers are trivially valid */
878 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
879 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
880 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
881 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
882 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
887 /* step 2a: make sure trigger sources are unique */
889 err |= cfc_check_trigger_is_unique(cmd->start_src);
890 err |= cfc_check_trigger_is_unique(cmd->convert_src);
891 err |= cfc_check_trigger_is_unique(cmd->stop_src);
893 /* step 2b: and mutually compatible */
898 /* Step 3: check if arguments are trivially valid */
900 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
901 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
903 if (cmd->convert_src == TRIG_TIMER)
904 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000);
905 else /* TRIG_FOLLOW */
906 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
908 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
910 if (cmd->stop_src == TRIG_COUNT)
911 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
913 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
918 /* step 4: fix up any arguments */
920 if (cmd->convert_src == TRIG_TIMER) {
921 arg = cmd->convert_arg;
922 i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
923 &devpriv->next_divisor1,
924 &devpriv->next_divisor2,
926 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
932 /* Step 5: check channel list */
934 err |= pci171x_ai_check_chanlist(dev, s, cmd);
942 static int pci171x_reset(struct comedi_device *dev)
944 const struct boardtype *board = dev->board_ptr;
945 struct pci1710_private *devpriv = dev->private;
947 outw(0x30, dev->iobase + PCI171x_CNTCTRL);
948 /* Software trigger, CNT0=external */
949 devpriv->CntrlReg = Control_SW | Control_CNT0;
950 /* reset any operations */
951 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
952 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
953 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
954 pci171x_start_pacer(dev, false);
955 devpriv->da_ranges = 0;
957 /* set DACs to 0..5V */
958 outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
959 outw(0, dev->iobase + PCI171x_DA1); /* set DA outputs to 0V */
960 outw(0, dev->iobase + PCI171x_DA2);
962 outw(0, dev->iobase + PCI171x_DO); /* digital outputs to 0 */
963 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
964 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
969 static int pci1720_reset(struct comedi_device *dev)
971 struct pci1710_private *devpriv = dev->private;
972 /* set synchronous output mode */
973 outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT);
974 devpriv->da_ranges = 0xAA;
975 /* set all ranges to +/-5V */
976 outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE);
977 outw(0x0800, dev->iobase + PCI1720_DA0); /* set outputs to 0V */
978 outw(0x0800, dev->iobase + PCI1720_DA1);
979 outw(0x0800, dev->iobase + PCI1720_DA2);
980 outw(0x0800, dev->iobase + PCI1720_DA3);
981 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
986 static int pci1710_reset(struct comedi_device *dev)
988 const struct boardtype *board = dev->board_ptr;
990 switch (board->cardtype) {
992 return pci1720_reset(dev);
994 return pci171x_reset(dev);
998 static int pci1710_auto_attach(struct comedi_device *dev,
999 unsigned long context)
1001 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1002 const struct boardtype *board = NULL;
1003 struct pci1710_private *devpriv;
1004 struct comedi_subdevice *s;
1005 int ret, subdev, n_subdevices;
1007 if (context < ARRAY_SIZE(boardtypes))
1008 board = &boardtypes[context];
1011 dev->board_ptr = board;
1012 dev->board_name = board->name;
1014 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1018 ret = comedi_pci_enable(dev);
1021 dev->iobase = pci_resource_start(pcidev, 2);
1024 if (board->n_aichan)
1028 if (board->has_di_do)
1030 if (board->has_counter)
1033 ret = comedi_alloc_subdevices(dev, n_subdevices);
1039 if (board->has_irq && pcidev->irq) {
1040 ret = request_irq(pcidev->irq, interrupt_service_pci1710,
1041 IRQF_SHARED, dev->board_name, dev);
1043 dev->irq = pcidev->irq;
1048 if (board->n_aichan) {
1049 s = &dev->subdevices[subdev];
1050 s->type = COMEDI_SUBD_AI;
1051 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
1052 if (board->has_diff_ai)
1053 s->subdev_flags |= SDF_DIFF;
1054 s->n_chan = board->n_aichan;
1055 s->maxdata = 0x0fff;
1056 s->range_table = board->rangelist_ai;
1057 s->insn_read = pci171x_ai_insn_read;
1059 dev->read_subdev = s;
1060 s->subdev_flags |= SDF_CMD_READ;
1061 s->len_chanlist = s->n_chan;
1062 s->do_cmdtest = pci171x_ai_cmdtest;
1063 s->do_cmd = pci171x_ai_cmd;
1064 s->cancel = pci171x_ai_cancel;
1069 if (board->has_ao) {
1070 s = &dev->subdevices[subdev];
1071 s->type = COMEDI_SUBD_AO;
1072 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1073 s->maxdata = 0x0fff;
1074 s->range_table = board->rangelist_ao;
1075 switch (board->cardtype) {
1078 s->insn_write = pci1720_ao_insn_write;
1082 s->insn_write = pci171x_ao_insn_write;
1086 ret = comedi_alloc_subdev_readback(s);
1090 /* initialize the readback values to match the board reset */
1091 if (board->cardtype == TYPE_PCI1720) {
1094 for (i = 0; i < s->n_chan; i++)
1095 s->readback[i] = 0x0800;
1101 if (board->has_di_do) {
1102 s = &dev->subdevices[subdev];
1103 s->type = COMEDI_SUBD_DI;
1104 s->subdev_flags = SDF_READABLE;
1107 s->range_table = &range_digital;
1108 s->insn_bits = pci171x_di_insn_bits;
1111 s = &dev->subdevices[subdev];
1112 s->type = COMEDI_SUBD_DO;
1113 s->subdev_flags = SDF_WRITABLE;
1116 s->range_table = &range_digital;
1117 s->insn_bits = pci171x_do_insn_bits;
1121 if (board->has_counter) {
1122 s = &dev->subdevices[subdev];
1123 s->type = COMEDI_SUBD_COUNTER;
1124 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1126 s->maxdata = 0xffff;
1127 s->range_table = &range_unknown;
1128 s->insn_read = pci171x_counter_insn_read;
1129 s->insn_write = pci171x_counter_insn_write;
1130 s->insn_config = pci171x_counter_insn_config;
1134 /* max_samples is half the FIFO size (2 bytes/sample) */
1135 devpriv->max_samples = (board->has_large_fifo) ? 2048 : 512;
1140 static void pci1710_detach(struct comedi_device *dev)
1144 comedi_pci_detach(dev);
1147 static struct comedi_driver adv_pci1710_driver = {
1148 .driver_name = "adv_pci1710",
1149 .module = THIS_MODULE,
1150 .auto_attach = pci1710_auto_attach,
1151 .detach = pci1710_detach,
1154 static int adv_pci1710_pci_probe(struct pci_dev *dev,
1155 const struct pci_device_id *id)
1157 return comedi_pci_auto_config(dev, &adv_pci1710_driver,
1161 static const struct pci_device_id adv_pci1710_pci_table[] = {
1163 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1164 PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050),
1165 .driver_data = BOARD_PCI1710,
1167 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1168 PCI_VENDOR_ID_ADVANTECH, 0x0000),
1169 .driver_data = BOARD_PCI1710,
1171 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1172 PCI_VENDOR_ID_ADVANTECH, 0xb100),
1173 .driver_data = BOARD_PCI1710,
1175 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1176 PCI_VENDOR_ID_ADVANTECH, 0xb200),
1177 .driver_data = BOARD_PCI1710,
1179 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1180 PCI_VENDOR_ID_ADVANTECH, 0xc100),
1181 .driver_data = BOARD_PCI1710,
1183 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1184 PCI_VENDOR_ID_ADVANTECH, 0xc200),
1185 .driver_data = BOARD_PCI1710,
1187 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd100),
1188 .driver_data = BOARD_PCI1710,
1190 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1191 PCI_VENDOR_ID_ADVANTECH, 0x0002),
1192 .driver_data = BOARD_PCI1710HG,
1194 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1195 PCI_VENDOR_ID_ADVANTECH, 0xb102),
1196 .driver_data = BOARD_PCI1710HG,
1198 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1199 PCI_VENDOR_ID_ADVANTECH, 0xb202),
1200 .driver_data = BOARD_PCI1710HG,
1202 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1203 PCI_VENDOR_ID_ADVANTECH, 0xc102),
1204 .driver_data = BOARD_PCI1710HG,
1206 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1207 PCI_VENDOR_ID_ADVANTECH, 0xc202),
1208 .driver_data = BOARD_PCI1710HG,
1210 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd102),
1211 .driver_data = BOARD_PCI1710HG,
1213 { PCI_VDEVICE(ADVANTECH, 0x1711), BOARD_PCI1711 },
1214 { PCI_VDEVICE(ADVANTECH, 0x1713), BOARD_PCI1713 },
1215 { PCI_VDEVICE(ADVANTECH, 0x1720), BOARD_PCI1720 },
1216 { PCI_VDEVICE(ADVANTECH, 0x1731), BOARD_PCI1731 },
1219 MODULE_DEVICE_TABLE(pci, adv_pci1710_pci_table);
1221 static struct pci_driver adv_pci1710_pci_driver = {
1222 .name = "adv_pci1710",
1223 .id_table = adv_pci1710_pci_table,
1224 .probe = adv_pci1710_pci_probe,
1225 .remove = comedi_pci_auto_unconfig,
1227 module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver);
1229 MODULE_AUTHOR("Comedi http://www.comedi.org");
1230 MODULE_DESCRIPTION("Comedi: Advantech PCI-1710 Series Multifunction DAS Cards");
1231 MODULE_LICENSE("GPL");