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 int n_aochan; /* num of D/A chans */
197 const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */
198 const char *rangecode_ai; /* range codes for programming */
199 const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */
200 unsigned int has_irq:1;
201 unsigned int has_large_fifo:1; /* 4K or 1K FIFO */
202 unsigned int has_diff_ai:1;
203 unsigned int has_di_do:1;
204 unsigned int has_counter:1;
207 static const struct boardtype boardtypes[] = {
210 .cardtype = TYPE_PCI171X,
213 .rangelist_ai = &range_pci1710_3,
214 .rangecode_ai = range_codes_pci1710_3,
215 .rangelist_ao = &range_pci171x_da,
222 [BOARD_PCI1710HG] = {
224 .cardtype = TYPE_PCI171X,
227 .rangelist_ai = &range_pci1710hg,
228 .rangecode_ai = range_codes_pci1710hg,
229 .rangelist_ao = &range_pci171x_da,
238 .cardtype = TYPE_PCI171X,
241 .rangelist_ai = &range_pci17x1,
242 .rangecode_ai = range_codes_pci17x1,
243 .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,
262 .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 short ao_data[4]; /* data output buffer */
289 unsigned int cnt0_write_wait; /* after a write, wait for update of the
293 /* used for gain list programming */
294 static const unsigned int muxonechan[] = {
295 0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707,
296 0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f,
297 0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717,
298 0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f
301 static int pci171x_ai_dropout(struct comedi_device *dev,
302 struct comedi_subdevice *s,
306 const struct boardtype *board = dev->board_ptr;
307 struct pci1710_private *devpriv = dev->private;
309 if (board->cardtype != TYPE_PCI1713) {
310 if ((val & 0xf000) != devpriv->act_chanlist[chan]) {
311 dev_err(dev->class_dev,
312 "A/D data droput: received from channel %d, expected %d\n",
314 (devpriv->act_chanlist[chan] >> 12) & 0xf);
321 static int pci171x_ai_check_chanlist(struct comedi_device *dev,
322 struct comedi_subdevice *s,
323 struct comedi_cmd *cmd)
325 struct pci1710_private *devpriv = dev->private;
326 unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
327 unsigned int last_aref = CR_AREF(cmd->chanlist[0]);
328 unsigned int next_chan = (chan0 + 1) % s->n_chan;
329 unsigned int chansegment[32];
333 if (cmd->chanlist_len == 1) {
334 devpriv->saved_seglen = cmd->chanlist_len;
338 /* first channel is always ok */
339 chansegment[0] = cmd->chanlist[0];
341 for (i = 1; i < cmd->chanlist_len; i++) {
342 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
343 unsigned int aref = CR_AREF(cmd->chanlist[i]);
345 if (cmd->chanlist[0] == cmd->chanlist[i])
346 break; /* we detected a loop, stop */
348 if (aref == AREF_DIFF && (chan & 1)) {
349 dev_err(dev->class_dev,
350 "Odd channel cannot be differential input!\n");
354 if (last_aref == AREF_DIFF)
355 next_chan = (next_chan + 1) % s->n_chan;
356 if (chan != next_chan) {
357 dev_err(dev->class_dev,
358 "channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
359 i, chan, next_chan, chan0);
363 /* next correct channel in list */
364 chansegment[i] = cmd->chanlist[i];
369 for (i = 0; i < cmd->chanlist_len; i++) {
370 if (cmd->chanlist[i] != chansegment[i % seglen]) {
371 dev_err(dev->class_dev,
372 "bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
373 i, CR_CHAN(chansegment[i]),
374 CR_RANGE(chansegment[i]),
375 CR_AREF(chansegment[i]),
376 CR_CHAN(cmd->chanlist[i % seglen]),
377 CR_RANGE(cmd->chanlist[i % seglen]),
378 CR_AREF(chansegment[i % seglen]));
382 devpriv->saved_seglen = seglen;
387 static void setup_channel_list(struct comedi_device *dev,
388 struct comedi_subdevice *s,
389 unsigned int *chanlist, unsigned int n_chan,
392 const struct boardtype *this_board = dev->board_ptr;
393 struct pci1710_private *devpriv = dev->private;
394 unsigned int i, range, chanprog;
396 for (i = 0; i < seglen; i++) { /* store range list to card */
397 chanprog = muxonechan[CR_CHAN(chanlist[i])];
398 outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */
399 range = this_board->rangecode_ai[CR_RANGE(chanlist[i])];
400 if (CR_AREF(chanlist[i]) == AREF_DIFF)
402 outw(range, dev->iobase + PCI171x_RANGE); /* select gain */
403 devpriv->act_chanlist[i] =
404 (CR_CHAN(chanlist[i]) << 12) & 0xf000;
406 for ( ; i < n_chan; i++) { /* store remainder of channel list */
407 devpriv->act_chanlist[i] =
408 (CR_CHAN(chanlist[i]) << 12) & 0xf000;
411 devpriv->ai_et_MuxVal =
412 CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
413 /* select channel interval to scan */
414 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
417 static int pci171x_ai_eoc(struct comedi_device *dev,
418 struct comedi_subdevice *s,
419 struct comedi_insn *insn,
420 unsigned long context)
424 status = inw(dev->iobase + PCI171x_STATUS);
425 if ((status & Status_FE) == 0)
430 static int pci171x_insn_read_ai(struct comedi_device *dev,
431 struct comedi_subdevice *s,
432 struct comedi_insn *insn, unsigned int *data)
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;
471 ==============================================================================
473 static int pci171x_insn_write_ao(struct comedi_device *dev,
474 struct comedi_subdevice *s,
475 struct comedi_insn *insn, unsigned int *data)
477 struct pci1710_private *devpriv = dev->private;
479 int n, chan, range, ofs;
481 chan = CR_CHAN(insn->chanspec);
482 range = CR_RANGE(insn->chanspec);
484 devpriv->da_ranges &= 0xfb;
485 devpriv->da_ranges |= (range << 2);
486 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
489 devpriv->da_ranges &= 0xfe;
490 devpriv->da_ranges |= range;
491 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
494 val = devpriv->ao_data[chan];
496 for (n = 0; n < insn->n; n++) {
498 outw(val, dev->iobase + ofs);
501 devpriv->ao_data[chan] = val;
508 ==============================================================================
510 static int pci171x_insn_read_ao(struct comedi_device *dev,
511 struct comedi_subdevice *s,
512 struct comedi_insn *insn, unsigned int *data)
514 struct pci1710_private *devpriv = dev->private;
517 chan = CR_CHAN(insn->chanspec);
518 for (n = 0; n < insn->n; n++)
519 data[n] = devpriv->ao_data[chan];
525 ==============================================================================
527 static int pci171x_insn_bits_di(struct comedi_device *dev,
528 struct comedi_subdevice *s,
529 struct comedi_insn *insn, unsigned int *data)
531 data[1] = inw(dev->iobase + PCI171x_DI);
536 static int pci171x_insn_bits_do(struct comedi_device *dev,
537 struct comedi_subdevice *s,
538 struct comedi_insn *insn,
541 if (comedi_dio_update_state(s, data))
542 outw(s->state, dev->iobase + PCI171x_DO);
549 static void pci171x_start_pacer(struct comedi_device *dev,
552 struct pci1710_private *devpriv = dev->private;
553 unsigned long timer_base = dev->iobase + PCI171X_TIMER_BASE;
555 i8254_set_mode(timer_base, 1, 2, I8254_MODE2 | I8254_BINARY);
556 i8254_set_mode(timer_base, 1, 1, I8254_MODE2 | I8254_BINARY);
559 i8254_write(timer_base, 1, 2, devpriv->divisor2);
560 i8254_write(timer_base, 1, 1, devpriv->divisor1);
565 ==============================================================================
567 static int pci171x_insn_counter_read(struct comedi_device *dev,
568 struct comedi_subdevice *s,
569 struct comedi_insn *insn,
572 unsigned int msb, lsb, ccntrl;
575 ccntrl = 0xD2; /* count only */
576 for (i = 0; i < insn->n; i++) {
577 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
579 lsb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
580 msb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
582 data[0] = lsb | (msb << 8);
589 ==============================================================================
591 static int pci171x_insn_counter_write(struct comedi_device *dev,
592 struct comedi_subdevice *s,
593 struct comedi_insn *insn,
596 struct pci1710_private *devpriv = dev->private;
597 uint msb, lsb, ccntrl, status;
599 lsb = data[0] & 0x00FF;
600 msb = (data[0] & 0xFF00) >> 8;
602 /* write lsb, then msb */
603 outw(lsb, dev->iobase + PCI171x_CNT0);
604 outw(msb, dev->iobase + PCI171x_CNT0);
606 if (devpriv->cnt0_write_wait) {
607 /* wait for the new count to be loaded */
610 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
611 status = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
612 } while (status & 0x40);
619 ==============================================================================
621 static int pci171x_insn_counter_config(struct comedi_device *dev,
622 struct comedi_subdevice *s,
623 struct comedi_insn *insn,
627 /* This doesn't work like a normal Comedi counter config */
628 struct pci1710_private *devpriv = dev->private;
631 devpriv->cnt0_write_wait = data[0] & 0x20;
633 /* internal or external clock? */
634 if (!(data[0] & 0x10)) { /* internal */
635 devpriv->CntrlReg &= ~Control_CNT0;
637 devpriv->CntrlReg |= Control_CNT0;
639 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
642 ccntrl |= Counter_M0;
644 ccntrl |= Counter_M1;
646 ccntrl |= Counter_M2;
648 ccntrl |= Counter_BCD;
649 ccntrl |= Counter_RW0; /* set read/write mode */
650 ccntrl |= Counter_RW1;
651 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
658 ==============================================================================
660 static int pci1720_insn_write_ao(struct comedi_device *dev,
661 struct comedi_subdevice *s,
662 struct comedi_insn *insn, unsigned int *data)
664 struct pci1710_private *devpriv = dev->private;
666 int n, rangereg, chan;
668 chan = CR_CHAN(insn->chanspec);
669 rangereg = devpriv->da_ranges & (~(0x03 << (chan << 1)));
670 rangereg |= (CR_RANGE(insn->chanspec) << (chan << 1));
671 if (rangereg != devpriv->da_ranges) {
672 outb(rangereg, dev->iobase + PCI1720_RANGE);
673 devpriv->da_ranges = rangereg;
675 val = devpriv->ao_data[chan];
677 for (n = 0; n < insn->n; n++) {
679 outw(val, dev->iobase + PCI1720_DA0 + (chan << 1));
680 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
683 devpriv->ao_data[chan] = val;
689 ==============================================================================
691 static int pci171x_ai_cancel(struct comedi_device *dev,
692 struct comedi_subdevice *s)
694 const struct boardtype *this_board = dev->board_ptr;
695 struct pci1710_private *devpriv = dev->private;
697 switch (this_board->cardtype) {
699 devpriv->CntrlReg &= Control_CNT0;
700 devpriv->CntrlReg |= Control_SW;
701 /* reset any operations */
702 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
703 pci171x_start_pacer(dev, false);
704 outb(0, dev->iobase + PCI171x_CLRFIFO);
705 outb(0, dev->iobase + PCI171x_CLRINT);
712 static void pci1710_handle_every_sample(struct comedi_device *dev,
713 struct comedi_subdevice *s)
715 struct comedi_cmd *cmd = &s->async->cmd;
720 status = inw(dev->iobase + PCI171x_STATUS);
721 if (status & Status_FE) {
722 dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", status);
723 s->async->events |= COMEDI_CB_ERROR;
724 comedi_handle_events(dev, s);
727 if (status & Status_FF) {
728 dev_dbg(dev->class_dev,
729 "A/D FIFO Full status (Fatal Error!) (%4x)\n", status);
730 s->async->events |= COMEDI_CB_ERROR;
731 comedi_handle_events(dev, s);
735 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
737 for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
738 val = inw(dev->iobase + PCI171x_AD_DATA);
739 ret = pci171x_ai_dropout(dev, s, s->async->cur_chan, val);
741 s->async->events |= COMEDI_CB_ERROR;
746 comedi_buf_write_samples(s, &val, 1);
748 if (cmd->stop_src == TRIG_COUNT &&
749 s->async->scans_done >= cmd->stop_arg) {
750 s->async->events |= COMEDI_CB_EOA;
755 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
757 comedi_handle_events(dev, s);
761 ==============================================================================
763 static int move_block_from_fifo(struct comedi_device *dev,
764 struct comedi_subdevice *s, int n, int turn)
770 for (i = 0; i < n; i++) {
771 val = inw(dev->iobase + PCI171x_AD_DATA);
773 ret = pci171x_ai_dropout(dev, s, s->async->cur_chan, val);
775 s->async->events |= COMEDI_CB_ERROR;
780 comedi_buf_write_samples(s, &val, 1);
785 static void pci1710_handle_fifo(struct comedi_device *dev,
786 struct comedi_subdevice *s)
788 struct pci1710_private *devpriv = dev->private;
789 struct comedi_cmd *cmd = &s->async->cmd;
790 unsigned int nsamples;
793 m = inw(dev->iobase + PCI171x_STATUS);
794 if (!(m & Status_FH)) {
795 dev_dbg(dev->class_dev, "A/D FIFO not half full! (%4x)\n", m);
796 s->async->events |= COMEDI_CB_ERROR;
797 comedi_handle_events(dev, s);
801 dev_dbg(dev->class_dev,
802 "A/D FIFO Full status (Fatal Error!) (%4x)\n", m);
803 s->async->events |= COMEDI_CB_ERROR;
804 comedi_handle_events(dev, s);
808 nsamples = devpriv->max_samples;
809 if (comedi_samples_to_bytes(s, nsamples) >= s->async->prealloc_bufsz) {
810 m = comedi_bytes_to_samples(s, s->async->prealloc_bufsz);
811 if (move_block_from_fifo(dev, s, m, 0))
817 if (move_block_from_fifo(dev, s, nsamples, 1))
821 if (cmd->stop_src == TRIG_COUNT &&
822 s->async->scans_done >= cmd->stop_arg) {
823 s->async->events |= COMEDI_CB_EOA;
824 comedi_handle_events(dev, s);
827 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
829 comedi_handle_events(dev, s);
833 ==============================================================================
835 static irqreturn_t interrupt_service_pci1710(int irq, void *d)
837 struct comedi_device *dev = d;
838 struct pci1710_private *devpriv = dev->private;
839 struct comedi_subdevice *s;
840 struct comedi_cmd *cmd;
842 if (!dev->attached) /* is device attached? */
843 return IRQ_NONE; /* no, exit */
845 s = dev->read_subdev;
846 cmd = &s->async->cmd;
848 /* is this interrupt from our board? */
849 if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))
850 return IRQ_NONE; /* no, exit */
852 if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */
854 devpriv->CntrlReg &= Control_CNT0;
855 devpriv->CntrlReg |= Control_SW; /* set software trigger */
856 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
857 devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
858 outb(0, dev->iobase + PCI171x_CLRFIFO);
859 outb(0, dev->iobase + PCI171x_CLRINT);
860 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
861 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
862 pci171x_start_pacer(dev, true);
866 if (cmd->flags & CMDF_WAKE_EOS)
867 pci1710_handle_every_sample(dev, s);
869 pci1710_handle_fifo(dev, s);
874 static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
876 struct pci1710_private *devpriv = dev->private;
877 struct comedi_cmd *cmd = &s->async->cmd;
879 pci171x_start_pacer(dev, false);
881 setup_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len,
882 devpriv->saved_seglen);
884 outb(0, dev->iobase + PCI171x_CLRFIFO);
885 outb(0, dev->iobase + PCI171x_CLRINT);
887 devpriv->CntrlReg &= Control_CNT0;
888 if ((cmd->flags & CMDF_WAKE_EOS) == 0)
889 devpriv->CntrlReg |= Control_ONEFH;
891 devpriv->divisor1 = devpriv->next_divisor1;
892 devpriv->divisor2 = devpriv->next_divisor2;
894 if (cmd->convert_src == TRIG_TIMER) {
895 devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
896 if (cmd->start_src == TRIG_EXT) {
897 devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
899 ~(Control_PACER | Control_ONEFH | Control_GATE);
900 devpriv->CntrlReg |= Control_EXT;
902 } else { /* TRIG_NOW */
905 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
907 if (cmd->start_src == TRIG_NOW)
908 pci171x_start_pacer(dev, true);
909 } else { /* TRIG_EXT */
910 devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
911 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
918 ==============================================================================
920 static int pci171x_ai_cmdtest(struct comedi_device *dev,
921 struct comedi_subdevice *s,
922 struct comedi_cmd *cmd)
924 struct pci1710_private *devpriv = dev->private;
928 /* Step 1 : check if triggers are trivially valid */
930 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
931 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
932 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
933 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
934 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
939 /* step 2a: make sure trigger sources are unique */
941 err |= cfc_check_trigger_is_unique(cmd->start_src);
942 err |= cfc_check_trigger_is_unique(cmd->convert_src);
943 err |= cfc_check_trigger_is_unique(cmd->stop_src);
945 /* step 2b: and mutually compatible */
950 /* Step 3: check if arguments are trivially valid */
952 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
953 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
955 if (cmd->convert_src == TRIG_TIMER)
956 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000);
957 else /* TRIG_FOLLOW */
958 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
960 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
962 if (cmd->stop_src == TRIG_COUNT)
963 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
965 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
970 /* step 4: fix up any arguments */
972 if (cmd->convert_src == TRIG_TIMER) {
973 arg = cmd->convert_arg;
974 i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
975 &devpriv->next_divisor1,
976 &devpriv->next_divisor2,
978 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
984 /* Step 5: check channel list */
986 err |= pci171x_ai_check_chanlist(dev, s, cmd);
995 ==============================================================================
997 static int pci171x_reset(struct comedi_device *dev)
999 const struct boardtype *this_board = dev->board_ptr;
1000 struct pci1710_private *devpriv = dev->private;
1002 outw(0x30, dev->iobase + PCI171x_CNTCTRL);
1003 /* Software trigger, CNT0=external */
1004 devpriv->CntrlReg = Control_SW | Control_CNT0;
1005 /* reset any operations */
1006 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
1007 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
1008 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
1009 pci171x_start_pacer(dev, false);
1010 devpriv->da_ranges = 0;
1011 if (this_board->n_aochan) {
1012 /* set DACs to 0..5V */
1013 outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
1014 outw(0, dev->iobase + PCI171x_DA1); /* set DA outputs to 0V */
1015 devpriv->ao_data[0] = 0x0000;
1016 if (this_board->n_aochan > 1) {
1017 outw(0, dev->iobase + PCI171x_DA2);
1018 devpriv->ao_data[1] = 0x0000;
1021 outw(0, dev->iobase + PCI171x_DO); /* digital outputs to 0 */
1022 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
1023 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
1029 ==============================================================================
1031 static int pci1720_reset(struct comedi_device *dev)
1033 struct pci1710_private *devpriv = dev->private;
1034 /* set synchronous output mode */
1035 outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT);
1036 devpriv->da_ranges = 0xAA;
1037 /* set all ranges to +/-5V */
1038 outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE);
1039 outw(0x0800, dev->iobase + PCI1720_DA0); /* set outputs to 0V */
1040 outw(0x0800, dev->iobase + PCI1720_DA1);
1041 outw(0x0800, dev->iobase + PCI1720_DA2);
1042 outw(0x0800, dev->iobase + PCI1720_DA3);
1043 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
1044 devpriv->ao_data[0] = 0x0800;
1045 devpriv->ao_data[1] = 0x0800;
1046 devpriv->ao_data[2] = 0x0800;
1047 devpriv->ao_data[3] = 0x0800;
1052 ==============================================================================
1054 static int pci1710_reset(struct comedi_device *dev)
1056 const struct boardtype *this_board = dev->board_ptr;
1058 switch (this_board->cardtype) {
1060 return pci1720_reset(dev);
1062 return pci171x_reset(dev);
1066 static int pci1710_auto_attach(struct comedi_device *dev,
1067 unsigned long context)
1069 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1070 const struct boardtype *this_board = NULL;
1071 struct pci1710_private *devpriv;
1072 struct comedi_subdevice *s;
1073 int ret, subdev, n_subdevices;
1075 if (context < ARRAY_SIZE(boardtypes))
1076 this_board = &boardtypes[context];
1079 dev->board_ptr = this_board;
1080 dev->board_name = this_board->name;
1082 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1086 ret = comedi_pci_enable(dev);
1089 dev->iobase = pci_resource_start(pcidev, 2);
1092 if (this_board->n_aichan)
1094 if (this_board->n_aochan)
1096 if (this_board->has_di_do)
1098 if (this_board->has_counter)
1101 ret = comedi_alloc_subdevices(dev, n_subdevices);
1107 if (this_board->has_irq && pcidev->irq) {
1108 ret = request_irq(pcidev->irq, interrupt_service_pci1710,
1109 IRQF_SHARED, dev->board_name, dev);
1111 dev->irq = pcidev->irq;
1116 if (this_board->n_aichan) {
1117 s = &dev->subdevices[subdev];
1118 s->type = COMEDI_SUBD_AI;
1119 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
1120 if (this_board->has_diff_ai)
1121 s->subdev_flags |= SDF_DIFF;
1122 s->n_chan = this_board->n_aichan;
1123 s->maxdata = 0x0fff;
1124 s->range_table = this_board->rangelist_ai;
1125 s->insn_read = pci171x_insn_read_ai;
1127 dev->read_subdev = s;
1128 s->subdev_flags |= SDF_CMD_READ;
1129 s->len_chanlist = s->n_chan;
1130 s->do_cmdtest = pci171x_ai_cmdtest;
1131 s->do_cmd = pci171x_ai_cmd;
1132 s->cancel = pci171x_ai_cancel;
1137 if (this_board->n_aochan) {
1138 s = &dev->subdevices[subdev];
1139 s->type = COMEDI_SUBD_AO;
1140 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1141 s->n_chan = this_board->n_aochan;
1142 s->maxdata = 0x0fff;
1143 s->len_chanlist = this_board->n_aochan;
1144 s->range_table = this_board->rangelist_ao;
1145 switch (this_board->cardtype) {
1147 s->insn_write = pci1720_insn_write_ao;
1150 s->insn_write = pci171x_insn_write_ao;
1153 s->insn_read = pci171x_insn_read_ao;
1157 if (this_board->has_di_do) {
1158 s = &dev->subdevices[subdev];
1159 s->type = COMEDI_SUBD_DI;
1160 s->subdev_flags = SDF_READABLE;
1163 s->range_table = &range_digital;
1164 s->insn_bits = pci171x_insn_bits_di;
1167 s = &dev->subdevices[subdev];
1168 s->type = COMEDI_SUBD_DO;
1169 s->subdev_flags = SDF_WRITABLE;
1172 s->range_table = &range_digital;
1173 s->insn_bits = pci171x_insn_bits_do;
1177 if (this_board->has_counter) {
1178 s = &dev->subdevices[subdev];
1179 s->type = COMEDI_SUBD_COUNTER;
1180 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1182 s->maxdata = 0xffff;
1183 s->range_table = &range_unknown;
1184 s->insn_read = pci171x_insn_counter_read;
1185 s->insn_write = pci171x_insn_counter_write;
1186 s->insn_config = pci171x_insn_counter_config;
1190 /* max_samples is half the FIFO size (2 bytes/sample) */
1191 devpriv->max_samples = (this_board->has_large_fifo) ? 2048 : 512;
1196 static void pci1710_detach(struct comedi_device *dev)
1200 comedi_pci_detach(dev);
1203 static struct comedi_driver adv_pci1710_driver = {
1204 .driver_name = "adv_pci1710",
1205 .module = THIS_MODULE,
1206 .auto_attach = pci1710_auto_attach,
1207 .detach = pci1710_detach,
1210 static int adv_pci1710_pci_probe(struct pci_dev *dev,
1211 const struct pci_device_id *id)
1213 return comedi_pci_auto_config(dev, &adv_pci1710_driver,
1217 static const struct pci_device_id adv_pci1710_pci_table[] = {
1219 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1220 PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050),
1221 .driver_data = BOARD_PCI1710,
1223 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1224 PCI_VENDOR_ID_ADVANTECH, 0x0000),
1225 .driver_data = BOARD_PCI1710,
1227 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1228 PCI_VENDOR_ID_ADVANTECH, 0xb100),
1229 .driver_data = BOARD_PCI1710,
1231 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1232 PCI_VENDOR_ID_ADVANTECH, 0xb200),
1233 .driver_data = BOARD_PCI1710,
1235 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1236 PCI_VENDOR_ID_ADVANTECH, 0xc100),
1237 .driver_data = BOARD_PCI1710,
1239 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1240 PCI_VENDOR_ID_ADVANTECH, 0xc200),
1241 .driver_data = BOARD_PCI1710,
1243 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd100),
1244 .driver_data = BOARD_PCI1710,
1246 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1247 PCI_VENDOR_ID_ADVANTECH, 0x0002),
1248 .driver_data = BOARD_PCI1710HG,
1250 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1251 PCI_VENDOR_ID_ADVANTECH, 0xb102),
1252 .driver_data = BOARD_PCI1710HG,
1254 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1255 PCI_VENDOR_ID_ADVANTECH, 0xb202),
1256 .driver_data = BOARD_PCI1710HG,
1258 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1259 PCI_VENDOR_ID_ADVANTECH, 0xc102),
1260 .driver_data = BOARD_PCI1710HG,
1262 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1263 PCI_VENDOR_ID_ADVANTECH, 0xc202),
1264 .driver_data = BOARD_PCI1710HG,
1266 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd102),
1267 .driver_data = BOARD_PCI1710HG,
1269 { PCI_VDEVICE(ADVANTECH, 0x1711), BOARD_PCI1711 },
1270 { PCI_VDEVICE(ADVANTECH, 0x1713), BOARD_PCI1713 },
1271 { PCI_VDEVICE(ADVANTECH, 0x1720), BOARD_PCI1720 },
1272 { PCI_VDEVICE(ADVANTECH, 0x1731), BOARD_PCI1731 },
1275 MODULE_DEVICE_TABLE(pci, adv_pci1710_pci_table);
1277 static struct pci_driver adv_pci1710_pci_driver = {
1278 .name = "adv_pci1710",
1279 .id_table = adv_pci1710_pci_table,
1280 .probe = adv_pci1710_pci_probe,
1281 .remove = comedi_pci_auto_unconfig,
1283 module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver);
1285 MODULE_AUTHOR("Comedi http://www.comedi.org");
1286 MODULE_DESCRIPTION("Comedi low-level driver");
1287 MODULE_LICENSE("GPL");