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 have_irq; /* 1=card support IRQ */
195 char cardtype; /* 0=1710& co. 2=1713, ... */
196 int n_aichan; /* num of A/D chans */
197 int n_aichand; /* num of A/D chans in diff mode */
198 int n_aochan; /* num of D/A chans */
199 int n_dichan; /* num of DI chans */
200 int n_dochan; /* num of DO chans */
201 int n_counter; /* num of counters */
202 int ai_maxdata; /* resolution of A/D */
203 int ao_maxdata; /* resolution of D/A */
204 const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */
205 const char *rangecode_ai; /* range codes for programming */
206 const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */
207 unsigned int ai_ns_min; /* max sample speed of card v ns */
208 unsigned int fifo_half_size; /* size of FIFO/2 */
211 static const struct boardtype boardtypes[] = {
215 .cardtype = TYPE_PCI171X,
222 .ai_maxdata = 0x0fff,
223 .ao_maxdata = 0x0fff,
224 .rangelist_ai = &range_pci1710_3,
225 .rangecode_ai = range_codes_pci1710_3,
226 .rangelist_ao = &range_pci171x_da,
228 .fifo_half_size = 2048,
230 [BOARD_PCI1710HG] = {
233 .cardtype = TYPE_PCI171X,
240 .ai_maxdata = 0x0fff,
241 .ao_maxdata = 0x0fff,
242 .rangelist_ai = &range_pci1710hg,
243 .rangecode_ai = range_codes_pci1710hg,
244 .rangelist_ao = &range_pci171x_da,
246 .fifo_half_size = 2048,
251 .cardtype = TYPE_PCI171X,
257 .ai_maxdata = 0x0fff,
258 .ao_maxdata = 0x0fff,
259 .rangelist_ai = &range_pci17x1,
260 .rangecode_ai = range_codes_pci17x1,
261 .rangelist_ao = &range_pci171x_da,
263 .fifo_half_size = 512,
268 .cardtype = TYPE_PCI1713,
271 .ai_maxdata = 0x0fff,
272 .rangelist_ai = &range_pci1710_3,
273 .rangecode_ai = range_codes_pci1710_3,
275 .fifo_half_size = 2048,
279 .cardtype = TYPE_PCI1720,
281 .ao_maxdata = 0x0fff,
282 .rangelist_ao = &range_pci1720,
287 .cardtype = TYPE_PCI171X,
291 .ai_maxdata = 0x0fff,
292 .rangelist_ai = &range_pci17x1,
293 .rangecode_ai = range_codes_pci17x1,
295 .fifo_half_size = 512,
299 struct pci1710_private {
300 unsigned int CntrlReg; /* Control register */
302 unsigned int ai_et_CntrlReg;
303 unsigned int ai_et_MuxVal;
304 unsigned int next_divisor1;
305 unsigned int next_divisor2;
306 unsigned int divisor1;
307 unsigned int divisor2;
308 unsigned int act_chanlist[32]; /* list of scanned channel */
309 unsigned char saved_seglen; /* len of the non-repeating chanlist */
310 unsigned char da_ranges; /* copy of D/A outpit range register */
311 unsigned short ao_data[4]; /* data output buffer */
312 unsigned int cnt0_write_wait; /* after a write, wait for update of the
316 /* used for gain list programming */
317 static const unsigned int muxonechan[] = {
318 0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707,
319 0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f,
320 0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717,
321 0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f
324 static int pci171x_ai_dropout(struct comedi_device *dev,
325 struct comedi_subdevice *s,
329 const struct boardtype *board = dev->board_ptr;
330 struct pci1710_private *devpriv = dev->private;
332 if (board->cardtype != TYPE_PCI1713) {
333 if ((val & 0xf000) != devpriv->act_chanlist[chan]) {
334 dev_err(dev->class_dev,
335 "A/D data droput: received from channel %d, expected %d\n",
337 (devpriv->act_chanlist[chan] >> 12) & 0xf);
344 static int pci171x_ai_check_chanlist(struct comedi_device *dev,
345 struct comedi_subdevice *s,
346 struct comedi_cmd *cmd)
348 struct pci1710_private *devpriv = dev->private;
349 unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
350 unsigned int last_aref = CR_AREF(cmd->chanlist[0]);
351 unsigned int next_chan = (chan0 + 1) % s->n_chan;
352 unsigned int chansegment[32];
356 if (cmd->chanlist_len == 1) {
357 devpriv->saved_seglen = cmd->chanlist_len;
361 /* first channel is always ok */
362 chansegment[0] = cmd->chanlist[0];
364 for (i = 1; i < cmd->chanlist_len; i++) {
365 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
366 unsigned int aref = CR_AREF(cmd->chanlist[i]);
368 if (cmd->chanlist[0] == cmd->chanlist[i])
369 break; /* we detected a loop, stop */
371 if (aref == AREF_DIFF && (chan & 1)) {
372 dev_err(dev->class_dev,
373 "Odd channel cannot be differential input!\n");
377 if (last_aref == AREF_DIFF)
378 next_chan = (next_chan + 1) % s->n_chan;
379 if (chan != next_chan) {
380 dev_err(dev->class_dev,
381 "channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
382 i, chan, next_chan, chan0);
386 /* next correct channel in list */
387 chansegment[i] = cmd->chanlist[i];
392 for (i = 0; i < cmd->chanlist_len; i++) {
393 if (cmd->chanlist[i] != chansegment[i % seglen]) {
394 dev_err(dev->class_dev,
395 "bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
396 i, CR_CHAN(chansegment[i]),
397 CR_RANGE(chansegment[i]),
398 CR_AREF(chansegment[i]),
399 CR_CHAN(cmd->chanlist[i % seglen]),
400 CR_RANGE(cmd->chanlist[i % seglen]),
401 CR_AREF(chansegment[i % seglen]));
405 devpriv->saved_seglen = seglen;
410 static void setup_channel_list(struct comedi_device *dev,
411 struct comedi_subdevice *s,
412 unsigned int *chanlist, unsigned int n_chan,
415 const struct boardtype *this_board = dev->board_ptr;
416 struct pci1710_private *devpriv = dev->private;
417 unsigned int i, range, chanprog;
419 for (i = 0; i < seglen; i++) { /* store range list to card */
420 chanprog = muxonechan[CR_CHAN(chanlist[i])];
421 outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */
422 range = this_board->rangecode_ai[CR_RANGE(chanlist[i])];
423 if (CR_AREF(chanlist[i]) == AREF_DIFF)
425 outw(range, dev->iobase + PCI171x_RANGE); /* select gain */
426 devpriv->act_chanlist[i] =
427 (CR_CHAN(chanlist[i]) << 12) & 0xf000;
429 for ( ; i < n_chan; i++) { /* store remainder of channel list */
430 devpriv->act_chanlist[i] =
431 (CR_CHAN(chanlist[i]) << 12) & 0xf000;
434 devpriv->ai_et_MuxVal =
435 CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
436 /* select channel interval to scan */
437 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
440 static int pci171x_ai_eoc(struct comedi_device *dev,
441 struct comedi_subdevice *s,
442 struct comedi_insn *insn,
443 unsigned long context)
447 status = inw(dev->iobase + PCI171x_STATUS);
448 if ((status & Status_FE) == 0)
453 static int pci171x_insn_read_ai(struct comedi_device *dev,
454 struct comedi_subdevice *s,
455 struct comedi_insn *insn, unsigned int *data)
457 struct pci1710_private *devpriv = dev->private;
458 unsigned int chan = CR_CHAN(insn->chanspec);
462 devpriv->CntrlReg &= Control_CNT0;
463 devpriv->CntrlReg |= Control_SW; /* set software trigger */
464 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
465 outb(0, dev->iobase + PCI171x_CLRFIFO);
466 outb(0, dev->iobase + PCI171x_CLRINT);
468 setup_channel_list(dev, s, &insn->chanspec, 1, 1);
470 for (i = 0; i < insn->n; i++) {
473 outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */
475 ret = comedi_timeout(dev, s, insn, pci171x_ai_eoc, 0);
479 val = inw(dev->iobase + PCI171x_AD_DATA);
480 ret = pci171x_ai_dropout(dev, s, chan, val);
484 data[i] = val & s->maxdata;
487 outb(0, dev->iobase + PCI171x_CLRFIFO);
488 outb(0, dev->iobase + PCI171x_CLRINT);
490 return ret ? ret : insn->n;
494 ==============================================================================
496 static int pci171x_insn_write_ao(struct comedi_device *dev,
497 struct comedi_subdevice *s,
498 struct comedi_insn *insn, unsigned int *data)
500 struct pci1710_private *devpriv = dev->private;
502 int n, chan, range, ofs;
504 chan = CR_CHAN(insn->chanspec);
505 range = CR_RANGE(insn->chanspec);
507 devpriv->da_ranges &= 0xfb;
508 devpriv->da_ranges |= (range << 2);
509 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
512 devpriv->da_ranges &= 0xfe;
513 devpriv->da_ranges |= range;
514 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
517 val = devpriv->ao_data[chan];
519 for (n = 0; n < insn->n; n++) {
521 outw(val, dev->iobase + ofs);
524 devpriv->ao_data[chan] = val;
531 ==============================================================================
533 static int pci171x_insn_read_ao(struct comedi_device *dev,
534 struct comedi_subdevice *s,
535 struct comedi_insn *insn, unsigned int *data)
537 struct pci1710_private *devpriv = dev->private;
540 chan = CR_CHAN(insn->chanspec);
541 for (n = 0; n < insn->n; n++)
542 data[n] = devpriv->ao_data[chan];
548 ==============================================================================
550 static int pci171x_insn_bits_di(struct comedi_device *dev,
551 struct comedi_subdevice *s,
552 struct comedi_insn *insn, unsigned int *data)
554 data[1] = inw(dev->iobase + PCI171x_DI);
559 static int pci171x_insn_bits_do(struct comedi_device *dev,
560 struct comedi_subdevice *s,
561 struct comedi_insn *insn,
564 if (comedi_dio_update_state(s, data))
565 outw(s->state, dev->iobase + PCI171x_DO);
572 static void pci171x_start_pacer(struct comedi_device *dev,
575 struct pci1710_private *devpriv = dev->private;
576 unsigned long timer_base = dev->iobase + PCI171X_TIMER_BASE;
578 i8254_set_mode(timer_base, 1, 2, I8254_MODE2 | I8254_BINARY);
579 i8254_set_mode(timer_base, 1, 1, I8254_MODE2 | I8254_BINARY);
582 i8254_write(timer_base, 1, 2, devpriv->divisor2);
583 i8254_write(timer_base, 1, 1, devpriv->divisor1);
588 ==============================================================================
590 static int pci171x_insn_counter_read(struct comedi_device *dev,
591 struct comedi_subdevice *s,
592 struct comedi_insn *insn,
595 unsigned int msb, lsb, ccntrl;
598 ccntrl = 0xD2; /* count only */
599 for (i = 0; i < insn->n; i++) {
600 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
602 lsb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
603 msb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
605 data[0] = lsb | (msb << 8);
612 ==============================================================================
614 static int pci171x_insn_counter_write(struct comedi_device *dev,
615 struct comedi_subdevice *s,
616 struct comedi_insn *insn,
619 struct pci1710_private *devpriv = dev->private;
620 uint msb, lsb, ccntrl, status;
622 lsb = data[0] & 0x00FF;
623 msb = (data[0] & 0xFF00) >> 8;
625 /* write lsb, then msb */
626 outw(lsb, dev->iobase + PCI171x_CNT0);
627 outw(msb, dev->iobase + PCI171x_CNT0);
629 if (devpriv->cnt0_write_wait) {
630 /* wait for the new count to be loaded */
633 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
634 status = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
635 } while (status & 0x40);
642 ==============================================================================
644 static int pci171x_insn_counter_config(struct comedi_device *dev,
645 struct comedi_subdevice *s,
646 struct comedi_insn *insn,
650 /* This doesn't work like a normal Comedi counter config */
651 struct pci1710_private *devpriv = dev->private;
654 devpriv->cnt0_write_wait = data[0] & 0x20;
656 /* internal or external clock? */
657 if (!(data[0] & 0x10)) { /* internal */
658 devpriv->CntrlReg &= ~Control_CNT0;
660 devpriv->CntrlReg |= Control_CNT0;
662 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
665 ccntrl |= Counter_M0;
667 ccntrl |= Counter_M1;
669 ccntrl |= Counter_M2;
671 ccntrl |= Counter_BCD;
672 ccntrl |= Counter_RW0; /* set read/write mode */
673 ccntrl |= Counter_RW1;
674 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
681 ==============================================================================
683 static int pci1720_insn_write_ao(struct comedi_device *dev,
684 struct comedi_subdevice *s,
685 struct comedi_insn *insn, unsigned int *data)
687 struct pci1710_private *devpriv = dev->private;
689 int n, rangereg, chan;
691 chan = CR_CHAN(insn->chanspec);
692 rangereg = devpriv->da_ranges & (~(0x03 << (chan << 1)));
693 rangereg |= (CR_RANGE(insn->chanspec) << (chan << 1));
694 if (rangereg != devpriv->da_ranges) {
695 outb(rangereg, dev->iobase + PCI1720_RANGE);
696 devpriv->da_ranges = rangereg;
698 val = devpriv->ao_data[chan];
700 for (n = 0; n < insn->n; n++) {
702 outw(val, dev->iobase + PCI1720_DA0 + (chan << 1));
703 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
706 devpriv->ao_data[chan] = val;
712 ==============================================================================
714 static int pci171x_ai_cancel(struct comedi_device *dev,
715 struct comedi_subdevice *s)
717 const struct boardtype *this_board = dev->board_ptr;
718 struct pci1710_private *devpriv = dev->private;
720 switch (this_board->cardtype) {
722 devpriv->CntrlReg &= Control_CNT0;
723 devpriv->CntrlReg |= Control_SW;
724 /* reset any operations */
725 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
726 pci171x_start_pacer(dev, false);
727 outb(0, dev->iobase + PCI171x_CLRFIFO);
728 outb(0, dev->iobase + PCI171x_CLRINT);
735 static void pci1710_handle_every_sample(struct comedi_device *dev,
736 struct comedi_subdevice *s)
738 struct comedi_cmd *cmd = &s->async->cmd;
743 status = inw(dev->iobase + PCI171x_STATUS);
744 if (status & Status_FE) {
745 dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", status);
746 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
747 comedi_handle_events(dev, s);
750 if (status & Status_FF) {
751 dev_dbg(dev->class_dev,
752 "A/D FIFO Full status (Fatal Error!) (%4x)\n", status);
753 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
754 comedi_handle_events(dev, s);
758 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
760 for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
761 val = inw(dev->iobase + PCI171x_AD_DATA);
762 ret = pci171x_ai_dropout(dev, s, s->async->cur_chan, val);
764 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
769 comedi_buf_write_samples(s, &val, 1);
771 if (cmd->stop_src == TRIG_COUNT &&
772 s->async->scans_done >= cmd->stop_arg) {
773 s->async->events |= COMEDI_CB_EOA;
778 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
780 comedi_handle_events(dev, s);
784 ==============================================================================
786 static int move_block_from_fifo(struct comedi_device *dev,
787 struct comedi_subdevice *s, int n, int turn)
793 for (i = 0; i < n; i++) {
794 val = inw(dev->iobase + PCI171x_AD_DATA);
796 ret = pci171x_ai_dropout(dev, s, s->async->cur_chan, val);
798 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
803 comedi_buf_write_samples(s, &val, 1);
808 static void pci1710_handle_fifo(struct comedi_device *dev,
809 struct comedi_subdevice *s)
811 const struct boardtype *this_board = dev->board_ptr;
812 struct comedi_cmd *cmd = &s->async->cmd;
813 unsigned int nsamples;
816 m = inw(dev->iobase + PCI171x_STATUS);
817 if (!(m & Status_FH)) {
818 dev_dbg(dev->class_dev, "A/D FIFO not half full! (%4x)\n", m);
819 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
820 comedi_handle_events(dev, s);
824 dev_dbg(dev->class_dev,
825 "A/D FIFO Full status (Fatal Error!) (%4x)\n", m);
826 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
827 comedi_handle_events(dev, s);
831 nsamples = this_board->fifo_half_size;
832 if (comedi_samples_to_bytes(s, nsamples) >= s->async->prealloc_bufsz) {
833 m = comedi_bytes_to_samples(s, s->async->prealloc_bufsz);
834 if (move_block_from_fifo(dev, s, m, 0))
840 if (move_block_from_fifo(dev, s, nsamples, 1))
844 if (cmd->stop_src == TRIG_COUNT &&
845 s->async->scans_done >= cmd->stop_arg) {
846 s->async->events |= COMEDI_CB_EOA;
847 comedi_handle_events(dev, s);
850 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
852 comedi_handle_events(dev, s);
856 ==============================================================================
858 static irqreturn_t interrupt_service_pci1710(int irq, void *d)
860 struct comedi_device *dev = d;
861 struct pci1710_private *devpriv = dev->private;
862 struct comedi_subdevice *s;
863 struct comedi_cmd *cmd;
865 if (!dev->attached) /* is device attached? */
866 return IRQ_NONE; /* no, exit */
868 s = dev->read_subdev;
869 cmd = &s->async->cmd;
871 /* is this interrupt from our board? */
872 if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))
873 return IRQ_NONE; /* no, exit */
875 if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */
877 devpriv->CntrlReg &= Control_CNT0;
878 devpriv->CntrlReg |= Control_SW; /* set software trigger */
879 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
880 devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
881 outb(0, dev->iobase + PCI171x_CLRFIFO);
882 outb(0, dev->iobase + PCI171x_CLRINT);
883 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
884 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
885 pci171x_start_pacer(dev, true);
889 if (cmd->flags & CMDF_WAKE_EOS)
890 pci1710_handle_every_sample(dev, s);
892 pci1710_handle_fifo(dev, s);
897 static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
899 struct pci1710_private *devpriv = dev->private;
900 struct comedi_cmd *cmd = &s->async->cmd;
902 pci171x_start_pacer(dev, false);
904 setup_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len,
905 devpriv->saved_seglen);
907 outb(0, dev->iobase + PCI171x_CLRFIFO);
908 outb(0, dev->iobase + PCI171x_CLRINT);
910 devpriv->CntrlReg &= Control_CNT0;
911 if ((cmd->flags & CMDF_WAKE_EOS) == 0)
912 devpriv->CntrlReg |= Control_ONEFH;
914 devpriv->divisor1 = devpriv->next_divisor1;
915 devpriv->divisor2 = devpriv->next_divisor2;
917 if (cmd->convert_src == TRIG_TIMER) {
918 devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
919 if (cmd->start_src == TRIG_EXT) {
920 devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
922 ~(Control_PACER | Control_ONEFH | Control_GATE);
923 devpriv->CntrlReg |= Control_EXT;
925 } else { /* TRIG_NOW */
928 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
930 if (cmd->start_src == TRIG_NOW)
931 pci171x_start_pacer(dev, true);
932 } else { /* TRIG_EXT */
933 devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
934 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
941 ==============================================================================
943 static int pci171x_ai_cmdtest(struct comedi_device *dev,
944 struct comedi_subdevice *s,
945 struct comedi_cmd *cmd)
947 const struct boardtype *this_board = dev->board_ptr;
948 struct pci1710_private *devpriv = dev->private;
952 /* Step 1 : check if triggers are trivially valid */
954 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
955 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
956 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
957 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
958 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
963 /* step 2a: make sure trigger sources are unique */
965 err |= cfc_check_trigger_is_unique(cmd->start_src);
966 err |= cfc_check_trigger_is_unique(cmd->convert_src);
967 err |= cfc_check_trigger_is_unique(cmd->stop_src);
969 /* step 2b: and mutually compatible */
974 /* Step 3: check if arguments are trivially valid */
976 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
977 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
979 if (cmd->convert_src == TRIG_TIMER)
980 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
981 this_board->ai_ns_min);
982 else /* TRIG_FOLLOW */
983 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
985 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
987 if (cmd->stop_src == TRIG_COUNT)
988 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
990 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
995 /* step 4: fix up any arguments */
997 if (cmd->convert_src == TRIG_TIMER) {
998 arg = cmd->convert_arg;
999 i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
1000 &devpriv->next_divisor1,
1001 &devpriv->next_divisor2,
1003 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
1009 /* Step 5: check channel list */
1011 err |= pci171x_ai_check_chanlist(dev, s, cmd);
1020 ==============================================================================
1022 static int pci171x_reset(struct comedi_device *dev)
1024 const struct boardtype *this_board = dev->board_ptr;
1025 struct pci1710_private *devpriv = dev->private;
1027 outw(0x30, dev->iobase + PCI171x_CNTCTRL);
1028 /* Software trigger, CNT0=external */
1029 devpriv->CntrlReg = Control_SW | Control_CNT0;
1030 /* reset any operations */
1031 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
1032 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
1033 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
1034 pci171x_start_pacer(dev, false);
1035 devpriv->da_ranges = 0;
1036 if (this_board->n_aochan) {
1037 /* set DACs to 0..5V */
1038 outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
1039 outw(0, dev->iobase + PCI171x_DA1); /* set DA outputs to 0V */
1040 devpriv->ao_data[0] = 0x0000;
1041 if (this_board->n_aochan > 1) {
1042 outw(0, dev->iobase + PCI171x_DA2);
1043 devpriv->ao_data[1] = 0x0000;
1046 outw(0, dev->iobase + PCI171x_DO); /* digital outputs to 0 */
1047 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
1048 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
1054 ==============================================================================
1056 static int pci1720_reset(struct comedi_device *dev)
1058 struct pci1710_private *devpriv = dev->private;
1059 /* set synchronous output mode */
1060 outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT);
1061 devpriv->da_ranges = 0xAA;
1062 /* set all ranges to +/-5V */
1063 outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE);
1064 outw(0x0800, dev->iobase + PCI1720_DA0); /* set outputs to 0V */
1065 outw(0x0800, dev->iobase + PCI1720_DA1);
1066 outw(0x0800, dev->iobase + PCI1720_DA2);
1067 outw(0x0800, dev->iobase + PCI1720_DA3);
1068 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
1069 devpriv->ao_data[0] = 0x0800;
1070 devpriv->ao_data[1] = 0x0800;
1071 devpriv->ao_data[2] = 0x0800;
1072 devpriv->ao_data[3] = 0x0800;
1077 ==============================================================================
1079 static int pci1710_reset(struct comedi_device *dev)
1081 const struct boardtype *this_board = dev->board_ptr;
1083 switch (this_board->cardtype) {
1085 return pci1720_reset(dev);
1087 return pci171x_reset(dev);
1091 static int pci1710_auto_attach(struct comedi_device *dev,
1092 unsigned long context)
1094 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1095 const struct boardtype *this_board = NULL;
1096 struct pci1710_private *devpriv;
1097 struct comedi_subdevice *s;
1098 int ret, subdev, n_subdevices;
1100 if (context < ARRAY_SIZE(boardtypes))
1101 this_board = &boardtypes[context];
1104 dev->board_ptr = this_board;
1105 dev->board_name = this_board->name;
1107 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1111 ret = comedi_pci_enable(dev);
1114 dev->iobase = pci_resource_start(pcidev, 2);
1117 if (this_board->n_aichan)
1119 if (this_board->n_aochan)
1121 if (this_board->n_dichan)
1123 if (this_board->n_dochan)
1125 if (this_board->n_counter)
1128 ret = comedi_alloc_subdevices(dev, n_subdevices);
1134 if (this_board->have_irq && pcidev->irq) {
1135 ret = request_irq(pcidev->irq, interrupt_service_pci1710,
1136 IRQF_SHARED, dev->board_name, dev);
1138 dev->irq = pcidev->irq;
1143 if (this_board->n_aichan) {
1144 s = &dev->subdevices[subdev];
1145 s->type = COMEDI_SUBD_AI;
1146 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
1147 if (this_board->n_aichand)
1148 s->subdev_flags |= SDF_DIFF;
1149 s->n_chan = this_board->n_aichan;
1150 s->maxdata = this_board->ai_maxdata;
1151 s->range_table = this_board->rangelist_ai;
1152 s->insn_read = pci171x_insn_read_ai;
1154 dev->read_subdev = s;
1155 s->subdev_flags |= SDF_CMD_READ;
1156 s->len_chanlist = s->n_chan;
1157 s->do_cmdtest = pci171x_ai_cmdtest;
1158 s->do_cmd = pci171x_ai_cmd;
1159 s->cancel = pci171x_ai_cancel;
1164 if (this_board->n_aochan) {
1165 s = &dev->subdevices[subdev];
1166 s->type = COMEDI_SUBD_AO;
1167 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1168 s->n_chan = this_board->n_aochan;
1169 s->maxdata = this_board->ao_maxdata;
1170 s->len_chanlist = this_board->n_aochan;
1171 s->range_table = this_board->rangelist_ao;
1172 switch (this_board->cardtype) {
1174 s->insn_write = pci1720_insn_write_ao;
1177 s->insn_write = pci171x_insn_write_ao;
1180 s->insn_read = pci171x_insn_read_ao;
1184 if (this_board->n_dichan) {
1185 s = &dev->subdevices[subdev];
1186 s->type = COMEDI_SUBD_DI;
1187 s->subdev_flags = SDF_READABLE;
1188 s->n_chan = this_board->n_dichan;
1190 s->len_chanlist = this_board->n_dichan;
1191 s->range_table = &range_digital;
1192 s->insn_bits = pci171x_insn_bits_di;
1196 if (this_board->n_dochan) {
1197 s = &dev->subdevices[subdev];
1198 s->type = COMEDI_SUBD_DO;
1199 s->subdev_flags = SDF_WRITABLE;
1200 s->n_chan = this_board->n_dochan;
1202 s->len_chanlist = this_board->n_dochan;
1203 s->range_table = &range_digital;
1204 s->insn_bits = pci171x_insn_bits_do;
1208 if (this_board->n_counter) {
1209 s = &dev->subdevices[subdev];
1210 s->type = COMEDI_SUBD_COUNTER;
1211 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1212 s->n_chan = this_board->n_counter;
1213 s->len_chanlist = this_board->n_counter;
1214 s->maxdata = 0xffff;
1215 s->range_table = &range_unknown;
1216 s->insn_read = pci171x_insn_counter_read;
1217 s->insn_write = pci171x_insn_counter_write;
1218 s->insn_config = pci171x_insn_counter_config;
1225 static void pci1710_detach(struct comedi_device *dev)
1229 comedi_pci_detach(dev);
1232 static struct comedi_driver adv_pci1710_driver = {
1233 .driver_name = "adv_pci1710",
1234 .module = THIS_MODULE,
1235 .auto_attach = pci1710_auto_attach,
1236 .detach = pci1710_detach,
1239 static int adv_pci1710_pci_probe(struct pci_dev *dev,
1240 const struct pci_device_id *id)
1242 return comedi_pci_auto_config(dev, &adv_pci1710_driver,
1246 static const struct pci_device_id adv_pci1710_pci_table[] = {
1248 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1249 PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050),
1250 .driver_data = BOARD_PCI1710,
1252 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1253 PCI_VENDOR_ID_ADVANTECH, 0x0000),
1254 .driver_data = BOARD_PCI1710,
1256 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1257 PCI_VENDOR_ID_ADVANTECH, 0xb100),
1258 .driver_data = BOARD_PCI1710,
1260 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1261 PCI_VENDOR_ID_ADVANTECH, 0xb200),
1262 .driver_data = BOARD_PCI1710,
1264 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1265 PCI_VENDOR_ID_ADVANTECH, 0xc100),
1266 .driver_data = BOARD_PCI1710,
1268 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1269 PCI_VENDOR_ID_ADVANTECH, 0xc200),
1270 .driver_data = BOARD_PCI1710,
1272 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd100),
1273 .driver_data = BOARD_PCI1710,
1275 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1276 PCI_VENDOR_ID_ADVANTECH, 0x0002),
1277 .driver_data = BOARD_PCI1710HG,
1279 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1280 PCI_VENDOR_ID_ADVANTECH, 0xb102),
1281 .driver_data = BOARD_PCI1710HG,
1283 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1284 PCI_VENDOR_ID_ADVANTECH, 0xb202),
1285 .driver_data = BOARD_PCI1710HG,
1287 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1288 PCI_VENDOR_ID_ADVANTECH, 0xc102),
1289 .driver_data = BOARD_PCI1710HG,
1291 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1292 PCI_VENDOR_ID_ADVANTECH, 0xc202),
1293 .driver_data = BOARD_PCI1710HG,
1295 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd102),
1296 .driver_data = BOARD_PCI1710HG,
1298 { PCI_VDEVICE(ADVANTECH, 0x1711), BOARD_PCI1711 },
1299 { PCI_VDEVICE(ADVANTECH, 0x1713), BOARD_PCI1713 },
1300 { PCI_VDEVICE(ADVANTECH, 0x1720), BOARD_PCI1720 },
1301 { PCI_VDEVICE(ADVANTECH, 0x1731), BOARD_PCI1731 },
1304 MODULE_DEVICE_TABLE(pci, adv_pci1710_pci_table);
1306 static struct pci_driver adv_pci1710_pci_driver = {
1307 .name = "adv_pci1710",
1308 .id_table = adv_pci1710_pci_table,
1309 .probe = adv_pci1710_pci_probe,
1310 .remove = comedi_pci_auto_unconfig,
1312 module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver);
1314 MODULE_AUTHOR("Comedi http://www.comedi.org");
1315 MODULE_DESCRIPTION("Comedi low-level driver");
1316 MODULE_LICENSE("GPL");