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 = {
132 static const char range_codes_pci1710_3[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
133 0x10, 0x11, 0x12, 0x13 };
135 static const struct comedi_lrange range_pci1710hg = {
152 static const char range_codes_pci1710hg[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
153 0x05, 0x06, 0x07, 0x10, 0x11,
156 static const struct comedi_lrange range_pci17x1 = {
166 static const char range_codes_pci17x1[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
168 static const struct comedi_lrange range_pci1720 = {
177 static const struct comedi_lrange range_pci171x_da = {
184 enum pci1710_boardid {
194 const char *name; /* board name */
195 char have_irq; /* 1=card support IRQ */
196 char cardtype; /* 0=1710& co. 2=1713, ... */
197 int n_aichan; /* num of A/D chans */
198 int n_aichand; /* num of A/D chans in diff mode */
199 int n_aochan; /* num of D/A chans */
200 int n_dichan; /* num of DI chans */
201 int n_dochan; /* num of DO chans */
202 int n_counter; /* num of counters */
203 int ai_maxdata; /* resolution of A/D */
204 int ao_maxdata; /* resolution of D/A */
205 const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */
206 const char *rangecode_ai; /* range codes for programming */
207 const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */
208 unsigned int ai_ns_min; /* max sample speed of card v ns */
209 unsigned int fifo_half_size; /* size of FIFO/2 */
212 static const struct boardtype boardtypes[] = {
216 .cardtype = TYPE_PCI171X,
223 .ai_maxdata = 0x0fff,
224 .ao_maxdata = 0x0fff,
225 .rangelist_ai = &range_pci1710_3,
226 .rangecode_ai = range_codes_pci1710_3,
227 .rangelist_ao = &range_pci171x_da,
229 .fifo_half_size = 2048,
231 [BOARD_PCI1710HG] = {
234 .cardtype = TYPE_PCI171X,
241 .ai_maxdata = 0x0fff,
242 .ao_maxdata = 0x0fff,
243 .rangelist_ai = &range_pci1710hg,
244 .rangecode_ai = range_codes_pci1710hg,
245 .rangelist_ao = &range_pci171x_da,
247 .fifo_half_size = 2048,
252 .cardtype = TYPE_PCI171X,
258 .ai_maxdata = 0x0fff,
259 .ao_maxdata = 0x0fff,
260 .rangelist_ai = &range_pci17x1,
261 .rangecode_ai = range_codes_pci17x1,
262 .rangelist_ao = &range_pci171x_da,
264 .fifo_half_size = 512,
269 .cardtype = TYPE_PCI1713,
272 .ai_maxdata = 0x0fff,
273 .rangelist_ai = &range_pci1710_3,
274 .rangecode_ai = range_codes_pci1710_3,
276 .fifo_half_size = 2048,
280 .cardtype = TYPE_PCI1720,
282 .ao_maxdata = 0x0fff,
283 .rangelist_ao = &range_pci1720,
288 .cardtype = TYPE_PCI171X,
292 .ai_maxdata = 0x0fff,
293 .rangelist_ai = &range_pci17x1,
294 .rangecode_ai = range_codes_pci17x1,
296 .fifo_half_size = 512,
300 struct pci1710_private {
301 char neverending_ai; /* we do unlimited AI */
302 unsigned int CntrlReg; /* Control register */
303 unsigned int i8254_osc_base; /* frequence of onboard oscilator */
304 unsigned int ai_do; /* what do AI? 0=nothing, 1 to 4 mode */
305 unsigned int ai_act_scan; /* how many scans we finished */
306 unsigned int ai_act_chan; /* actual position in actual scan */
307 unsigned int ai_buf_ptr; /* data buffer ptr in samples */
308 unsigned char ai_eos; /* 1=EOS wake up */
310 unsigned int ai_et_CntrlReg;
311 unsigned int ai_et_MuxVal;
312 unsigned int ai_et_div1, ai_et_div2;
313 unsigned int act_chanlist[32]; /* list of scanned channel */
314 unsigned char act_chanlist_len; /* len of scanlist */
315 unsigned char act_chanlist_pos; /* actual position in MUX list */
316 unsigned char da_ranges; /* copy of D/A outpit range register */
317 unsigned int ai_scans; /* len of scanlist */
318 unsigned int ai_n_chan; /* how many channels is measured */
319 unsigned int *ai_chanlist; /* actaul chanlist */
320 unsigned int ai_flags; /* flaglist */
321 unsigned int ai_data_len; /* len of data buffer */
322 unsigned int ai_timer1; /* timers */
323 unsigned int ai_timer2;
324 unsigned short ao_data[4]; /* data output buffer */
325 unsigned int cnt0_write_wait; /* after a write, wait for update of the
329 /* used for gain list programming */
330 static const unsigned int muxonechan[] = {
331 0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707,
332 0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f,
333 0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717,
334 0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f
338 ==============================================================================
339 Check if channel list from user is built correctly
340 If it's ok, then program scan/gain logic.
341 This works for all cards.
343 static int check_channel_list(struct comedi_device *dev,
344 struct comedi_subdevice *s,
345 unsigned int *chanlist, unsigned int n_chan)
347 unsigned int chansegment[32];
348 unsigned int i, nowmustbechan, seglen, segpos;
350 /* correct channel and range number check itself comedi/range.c */
352 comedi_error(dev, "range/channel list is empty!");
357 return 1; /* seglen=1 */
359 chansegment[0] = chanlist[0]; /* first channel is every time ok */
360 for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {
361 if (chanlist[0] == chanlist[i])
362 break; /* we detected a loop, stop */
363 if ((CR_CHAN(chanlist[i]) & 1) &&
364 (CR_AREF(chanlist[i]) == AREF_DIFF)) {
365 comedi_error(dev, "Odd channel cannot be differential input!\n");
368 nowmustbechan = (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
369 if (CR_AREF(chansegment[i - 1]) == AREF_DIFF)
370 nowmustbechan = (nowmustbechan + 1) % s->n_chan;
371 if (nowmustbechan != CR_CHAN(chanlist[i])) {
372 printk("channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
373 i, CR_CHAN(chanlist[i]), nowmustbechan,
374 CR_CHAN(chanlist[0]));
377 chansegment[i] = chanlist[i]; /* next correct channel in list */
380 for (i = 0, segpos = 0; i < n_chan; i++) {
381 if (chanlist[i] != chansegment[i % seglen]) {
382 printk("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
383 i, CR_CHAN(chansegment[i]),
384 CR_RANGE(chansegment[i]),
385 CR_AREF(chansegment[i]),
386 CR_CHAN(chanlist[i % seglen]),
387 CR_RANGE(chanlist[i % seglen]),
388 CR_AREF(chansegment[i % seglen]));
395 static void setup_channel_list(struct comedi_device *dev,
396 struct comedi_subdevice *s,
397 unsigned int *chanlist, unsigned int n_chan,
400 const struct boardtype *this_board = comedi_board(dev);
401 struct pci1710_private *devpriv = dev->private;
402 unsigned int i, range, chanprog;
404 devpriv->act_chanlist_len = seglen;
405 devpriv->act_chanlist_pos = 0;
407 for (i = 0; i < seglen; i++) { /* store range list to card */
408 chanprog = muxonechan[CR_CHAN(chanlist[i])];
409 outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */
410 range = this_board->rangecode_ai[CR_RANGE(chanlist[i])];
411 if (CR_AREF(chanlist[i]) == AREF_DIFF)
413 outw(range, dev->iobase + PCI171x_RANGE); /* select gain */
414 #ifdef PCI171x_PARANOIDCHECK
415 devpriv->act_chanlist[i] =
416 (CR_CHAN(chanlist[i]) << 12) & 0xf000;
419 #ifdef PCI171x_PARANOIDCHECK
420 for ( ; i < n_chan; i++) { /* store remainder of channel list */
421 devpriv->act_chanlist[i] =
422 (CR_CHAN(chanlist[i]) << 12) & 0xf000;
426 devpriv->ai_et_MuxVal =
427 CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
428 /* select channel interval to scan */
429 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
433 ==============================================================================
435 static int pci171x_insn_read_ai(struct comedi_device *dev,
436 struct comedi_subdevice *s,
437 struct comedi_insn *insn, unsigned int *data)
439 struct pci1710_private *devpriv = dev->private;
441 #ifdef PCI171x_PARANOIDCHECK
442 const struct boardtype *this_board = comedi_board(dev);
446 devpriv->CntrlReg &= Control_CNT0;
447 devpriv->CntrlReg |= Control_SW; /* set software trigger */
448 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
449 outb(0, dev->iobase + PCI171x_CLRFIFO);
450 outb(0, dev->iobase + PCI171x_CLRINT);
452 setup_channel_list(dev, s, &insn->chanspec, 1, 1);
454 for (n = 0; n < insn->n; n++) {
455 outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */
459 if (!(inw(dev->iobase + PCI171x_STATUS) & Status_FE))
462 comedi_error(dev, "A/D insn timeout");
463 outb(0, dev->iobase + PCI171x_CLRFIFO);
464 outb(0, dev->iobase + PCI171x_CLRINT);
469 #ifdef PCI171x_PARANOIDCHECK
470 idata = inw(dev->iobase + PCI171x_AD_DATA);
471 if (this_board->cardtype != TYPE_PCI1713)
472 if ((idata & 0xf000) != devpriv->act_chanlist[0]) {
473 comedi_error(dev, "A/D insn data droput!");
476 data[n] = idata & 0x0fff;
478 data[n] = inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff;
483 outb(0, dev->iobase + PCI171x_CLRFIFO);
484 outb(0, dev->iobase + PCI171x_CLRINT);
490 ==============================================================================
492 static int pci171x_insn_write_ao(struct comedi_device *dev,
493 struct comedi_subdevice *s,
494 struct comedi_insn *insn, unsigned int *data)
496 struct pci1710_private *devpriv = dev->private;
497 int n, chan, range, ofs;
499 chan = CR_CHAN(insn->chanspec);
500 range = CR_RANGE(insn->chanspec);
502 devpriv->da_ranges &= 0xfb;
503 devpriv->da_ranges |= (range << 2);
504 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
507 devpriv->da_ranges &= 0xfe;
508 devpriv->da_ranges |= range;
509 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
513 for (n = 0; n < insn->n; n++)
514 outw(data[n], dev->iobase + ofs);
516 devpriv->ao_data[chan] = data[n];
523 ==============================================================================
525 static int pci171x_insn_read_ao(struct comedi_device *dev,
526 struct comedi_subdevice *s,
527 struct comedi_insn *insn, unsigned int *data)
529 struct pci1710_private *devpriv = dev->private;
532 chan = CR_CHAN(insn->chanspec);
533 for (n = 0; n < insn->n; n++)
534 data[n] = devpriv->ao_data[chan];
540 ==============================================================================
542 static int pci171x_insn_bits_di(struct comedi_device *dev,
543 struct comedi_subdevice *s,
544 struct comedi_insn *insn, unsigned int *data)
546 data[1] = inw(dev->iobase + PCI171x_DI);
551 static int pci171x_insn_bits_do(struct comedi_device *dev,
552 struct comedi_subdevice *s,
553 struct comedi_insn *insn,
556 if (comedi_dio_update_state(s, data))
557 outw(s->state, dev->iobase + PCI171x_DO);
565 ==============================================================================
567 static void start_pacer(struct comedi_device *dev, int mode,
568 unsigned int divisor1, unsigned int divisor2)
570 outw(0xb4, dev->iobase + PCI171x_CNTCTRL);
571 outw(0x74, dev->iobase + PCI171x_CNTCTRL);
574 outw(divisor2 & 0xff, dev->iobase + PCI171x_CNT2);
575 outw((divisor2 >> 8) & 0xff, dev->iobase + PCI171x_CNT2);
576 outw(divisor1 & 0xff, dev->iobase + PCI171x_CNT1);
577 outw((divisor1 >> 8) & 0xff, dev->iobase + PCI171x_CNT1);
582 ==============================================================================
584 static int pci171x_insn_counter_read(struct comedi_device *dev,
585 struct comedi_subdevice *s,
586 struct comedi_insn *insn,
589 unsigned int msb, lsb, ccntrl;
592 ccntrl = 0xD2; /* count only */
593 for (i = 0; i < insn->n; i++) {
594 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
596 lsb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
597 msb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
599 data[0] = lsb | (msb << 8);
606 ==============================================================================
608 static int pci171x_insn_counter_write(struct comedi_device *dev,
609 struct comedi_subdevice *s,
610 struct comedi_insn *insn,
613 struct pci1710_private *devpriv = dev->private;
614 uint msb, lsb, ccntrl, status;
616 lsb = data[0] & 0x00FF;
617 msb = (data[0] & 0xFF00) >> 8;
619 /* write lsb, then msb */
620 outw(lsb, dev->iobase + PCI171x_CNT0);
621 outw(msb, dev->iobase + PCI171x_CNT0);
623 if (devpriv->cnt0_write_wait) {
624 /* wait for the new count to be loaded */
627 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
628 status = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
629 } while (status & 0x40);
636 ==============================================================================
638 static int pci171x_insn_counter_config(struct comedi_device *dev,
639 struct comedi_subdevice *s,
640 struct comedi_insn *insn,
644 /* This doesn't work like a normal Comedi counter config */
645 struct pci1710_private *devpriv = dev->private;
648 devpriv->cnt0_write_wait = data[0] & 0x20;
650 /* internal or external clock? */
651 if (!(data[0] & 0x10)) { /* internal */
652 devpriv->CntrlReg &= ~Control_CNT0;
654 devpriv->CntrlReg |= Control_CNT0;
656 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
659 ccntrl |= Counter_M0;
661 ccntrl |= Counter_M1;
663 ccntrl |= Counter_M2;
665 ccntrl |= Counter_BCD;
666 ccntrl |= Counter_RW0; /* set read/write mode */
667 ccntrl |= Counter_RW1;
668 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
675 ==============================================================================
677 static int pci1720_insn_write_ao(struct comedi_device *dev,
678 struct comedi_subdevice *s,
679 struct comedi_insn *insn, unsigned int *data)
681 struct pci1710_private *devpriv = dev->private;
682 int n, rangereg, chan;
684 chan = CR_CHAN(insn->chanspec);
685 rangereg = devpriv->da_ranges & (~(0x03 << (chan << 1)));
686 rangereg |= (CR_RANGE(insn->chanspec) << (chan << 1));
687 if (rangereg != devpriv->da_ranges) {
688 outb(rangereg, dev->iobase + PCI1720_RANGE);
689 devpriv->da_ranges = rangereg;
692 for (n = 0; n < insn->n; n++) {
693 outw(data[n], dev->iobase + PCI1720_DA0 + (chan << 1));
694 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
697 devpriv->ao_data[chan] = data[n];
703 ==============================================================================
705 static int pci171x_ai_cancel(struct comedi_device *dev,
706 struct comedi_subdevice *s)
708 const struct boardtype *this_board = comedi_board(dev);
709 struct pci1710_private *devpriv = dev->private;
711 switch (this_board->cardtype) {
713 devpriv->CntrlReg &= Control_CNT0;
714 devpriv->CntrlReg |= Control_SW;
716 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */
717 start_pacer(dev, -1, 0, 0);
718 outb(0, dev->iobase + PCI171x_CLRFIFO);
719 outb(0, dev->iobase + PCI171x_CLRINT);
724 devpriv->ai_act_scan = 0;
725 s->async->cur_chan = 0;
726 devpriv->ai_buf_ptr = 0;
727 devpriv->neverending_ai = 0;
733 ==============================================================================
735 static void interrupt_pci1710_every_sample(void *d)
737 struct comedi_device *dev = d;
738 struct pci1710_private *devpriv = dev->private;
739 struct comedi_subdevice *s = dev->read_subdev;
741 #ifdef PCI171x_PARANOIDCHECK
742 const struct boardtype *this_board = comedi_board(dev);
743 unsigned short sampl;
746 m = inw(dev->iobase + PCI171x_STATUS);
748 dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", m);
749 pci171x_ai_cancel(dev, s);
750 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
751 comedi_event(dev, s);
755 dev_dbg(dev->class_dev,
756 "A/D FIFO Full status (Fatal Error!) (%4x)\n", m);
757 pci171x_ai_cancel(dev, s);
758 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
759 comedi_event(dev, s);
763 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
765 for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
766 #ifdef PCI171x_PARANOIDCHECK
767 sampl = inw(dev->iobase + PCI171x_AD_DATA);
768 if (this_board->cardtype != TYPE_PCI1713)
769 if ((sampl & 0xf000) !=
770 devpriv->act_chanlist[s->async->cur_chan]) {
772 ("comedi: A/D data dropout: received data from channel %d, expected %d!\n",
773 (sampl & 0xf000) >> 12,
776 async->cur_chan] & 0xf000) >>
778 pci171x_ai_cancel(dev, s);
780 COMEDI_CB_EOA | COMEDI_CB_ERROR;
781 comedi_event(dev, s);
784 comedi_buf_put(s->async, sampl & 0x0fff);
786 comedi_buf_put(s->async,
787 inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
789 ++s->async->cur_chan;
791 if (s->async->cur_chan >= devpriv->ai_n_chan)
792 s->async->cur_chan = 0;
795 if (s->async->cur_chan == 0) { /* one scan done */
796 devpriv->ai_act_scan++;
797 if ((!devpriv->neverending_ai) &&
798 (devpriv->ai_act_scan >= devpriv->ai_scans)) {
799 /* all data sampled */
800 pci171x_ai_cancel(dev, s);
801 s->async->events |= COMEDI_CB_EOA;
802 comedi_event(dev, s);
808 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
810 comedi_event(dev, s);
814 ==============================================================================
816 static int move_block_from_fifo(struct comedi_device *dev,
817 struct comedi_subdevice *s, int n, int turn)
819 struct pci1710_private *devpriv = dev->private;
821 #ifdef PCI171x_PARANOIDCHECK
822 const struct boardtype *this_board = comedi_board(dev);
823 unsigned short sampl;
826 j = s->async->cur_chan;
827 for (i = 0; i < n; i++) {
828 #ifdef PCI171x_PARANOIDCHECK
829 sampl = inw(dev->iobase + PCI171x_AD_DATA);
830 if (this_board->cardtype != TYPE_PCI1713)
831 if ((sampl & 0xf000) != devpriv->act_chanlist[j]) {
832 dev_dbg(dev->class_dev,
833 "A/D FIFO data dropout: received data from channel %d, expected %d! (%d/%d/%d/%d/%d/%4x)\n",
834 (sampl & 0xf000) >> 12,
835 (devpriv->act_chanlist[j] & 0xf000) >> 12,
836 i, j, devpriv->ai_act_scan, n, turn,
838 pci171x_ai_cancel(dev, s);
840 COMEDI_CB_EOA | COMEDI_CB_ERROR;
841 comedi_event(dev, s);
844 comedi_buf_put(s->async, sampl & 0x0fff);
846 comedi_buf_put(s->async,
847 inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
850 if (j >= devpriv->ai_n_chan) {
852 devpriv->ai_act_scan++;
855 s->async->cur_chan = j;
860 ==============================================================================
862 static void interrupt_pci1710_half_fifo(void *d)
864 struct comedi_device *dev = d;
865 const struct boardtype *this_board = comedi_board(dev);
866 struct pci1710_private *devpriv = dev->private;
867 struct comedi_subdevice *s = dev->read_subdev;
870 m = inw(dev->iobase + PCI171x_STATUS);
871 if (!(m & Status_FH)) {
872 dev_dbg(dev->class_dev, "A/D FIFO not half full! (%4x)\n", m);
873 pci171x_ai_cancel(dev, s);
874 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
875 comedi_event(dev, s);
879 dev_dbg(dev->class_dev,
880 "A/D FIFO Full status (Fatal Error!) (%4x)\n", m);
881 pci171x_ai_cancel(dev, s);
882 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
883 comedi_event(dev, s);
887 samplesinbuf = this_board->fifo_half_size;
888 if (samplesinbuf * sizeof(short) >= devpriv->ai_data_len) {
889 m = devpriv->ai_data_len / sizeof(short);
890 if (move_block_from_fifo(dev, s, m, 0))
896 if (move_block_from_fifo(dev, s, samplesinbuf, 1))
900 if (!devpriv->neverending_ai)
901 if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data
903 pci171x_ai_cancel(dev, s);
904 s->async->events |= COMEDI_CB_EOA;
905 comedi_event(dev, s);
908 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
910 comedi_event(dev, s);
914 ==============================================================================
916 static irqreturn_t interrupt_service_pci1710(int irq, void *d)
918 struct comedi_device *dev = d;
919 struct pci1710_private *devpriv = dev->private;
921 if (!dev->attached) /* is device attached? */
922 return IRQ_NONE; /* no, exit */
923 /* is this interrupt from our board? */
924 if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))
925 return IRQ_NONE; /* no, exit */
927 if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */
929 devpriv->CntrlReg &= Control_CNT0;
930 devpriv->CntrlReg |= Control_SW; /* set software trigger */
931 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
932 devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
933 outb(0, dev->iobase + PCI171x_CLRFIFO);
934 outb(0, dev->iobase + PCI171x_CLRINT);
935 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
936 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
938 start_pacer(dev, 1, devpriv->ai_et_div1, devpriv->ai_et_div2);
941 if (devpriv->ai_eos) { /* We use FIFO half full INT or not? */
942 interrupt_pci1710_every_sample(d);
944 interrupt_pci1710_half_fifo(d);
950 ==============================================================================
952 static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev,
953 struct comedi_subdevice *s)
955 const struct boardtype *this_board = comedi_board(dev);
956 struct pci1710_private *devpriv = dev->private;
957 unsigned int divisor1 = 0, divisor2 = 0;
960 start_pacer(dev, -1, 0, 0); /* stop pacer */
962 seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
966 setup_channel_list(dev, s, devpriv->ai_chanlist,
967 devpriv->ai_n_chan, seglen);
969 outb(0, dev->iobase + PCI171x_CLRFIFO);
970 outb(0, dev->iobase + PCI171x_CLRINT);
972 devpriv->ai_do = mode;
974 devpriv->ai_act_scan = 0;
975 s->async->cur_chan = 0;
976 devpriv->ai_buf_ptr = 0;
977 devpriv->neverending_ai = 0;
979 devpriv->CntrlReg &= Control_CNT0;
980 /* don't we want wake up every scan? devpriv->ai_eos=1; */
981 if ((devpriv->ai_flags & TRIG_WAKE_EOS)) {
984 devpriv->CntrlReg |= Control_ONEFH;
988 if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1))
989 devpriv->neverending_ai = 1;
990 /* well, user want neverending */
992 devpriv->neverending_ai = 0;
997 if (devpriv->ai_timer1 < this_board->ai_ns_min)
998 devpriv->ai_timer1 = this_board->ai_ns_min;
999 devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
1001 devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
1002 devpriv->CntrlReg &=
1003 ~(Control_PACER | Control_ONEFH | Control_GATE);
1004 devpriv->CntrlReg |= Control_EXT;
1009 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base,
1010 &divisor1, &divisor2,
1011 &devpriv->ai_timer1,
1013 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
1016 start_pacer(dev, mode, divisor1, divisor2);
1018 devpriv->ai_et_div1 = divisor1;
1019 devpriv->ai_et_div2 = divisor2;
1023 devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
1024 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
1032 ==============================================================================
1034 static int pci171x_ai_cmdtest(struct comedi_device *dev,
1035 struct comedi_subdevice *s,
1036 struct comedi_cmd *cmd)
1038 const struct boardtype *this_board = comedi_board(dev);
1039 struct pci1710_private *devpriv = dev->private;
1042 unsigned int divisor1 = 0, divisor2 = 0;
1044 /* Step 1 : check if triggers are trivially valid */
1046 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
1047 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
1048 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
1049 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
1050 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
1055 /* step 2a: make sure trigger sources are unique */
1057 err |= cfc_check_trigger_is_unique(cmd->start_src);
1058 err |= cfc_check_trigger_is_unique(cmd->convert_src);
1059 err |= cfc_check_trigger_is_unique(cmd->stop_src);
1061 /* step 2b: and mutually compatible */
1066 /* Step 3: check if arguments are trivially valid */
1068 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
1069 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
1071 if (cmd->convert_src == TRIG_TIMER)
1072 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
1073 this_board->ai_ns_min);
1074 else /* TRIG_FOLLOW */
1075 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
1077 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
1079 if (cmd->stop_src == TRIG_COUNT)
1080 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
1081 else /* TRIG_NONE */
1082 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
1087 /* step 4: fix up any arguments */
1089 if (cmd->convert_src == TRIG_TIMER) {
1090 tmp = cmd->convert_arg;
1091 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base,
1092 &divisor1, &divisor2,
1093 &cmd->convert_arg, cmd->flags);
1094 if (cmd->convert_arg < this_board->ai_ns_min)
1095 cmd->convert_arg = this_board->ai_ns_min;
1096 if (tmp != cmd->convert_arg)
1103 /* step 5: complain about special chanlist considerations */
1105 if (cmd->chanlist) {
1106 if (!check_channel_list(dev, s, cmd->chanlist,
1108 return 5; /* incorrect channels list */
1115 ==============================================================================
1117 static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1119 struct pci1710_private *devpriv = dev->private;
1120 struct comedi_cmd *cmd = &s->async->cmd;
1122 devpriv->ai_n_chan = cmd->chanlist_len;
1123 devpriv->ai_chanlist = cmd->chanlist;
1124 devpriv->ai_flags = cmd->flags;
1125 devpriv->ai_data_len = s->async->prealloc_bufsz;
1126 devpriv->ai_timer1 = 0;
1127 devpriv->ai_timer2 = 0;
1129 if (cmd->stop_src == TRIG_COUNT)
1130 devpriv->ai_scans = cmd->stop_arg;
1132 devpriv->ai_scans = 0;
1135 if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 2, 3 */
1136 if (cmd->convert_src == TRIG_TIMER) { /* mode 1 and 2 */
1137 devpriv->ai_timer1 = cmd->convert_arg;
1138 return pci171x_ai_docmd_and_mode(cmd->start_src ==
1139 TRIG_EXT ? 2 : 1, dev,
1142 if (cmd->convert_src == TRIG_EXT) { /* mode 3 */
1143 return pci171x_ai_docmd_and_mode(3, dev, s);
1151 ==============================================================================
1153 static int pci171x_reset(struct comedi_device *dev)
1155 const struct boardtype *this_board = comedi_board(dev);
1156 struct pci1710_private *devpriv = dev->private;
1158 outw(0x30, dev->iobase + PCI171x_CNTCTRL);
1159 devpriv->CntrlReg = Control_SW | Control_CNT0; /* Software trigger, CNT0=external */
1160 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */
1161 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
1162 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
1163 start_pacer(dev, -1, 0, 0); /* stop 8254 */
1164 devpriv->da_ranges = 0;
1165 if (this_board->n_aochan) {
1166 outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); /* set DACs to 0..5V */
1167 outw(0, dev->iobase + PCI171x_DA1); /* set DA outputs to 0V */
1168 devpriv->ao_data[0] = 0x0000;
1169 if (this_board->n_aochan > 1) {
1170 outw(0, dev->iobase + PCI171x_DA2);
1171 devpriv->ao_data[1] = 0x0000;
1174 outw(0, dev->iobase + PCI171x_DO); /* digital outputs to 0 */
1175 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
1176 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
1182 ==============================================================================
1184 static int pci1720_reset(struct comedi_device *dev)
1186 struct pci1710_private *devpriv = dev->private;
1188 outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT); /* set synchronous output mode */
1189 devpriv->da_ranges = 0xAA;
1190 outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE); /* set all ranges to +/-5V */
1191 outw(0x0800, dev->iobase + PCI1720_DA0); /* set outputs to 0V */
1192 outw(0x0800, dev->iobase + PCI1720_DA1);
1193 outw(0x0800, dev->iobase + PCI1720_DA2);
1194 outw(0x0800, dev->iobase + PCI1720_DA3);
1195 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
1196 devpriv->ao_data[0] = 0x0800;
1197 devpriv->ao_data[1] = 0x0800;
1198 devpriv->ao_data[2] = 0x0800;
1199 devpriv->ao_data[3] = 0x0800;
1204 ==============================================================================
1206 static int pci1710_reset(struct comedi_device *dev)
1208 const struct boardtype *this_board = comedi_board(dev);
1210 switch (this_board->cardtype) {
1212 return pci1720_reset(dev);
1214 return pci171x_reset(dev);
1218 static int pci1710_auto_attach(struct comedi_device *dev,
1219 unsigned long context)
1221 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1222 const struct boardtype *this_board = NULL;
1223 struct pci1710_private *devpriv;
1224 struct comedi_subdevice *s;
1225 int ret, subdev, n_subdevices;
1227 if (context < ARRAY_SIZE(boardtypes))
1228 this_board = &boardtypes[context];
1231 dev->board_ptr = this_board;
1232 dev->board_name = this_board->name;
1234 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1238 ret = comedi_pci_enable(dev);
1241 dev->iobase = pci_resource_start(pcidev, 2);
1244 if (this_board->n_aichan)
1246 if (this_board->n_aochan)
1248 if (this_board->n_dichan)
1250 if (this_board->n_dochan)
1252 if (this_board->n_counter)
1255 ret = comedi_alloc_subdevices(dev, n_subdevices);
1261 if (this_board->have_irq && pcidev->irq) {
1262 ret = request_irq(pcidev->irq, interrupt_service_pci1710,
1263 IRQF_SHARED, dev->board_name, dev);
1265 dev->irq = pcidev->irq;
1270 if (this_board->n_aichan) {
1271 s = &dev->subdevices[subdev];
1272 s->type = COMEDI_SUBD_AI;
1273 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
1274 if (this_board->n_aichand)
1275 s->subdev_flags |= SDF_DIFF;
1276 s->n_chan = this_board->n_aichan;
1277 s->maxdata = this_board->ai_maxdata;
1278 s->range_table = this_board->rangelist_ai;
1279 s->insn_read = pci171x_insn_read_ai;
1281 dev->read_subdev = s;
1282 s->subdev_flags |= SDF_CMD_READ;
1283 s->len_chanlist = s->n_chan;
1284 s->do_cmdtest = pci171x_ai_cmdtest;
1285 s->do_cmd = pci171x_ai_cmd;
1286 s->cancel = pci171x_ai_cancel;
1288 devpriv->i8254_osc_base = I8254_OSC_BASE_10MHZ;
1292 if (this_board->n_aochan) {
1293 s = &dev->subdevices[subdev];
1294 s->type = COMEDI_SUBD_AO;
1295 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1296 s->n_chan = this_board->n_aochan;
1297 s->maxdata = this_board->ao_maxdata;
1298 s->len_chanlist = this_board->n_aochan;
1299 s->range_table = this_board->rangelist_ao;
1300 switch (this_board->cardtype) {
1302 s->insn_write = pci1720_insn_write_ao;
1305 s->insn_write = pci171x_insn_write_ao;
1308 s->insn_read = pci171x_insn_read_ao;
1312 if (this_board->n_dichan) {
1313 s = &dev->subdevices[subdev];
1314 s->type = COMEDI_SUBD_DI;
1315 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
1316 s->n_chan = this_board->n_dichan;
1318 s->len_chanlist = this_board->n_dichan;
1319 s->range_table = &range_digital;
1320 s->insn_bits = pci171x_insn_bits_di;
1324 if (this_board->n_dochan) {
1325 s = &dev->subdevices[subdev];
1326 s->type = COMEDI_SUBD_DO;
1327 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1328 s->n_chan = this_board->n_dochan;
1330 s->len_chanlist = this_board->n_dochan;
1331 s->range_table = &range_digital;
1332 s->insn_bits = pci171x_insn_bits_do;
1336 if (this_board->n_counter) {
1337 s = &dev->subdevices[subdev];
1338 s->type = COMEDI_SUBD_COUNTER;
1339 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1340 s->n_chan = this_board->n_counter;
1341 s->len_chanlist = this_board->n_counter;
1342 s->maxdata = 0xffff;
1343 s->range_table = &range_unknown;
1344 s->insn_read = pci171x_insn_counter_read;
1345 s->insn_write = pci171x_insn_counter_write;
1346 s->insn_config = pci171x_insn_counter_config;
1350 dev_info(dev->class_dev, "%s attached, irq %sabled\n",
1351 dev->board_name, dev->irq ? "en" : "dis");
1356 static void pci1710_detach(struct comedi_device *dev)
1361 free_irq(dev->irq, dev);
1362 comedi_pci_disable(dev);
1365 static struct comedi_driver adv_pci1710_driver = {
1366 .driver_name = "adv_pci1710",
1367 .module = THIS_MODULE,
1368 .auto_attach = pci1710_auto_attach,
1369 .detach = pci1710_detach,
1372 static int adv_pci1710_pci_probe(struct pci_dev *dev,
1373 const struct pci_device_id *id)
1375 return comedi_pci_auto_config(dev, &adv_pci1710_driver,
1379 static const struct pci_device_id adv_pci1710_pci_table[] = {
1381 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1382 PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050),
1383 .driver_data = BOARD_PCI1710,
1385 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1386 PCI_VENDOR_ID_ADVANTECH, 0x0000),
1387 .driver_data = BOARD_PCI1710,
1389 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1390 PCI_VENDOR_ID_ADVANTECH, 0xb100),
1391 .driver_data = BOARD_PCI1710,
1393 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1394 PCI_VENDOR_ID_ADVANTECH, 0xb200),
1395 .driver_data = BOARD_PCI1710,
1397 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1398 PCI_VENDOR_ID_ADVANTECH, 0xc100),
1399 .driver_data = BOARD_PCI1710,
1401 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1402 PCI_VENDOR_ID_ADVANTECH, 0xc200),
1403 .driver_data = BOARD_PCI1710,
1405 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd100),
1406 .driver_data = BOARD_PCI1710,
1408 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1409 PCI_VENDOR_ID_ADVANTECH, 0x0002),
1410 .driver_data = BOARD_PCI1710HG,
1412 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1413 PCI_VENDOR_ID_ADVANTECH, 0xb102),
1414 .driver_data = BOARD_PCI1710HG,
1416 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1417 PCI_VENDOR_ID_ADVANTECH, 0xb202),
1418 .driver_data = BOARD_PCI1710HG,
1420 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1421 PCI_VENDOR_ID_ADVANTECH, 0xc102),
1422 .driver_data = BOARD_PCI1710HG,
1424 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1425 PCI_VENDOR_ID_ADVANTECH, 0xc202),
1426 .driver_data = BOARD_PCI1710HG,
1428 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd102),
1429 .driver_data = BOARD_PCI1710HG,
1431 { PCI_VDEVICE(ADVANTECH, 0x1711), BOARD_PCI1711 },
1432 { PCI_VDEVICE(ADVANTECH, 0x1713), BOARD_PCI1713 },
1433 { PCI_VDEVICE(ADVANTECH, 0x1720), BOARD_PCI1720 },
1434 { PCI_VDEVICE(ADVANTECH, 0x1731), BOARD_PCI1731 },
1437 MODULE_DEVICE_TABLE(pci, adv_pci1710_pci_table);
1439 static struct pci_driver adv_pci1710_pci_driver = {
1440 .name = "adv_pci1710",
1441 .id_table = adv_pci1710_pci_table,
1442 .probe = adv_pci1710_pci_probe,
1443 .remove = comedi_pci_auto_unconfig,
1445 module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver);
1447 MODULE_AUTHOR("Comedi http://www.comedi.org");
1448 MODULE_DESCRIPTION("Comedi low-level driver");
1449 MODULE_LICENSE("GPL");