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;
495 static int pci171x_di_insn_bits(struct comedi_device *dev,
496 struct comedi_subdevice *s,
497 struct comedi_insn *insn,
500 data[1] = inw(dev->iobase + PCI171x_DI);
505 static int pci171x_do_insn_bits(struct comedi_device *dev,
506 struct comedi_subdevice *s,
507 struct comedi_insn *insn,
510 if (comedi_dio_update_state(s, data))
511 outw(s->state, dev->iobase + PCI171x_DO);
518 static void pci171x_start_pacer(struct comedi_device *dev,
521 struct pci1710_private *devpriv = dev->private;
522 unsigned long timer_base = dev->iobase + PCI171X_TIMER_BASE;
524 i8254_set_mode(timer_base, 1, 2, I8254_MODE2 | I8254_BINARY);
525 i8254_set_mode(timer_base, 1, 1, I8254_MODE2 | I8254_BINARY);
528 i8254_write(timer_base, 1, 2, devpriv->divisor2);
529 i8254_write(timer_base, 1, 1, devpriv->divisor1);
533 static int pci171x_counter_insn_read(struct comedi_device *dev,
534 struct comedi_subdevice *s,
535 struct comedi_insn *insn,
538 unsigned int msb, lsb, ccntrl;
541 ccntrl = 0xD2; /* count only */
542 for (i = 0; i < insn->n; i++) {
543 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
545 lsb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
546 msb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
548 data[0] = lsb | (msb << 8);
554 static int pci171x_counter_insn_write(struct comedi_device *dev,
555 struct comedi_subdevice *s,
556 struct comedi_insn *insn,
559 struct pci1710_private *devpriv = dev->private;
560 uint msb, lsb, ccntrl, status;
562 lsb = data[0] & 0x00FF;
563 msb = (data[0] & 0xFF00) >> 8;
565 /* write lsb, then msb */
566 outw(lsb, dev->iobase + PCI171x_CNT0);
567 outw(msb, dev->iobase + PCI171x_CNT0);
569 if (devpriv->cnt0_write_wait) {
570 /* wait for the new count to be loaded */
573 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
574 status = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
575 } while (status & 0x40);
581 static int pci171x_counter_insn_config(struct comedi_device *dev,
582 struct comedi_subdevice *s,
583 struct comedi_insn *insn,
587 /* This doesn't work like a normal Comedi counter config */
588 struct pci1710_private *devpriv = dev->private;
591 devpriv->cnt0_write_wait = data[0] & 0x20;
593 /* internal or external clock? */
594 if (!(data[0] & 0x10)) { /* internal */
595 devpriv->CntrlReg &= ~Control_CNT0;
597 devpriv->CntrlReg |= Control_CNT0;
599 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
602 ccntrl |= Counter_M0;
604 ccntrl |= Counter_M1;
606 ccntrl |= Counter_M2;
608 ccntrl |= Counter_BCD;
609 ccntrl |= Counter_RW0; /* set read/write mode */
610 ccntrl |= Counter_RW1;
611 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
617 static int pci1720_ao_insn_write(struct comedi_device *dev,
618 struct comedi_subdevice *s,
619 struct comedi_insn *insn,
622 struct pci1710_private *devpriv = dev->private;
623 unsigned int chan = CR_CHAN(insn->chanspec);
624 unsigned int range = CR_RANGE(insn->chanspec);
628 val = devpriv->da_ranges & (~(0x03 << (chan << 1)));
629 val |= (range << (chan << 1));
630 if (val != devpriv->da_ranges) {
631 outb(val, dev->iobase + PCI1720_RANGE);
632 devpriv->da_ranges = val;
635 val = s->readback[chan];
636 for (i = 0; i < insn->n; i++) {
638 outw(val, dev->iobase + PCI1720_DA0 + (chan << 1));
639 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
642 s->readback[chan] = val;
648 ==============================================================================
650 static int pci171x_ai_cancel(struct comedi_device *dev,
651 struct comedi_subdevice *s)
653 const struct boardtype *this_board = dev->board_ptr;
654 struct pci1710_private *devpriv = dev->private;
656 switch (this_board->cardtype) {
658 devpriv->CntrlReg &= Control_CNT0;
659 devpriv->CntrlReg |= Control_SW;
660 /* reset any operations */
661 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
662 pci171x_start_pacer(dev, false);
663 outb(0, dev->iobase + PCI171x_CLRFIFO);
664 outb(0, dev->iobase + PCI171x_CLRINT);
671 static void pci1710_handle_every_sample(struct comedi_device *dev,
672 struct comedi_subdevice *s)
674 struct comedi_cmd *cmd = &s->async->cmd;
679 status = inw(dev->iobase + PCI171x_STATUS);
680 if (status & Status_FE) {
681 dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", status);
682 s->async->events |= COMEDI_CB_ERROR;
683 comedi_handle_events(dev, s);
686 if (status & Status_FF) {
687 dev_dbg(dev->class_dev,
688 "A/D FIFO Full status (Fatal Error!) (%4x)\n", status);
689 s->async->events |= COMEDI_CB_ERROR;
690 comedi_handle_events(dev, s);
694 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
696 for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
697 val = inw(dev->iobase + PCI171x_AD_DATA);
698 ret = pci171x_ai_dropout(dev, s, s->async->cur_chan, val);
700 s->async->events |= COMEDI_CB_ERROR;
705 comedi_buf_write_samples(s, &val, 1);
707 if (cmd->stop_src == TRIG_COUNT &&
708 s->async->scans_done >= cmd->stop_arg) {
709 s->async->events |= COMEDI_CB_EOA;
714 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
716 comedi_handle_events(dev, s);
720 ==============================================================================
722 static int move_block_from_fifo(struct comedi_device *dev,
723 struct comedi_subdevice *s, int n, int turn)
729 for (i = 0; i < n; i++) {
730 val = inw(dev->iobase + PCI171x_AD_DATA);
732 ret = pci171x_ai_dropout(dev, s, s->async->cur_chan, val);
734 s->async->events |= COMEDI_CB_ERROR;
739 comedi_buf_write_samples(s, &val, 1);
744 static void pci1710_handle_fifo(struct comedi_device *dev,
745 struct comedi_subdevice *s)
747 struct pci1710_private *devpriv = dev->private;
748 struct comedi_cmd *cmd = &s->async->cmd;
749 unsigned int nsamples;
752 m = inw(dev->iobase + PCI171x_STATUS);
753 if (!(m & Status_FH)) {
754 dev_dbg(dev->class_dev, "A/D FIFO not half full! (%4x)\n", m);
755 s->async->events |= COMEDI_CB_ERROR;
756 comedi_handle_events(dev, s);
760 dev_dbg(dev->class_dev,
761 "A/D FIFO Full status (Fatal Error!) (%4x)\n", m);
762 s->async->events |= COMEDI_CB_ERROR;
763 comedi_handle_events(dev, s);
767 nsamples = devpriv->max_samples;
768 if (comedi_samples_to_bytes(s, nsamples) >= s->async->prealloc_bufsz) {
769 m = comedi_bytes_to_samples(s, s->async->prealloc_bufsz);
770 if (move_block_from_fifo(dev, s, m, 0))
776 if (move_block_from_fifo(dev, s, nsamples, 1))
780 if (cmd->stop_src == TRIG_COUNT &&
781 s->async->scans_done >= cmd->stop_arg) {
782 s->async->events |= COMEDI_CB_EOA;
783 comedi_handle_events(dev, s);
786 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
788 comedi_handle_events(dev, s);
792 ==============================================================================
794 static irqreturn_t interrupt_service_pci1710(int irq, void *d)
796 struct comedi_device *dev = d;
797 struct pci1710_private *devpriv = dev->private;
798 struct comedi_subdevice *s;
799 struct comedi_cmd *cmd;
801 if (!dev->attached) /* is device attached? */
802 return IRQ_NONE; /* no, exit */
804 s = dev->read_subdev;
805 cmd = &s->async->cmd;
807 /* is this interrupt from our board? */
808 if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))
809 return IRQ_NONE; /* no, exit */
811 if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */
813 devpriv->CntrlReg &= Control_CNT0;
814 devpriv->CntrlReg |= Control_SW; /* set software trigger */
815 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
816 devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
817 outb(0, dev->iobase + PCI171x_CLRFIFO);
818 outb(0, dev->iobase + PCI171x_CLRINT);
819 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
820 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
821 pci171x_start_pacer(dev, true);
825 if (cmd->flags & CMDF_WAKE_EOS)
826 pci1710_handle_every_sample(dev, s);
828 pci1710_handle_fifo(dev, s);
833 static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
835 struct pci1710_private *devpriv = dev->private;
836 struct comedi_cmd *cmd = &s->async->cmd;
838 pci171x_start_pacer(dev, false);
840 setup_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len,
841 devpriv->saved_seglen);
843 outb(0, dev->iobase + PCI171x_CLRFIFO);
844 outb(0, dev->iobase + PCI171x_CLRINT);
846 devpriv->CntrlReg &= Control_CNT0;
847 if ((cmd->flags & CMDF_WAKE_EOS) == 0)
848 devpriv->CntrlReg |= Control_ONEFH;
850 devpriv->divisor1 = devpriv->next_divisor1;
851 devpriv->divisor2 = devpriv->next_divisor2;
853 if (cmd->convert_src == TRIG_TIMER) {
854 devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
855 if (cmd->start_src == TRIG_EXT) {
856 devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
858 ~(Control_PACER | Control_ONEFH | Control_GATE);
859 devpriv->CntrlReg |= Control_EXT;
861 } else { /* TRIG_NOW */
864 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
866 if (cmd->start_src == TRIG_NOW)
867 pci171x_start_pacer(dev, true);
868 } else { /* TRIG_EXT */
869 devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
870 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
877 ==============================================================================
879 static int pci171x_ai_cmdtest(struct comedi_device *dev,
880 struct comedi_subdevice *s,
881 struct comedi_cmd *cmd)
883 struct pci1710_private *devpriv = dev->private;
887 /* Step 1 : check if triggers are trivially valid */
889 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
890 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
891 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
892 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
893 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
898 /* step 2a: make sure trigger sources are unique */
900 err |= cfc_check_trigger_is_unique(cmd->start_src);
901 err |= cfc_check_trigger_is_unique(cmd->convert_src);
902 err |= cfc_check_trigger_is_unique(cmd->stop_src);
904 /* step 2b: and mutually compatible */
909 /* Step 3: check if arguments are trivially valid */
911 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
912 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
914 if (cmd->convert_src == TRIG_TIMER)
915 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000);
916 else /* TRIG_FOLLOW */
917 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
919 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
921 if (cmd->stop_src == TRIG_COUNT)
922 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
924 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
929 /* step 4: fix up any arguments */
931 if (cmd->convert_src == TRIG_TIMER) {
932 arg = cmd->convert_arg;
933 i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
934 &devpriv->next_divisor1,
935 &devpriv->next_divisor2,
937 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
943 /* Step 5: check channel list */
945 err |= pci171x_ai_check_chanlist(dev, s, cmd);
954 ==============================================================================
956 static int pci171x_reset(struct comedi_device *dev)
958 const struct boardtype *this_board = dev->board_ptr;
959 struct pci1710_private *devpriv = dev->private;
961 outw(0x30, dev->iobase + PCI171x_CNTCTRL);
962 /* Software trigger, CNT0=external */
963 devpriv->CntrlReg = Control_SW | Control_CNT0;
964 /* reset any operations */
965 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
966 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
967 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
968 pci171x_start_pacer(dev, false);
969 devpriv->da_ranges = 0;
970 if (this_board->has_ao) {
971 /* set DACs to 0..5V */
972 outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
973 outw(0, dev->iobase + PCI171x_DA1); /* set DA outputs to 0V */
974 outw(0, dev->iobase + PCI171x_DA2);
976 outw(0, dev->iobase + PCI171x_DO); /* digital outputs to 0 */
977 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
978 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
984 ==============================================================================
986 static int pci1720_reset(struct comedi_device *dev)
988 struct pci1710_private *devpriv = dev->private;
989 /* set synchronous output mode */
990 outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT);
991 devpriv->da_ranges = 0xAA;
992 /* set all ranges to +/-5V */
993 outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE);
994 outw(0x0800, dev->iobase + PCI1720_DA0); /* set outputs to 0V */
995 outw(0x0800, dev->iobase + PCI1720_DA1);
996 outw(0x0800, dev->iobase + PCI1720_DA2);
997 outw(0x0800, dev->iobase + PCI1720_DA3);
998 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
1004 ==============================================================================
1006 static int pci1710_reset(struct comedi_device *dev)
1008 const struct boardtype *this_board = dev->board_ptr;
1010 switch (this_board->cardtype) {
1012 return pci1720_reset(dev);
1014 return pci171x_reset(dev);
1018 static int pci1710_auto_attach(struct comedi_device *dev,
1019 unsigned long context)
1021 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1022 const struct boardtype *this_board = NULL;
1023 struct pci1710_private *devpriv;
1024 struct comedi_subdevice *s;
1025 int ret, subdev, n_subdevices;
1027 if (context < ARRAY_SIZE(boardtypes))
1028 this_board = &boardtypes[context];
1031 dev->board_ptr = this_board;
1032 dev->board_name = this_board->name;
1034 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1038 ret = comedi_pci_enable(dev);
1041 dev->iobase = pci_resource_start(pcidev, 2);
1044 if (this_board->n_aichan)
1046 if (this_board->has_ao)
1048 if (this_board->has_di_do)
1050 if (this_board->has_counter)
1053 ret = comedi_alloc_subdevices(dev, n_subdevices);
1059 if (this_board->has_irq && pcidev->irq) {
1060 ret = request_irq(pcidev->irq, interrupt_service_pci1710,
1061 IRQF_SHARED, dev->board_name, dev);
1063 dev->irq = pcidev->irq;
1068 if (this_board->n_aichan) {
1069 s = &dev->subdevices[subdev];
1070 s->type = COMEDI_SUBD_AI;
1071 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
1072 if (this_board->has_diff_ai)
1073 s->subdev_flags |= SDF_DIFF;
1074 s->n_chan = this_board->n_aichan;
1075 s->maxdata = 0x0fff;
1076 s->range_table = this_board->rangelist_ai;
1077 s->insn_read = pci171x_insn_read_ai;
1079 dev->read_subdev = s;
1080 s->subdev_flags |= SDF_CMD_READ;
1081 s->len_chanlist = s->n_chan;
1082 s->do_cmdtest = pci171x_ai_cmdtest;
1083 s->do_cmd = pci171x_ai_cmd;
1084 s->cancel = pci171x_ai_cancel;
1089 if (this_board->has_ao) {
1090 s = &dev->subdevices[subdev];
1091 s->type = COMEDI_SUBD_AO;
1092 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1093 s->maxdata = 0x0fff;
1094 s->range_table = this_board->rangelist_ao;
1095 switch (this_board->cardtype) {
1098 s->insn_write = pci1720_ao_insn_write;
1102 s->insn_write = pci171x_ao_insn_write;
1106 ret = comedi_alloc_subdev_readback(s);
1110 /* initialize the readback values to match the board reset */
1111 if (this_board->cardtype == TYPE_PCI1720) {
1114 for (i = 0; i < s->n_chan; i++)
1115 s->readback[i] = 0x0800;
1121 if (this_board->has_di_do) {
1122 s = &dev->subdevices[subdev];
1123 s->type = COMEDI_SUBD_DI;
1124 s->subdev_flags = SDF_READABLE;
1127 s->range_table = &range_digital;
1128 s->insn_bits = pci171x_di_insn_bits;
1131 s = &dev->subdevices[subdev];
1132 s->type = COMEDI_SUBD_DO;
1133 s->subdev_flags = SDF_WRITABLE;
1136 s->range_table = &range_digital;
1137 s->insn_bits = pci171x_do_insn_bits;
1141 if (this_board->has_counter) {
1142 s = &dev->subdevices[subdev];
1143 s->type = COMEDI_SUBD_COUNTER;
1144 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1146 s->maxdata = 0xffff;
1147 s->range_table = &range_unknown;
1148 s->insn_read = pci171x_counter_insn_read;
1149 s->insn_write = pci171x_counter_insn_write;
1150 s->insn_config = pci171x_counter_insn_config;
1154 /* max_samples is half the FIFO size (2 bytes/sample) */
1155 devpriv->max_samples = (this_board->has_large_fifo) ? 2048 : 512;
1160 static void pci1710_detach(struct comedi_device *dev)
1164 comedi_pci_detach(dev);
1167 static struct comedi_driver adv_pci1710_driver = {
1168 .driver_name = "adv_pci1710",
1169 .module = THIS_MODULE,
1170 .auto_attach = pci1710_auto_attach,
1171 .detach = pci1710_detach,
1174 static int adv_pci1710_pci_probe(struct pci_dev *dev,
1175 const struct pci_device_id *id)
1177 return comedi_pci_auto_config(dev, &adv_pci1710_driver,
1181 static const struct pci_device_id adv_pci1710_pci_table[] = {
1183 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1184 PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050),
1185 .driver_data = BOARD_PCI1710,
1187 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1188 PCI_VENDOR_ID_ADVANTECH, 0x0000),
1189 .driver_data = BOARD_PCI1710,
1191 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1192 PCI_VENDOR_ID_ADVANTECH, 0xb100),
1193 .driver_data = BOARD_PCI1710,
1195 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1196 PCI_VENDOR_ID_ADVANTECH, 0xb200),
1197 .driver_data = BOARD_PCI1710,
1199 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1200 PCI_VENDOR_ID_ADVANTECH, 0xc100),
1201 .driver_data = BOARD_PCI1710,
1203 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1204 PCI_VENDOR_ID_ADVANTECH, 0xc200),
1205 .driver_data = BOARD_PCI1710,
1207 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd100),
1208 .driver_data = BOARD_PCI1710,
1210 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1211 PCI_VENDOR_ID_ADVANTECH, 0x0002),
1212 .driver_data = BOARD_PCI1710HG,
1214 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1215 PCI_VENDOR_ID_ADVANTECH, 0xb102),
1216 .driver_data = BOARD_PCI1710HG,
1218 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1219 PCI_VENDOR_ID_ADVANTECH, 0xb202),
1220 .driver_data = BOARD_PCI1710HG,
1222 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1223 PCI_VENDOR_ID_ADVANTECH, 0xc102),
1224 .driver_data = BOARD_PCI1710HG,
1226 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1227 PCI_VENDOR_ID_ADVANTECH, 0xc202),
1228 .driver_data = BOARD_PCI1710HG,
1230 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd102),
1231 .driver_data = BOARD_PCI1710HG,
1233 { PCI_VDEVICE(ADVANTECH, 0x1711), BOARD_PCI1711 },
1234 { PCI_VDEVICE(ADVANTECH, 0x1713), BOARD_PCI1713 },
1235 { PCI_VDEVICE(ADVANTECH, 0x1720), BOARD_PCI1720 },
1236 { PCI_VDEVICE(ADVANTECH, 0x1731), BOARD_PCI1731 },
1239 MODULE_DEVICE_TABLE(pci, adv_pci1710_pci_table);
1241 static struct pci_driver adv_pci1710_pci_driver = {
1242 .name = "adv_pci1710",
1243 .id_table = adv_pci1710_pci_table,
1244 .probe = adv_pci1710_pci_probe,
1245 .remove = comedi_pci_auto_unconfig,
1247 module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver);
1249 MODULE_AUTHOR("Comedi http://www.comedi.org");
1250 MODULE_DESCRIPTION("Comedi low-level driver");
1251 MODULE_LICENSE("GPL");