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 #define PCI171x_PARANOIDCHECK /* if defined, then is used code which control
55 * correct channel number on every 12 bit
58 /* hardware types of the cards */
59 #define TYPE_PCI171X 0
60 #define TYPE_PCI1713 2
61 #define TYPE_PCI1720 3
63 #define PCI171x_AD_DATA 0 /* R: A/D data */
64 #define PCI171x_SOFTTRG 0 /* W: soft trigger for A/D */
65 #define PCI171x_RANGE 2 /* W: A/D gain/range register */
66 #define PCI171x_MUX 4 /* W: A/D multiplexor control */
67 #define PCI171x_STATUS 6 /* R: status register */
68 #define PCI171x_CONTROL 6 /* W: control register */
69 #define PCI171x_CLRINT 8 /* W: clear interrupts request */
70 #define PCI171x_CLRFIFO 9 /* W: clear FIFO */
71 #define PCI171x_DA1 10 /* W: D/A register */
72 #define PCI171x_DA2 12 /* W: D/A register */
73 #define PCI171x_DAREF 14 /* W: D/A reference control */
74 #define PCI171x_DI 16 /* R: digi inputs */
75 #define PCI171x_DO 16 /* R: digi inputs */
76 #define PCI171x_CNT0 24 /* R/W: 8254 counter 0 */
77 #define PCI171x_CNT1 26 /* R/W: 8254 counter 1 */
78 #define PCI171x_CNT2 28 /* R/W: 8254 counter 2 */
79 #define PCI171x_CNTCTRL 30 /* W: 8254 counter control */
81 /* upper bits from status register (PCI171x_STATUS) (lower is same with control
83 #define Status_FE 0x0100 /* 1=FIFO is empty */
84 #define Status_FH 0x0200 /* 1=FIFO is half full */
85 #define Status_FF 0x0400 /* 1=FIFO is full, fatal error */
86 #define Status_IRQ 0x0800 /* 1=IRQ occurred */
87 /* bits from control register (PCI171x_CONTROL) */
88 #define Control_CNT0 0x0040 /* 1=CNT0 have external source,
89 * 0=have internal 100kHz source */
90 #define Control_ONEFH 0x0020 /* 1=IRQ on FIFO is half full, 0=every sample */
91 #define Control_IRQEN 0x0010 /* 1=enable IRQ */
92 #define Control_GATE 0x0008 /* 1=enable external trigger GATE (8254?) */
93 #define Control_EXT 0x0004 /* 1=external trigger source */
94 #define Control_PACER 0x0002 /* 1=enable internal 8254 trigger source */
95 #define Control_SW 0x0001 /* 1=enable software trigger source */
96 /* bits from counter control register (PCI171x_CNTCTRL) */
97 #define Counter_BCD 0x0001 /* 0 = binary counter, 1 = BCD counter */
98 #define Counter_M0 0x0002 /* M0-M2 select modes 0-5 */
99 #define Counter_M1 0x0004 /* 000 = mode 0, 010 = mode 2 ... */
100 #define Counter_M2 0x0008
101 #define Counter_RW0 0x0010 /* RW0/RW1 select read/write mode */
102 #define Counter_RW1 0x0020
103 #define Counter_SC0 0x0040 /* Select Counter. Only 00 or 11 may */
104 #define Counter_SC1 0x0080 /* be used, 00 for CNT0,
105 * 11 for read-back command */
107 #define PCI1720_DA0 0 /* W: D/A register 0 */
108 #define PCI1720_DA1 2 /* W: D/A register 1 */
109 #define PCI1720_DA2 4 /* W: D/A register 2 */
110 #define PCI1720_DA3 6 /* W: D/A register 3 */
111 #define PCI1720_RANGE 8 /* R/W: D/A range register */
112 #define PCI1720_SYNCOUT 9 /* W: D/A synchronized output register */
113 #define PCI1720_SYNCONT 15 /* R/W: D/A synchronized control */
115 /* D/A synchronized control (PCI1720_SYNCONT) */
116 #define Syncont_SC0 1 /* set synchronous output mode */
118 static const struct comedi_lrange range_pci1710_3 = { 9, {
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 = { 12, {
150 static const char range_codes_pci1710hg[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
151 0x05, 0x06, 0x07, 0x10, 0x11,
154 static const struct comedi_lrange range_pci17x1 = { 5, {
163 static const char range_codes_pci17x1[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
165 static const struct comedi_lrange range_pci1720 = { 4, {
173 static const struct comedi_lrange range_pci171x_da = { 2, {
179 enum pci1710_boardid {
189 const char *name; /* board name */
190 char have_irq; /* 1=card support IRQ */
191 char cardtype; /* 0=1710& co. 2=1713, ... */
192 int n_aichan; /* num of A/D chans */
193 int n_aichand; /* num of A/D chans in diff mode */
194 int n_aochan; /* num of D/A chans */
195 int n_dichan; /* num of DI chans */
196 int n_dochan; /* num of DO chans */
197 int n_counter; /* num of counters */
198 int ai_maxdata; /* resolution of A/D */
199 int ao_maxdata; /* resolution of D/A */
200 const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */
201 const char *rangecode_ai; /* range codes for programming */
202 const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */
203 unsigned int ai_ns_min; /* max sample speed of card v ns */
204 unsigned int fifo_half_size; /* size of FIFO/2 */
207 static const struct boardtype boardtypes[] = {
211 .cardtype = TYPE_PCI171X,
218 .ai_maxdata = 0x0fff,
219 .ao_maxdata = 0x0fff,
220 .rangelist_ai = &range_pci1710_3,
221 .rangecode_ai = range_codes_pci1710_3,
222 .rangelist_ao = &range_pci171x_da,
224 .fifo_half_size = 2048,
226 [BOARD_PCI1710HG] = {
229 .cardtype = TYPE_PCI171X,
236 .ai_maxdata = 0x0fff,
237 .ao_maxdata = 0x0fff,
238 .rangelist_ai = &range_pci1710hg,
239 .rangecode_ai = range_codes_pci1710hg,
240 .rangelist_ao = &range_pci171x_da,
242 .fifo_half_size = 2048,
247 .cardtype = TYPE_PCI171X,
253 .ai_maxdata = 0x0fff,
254 .ao_maxdata = 0x0fff,
255 .rangelist_ai = &range_pci17x1,
256 .rangecode_ai = range_codes_pci17x1,
257 .rangelist_ao = &range_pci171x_da,
259 .fifo_half_size = 512,
264 .cardtype = TYPE_PCI1713,
267 .ai_maxdata = 0x0fff,
268 .rangelist_ai = &range_pci1710_3,
269 .rangecode_ai = range_codes_pci1710_3,
271 .fifo_half_size = 2048,
275 .cardtype = TYPE_PCI1720,
277 .ao_maxdata = 0x0fff,
278 .rangelist_ao = &range_pci1720,
283 .cardtype = TYPE_PCI171X,
287 .ai_maxdata = 0x0fff,
288 .rangelist_ai = &range_pci17x1,
289 .rangecode_ai = range_codes_pci17x1,
291 .fifo_half_size = 512,
295 struct pci1710_private {
296 char neverending_ai; /* we do unlimited AI */
297 unsigned int CntrlReg; /* Control register */
298 unsigned int i8254_osc_base; /* frequence of onboard oscilator */
299 unsigned int ai_do; /* what do AI? 0=nothing, 1 to 4 mode */
300 unsigned int ai_act_scan; /* how many scans we finished */
301 unsigned int ai_act_chan; /* actual position in actual scan */
302 unsigned int ai_buf_ptr; /* data buffer ptr in samples */
303 unsigned char ai_eos; /* 1=EOS wake up */
305 unsigned int ai_et_CntrlReg;
306 unsigned int ai_et_MuxVal;
307 unsigned int ai_et_div1, ai_et_div2;
308 unsigned int act_chanlist[32]; /* list of scanned channel */
309 unsigned char act_chanlist_len; /* len of scanlist */
310 unsigned char act_chanlist_pos; /* actual position in MUX list */
311 unsigned char da_ranges; /* copy of D/A outpit range register */
312 unsigned int ai_scans; /* len of scanlist */
313 unsigned int ai_n_chan; /* how many channels is measured */
314 unsigned int *ai_chanlist; /* actaul chanlist */
315 unsigned int ai_flags; /* flaglist */
316 unsigned int ai_data_len; /* len of data buffer */
317 unsigned int ai_timer1; /* timers */
318 unsigned int ai_timer2;
319 unsigned short ao_data[4]; /* data output buffer */
320 unsigned int cnt0_write_wait; /* after a write, wait for update of the
324 /* used for gain list programming */
325 static const unsigned int muxonechan[] = {
326 0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707,
327 0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f,
328 0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717,
329 0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f
333 ==============================================================================
334 Check if channel list from user is built correctly
335 If it's ok, then program scan/gain logic.
336 This works for all cards.
338 static int check_channel_list(struct comedi_device *dev,
339 struct comedi_subdevice *s,
340 unsigned int *chanlist, unsigned int n_chan)
342 unsigned int chansegment[32];
343 unsigned int i, nowmustbechan, seglen, segpos;
345 /* correct channel and range number check itself comedi/range.c */
347 comedi_error(dev, "range/channel list is empty!");
352 return 1; /* seglen=1 */
354 chansegment[0] = chanlist[0]; /* first channel is every time ok */
355 for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {
356 if (chanlist[0] == chanlist[i])
357 break; /* we detected a loop, stop */
358 if ((CR_CHAN(chanlist[i]) & 1) &&
359 (CR_AREF(chanlist[i]) == AREF_DIFF)) {
360 comedi_error(dev, "Odd channel cannot be differential input!\n");
363 nowmustbechan = (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
364 if (CR_AREF(chansegment[i - 1]) == AREF_DIFF)
365 nowmustbechan = (nowmustbechan + 1) % s->n_chan;
366 if (nowmustbechan != CR_CHAN(chanlist[i])) {
367 printk("channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
368 i, CR_CHAN(chanlist[i]), nowmustbechan,
369 CR_CHAN(chanlist[0]));
372 chansegment[i] = chanlist[i]; /* next correct channel in list */
375 for (i = 0, segpos = 0; i < n_chan; i++) {
376 if (chanlist[i] != chansegment[i % seglen]) {
377 printk("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
378 i, CR_CHAN(chansegment[i]),
379 CR_RANGE(chansegment[i]),
380 CR_AREF(chansegment[i]),
381 CR_CHAN(chanlist[i % seglen]),
382 CR_RANGE(chanlist[i % seglen]),
383 CR_AREF(chansegment[i % seglen]));
390 static void setup_channel_list(struct comedi_device *dev,
391 struct comedi_subdevice *s,
392 unsigned int *chanlist, unsigned int n_chan,
395 const struct boardtype *this_board = comedi_board(dev);
396 struct pci1710_private *devpriv = dev->private;
397 unsigned int i, range, chanprog;
399 devpriv->act_chanlist_len = seglen;
400 devpriv->act_chanlist_pos = 0;
402 for (i = 0; i < seglen; i++) { /* store range list to card */
403 chanprog = muxonechan[CR_CHAN(chanlist[i])];
404 outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */
405 range = this_board->rangecode_ai[CR_RANGE(chanlist[i])];
406 if (CR_AREF(chanlist[i]) == AREF_DIFF)
408 outw(range, dev->iobase + PCI171x_RANGE); /* select gain */
409 #ifdef PCI171x_PARANOIDCHECK
410 devpriv->act_chanlist[i] =
411 (CR_CHAN(chanlist[i]) << 12) & 0xf000;
414 #ifdef PCI171x_PARANOIDCHECK
415 for ( ; i < n_chan; i++) { /* store remainder of channel list */
416 devpriv->act_chanlist[i] =
417 (CR_CHAN(chanlist[i]) << 12) & 0xf000;
421 devpriv->ai_et_MuxVal =
422 CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
423 /* select channel interval to scan */
424 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
428 ==============================================================================
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;
436 #ifdef PCI171x_PARANOIDCHECK
437 const struct boardtype *this_board = comedi_board(dev);
441 devpriv->CntrlReg &= Control_CNT0;
442 devpriv->CntrlReg |= Control_SW; /* set software trigger */
443 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
444 outb(0, dev->iobase + PCI171x_CLRFIFO);
445 outb(0, dev->iobase + PCI171x_CLRINT);
447 setup_channel_list(dev, s, &insn->chanspec, 1, 1);
449 for (n = 0; n < insn->n; n++) {
450 outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */
454 if (!(inw(dev->iobase + PCI171x_STATUS) & Status_FE))
457 comedi_error(dev, "A/D insn timeout");
458 outb(0, dev->iobase + PCI171x_CLRFIFO);
459 outb(0, dev->iobase + PCI171x_CLRINT);
464 #ifdef PCI171x_PARANOIDCHECK
465 idata = inw(dev->iobase + PCI171x_AD_DATA);
466 if (this_board->cardtype != TYPE_PCI1713)
467 if ((idata & 0xf000) != devpriv->act_chanlist[0]) {
468 comedi_error(dev, "A/D insn data droput!");
471 data[n] = idata & 0x0fff;
473 data[n] = inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff;
478 outb(0, dev->iobase + PCI171x_CLRFIFO);
479 outb(0, dev->iobase + PCI171x_CLRINT);
485 ==============================================================================
487 static int pci171x_insn_write_ao(struct comedi_device *dev,
488 struct comedi_subdevice *s,
489 struct comedi_insn *insn, unsigned int *data)
491 struct pci1710_private *devpriv = dev->private;
492 int n, chan, range, ofs;
494 chan = CR_CHAN(insn->chanspec);
495 range = CR_RANGE(insn->chanspec);
497 devpriv->da_ranges &= 0xfb;
498 devpriv->da_ranges |= (range << 2);
499 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
502 devpriv->da_ranges &= 0xfe;
503 devpriv->da_ranges |= range;
504 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
508 for (n = 0; n < insn->n; n++)
509 outw(data[n], dev->iobase + ofs);
511 devpriv->ao_data[chan] = data[n];
518 ==============================================================================
520 static int pci171x_insn_read_ao(struct comedi_device *dev,
521 struct comedi_subdevice *s,
522 struct comedi_insn *insn, unsigned int *data)
524 struct pci1710_private *devpriv = dev->private;
527 chan = CR_CHAN(insn->chanspec);
528 for (n = 0; n < insn->n; n++)
529 data[n] = devpriv->ao_data[chan];
535 ==============================================================================
537 static int pci171x_insn_bits_di(struct comedi_device *dev,
538 struct comedi_subdevice *s,
539 struct comedi_insn *insn, unsigned int *data)
541 data[1] = inw(dev->iobase + PCI171x_DI);
546 static int pci171x_insn_bits_do(struct comedi_device *dev,
547 struct comedi_subdevice *s,
548 struct comedi_insn *insn,
551 if (comedi_dio_update_state(s, data))
552 outw(s->state, dev->iobase + PCI171x_DO);
560 ==============================================================================
562 static void start_pacer(struct comedi_device *dev, int mode,
563 unsigned int divisor1, unsigned int divisor2)
565 outw(0xb4, dev->iobase + PCI171x_CNTCTRL);
566 outw(0x74, dev->iobase + PCI171x_CNTCTRL);
569 outw(divisor2 & 0xff, dev->iobase + PCI171x_CNT2);
570 outw((divisor2 >> 8) & 0xff, dev->iobase + PCI171x_CNT2);
571 outw(divisor1 & 0xff, dev->iobase + PCI171x_CNT1);
572 outw((divisor1 >> 8) & 0xff, dev->iobase + PCI171x_CNT1);
577 ==============================================================================
579 static int pci171x_insn_counter_read(struct comedi_device *dev,
580 struct comedi_subdevice *s,
581 struct comedi_insn *insn,
584 unsigned int msb, lsb, ccntrl;
587 ccntrl = 0xD2; /* count only */
588 for (i = 0; i < insn->n; i++) {
589 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
591 lsb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
592 msb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
594 data[0] = lsb | (msb << 8);
601 ==============================================================================
603 static int pci171x_insn_counter_write(struct comedi_device *dev,
604 struct comedi_subdevice *s,
605 struct comedi_insn *insn,
608 struct pci1710_private *devpriv = dev->private;
609 uint msb, lsb, ccntrl, status;
611 lsb = data[0] & 0x00FF;
612 msb = (data[0] & 0xFF00) >> 8;
614 /* write lsb, then msb */
615 outw(lsb, dev->iobase + PCI171x_CNT0);
616 outw(msb, dev->iobase + PCI171x_CNT0);
618 if (devpriv->cnt0_write_wait) {
619 /* wait for the new count to be loaded */
622 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
623 status = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
624 } while (status & 0x40);
631 ==============================================================================
633 static int pci171x_insn_counter_config(struct comedi_device *dev,
634 struct comedi_subdevice *s,
635 struct comedi_insn *insn,
639 /* This doesn't work like a normal Comedi counter config */
640 struct pci1710_private *devpriv = dev->private;
643 devpriv->cnt0_write_wait = data[0] & 0x20;
645 /* internal or external clock? */
646 if (!(data[0] & 0x10)) { /* internal */
647 devpriv->CntrlReg &= ~Control_CNT0;
649 devpriv->CntrlReg |= Control_CNT0;
651 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
654 ccntrl |= Counter_M0;
656 ccntrl |= Counter_M1;
658 ccntrl |= Counter_M2;
660 ccntrl |= Counter_BCD;
661 ccntrl |= Counter_RW0; /* set read/write mode */
662 ccntrl |= Counter_RW1;
663 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
670 ==============================================================================
672 static int pci1720_insn_write_ao(struct comedi_device *dev,
673 struct comedi_subdevice *s,
674 struct comedi_insn *insn, unsigned int *data)
676 struct pci1710_private *devpriv = dev->private;
677 int n, rangereg, chan;
679 chan = CR_CHAN(insn->chanspec);
680 rangereg = devpriv->da_ranges & (~(0x03 << (chan << 1)));
681 rangereg |= (CR_RANGE(insn->chanspec) << (chan << 1));
682 if (rangereg != devpriv->da_ranges) {
683 outb(rangereg, dev->iobase + PCI1720_RANGE);
684 devpriv->da_ranges = rangereg;
687 for (n = 0; n < insn->n; n++) {
688 outw(data[n], dev->iobase + PCI1720_DA0 + (chan << 1));
689 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
692 devpriv->ao_data[chan] = data[n];
698 ==============================================================================
700 static int pci171x_ai_cancel(struct comedi_device *dev,
701 struct comedi_subdevice *s)
703 const struct boardtype *this_board = comedi_board(dev);
704 struct pci1710_private *devpriv = dev->private;
706 switch (this_board->cardtype) {
708 devpriv->CntrlReg &= Control_CNT0;
709 devpriv->CntrlReg |= Control_SW;
711 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */
712 start_pacer(dev, -1, 0, 0);
713 outb(0, dev->iobase + PCI171x_CLRFIFO);
714 outb(0, dev->iobase + PCI171x_CLRINT);
719 devpriv->ai_act_scan = 0;
720 s->async->cur_chan = 0;
721 devpriv->ai_buf_ptr = 0;
722 devpriv->neverending_ai = 0;
728 ==============================================================================
730 static void interrupt_pci1710_every_sample(void *d)
732 struct comedi_device *dev = d;
733 struct pci1710_private *devpriv = dev->private;
734 struct comedi_subdevice *s = &dev->subdevices[0];
736 #ifdef PCI171x_PARANOIDCHECK
737 const struct boardtype *this_board = comedi_board(dev);
738 unsigned short sampl;
741 m = inw(dev->iobase + PCI171x_STATUS);
743 dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", m);
744 pci171x_ai_cancel(dev, s);
745 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
746 comedi_event(dev, s);
750 dev_dbg(dev->class_dev,
751 "A/D FIFO Full status (Fatal Error!) (%4x)\n", m);
752 pci171x_ai_cancel(dev, s);
753 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
754 comedi_event(dev, s);
758 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
760 for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
761 #ifdef PCI171x_PARANOIDCHECK
762 sampl = inw(dev->iobase + PCI171x_AD_DATA);
763 if (this_board->cardtype != TYPE_PCI1713)
764 if ((sampl & 0xf000) !=
765 devpriv->act_chanlist[s->async->cur_chan]) {
767 ("comedi: A/D data dropout: received data from channel %d, expected %d!\n",
768 (sampl & 0xf000) >> 12,
771 async->cur_chan] & 0xf000) >>
773 pci171x_ai_cancel(dev, s);
775 COMEDI_CB_EOA | COMEDI_CB_ERROR;
776 comedi_event(dev, s);
779 comedi_buf_put(s->async, sampl & 0x0fff);
781 comedi_buf_put(s->async,
782 inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
784 ++s->async->cur_chan;
786 if (s->async->cur_chan >= devpriv->ai_n_chan)
787 s->async->cur_chan = 0;
790 if (s->async->cur_chan == 0) { /* one scan done */
791 devpriv->ai_act_scan++;
792 if ((!devpriv->neverending_ai) &&
793 (devpriv->ai_act_scan >= devpriv->ai_scans)) {
794 /* all data sampled */
795 pci171x_ai_cancel(dev, s);
796 s->async->events |= COMEDI_CB_EOA;
797 comedi_event(dev, s);
803 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
805 comedi_event(dev, s);
809 ==============================================================================
811 static int move_block_from_fifo(struct comedi_device *dev,
812 struct comedi_subdevice *s, int n, int turn)
814 struct pci1710_private *devpriv = dev->private;
816 #ifdef PCI171x_PARANOIDCHECK
817 const struct boardtype *this_board = comedi_board(dev);
818 unsigned short sampl;
821 j = s->async->cur_chan;
822 for (i = 0; i < n; i++) {
823 #ifdef PCI171x_PARANOIDCHECK
824 sampl = inw(dev->iobase + PCI171x_AD_DATA);
825 if (this_board->cardtype != TYPE_PCI1713)
826 if ((sampl & 0xf000) != devpriv->act_chanlist[j]) {
827 dev_dbg(dev->class_dev,
828 "A/D FIFO data dropout: received data from channel %d, expected %d! (%d/%d/%d/%d/%d/%4x)\n",
829 (sampl & 0xf000) >> 12,
830 (devpriv->act_chanlist[j] & 0xf000) >> 12,
831 i, j, devpriv->ai_act_scan, n, turn,
833 pci171x_ai_cancel(dev, s);
835 COMEDI_CB_EOA | COMEDI_CB_ERROR;
836 comedi_event(dev, s);
839 comedi_buf_put(s->async, sampl & 0x0fff);
841 comedi_buf_put(s->async,
842 inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
845 if (j >= devpriv->ai_n_chan) {
847 devpriv->ai_act_scan++;
850 s->async->cur_chan = j;
855 ==============================================================================
857 static void interrupt_pci1710_half_fifo(void *d)
859 struct comedi_device *dev = d;
860 const struct boardtype *this_board = comedi_board(dev);
861 struct pci1710_private *devpriv = dev->private;
862 struct comedi_subdevice *s = &dev->subdevices[0];
865 m = inw(dev->iobase + PCI171x_STATUS);
866 if (!(m & Status_FH)) {
867 dev_dbg(dev->class_dev, "A/D FIFO not half full! (%4x)\n", m);
868 pci171x_ai_cancel(dev, s);
869 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
870 comedi_event(dev, s);
874 dev_dbg(dev->class_dev,
875 "A/D FIFO Full status (Fatal Error!) (%4x)\n", m);
876 pci171x_ai_cancel(dev, s);
877 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
878 comedi_event(dev, s);
882 samplesinbuf = this_board->fifo_half_size;
883 if (samplesinbuf * sizeof(short) >= devpriv->ai_data_len) {
884 m = devpriv->ai_data_len / sizeof(short);
885 if (move_block_from_fifo(dev, s, m, 0))
891 if (move_block_from_fifo(dev, s, samplesinbuf, 1))
895 if (!devpriv->neverending_ai)
896 if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data
898 pci171x_ai_cancel(dev, s);
899 s->async->events |= COMEDI_CB_EOA;
900 comedi_event(dev, s);
903 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
905 comedi_event(dev, s);
909 ==============================================================================
911 static irqreturn_t interrupt_service_pci1710(int irq, void *d)
913 struct comedi_device *dev = d;
914 struct pci1710_private *devpriv = dev->private;
916 if (!dev->attached) /* is device attached? */
917 return IRQ_NONE; /* no, exit */
918 /* is this interrupt from our board? */
919 if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))
920 return IRQ_NONE; /* no, exit */
922 if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */
924 devpriv->CntrlReg &= Control_CNT0;
925 devpriv->CntrlReg |= Control_SW; /* set software trigger */
926 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
927 devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
928 outb(0, dev->iobase + PCI171x_CLRFIFO);
929 outb(0, dev->iobase + PCI171x_CLRINT);
930 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
931 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
933 start_pacer(dev, 1, devpriv->ai_et_div1, devpriv->ai_et_div2);
936 if (devpriv->ai_eos) { /* We use FIFO half full INT or not? */
937 interrupt_pci1710_every_sample(d);
939 interrupt_pci1710_half_fifo(d);
945 ==============================================================================
947 static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev,
948 struct comedi_subdevice *s)
950 const struct boardtype *this_board = comedi_board(dev);
951 struct pci1710_private *devpriv = dev->private;
952 unsigned int divisor1 = 0, divisor2 = 0;
955 start_pacer(dev, -1, 0, 0); /* stop pacer */
957 seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
961 setup_channel_list(dev, s, devpriv->ai_chanlist,
962 devpriv->ai_n_chan, seglen);
964 outb(0, dev->iobase + PCI171x_CLRFIFO);
965 outb(0, dev->iobase + PCI171x_CLRINT);
967 devpriv->ai_do = mode;
969 devpriv->ai_act_scan = 0;
970 s->async->cur_chan = 0;
971 devpriv->ai_buf_ptr = 0;
972 devpriv->neverending_ai = 0;
974 devpriv->CntrlReg &= Control_CNT0;
975 /* don't we want wake up every scan? devpriv->ai_eos=1; */
976 if ((devpriv->ai_flags & TRIG_WAKE_EOS)) {
979 devpriv->CntrlReg |= Control_ONEFH;
983 if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1))
984 devpriv->neverending_ai = 1;
985 /* well, user want neverending */
987 devpriv->neverending_ai = 0;
992 if (devpriv->ai_timer1 < this_board->ai_ns_min)
993 devpriv->ai_timer1 = this_board->ai_ns_min;
994 devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
996 devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
998 ~(Control_PACER | Control_ONEFH | Control_GATE);
999 devpriv->CntrlReg |= Control_EXT;
1004 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base,
1005 &divisor1, &divisor2,
1006 &devpriv->ai_timer1,
1008 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
1011 start_pacer(dev, mode, divisor1, divisor2);
1013 devpriv->ai_et_div1 = divisor1;
1014 devpriv->ai_et_div2 = divisor2;
1018 devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
1019 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
1027 ==============================================================================
1029 static int pci171x_ai_cmdtest(struct comedi_device *dev,
1030 struct comedi_subdevice *s,
1031 struct comedi_cmd *cmd)
1033 const struct boardtype *this_board = comedi_board(dev);
1034 struct pci1710_private *devpriv = dev->private;
1037 unsigned int divisor1 = 0, divisor2 = 0;
1039 /* Step 1 : check if triggers are trivially valid */
1041 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
1042 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
1043 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
1044 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
1045 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
1050 /* step 2a: make sure trigger sources are unique */
1052 err |= cfc_check_trigger_is_unique(cmd->start_src);
1053 err |= cfc_check_trigger_is_unique(cmd->convert_src);
1054 err |= cfc_check_trigger_is_unique(cmd->stop_src);
1056 /* step 2b: and mutually compatible */
1061 /* Step 3: check if arguments are trivially valid */
1063 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
1064 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
1066 if (cmd->convert_src == TRIG_TIMER)
1067 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
1068 this_board->ai_ns_min);
1069 else /* TRIG_FOLLOW */
1070 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
1072 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
1074 if (cmd->stop_src == TRIG_COUNT)
1075 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
1076 else /* TRIG_NONE */
1077 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
1082 /* step 4: fix up any arguments */
1084 if (cmd->convert_src == TRIG_TIMER) {
1085 tmp = cmd->convert_arg;
1086 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base,
1087 &divisor1, &divisor2,
1088 &cmd->convert_arg, cmd->flags);
1089 if (cmd->convert_arg < this_board->ai_ns_min)
1090 cmd->convert_arg = this_board->ai_ns_min;
1091 if (tmp != cmd->convert_arg)
1098 /* step 5: complain about special chanlist considerations */
1100 if (cmd->chanlist) {
1101 if (!check_channel_list(dev, s, cmd->chanlist,
1103 return 5; /* incorrect channels list */
1110 ==============================================================================
1112 static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1114 struct pci1710_private *devpriv = dev->private;
1115 struct comedi_cmd *cmd = &s->async->cmd;
1117 devpriv->ai_n_chan = cmd->chanlist_len;
1118 devpriv->ai_chanlist = cmd->chanlist;
1119 devpriv->ai_flags = cmd->flags;
1120 devpriv->ai_data_len = s->async->prealloc_bufsz;
1121 devpriv->ai_timer1 = 0;
1122 devpriv->ai_timer2 = 0;
1124 if (cmd->stop_src == TRIG_COUNT)
1125 devpriv->ai_scans = cmd->stop_arg;
1127 devpriv->ai_scans = 0;
1130 if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 2, 3 */
1131 if (cmd->convert_src == TRIG_TIMER) { /* mode 1 and 2 */
1132 devpriv->ai_timer1 = cmd->convert_arg;
1133 return pci171x_ai_docmd_and_mode(cmd->start_src ==
1134 TRIG_EXT ? 2 : 1, dev,
1137 if (cmd->convert_src == TRIG_EXT) { /* mode 3 */
1138 return pci171x_ai_docmd_and_mode(3, dev, s);
1146 ==============================================================================
1148 static int pci171x_reset(struct comedi_device *dev)
1150 const struct boardtype *this_board = comedi_board(dev);
1151 struct pci1710_private *devpriv = dev->private;
1153 outw(0x30, dev->iobase + PCI171x_CNTCTRL);
1154 devpriv->CntrlReg = Control_SW | Control_CNT0; /* Software trigger, CNT0=external */
1155 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */
1156 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
1157 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
1158 start_pacer(dev, -1, 0, 0); /* stop 8254 */
1159 devpriv->da_ranges = 0;
1160 if (this_board->n_aochan) {
1161 outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); /* set DACs to 0..5V */
1162 outw(0, dev->iobase + PCI171x_DA1); /* set DA outputs to 0V */
1163 devpriv->ao_data[0] = 0x0000;
1164 if (this_board->n_aochan > 1) {
1165 outw(0, dev->iobase + PCI171x_DA2);
1166 devpriv->ao_data[1] = 0x0000;
1169 outw(0, dev->iobase + PCI171x_DO); /* digital outputs to 0 */
1170 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
1171 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
1177 ==============================================================================
1179 static int pci1720_reset(struct comedi_device *dev)
1181 struct pci1710_private *devpriv = dev->private;
1183 outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT); /* set synchronous output mode */
1184 devpriv->da_ranges = 0xAA;
1185 outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE); /* set all ranges to +/-5V */
1186 outw(0x0800, dev->iobase + PCI1720_DA0); /* set outputs to 0V */
1187 outw(0x0800, dev->iobase + PCI1720_DA1);
1188 outw(0x0800, dev->iobase + PCI1720_DA2);
1189 outw(0x0800, dev->iobase + PCI1720_DA3);
1190 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
1191 devpriv->ao_data[0] = 0x0800;
1192 devpriv->ao_data[1] = 0x0800;
1193 devpriv->ao_data[2] = 0x0800;
1194 devpriv->ao_data[3] = 0x0800;
1199 ==============================================================================
1201 static int pci1710_reset(struct comedi_device *dev)
1203 const struct boardtype *this_board = comedi_board(dev);
1205 switch (this_board->cardtype) {
1207 return pci1720_reset(dev);
1209 return pci171x_reset(dev);
1213 static int pci1710_auto_attach(struct comedi_device *dev,
1214 unsigned long context)
1216 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1217 const struct boardtype *this_board = NULL;
1218 struct pci1710_private *devpriv;
1219 struct comedi_subdevice *s;
1220 int ret, subdev, n_subdevices;
1222 if (context < ARRAY_SIZE(boardtypes))
1223 this_board = &boardtypes[context];
1226 dev->board_ptr = this_board;
1227 dev->board_name = this_board->name;
1229 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1233 ret = comedi_pci_enable(dev);
1236 dev->iobase = pci_resource_start(pcidev, 2);
1239 if (this_board->n_aichan)
1241 if (this_board->n_aochan)
1243 if (this_board->n_dichan)
1245 if (this_board->n_dochan)
1247 if (this_board->n_counter)
1250 ret = comedi_alloc_subdevices(dev, n_subdevices);
1256 if (this_board->have_irq && pcidev->irq) {
1257 ret = request_irq(pcidev->irq, interrupt_service_pci1710,
1258 IRQF_SHARED, dev->board_name, dev);
1260 dev->irq = pcidev->irq;
1265 if (this_board->n_aichan) {
1266 s = &dev->subdevices[subdev];
1267 s->type = COMEDI_SUBD_AI;
1268 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
1269 if (this_board->n_aichand)
1270 s->subdev_flags |= SDF_DIFF;
1271 s->n_chan = this_board->n_aichan;
1272 s->maxdata = this_board->ai_maxdata;
1273 s->range_table = this_board->rangelist_ai;
1274 s->insn_read = pci171x_insn_read_ai;
1276 dev->read_subdev = s;
1277 s->subdev_flags |= SDF_CMD_READ;
1278 s->len_chanlist = s->n_chan;
1279 s->do_cmdtest = pci171x_ai_cmdtest;
1280 s->do_cmd = pci171x_ai_cmd;
1281 s->cancel = pci171x_ai_cancel;
1283 devpriv->i8254_osc_base = I8254_OSC_BASE_10MHZ;
1287 if (this_board->n_aochan) {
1288 s = &dev->subdevices[subdev];
1289 s->type = COMEDI_SUBD_AO;
1290 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1291 s->n_chan = this_board->n_aochan;
1292 s->maxdata = this_board->ao_maxdata;
1293 s->len_chanlist = this_board->n_aochan;
1294 s->range_table = this_board->rangelist_ao;
1295 switch (this_board->cardtype) {
1297 s->insn_write = pci1720_insn_write_ao;
1300 s->insn_write = pci171x_insn_write_ao;
1303 s->insn_read = pci171x_insn_read_ao;
1307 if (this_board->n_dichan) {
1308 s = &dev->subdevices[subdev];
1309 s->type = COMEDI_SUBD_DI;
1310 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
1311 s->n_chan = this_board->n_dichan;
1313 s->len_chanlist = this_board->n_dichan;
1314 s->range_table = &range_digital;
1315 s->insn_bits = pci171x_insn_bits_di;
1319 if (this_board->n_dochan) {
1320 s = &dev->subdevices[subdev];
1321 s->type = COMEDI_SUBD_DO;
1322 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1323 s->n_chan = this_board->n_dochan;
1325 s->len_chanlist = this_board->n_dochan;
1326 s->range_table = &range_digital;
1327 s->insn_bits = pci171x_insn_bits_do;
1331 if (this_board->n_counter) {
1332 s = &dev->subdevices[subdev];
1333 s->type = COMEDI_SUBD_COUNTER;
1334 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1335 s->n_chan = this_board->n_counter;
1336 s->len_chanlist = this_board->n_counter;
1337 s->maxdata = 0xffff;
1338 s->range_table = &range_unknown;
1339 s->insn_read = pci171x_insn_counter_read;
1340 s->insn_write = pci171x_insn_counter_write;
1341 s->insn_config = pci171x_insn_counter_config;
1345 dev_info(dev->class_dev, "%s attached, irq %sabled\n",
1346 dev->board_name, dev->irq ? "en" : "dis");
1351 static void pci1710_detach(struct comedi_device *dev)
1356 free_irq(dev->irq, dev);
1357 comedi_pci_disable(dev);
1360 static struct comedi_driver adv_pci1710_driver = {
1361 .driver_name = "adv_pci1710",
1362 .module = THIS_MODULE,
1363 .auto_attach = pci1710_auto_attach,
1364 .detach = pci1710_detach,
1367 static int adv_pci1710_pci_probe(struct pci_dev *dev,
1368 const struct pci_device_id *id)
1370 return comedi_pci_auto_config(dev, &adv_pci1710_driver,
1374 static const struct pci_device_id adv_pci1710_pci_table[] = {
1376 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1377 PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050),
1378 .driver_data = BOARD_PCI1710,
1380 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1381 PCI_VENDOR_ID_ADVANTECH, 0x0000),
1382 .driver_data = BOARD_PCI1710,
1384 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1385 PCI_VENDOR_ID_ADVANTECH, 0xb100),
1386 .driver_data = BOARD_PCI1710,
1388 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1389 PCI_VENDOR_ID_ADVANTECH, 0xb200),
1390 .driver_data = BOARD_PCI1710,
1392 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1393 PCI_VENDOR_ID_ADVANTECH, 0xc100),
1394 .driver_data = BOARD_PCI1710,
1396 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1397 PCI_VENDOR_ID_ADVANTECH, 0xc200),
1398 .driver_data = BOARD_PCI1710,
1400 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd100),
1401 .driver_data = BOARD_PCI1710,
1403 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1404 PCI_VENDOR_ID_ADVANTECH, 0x0002),
1405 .driver_data = BOARD_PCI1710HG,
1407 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1408 PCI_VENDOR_ID_ADVANTECH, 0xb102),
1409 .driver_data = BOARD_PCI1710HG,
1411 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1412 PCI_VENDOR_ID_ADVANTECH, 0xb202),
1413 .driver_data = BOARD_PCI1710HG,
1415 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1416 PCI_VENDOR_ID_ADVANTECH, 0xc102),
1417 .driver_data = BOARD_PCI1710HG,
1419 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1420 PCI_VENDOR_ID_ADVANTECH, 0xc202),
1421 .driver_data = BOARD_PCI1710HG,
1423 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd102),
1424 .driver_data = BOARD_PCI1710HG,
1426 { PCI_VDEVICE(ADVANTECH, 0x1711), BOARD_PCI1711 },
1427 { PCI_VDEVICE(ADVANTECH, 0x1713), BOARD_PCI1713 },
1428 { PCI_VDEVICE(ADVANTECH, 0x1720), BOARD_PCI1720 },
1429 { PCI_VDEVICE(ADVANTECH, 0x1731), BOARD_PCI1731 },
1432 MODULE_DEVICE_TABLE(pci, adv_pci1710_pci_table);
1434 static struct pci_driver adv_pci1710_pci_driver = {
1435 .name = "adv_pci1710",
1436 .id_table = adv_pci1710_pci_table,
1437 .probe = adv_pci1710_pci_probe,
1438 .remove = comedi_pci_auto_unconfig,
1440 module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver);
1442 MODULE_AUTHOR("Comedi http://www.comedi.org");
1443 MODULE_DESCRIPTION("Comedi low-level driver");
1444 MODULE_LICENSE("GPL");