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 information.
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/interrupt.h>
47 #include "../comedi_pci.h"
49 #include "comedi_8254.h"
50 #include "amcc_s5933.h"
52 #define PCI171x_AD_DATA 0 /* R: A/D data */
53 #define PCI171x_SOFTTRG 0 /* W: soft trigger for A/D */
54 #define PCI171x_RANGE 2 /* W: A/D gain/range register */
55 #define PCI171x_MUX 4 /* W: A/D multiplexor control */
56 #define PCI171x_STATUS 6 /* R: status register */
57 #define PCI171x_CONTROL 6 /* W: control register */
58 #define PCI171x_CLRINT 8 /* W: clear interrupts request */
59 #define PCI171x_CLRFIFO 9 /* W: clear FIFO */
60 #define PCI171x_DA1 10 /* W: D/A register */
61 #define PCI171x_DA2 12 /* W: D/A register */
62 #define PCI171x_DAREF 14 /* W: D/A reference control */
63 #define PCI171x_DI 16 /* R: digi inputs */
64 #define PCI171x_DO 16 /* R: digi inputs */
66 #define PCI171X_TIMER_BASE 0x18
68 /* upper bits from status register (PCI171x_STATUS) (lower is same with control
70 #define Status_FE 0x0100 /* 1=FIFO is empty */
71 #define Status_FH 0x0200 /* 1=FIFO is half full */
72 #define Status_FF 0x0400 /* 1=FIFO is full, fatal error */
73 #define Status_IRQ 0x0800 /* 1=IRQ occurred */
74 /* bits from control register (PCI171x_CONTROL) */
75 #define Control_CNT0 0x0040 /* 1=CNT0 have external source,
76 * 0=have internal 100kHz source */
77 #define Control_ONEFH 0x0020 /* 1=IRQ on FIFO is half full, 0=every sample */
78 #define Control_IRQEN 0x0010 /* 1=enable IRQ */
79 #define Control_GATE 0x0008 /* 1=enable external trigger GATE (8254?) */
80 #define Control_EXT 0x0004 /* 1=external trigger source */
81 #define Control_PACER 0x0002 /* 1=enable internal 8254 trigger source */
82 #define Control_SW 0x0001 /* 1=enable software trigger source */
84 #define PCI1720_DA0 0 /* W: D/A register 0 */
85 #define PCI1720_DA1 2 /* W: D/A register 1 */
86 #define PCI1720_DA2 4 /* W: D/A register 2 */
87 #define PCI1720_DA3 6 /* W: D/A register 3 */
88 #define PCI1720_RANGE 8 /* R/W: D/A range register */
89 #define PCI1720_SYNCOUT 9 /* W: D/A synchronized output register */
90 #define PCI1720_SYNCONT 15 /* R/W: D/A synchronized control */
92 /* D/A synchronized control (PCI1720_SYNCONT) */
93 #define Syncont_SC0 1 /* set synchronous output mode */
95 static const struct comedi_lrange range_pci1710_3 = {
109 static const char range_codes_pci1710_3[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
110 0x10, 0x11, 0x12, 0x13 };
112 static const struct comedi_lrange range_pci1710hg = {
129 static const char range_codes_pci1710hg[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
130 0x05, 0x06, 0x07, 0x10, 0x11,
133 static const struct comedi_lrange range_pci17x1 = {
143 static const char range_codes_pci17x1[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
145 static const struct comedi_lrange pci1720_ao_range = {
154 static const struct comedi_lrange pci171x_ao_range = {
161 enum pci1710_boardid {
171 const char *name; /* board name */
172 int n_aichan; /* num of A/D chans */
173 const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */
174 const char *rangecode_ai; /* range codes for programming */
175 unsigned int is_pci1713:1;
176 unsigned int is_pci1720:1;
177 unsigned int has_irq:1;
178 unsigned int has_large_fifo:1; /* 4K or 1K FIFO */
179 unsigned int has_diff_ai:1;
180 unsigned int has_ao:1;
181 unsigned int has_di_do:1;
182 unsigned int has_counter:1;
185 static const struct boardtype boardtypes[] = {
189 .rangelist_ai = &range_pci1710_3,
190 .rangecode_ai = range_codes_pci1710_3,
198 [BOARD_PCI1710HG] = {
201 .rangelist_ai = &range_pci1710hg,
202 .rangecode_ai = range_codes_pci1710hg,
213 .rangelist_ai = &range_pci17x1,
214 .rangecode_ai = range_codes_pci17x1,
223 .rangelist_ai = &range_pci1710_3,
224 .rangecode_ai = range_codes_pci1710_3,
238 .rangelist_ai = &range_pci17x1,
239 .rangecode_ai = range_codes_pci17x1,
245 struct pci1710_private {
246 unsigned int max_samples;
247 unsigned int CntrlReg; /* Control register */
249 unsigned int ai_et_CntrlReg;
250 unsigned int ai_et_MuxVal;
251 unsigned int act_chanlist[32]; /* list of scanned channel */
252 unsigned char saved_seglen; /* len of the non-repeating chanlist */
253 unsigned char da_ranges; /* copy of D/A outpit range register */
256 static int pci171x_ai_check_chanlist(struct comedi_device *dev,
257 struct comedi_subdevice *s,
258 struct comedi_cmd *cmd)
260 struct pci1710_private *devpriv = dev->private;
261 unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
262 unsigned int last_aref = CR_AREF(cmd->chanlist[0]);
263 unsigned int next_chan = (chan0 + 1) % s->n_chan;
264 unsigned int chansegment[32];
268 if (cmd->chanlist_len == 1) {
269 devpriv->saved_seglen = cmd->chanlist_len;
273 /* first channel is always ok */
274 chansegment[0] = cmd->chanlist[0];
276 for (i = 1; i < cmd->chanlist_len; i++) {
277 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
278 unsigned int aref = CR_AREF(cmd->chanlist[i]);
280 if (cmd->chanlist[0] == cmd->chanlist[i])
281 break; /* we detected a loop, stop */
283 if (aref == AREF_DIFF && (chan & 1)) {
284 dev_err(dev->class_dev,
285 "Odd channel cannot be differential input!\n");
289 if (last_aref == AREF_DIFF)
290 next_chan = (next_chan + 1) % s->n_chan;
291 if (chan != next_chan) {
292 dev_err(dev->class_dev,
293 "channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
294 i, chan, next_chan, chan0);
298 /* next correct channel in list */
299 chansegment[i] = cmd->chanlist[i];
304 for (i = 0; i < cmd->chanlist_len; i++) {
305 if (cmd->chanlist[i] != chansegment[i % seglen]) {
306 dev_err(dev->class_dev,
307 "bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
308 i, CR_CHAN(chansegment[i]),
309 CR_RANGE(chansegment[i]),
310 CR_AREF(chansegment[i]),
311 CR_CHAN(cmd->chanlist[i % seglen]),
312 CR_RANGE(cmd->chanlist[i % seglen]),
313 CR_AREF(chansegment[i % seglen]));
317 devpriv->saved_seglen = seglen;
322 static void pci171x_ai_setup_chanlist(struct comedi_device *dev,
323 struct comedi_subdevice *s,
324 unsigned int *chanlist,
328 const struct boardtype *board = dev->board_ptr;
329 struct pci1710_private *devpriv = dev->private;
330 unsigned int first_chan = CR_CHAN(chanlist[0]);
331 unsigned int last_chan = CR_CHAN(chanlist[seglen - 1]);
334 for (i = 0; i < seglen; i++) { /* store range list to card */
335 unsigned int chan = CR_CHAN(chanlist[i]);
336 unsigned int range = CR_RANGE(chanlist[i]);
337 unsigned int aref = CR_AREF(chanlist[i]);
338 unsigned int rangeval;
340 rangeval = board->rangecode_ai[range];
341 if (aref == AREF_DIFF)
344 /* select channel and set range */
345 outw(chan | (chan << 8), dev->iobase + PCI171x_MUX);
346 outw(rangeval, dev->iobase + PCI171x_RANGE);
348 devpriv->act_chanlist[i] = chan;
350 for ( ; i < n_chan; i++) /* store remainder of channel list */
351 devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]);
353 /* select channel interval to scan */
354 devpriv->ai_et_MuxVal = first_chan | (last_chan << 8);
355 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
358 static int pci171x_ai_eoc(struct comedi_device *dev,
359 struct comedi_subdevice *s,
360 struct comedi_insn *insn,
361 unsigned long context)
365 status = inw(dev->iobase + PCI171x_STATUS);
366 if ((status & Status_FE) == 0)
371 static int pci171x_ai_read_sample(struct comedi_device *dev,
372 struct comedi_subdevice *s,
373 unsigned int cur_chan,
376 const struct boardtype *board = dev->board_ptr;
377 struct pci1710_private *devpriv = dev->private;
381 sample = inw(dev->iobase + PCI171x_AD_DATA);
382 if (!board->is_pci1713) {
384 * The upper 4 bits of the 16-bit sample are the channel number
385 * that the sample was acquired from. Verify that this channel
386 * number matches the expected channel number.
389 if (chan != devpriv->act_chanlist[cur_chan]) {
390 dev_err(dev->class_dev,
391 "A/D data droput: received from channel %d, expected %d\n",
392 chan, devpriv->act_chanlist[cur_chan]);
396 *val = sample & s->maxdata;
400 static int pci171x_ai_insn_read(struct comedi_device *dev,
401 struct comedi_subdevice *s,
402 struct comedi_insn *insn,
405 struct pci1710_private *devpriv = dev->private;
409 devpriv->CntrlReg &= Control_CNT0;
410 devpriv->CntrlReg |= Control_SW; /* set software trigger */
411 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
412 outb(0, dev->iobase + PCI171x_CLRFIFO);
413 outb(0, dev->iobase + PCI171x_CLRINT);
415 pci171x_ai_setup_chanlist(dev, s, &insn->chanspec, 1, 1);
417 for (i = 0; i < insn->n; i++) {
420 outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */
422 ret = comedi_timeout(dev, s, insn, pci171x_ai_eoc, 0);
426 ret = pci171x_ai_read_sample(dev, s, 0, &val);
433 outb(0, dev->iobase + PCI171x_CLRFIFO);
434 outb(0, dev->iobase + PCI171x_CLRINT);
436 return ret ? ret : insn->n;
439 static int pci171x_ao_insn_write(struct comedi_device *dev,
440 struct comedi_subdevice *s,
441 struct comedi_insn *insn,
444 struct pci1710_private *devpriv = dev->private;
445 unsigned int chan = CR_CHAN(insn->chanspec);
446 unsigned int range = CR_RANGE(insn->chanspec);
447 unsigned int reg = chan ? PCI171x_DA2 : PCI171x_DA1;
448 unsigned int val = s->readback[chan];
451 devpriv->da_ranges &= ~(1 << (chan << 1));
452 devpriv->da_ranges |= (range << (chan << 1));
453 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
455 for (i = 0; i < insn->n; i++) {
457 outw(val, dev->iobase + reg);
460 s->readback[chan] = val;
465 static int pci171x_di_insn_bits(struct comedi_device *dev,
466 struct comedi_subdevice *s,
467 struct comedi_insn *insn,
470 data[1] = inw(dev->iobase + PCI171x_DI);
475 static int pci171x_do_insn_bits(struct comedi_device *dev,
476 struct comedi_subdevice *s,
477 struct comedi_insn *insn,
480 if (comedi_dio_update_state(s, data))
481 outw(s->state, dev->iobase + PCI171x_DO);
488 static int pci1720_ao_insn_write(struct comedi_device *dev,
489 struct comedi_subdevice *s,
490 struct comedi_insn *insn,
493 struct pci1710_private *devpriv = dev->private;
494 unsigned int chan = CR_CHAN(insn->chanspec);
495 unsigned int range = CR_RANGE(insn->chanspec);
499 val = devpriv->da_ranges & (~(0x03 << (chan << 1)));
500 val |= (range << (chan << 1));
501 if (val != devpriv->da_ranges) {
502 outb(val, dev->iobase + PCI1720_RANGE);
503 devpriv->da_ranges = val;
506 val = s->readback[chan];
507 for (i = 0; i < insn->n; i++) {
509 outw(val, dev->iobase + PCI1720_DA0 + (chan << 1));
510 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
513 s->readback[chan] = val;
518 static int pci171x_ai_cancel(struct comedi_device *dev,
519 struct comedi_subdevice *s)
521 struct pci1710_private *devpriv = dev->private;
523 devpriv->CntrlReg &= Control_CNT0;
524 devpriv->CntrlReg |= Control_SW;
525 /* reset any operations */
526 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
527 comedi_8254_pacer_enable(dev->pacer, 1, 2, false);
528 outb(0, dev->iobase + PCI171x_CLRFIFO);
529 outb(0, dev->iobase + PCI171x_CLRINT);
534 static void pci1710_handle_every_sample(struct comedi_device *dev,
535 struct comedi_subdevice *s)
537 struct comedi_cmd *cmd = &s->async->cmd;
542 status = inw(dev->iobase + PCI171x_STATUS);
543 if (status & Status_FE) {
544 dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", status);
545 s->async->events |= COMEDI_CB_ERROR;
548 if (status & Status_FF) {
549 dev_dbg(dev->class_dev,
550 "A/D FIFO Full status (Fatal Error!) (%4x)\n", status);
551 s->async->events |= COMEDI_CB_ERROR;
555 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
557 for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
558 ret = pci171x_ai_read_sample(dev, s, s->async->cur_chan, &val);
560 s->async->events |= COMEDI_CB_ERROR;
564 comedi_buf_write_samples(s, &val, 1);
566 if (cmd->stop_src == TRIG_COUNT &&
567 s->async->scans_done >= cmd->stop_arg) {
568 s->async->events |= COMEDI_CB_EOA;
573 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
576 static void pci1710_handle_fifo(struct comedi_device *dev,
577 struct comedi_subdevice *s)
579 struct pci1710_private *devpriv = dev->private;
580 struct comedi_async *async = s->async;
581 struct comedi_cmd *cmd = &async->cmd;
585 status = inw(dev->iobase + PCI171x_STATUS);
586 if (!(status & Status_FH)) {
587 dev_dbg(dev->class_dev, "A/D FIFO not half full!\n");
588 async->events |= COMEDI_CB_ERROR;
591 if (status & Status_FF) {
592 dev_dbg(dev->class_dev,
593 "A/D FIFO Full status (Fatal Error!)\n");
594 async->events |= COMEDI_CB_ERROR;
598 for (i = 0; i < devpriv->max_samples; i++) {
602 ret = pci171x_ai_read_sample(dev, s, s->async->cur_chan, &val);
604 s->async->events |= COMEDI_CB_ERROR;
608 if (!comedi_buf_write_samples(s, &val, 1))
611 if (cmd->stop_src == TRIG_COUNT &&
612 async->scans_done >= cmd->stop_arg) {
613 async->events |= COMEDI_CB_EOA;
618 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
621 static irqreturn_t interrupt_service_pci1710(int irq, void *d)
623 struct comedi_device *dev = d;
624 struct pci1710_private *devpriv = dev->private;
625 struct comedi_subdevice *s;
626 struct comedi_cmd *cmd;
628 if (!dev->attached) /* is device attached? */
629 return IRQ_NONE; /* no, exit */
631 s = dev->read_subdev;
632 cmd = &s->async->cmd;
634 /* is this interrupt from our board? */
635 if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))
636 return IRQ_NONE; /* no, exit */
638 if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */
640 devpriv->CntrlReg &= Control_CNT0;
641 devpriv->CntrlReg |= Control_SW; /* set software trigger */
642 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
643 devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
644 outb(0, dev->iobase + PCI171x_CLRFIFO);
645 outb(0, dev->iobase + PCI171x_CLRINT);
646 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
647 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
648 comedi_8254_pacer_enable(dev->pacer, 1, 2, true);
652 if (cmd->flags & CMDF_WAKE_EOS)
653 pci1710_handle_every_sample(dev, s);
655 pci1710_handle_fifo(dev, s);
657 comedi_handle_events(dev, s);
662 static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
664 struct pci1710_private *devpriv = dev->private;
665 struct comedi_cmd *cmd = &s->async->cmd;
667 pci171x_ai_setup_chanlist(dev, s, cmd->chanlist, cmd->chanlist_len,
668 devpriv->saved_seglen);
670 outb(0, dev->iobase + PCI171x_CLRFIFO);
671 outb(0, dev->iobase + PCI171x_CLRINT);
673 devpriv->CntrlReg &= Control_CNT0;
674 if ((cmd->flags & CMDF_WAKE_EOS) == 0)
675 devpriv->CntrlReg |= Control_ONEFH;
677 if (cmd->convert_src == TRIG_TIMER) {
678 comedi_8254_update_divisors(dev->pacer);
680 devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
681 if (cmd->start_src == TRIG_EXT) {
682 devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
684 ~(Control_PACER | Control_ONEFH | Control_GATE);
685 devpriv->CntrlReg |= Control_EXT;
687 } else { /* TRIG_NOW */
690 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
692 if (cmd->start_src == TRIG_NOW)
693 comedi_8254_pacer_enable(dev->pacer, 1, 2, true);
694 } else { /* TRIG_EXT */
695 devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
696 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
702 static int pci171x_ai_cmdtest(struct comedi_device *dev,
703 struct comedi_subdevice *s,
704 struct comedi_cmd *cmd)
708 /* Step 1 : check if triggers are trivially valid */
710 err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
711 err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
712 err |= comedi_check_trigger_src(&cmd->convert_src,
713 TRIG_TIMER | TRIG_EXT);
714 err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
715 err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
720 /* step 2a: make sure trigger sources are unique */
722 err |= comedi_check_trigger_is_unique(cmd->start_src);
723 err |= comedi_check_trigger_is_unique(cmd->convert_src);
724 err |= comedi_check_trigger_is_unique(cmd->stop_src);
726 /* step 2b: and mutually compatible */
731 /* Step 3: check if arguments are trivially valid */
733 err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
734 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
736 if (cmd->convert_src == TRIG_TIMER)
737 err |= comedi_check_trigger_arg_min(&cmd->convert_arg, 10000);
738 else /* TRIG_FOLLOW */
739 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
741 err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
744 if (cmd->stop_src == TRIG_COUNT)
745 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
747 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
752 /* step 4: fix up any arguments */
754 if (cmd->convert_src == TRIG_TIMER) {
755 unsigned int arg = cmd->convert_arg;
757 comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags);
758 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
764 /* Step 5: check channel list */
766 err |= pci171x_ai_check_chanlist(dev, s, cmd);
774 static int pci171x_insn_counter_config(struct comedi_device *dev,
775 struct comedi_subdevice *s,
776 struct comedi_insn *insn,
779 struct pci1710_private *devpriv = dev->private;
782 case INSN_CONFIG_SET_CLOCK_SRC:
784 case 0: /* internal */
785 devpriv->ai_et_CntrlReg &= ~Control_CNT0;
787 case 1: /* external */
788 devpriv->ai_et_CntrlReg |= Control_CNT0;
793 outw(devpriv->ai_et_CntrlReg, dev->iobase + PCI171x_CONTROL);
795 case INSN_CONFIG_GET_CLOCK_SRC:
796 if (devpriv->ai_et_CntrlReg & Control_CNT0) {
801 data[2] = I8254_OSC_BASE_10MHZ;
811 static int pci171x_reset(struct comedi_device *dev)
813 const struct boardtype *board = dev->board_ptr;
814 struct pci1710_private *devpriv = dev->private;
816 /* Software trigger, CNT0=external */
817 devpriv->CntrlReg = Control_SW | Control_CNT0;
818 /* reset any operations */
819 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
820 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
821 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
822 devpriv->da_ranges = 0;
824 /* set DACs to 0..5V */
825 outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
826 outw(0, dev->iobase + PCI171x_DA1); /* set DA outputs to 0V */
827 outw(0, dev->iobase + PCI171x_DA2);
829 outw(0, dev->iobase + PCI171x_DO); /* digital outputs to 0 */
830 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
831 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
836 static int pci1720_reset(struct comedi_device *dev)
838 struct pci1710_private *devpriv = dev->private;
839 /* set synchronous output mode */
840 outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT);
841 devpriv->da_ranges = 0xAA;
842 /* set all ranges to +/-5V */
843 outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE);
844 outw(0x0800, dev->iobase + PCI1720_DA0); /* set outputs to 0V */
845 outw(0x0800, dev->iobase + PCI1720_DA1);
846 outw(0x0800, dev->iobase + PCI1720_DA2);
847 outw(0x0800, dev->iobase + PCI1720_DA3);
848 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
853 static int pci1710_reset(struct comedi_device *dev)
855 const struct boardtype *board = dev->board_ptr;
857 if (board->is_pci1720)
858 return pci1720_reset(dev);
860 return pci171x_reset(dev);
863 static int pci1710_auto_attach(struct comedi_device *dev,
864 unsigned long context)
866 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
867 const struct boardtype *board = NULL;
868 struct pci1710_private *devpriv;
869 struct comedi_subdevice *s;
870 int ret, subdev, n_subdevices;
872 if (context < ARRAY_SIZE(boardtypes))
873 board = &boardtypes[context];
876 dev->board_ptr = board;
877 dev->board_name = board->name;
879 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
883 ret = comedi_pci_enable(dev);
886 dev->iobase = pci_resource_start(pcidev, 2);
888 dev->pacer = comedi_8254_init(dev->iobase + PCI171X_TIMER_BASE,
889 I8254_OSC_BASE_10MHZ, I8254_IO16, 0);
898 if (board->has_di_do)
900 if (board->has_counter)
903 ret = comedi_alloc_subdevices(dev, n_subdevices);
909 if (board->has_irq && pcidev->irq) {
910 ret = request_irq(pcidev->irq, interrupt_service_pci1710,
911 IRQF_SHARED, dev->board_name, dev);
913 dev->irq = pcidev->irq;
918 if (board->n_aichan) {
919 s = &dev->subdevices[subdev];
920 s->type = COMEDI_SUBD_AI;
921 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
922 if (board->has_diff_ai)
923 s->subdev_flags |= SDF_DIFF;
924 s->n_chan = board->n_aichan;
926 s->range_table = board->rangelist_ai;
927 s->insn_read = pci171x_ai_insn_read;
929 dev->read_subdev = s;
930 s->subdev_flags |= SDF_CMD_READ;
931 s->len_chanlist = s->n_chan;
932 s->do_cmdtest = pci171x_ai_cmdtest;
933 s->do_cmd = pci171x_ai_cmd;
934 s->cancel = pci171x_ai_cancel;
940 s = &dev->subdevices[subdev];
941 s->type = COMEDI_SUBD_AO;
942 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
944 if (board->is_pci1720) {
946 s->range_table = &pci1720_ao_range;
947 s->insn_write = pci1720_ao_insn_write;
950 s->range_table = &pci171x_ao_range;
951 s->insn_write = pci171x_ao_insn_write;
954 ret = comedi_alloc_subdev_readback(s);
958 /* initialize the readback values to match the board reset */
959 if (board->is_pci1720) {
962 for (i = 0; i < s->n_chan; i++)
963 s->readback[i] = 0x0800;
969 if (board->has_di_do) {
970 s = &dev->subdevices[subdev];
971 s->type = COMEDI_SUBD_DI;
972 s->subdev_flags = SDF_READABLE;
975 s->range_table = &range_digital;
976 s->insn_bits = pci171x_di_insn_bits;
979 s = &dev->subdevices[subdev];
980 s->type = COMEDI_SUBD_DO;
981 s->subdev_flags = SDF_WRITABLE;
984 s->range_table = &range_digital;
985 s->insn_bits = pci171x_do_insn_bits;
989 /* Counter subdevice (8254) */
990 if (board->has_counter) {
991 s = &dev->subdevices[subdev];
992 comedi_8254_subdevice_init(s, dev->pacer);
994 dev->pacer->insn_config = pci171x_insn_counter_config;
996 /* counters 1 and 2 are used internally for the pacer */
997 comedi_8254_set_busy(dev->pacer, 1, true);
998 comedi_8254_set_busy(dev->pacer, 2, true);
1003 /* max_samples is half the FIFO size (2 bytes/sample) */
1004 devpriv->max_samples = (board->has_large_fifo) ? 2048 : 512;
1009 static void pci1710_detach(struct comedi_device *dev)
1013 comedi_pci_detach(dev);
1016 static struct comedi_driver adv_pci1710_driver = {
1017 .driver_name = "adv_pci1710",
1018 .module = THIS_MODULE,
1019 .auto_attach = pci1710_auto_attach,
1020 .detach = pci1710_detach,
1023 static int adv_pci1710_pci_probe(struct pci_dev *dev,
1024 const struct pci_device_id *id)
1026 return comedi_pci_auto_config(dev, &adv_pci1710_driver,
1030 static const struct pci_device_id adv_pci1710_pci_table[] = {
1032 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1033 PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050),
1034 .driver_data = BOARD_PCI1710,
1036 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1037 PCI_VENDOR_ID_ADVANTECH, 0x0000),
1038 .driver_data = BOARD_PCI1710,
1040 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1041 PCI_VENDOR_ID_ADVANTECH, 0xb100),
1042 .driver_data = BOARD_PCI1710,
1044 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1045 PCI_VENDOR_ID_ADVANTECH, 0xb200),
1046 .driver_data = BOARD_PCI1710,
1048 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1049 PCI_VENDOR_ID_ADVANTECH, 0xc100),
1050 .driver_data = BOARD_PCI1710,
1052 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1053 PCI_VENDOR_ID_ADVANTECH, 0xc200),
1054 .driver_data = BOARD_PCI1710,
1056 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd100),
1057 .driver_data = BOARD_PCI1710,
1059 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1060 PCI_VENDOR_ID_ADVANTECH, 0x0002),
1061 .driver_data = BOARD_PCI1710HG,
1063 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1064 PCI_VENDOR_ID_ADVANTECH, 0xb102),
1065 .driver_data = BOARD_PCI1710HG,
1067 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1068 PCI_VENDOR_ID_ADVANTECH, 0xb202),
1069 .driver_data = BOARD_PCI1710HG,
1071 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1072 PCI_VENDOR_ID_ADVANTECH, 0xc102),
1073 .driver_data = BOARD_PCI1710HG,
1075 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1076 PCI_VENDOR_ID_ADVANTECH, 0xc202),
1077 .driver_data = BOARD_PCI1710HG,
1079 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd102),
1080 .driver_data = BOARD_PCI1710HG,
1082 { PCI_VDEVICE(ADVANTECH, 0x1711), BOARD_PCI1711 },
1083 { PCI_VDEVICE(ADVANTECH, 0x1713), BOARD_PCI1713 },
1084 { PCI_VDEVICE(ADVANTECH, 0x1720), BOARD_PCI1720 },
1085 { PCI_VDEVICE(ADVANTECH, 0x1731), BOARD_PCI1731 },
1088 MODULE_DEVICE_TABLE(pci, adv_pci1710_pci_table);
1090 static struct pci_driver adv_pci1710_pci_driver = {
1091 .name = "adv_pci1710",
1092 .id_table = adv_pci1710_pci_table,
1093 .probe = adv_pci1710_pci_probe,
1094 .remove = comedi_pci_auto_unconfig,
1096 module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver);
1098 MODULE_AUTHOR("Comedi http://www.comedi.org");
1099 MODULE_DESCRIPTION("Comedi: Advantech PCI-1710 Series Multifunction DAS Cards");
1100 MODULE_LICENSE("GPL");