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 *this_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 = this_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_insn_read_ai(struct comedi_device *dev,
430 struct comedi_subdevice *s,
431 struct comedi_insn *insn, unsigned int *data)
433 struct pci1710_private *devpriv = dev->private;
434 unsigned int chan = CR_CHAN(insn->chanspec);
438 devpriv->CntrlReg &= Control_CNT0;
439 devpriv->CntrlReg |= Control_SW; /* set software trigger */
440 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
441 outb(0, dev->iobase + PCI171x_CLRFIFO);
442 outb(0, dev->iobase + PCI171x_CLRINT);
444 setup_channel_list(dev, s, &insn->chanspec, 1, 1);
446 for (i = 0; i < insn->n; i++) {
449 outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */
451 ret = comedi_timeout(dev, s, insn, pci171x_ai_eoc, 0);
455 val = inw(dev->iobase + PCI171x_AD_DATA);
456 ret = pci171x_ai_dropout(dev, s, chan, val);
460 data[i] = val & s->maxdata;
463 outb(0, dev->iobase + PCI171x_CLRFIFO);
464 outb(0, dev->iobase + PCI171x_CLRINT);
466 return ret ? ret : insn->n;
469 static int pci171x_ao_insn_write(struct comedi_device *dev,
470 struct comedi_subdevice *s,
471 struct comedi_insn *insn,
474 struct pci1710_private *devpriv = dev->private;
475 unsigned int chan = CR_CHAN(insn->chanspec);
476 unsigned int range = CR_RANGE(insn->chanspec);
477 unsigned int reg = chan ? PCI171x_DA2 : PCI171x_DA1;
478 unsigned int val = s->readback[chan];
481 devpriv->da_ranges &= ~(1 << (chan << 1));
482 devpriv->da_ranges |= (range << (chan << 1));
483 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
485 for (i = 0; i < insn->n; i++) {
487 outw(val, dev->iobase + reg);
490 s->readback[chan] = val;
496 ==============================================================================
498 static int pci171x_insn_bits_di(struct comedi_device *dev,
499 struct comedi_subdevice *s,
500 struct comedi_insn *insn, unsigned int *data)
502 data[1] = inw(dev->iobase + PCI171x_DI);
507 static int pci171x_insn_bits_do(struct comedi_device *dev,
508 struct comedi_subdevice *s,
509 struct comedi_insn *insn,
512 if (comedi_dio_update_state(s, data))
513 outw(s->state, dev->iobase + PCI171x_DO);
520 static void pci171x_start_pacer(struct comedi_device *dev,
523 struct pci1710_private *devpriv = dev->private;
524 unsigned long timer_base = dev->iobase + PCI171X_TIMER_BASE;
526 i8254_set_mode(timer_base, 1, 2, I8254_MODE2 | I8254_BINARY);
527 i8254_set_mode(timer_base, 1, 1, I8254_MODE2 | I8254_BINARY);
530 i8254_write(timer_base, 1, 2, devpriv->divisor2);
531 i8254_write(timer_base, 1, 1, devpriv->divisor1);
535 static int pci171x_counter_insn_read(struct comedi_device *dev,
536 struct comedi_subdevice *s,
537 struct comedi_insn *insn,
540 unsigned int msb, lsb, ccntrl;
543 ccntrl = 0xD2; /* count only */
544 for (i = 0; i < insn->n; i++) {
545 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
547 lsb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
548 msb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
550 data[0] = lsb | (msb << 8);
556 static int pci171x_counter_insn_write(struct comedi_device *dev,
557 struct comedi_subdevice *s,
558 struct comedi_insn *insn,
561 struct pci1710_private *devpriv = dev->private;
562 uint msb, lsb, ccntrl, status;
564 lsb = data[0] & 0x00FF;
565 msb = (data[0] & 0xFF00) >> 8;
567 /* write lsb, then msb */
568 outw(lsb, dev->iobase + PCI171x_CNT0);
569 outw(msb, dev->iobase + PCI171x_CNT0);
571 if (devpriv->cnt0_write_wait) {
572 /* wait for the new count to be loaded */
575 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
576 status = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
577 } while (status & 0x40);
583 static int pci171x_counter_insn_config(struct comedi_device *dev,
584 struct comedi_subdevice *s,
585 struct comedi_insn *insn,
589 /* This doesn't work like a normal Comedi counter config */
590 struct pci1710_private *devpriv = dev->private;
593 devpriv->cnt0_write_wait = data[0] & 0x20;
595 /* internal or external clock? */
596 if (!(data[0] & 0x10)) { /* internal */
597 devpriv->CntrlReg &= ~Control_CNT0;
599 devpriv->CntrlReg |= Control_CNT0;
601 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
604 ccntrl |= Counter_M0;
606 ccntrl |= Counter_M1;
608 ccntrl |= Counter_M2;
610 ccntrl |= Counter_BCD;
611 ccntrl |= Counter_RW0; /* set read/write mode */
612 ccntrl |= Counter_RW1;
613 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
619 static int pci1720_ao_insn_write(struct comedi_device *dev,
620 struct comedi_subdevice *s,
621 struct comedi_insn *insn,
624 struct pci1710_private *devpriv = dev->private;
625 unsigned int chan = CR_CHAN(insn->chanspec);
626 unsigned int range = CR_RANGE(insn->chanspec);
630 val = devpriv->da_ranges & (~(0x03 << (chan << 1)));
631 val |= (range << (chan << 1));
632 if (val != devpriv->da_ranges) {
633 outb(val, dev->iobase + PCI1720_RANGE);
634 devpriv->da_ranges = val;
637 val = s->readback[chan];
638 for (i = 0; i < insn->n; i++) {
640 outw(val, dev->iobase + PCI1720_DA0 + (chan << 1));
641 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
644 s->readback[chan] = val;
650 ==============================================================================
652 static int pci171x_ai_cancel(struct comedi_device *dev,
653 struct comedi_subdevice *s)
655 const struct boardtype *this_board = dev->board_ptr;
656 struct pci1710_private *devpriv = dev->private;
658 switch (this_board->cardtype) {
660 devpriv->CntrlReg &= Control_CNT0;
661 devpriv->CntrlReg |= Control_SW;
662 /* reset any operations */
663 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
664 pci171x_start_pacer(dev, false);
665 outb(0, dev->iobase + PCI171x_CLRFIFO);
666 outb(0, dev->iobase + PCI171x_CLRINT);
673 static void pci1710_handle_every_sample(struct comedi_device *dev,
674 struct comedi_subdevice *s)
676 struct comedi_cmd *cmd = &s->async->cmd;
681 status = inw(dev->iobase + PCI171x_STATUS);
682 if (status & Status_FE) {
683 dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", status);
684 s->async->events |= COMEDI_CB_ERROR;
685 comedi_handle_events(dev, s);
688 if (status & Status_FF) {
689 dev_dbg(dev->class_dev,
690 "A/D FIFO Full status (Fatal Error!) (%4x)\n", status);
691 s->async->events |= COMEDI_CB_ERROR;
692 comedi_handle_events(dev, s);
696 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
698 for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
699 val = inw(dev->iobase + PCI171x_AD_DATA);
700 ret = pci171x_ai_dropout(dev, s, s->async->cur_chan, val);
702 s->async->events |= COMEDI_CB_ERROR;
707 comedi_buf_write_samples(s, &val, 1);
709 if (cmd->stop_src == TRIG_COUNT &&
710 s->async->scans_done >= cmd->stop_arg) {
711 s->async->events |= COMEDI_CB_EOA;
716 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
718 comedi_handle_events(dev, s);
722 ==============================================================================
724 static int move_block_from_fifo(struct comedi_device *dev,
725 struct comedi_subdevice *s, int n, int turn)
731 for (i = 0; i < n; i++) {
732 val = inw(dev->iobase + PCI171x_AD_DATA);
734 ret = pci171x_ai_dropout(dev, s, s->async->cur_chan, val);
736 s->async->events |= COMEDI_CB_ERROR;
741 comedi_buf_write_samples(s, &val, 1);
746 static void pci1710_handle_fifo(struct comedi_device *dev,
747 struct comedi_subdevice *s)
749 struct pci1710_private *devpriv = dev->private;
750 struct comedi_cmd *cmd = &s->async->cmd;
751 unsigned int nsamples;
754 m = inw(dev->iobase + PCI171x_STATUS);
755 if (!(m & Status_FH)) {
756 dev_dbg(dev->class_dev, "A/D FIFO not half full! (%4x)\n", m);
757 s->async->events |= COMEDI_CB_ERROR;
758 comedi_handle_events(dev, s);
762 dev_dbg(dev->class_dev,
763 "A/D FIFO Full status (Fatal Error!) (%4x)\n", m);
764 s->async->events |= COMEDI_CB_ERROR;
765 comedi_handle_events(dev, s);
769 nsamples = devpriv->max_samples;
770 if (comedi_samples_to_bytes(s, nsamples) >= s->async->prealloc_bufsz) {
771 m = comedi_bytes_to_samples(s, s->async->prealloc_bufsz);
772 if (move_block_from_fifo(dev, s, m, 0))
778 if (move_block_from_fifo(dev, s, nsamples, 1))
782 if (cmd->stop_src == TRIG_COUNT &&
783 s->async->scans_done >= cmd->stop_arg) {
784 s->async->events |= COMEDI_CB_EOA;
785 comedi_handle_events(dev, s);
788 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
790 comedi_handle_events(dev, s);
794 ==============================================================================
796 static irqreturn_t interrupt_service_pci1710(int irq, void *d)
798 struct comedi_device *dev = d;
799 struct pci1710_private *devpriv = dev->private;
800 struct comedi_subdevice *s;
801 struct comedi_cmd *cmd;
803 if (!dev->attached) /* is device attached? */
804 return IRQ_NONE; /* no, exit */
806 s = dev->read_subdev;
807 cmd = &s->async->cmd;
809 /* is this interrupt from our board? */
810 if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))
811 return IRQ_NONE; /* no, exit */
813 if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */
815 devpriv->CntrlReg &= Control_CNT0;
816 devpriv->CntrlReg |= Control_SW; /* set software trigger */
817 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
818 devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
819 outb(0, dev->iobase + PCI171x_CLRFIFO);
820 outb(0, dev->iobase + PCI171x_CLRINT);
821 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
822 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
823 pci171x_start_pacer(dev, true);
827 if (cmd->flags & CMDF_WAKE_EOS)
828 pci1710_handle_every_sample(dev, s);
830 pci1710_handle_fifo(dev, s);
835 static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
837 struct pci1710_private *devpriv = dev->private;
838 struct comedi_cmd *cmd = &s->async->cmd;
840 pci171x_start_pacer(dev, false);
842 setup_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len,
843 devpriv->saved_seglen);
845 outb(0, dev->iobase + PCI171x_CLRFIFO);
846 outb(0, dev->iobase + PCI171x_CLRINT);
848 devpriv->CntrlReg &= Control_CNT0;
849 if ((cmd->flags & CMDF_WAKE_EOS) == 0)
850 devpriv->CntrlReg |= Control_ONEFH;
852 devpriv->divisor1 = devpriv->next_divisor1;
853 devpriv->divisor2 = devpriv->next_divisor2;
855 if (cmd->convert_src == TRIG_TIMER) {
856 devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
857 if (cmd->start_src == TRIG_EXT) {
858 devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
860 ~(Control_PACER | Control_ONEFH | Control_GATE);
861 devpriv->CntrlReg |= Control_EXT;
863 } else { /* TRIG_NOW */
866 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
868 if (cmd->start_src == TRIG_NOW)
869 pci171x_start_pacer(dev, true);
870 } else { /* TRIG_EXT */
871 devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
872 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
879 ==============================================================================
881 static int pci171x_ai_cmdtest(struct comedi_device *dev,
882 struct comedi_subdevice *s,
883 struct comedi_cmd *cmd)
885 struct pci1710_private *devpriv = dev->private;
889 /* Step 1 : check if triggers are trivially valid */
891 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
892 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
893 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
894 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
895 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
900 /* step 2a: make sure trigger sources are unique */
902 err |= cfc_check_trigger_is_unique(cmd->start_src);
903 err |= cfc_check_trigger_is_unique(cmd->convert_src);
904 err |= cfc_check_trigger_is_unique(cmd->stop_src);
906 /* step 2b: and mutually compatible */
911 /* Step 3: check if arguments are trivially valid */
913 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
914 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
916 if (cmd->convert_src == TRIG_TIMER)
917 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000);
918 else /* TRIG_FOLLOW */
919 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
921 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
923 if (cmd->stop_src == TRIG_COUNT)
924 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
926 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
931 /* step 4: fix up any arguments */
933 if (cmd->convert_src == TRIG_TIMER) {
934 arg = cmd->convert_arg;
935 i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
936 &devpriv->next_divisor1,
937 &devpriv->next_divisor2,
939 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
945 /* Step 5: check channel list */
947 err |= pci171x_ai_check_chanlist(dev, s, cmd);
956 ==============================================================================
958 static int pci171x_reset(struct comedi_device *dev)
960 const struct boardtype *this_board = dev->board_ptr;
961 struct pci1710_private *devpriv = dev->private;
963 outw(0x30, dev->iobase + PCI171x_CNTCTRL);
964 /* Software trigger, CNT0=external */
965 devpriv->CntrlReg = Control_SW | Control_CNT0;
966 /* reset any operations */
967 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
968 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
969 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
970 pci171x_start_pacer(dev, false);
971 devpriv->da_ranges = 0;
972 if (this_board->has_ao) {
973 /* set DACs to 0..5V */
974 outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
975 outw(0, dev->iobase + PCI171x_DA1); /* set DA outputs to 0V */
976 outw(0, dev->iobase + PCI171x_DA2);
978 outw(0, dev->iobase + PCI171x_DO); /* digital outputs to 0 */
979 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
980 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
986 ==============================================================================
988 static int pci1720_reset(struct comedi_device *dev)
990 struct pci1710_private *devpriv = dev->private;
991 /* set synchronous output mode */
992 outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT);
993 devpriv->da_ranges = 0xAA;
994 /* set all ranges to +/-5V */
995 outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE);
996 outw(0x0800, dev->iobase + PCI1720_DA0); /* set outputs to 0V */
997 outw(0x0800, dev->iobase + PCI1720_DA1);
998 outw(0x0800, dev->iobase + PCI1720_DA2);
999 outw(0x0800, dev->iobase + PCI1720_DA3);
1000 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
1006 ==============================================================================
1008 static int pci1710_reset(struct comedi_device *dev)
1010 const struct boardtype *this_board = dev->board_ptr;
1012 switch (this_board->cardtype) {
1014 return pci1720_reset(dev);
1016 return pci171x_reset(dev);
1020 static int pci1710_auto_attach(struct comedi_device *dev,
1021 unsigned long context)
1023 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1024 const struct boardtype *this_board = NULL;
1025 struct pci1710_private *devpriv;
1026 struct comedi_subdevice *s;
1027 int ret, subdev, n_subdevices;
1029 if (context < ARRAY_SIZE(boardtypes))
1030 this_board = &boardtypes[context];
1033 dev->board_ptr = this_board;
1034 dev->board_name = this_board->name;
1036 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1040 ret = comedi_pci_enable(dev);
1043 dev->iobase = pci_resource_start(pcidev, 2);
1046 if (this_board->n_aichan)
1048 if (this_board->has_ao)
1050 if (this_board->has_di_do)
1052 if (this_board->has_counter)
1055 ret = comedi_alloc_subdevices(dev, n_subdevices);
1061 if (this_board->has_irq && pcidev->irq) {
1062 ret = request_irq(pcidev->irq, interrupt_service_pci1710,
1063 IRQF_SHARED, dev->board_name, dev);
1065 dev->irq = pcidev->irq;
1070 if (this_board->n_aichan) {
1071 s = &dev->subdevices[subdev];
1072 s->type = COMEDI_SUBD_AI;
1073 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
1074 if (this_board->has_diff_ai)
1075 s->subdev_flags |= SDF_DIFF;
1076 s->n_chan = this_board->n_aichan;
1077 s->maxdata = 0x0fff;
1078 s->range_table = this_board->rangelist_ai;
1079 s->insn_read = pci171x_insn_read_ai;
1081 dev->read_subdev = s;
1082 s->subdev_flags |= SDF_CMD_READ;
1083 s->len_chanlist = s->n_chan;
1084 s->do_cmdtest = pci171x_ai_cmdtest;
1085 s->do_cmd = pci171x_ai_cmd;
1086 s->cancel = pci171x_ai_cancel;
1091 if (this_board->has_ao) {
1092 s = &dev->subdevices[subdev];
1093 s->type = COMEDI_SUBD_AO;
1094 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1095 s->maxdata = 0x0fff;
1096 s->range_table = this_board->rangelist_ao;
1097 switch (this_board->cardtype) {
1100 s->insn_write = pci1720_ao_insn_write;
1104 s->insn_write = pci171x_ao_insn_write;
1108 ret = comedi_alloc_subdev_readback(s);
1112 /* initialize the readback values to match the board reset */
1113 if (this_board->cardtype == TYPE_PCI1720) {
1116 for (i = 0; i < s->n_chan; i++)
1117 s->readback[i] = 0x0800;
1123 if (this_board->has_di_do) {
1124 s = &dev->subdevices[subdev];
1125 s->type = COMEDI_SUBD_DI;
1126 s->subdev_flags = SDF_READABLE;
1129 s->range_table = &range_digital;
1130 s->insn_bits = pci171x_insn_bits_di;
1133 s = &dev->subdevices[subdev];
1134 s->type = COMEDI_SUBD_DO;
1135 s->subdev_flags = SDF_WRITABLE;
1138 s->range_table = &range_digital;
1139 s->insn_bits = pci171x_insn_bits_do;
1143 if (this_board->has_counter) {
1144 s = &dev->subdevices[subdev];
1145 s->type = COMEDI_SUBD_COUNTER;
1146 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1148 s->maxdata = 0xffff;
1149 s->range_table = &range_unknown;
1150 s->insn_read = pci171x_counter_insn_read;
1151 s->insn_write = pci171x_counter_insn_write;
1152 s->insn_config = pci171x_counter_insn_config;
1156 /* max_samples is half the FIFO size (2 bytes/sample) */
1157 devpriv->max_samples = (this_board->has_large_fifo) ? 2048 : 512;
1162 static void pci1710_detach(struct comedi_device *dev)
1166 comedi_pci_detach(dev);
1169 static struct comedi_driver adv_pci1710_driver = {
1170 .driver_name = "adv_pci1710",
1171 .module = THIS_MODULE,
1172 .auto_attach = pci1710_auto_attach,
1173 .detach = pci1710_detach,
1176 static int adv_pci1710_pci_probe(struct pci_dev *dev,
1177 const struct pci_device_id *id)
1179 return comedi_pci_auto_config(dev, &adv_pci1710_driver,
1183 static const struct pci_device_id adv_pci1710_pci_table[] = {
1185 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1186 PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050),
1187 .driver_data = BOARD_PCI1710,
1189 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1190 PCI_VENDOR_ID_ADVANTECH, 0x0000),
1191 .driver_data = BOARD_PCI1710,
1193 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1194 PCI_VENDOR_ID_ADVANTECH, 0xb100),
1195 .driver_data = BOARD_PCI1710,
1197 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1198 PCI_VENDOR_ID_ADVANTECH, 0xb200),
1199 .driver_data = BOARD_PCI1710,
1201 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1202 PCI_VENDOR_ID_ADVANTECH, 0xc100),
1203 .driver_data = BOARD_PCI1710,
1205 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1206 PCI_VENDOR_ID_ADVANTECH, 0xc200),
1207 .driver_data = BOARD_PCI1710,
1209 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd100),
1210 .driver_data = BOARD_PCI1710,
1212 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1213 PCI_VENDOR_ID_ADVANTECH, 0x0002),
1214 .driver_data = BOARD_PCI1710HG,
1216 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1217 PCI_VENDOR_ID_ADVANTECH, 0xb102),
1218 .driver_data = BOARD_PCI1710HG,
1220 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1221 PCI_VENDOR_ID_ADVANTECH, 0xb202),
1222 .driver_data = BOARD_PCI1710HG,
1224 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1225 PCI_VENDOR_ID_ADVANTECH, 0xc102),
1226 .driver_data = BOARD_PCI1710HG,
1228 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1229 PCI_VENDOR_ID_ADVANTECH, 0xc202),
1230 .driver_data = BOARD_PCI1710HG,
1232 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd102),
1233 .driver_data = BOARD_PCI1710HG,
1235 { PCI_VDEVICE(ADVANTECH, 0x1711), BOARD_PCI1711 },
1236 { PCI_VDEVICE(ADVANTECH, 0x1713), BOARD_PCI1713 },
1237 { PCI_VDEVICE(ADVANTECH, 0x1720), BOARD_PCI1720 },
1238 { PCI_VDEVICE(ADVANTECH, 0x1731), BOARD_PCI1731 },
1241 MODULE_DEVICE_TABLE(pci, adv_pci1710_pci_table);
1243 static struct pci_driver adv_pci1710_pci_driver = {
1244 .name = "adv_pci1710",
1245 .id_table = adv_pci1710_pci_table,
1246 .probe = adv_pci1710_pci_probe,
1247 .remove = comedi_pci_auto_unconfig,
1249 module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver);
1251 MODULE_AUTHOR("Comedi http://www.comedi.org");
1252 MODULE_DESCRIPTION("Comedi low-level driver");
1253 MODULE_LICENSE("GPL");