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 printk("comedi%d: A/D FIFO empty (%4x)\n", dev->minor, m);
744 pci171x_ai_cancel(dev, s);
745 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
746 comedi_event(dev, s);
751 ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
753 pci171x_ai_cancel(dev, s);
754 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
755 comedi_event(dev, s);
759 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
761 for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
762 #ifdef PCI171x_PARANOIDCHECK
763 sampl = inw(dev->iobase + PCI171x_AD_DATA);
764 if (this_board->cardtype != TYPE_PCI1713)
765 if ((sampl & 0xf000) !=
766 devpriv->act_chanlist[s->async->cur_chan]) {
768 ("comedi: A/D data dropout: received data from channel %d, expected %d!\n",
769 (sampl & 0xf000) >> 12,
772 async->cur_chan] & 0xf000) >>
774 pci171x_ai_cancel(dev, s);
776 COMEDI_CB_EOA | COMEDI_CB_ERROR;
777 comedi_event(dev, s);
780 comedi_buf_put(s->async, sampl & 0x0fff);
782 comedi_buf_put(s->async,
783 inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
785 ++s->async->cur_chan;
787 if (s->async->cur_chan >= devpriv->ai_n_chan)
788 s->async->cur_chan = 0;
791 if (s->async->cur_chan == 0) { /* one scan done */
792 devpriv->ai_act_scan++;
793 if ((!devpriv->neverending_ai) &&
794 (devpriv->ai_act_scan >= devpriv->ai_scans)) {
795 /* all data sampled */
796 pci171x_ai_cancel(dev, s);
797 s->async->events |= COMEDI_CB_EOA;
798 comedi_event(dev, s);
804 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
806 comedi_event(dev, s);
810 ==============================================================================
812 static int move_block_from_fifo(struct comedi_device *dev,
813 struct comedi_subdevice *s, int n, int turn)
815 struct pci1710_private *devpriv = dev->private;
817 #ifdef PCI171x_PARANOIDCHECK
818 const struct boardtype *this_board = comedi_board(dev);
819 unsigned short sampl;
822 j = s->async->cur_chan;
823 for (i = 0; i < n; i++) {
824 #ifdef PCI171x_PARANOIDCHECK
825 sampl = inw(dev->iobase + PCI171x_AD_DATA);
826 if (this_board->cardtype != TYPE_PCI1713)
827 if ((sampl & 0xf000) != devpriv->act_chanlist[j]) {
829 ("comedi%d: A/D FIFO data dropout: received data from channel %d, expected %d! (%d/%d/%d/%d/%d/%4x)\n",
830 dev->minor, (sampl & 0xf000) >> 12,
831 (devpriv->act_chanlist[j] & 0xf000) >> 12,
832 i, j, devpriv->ai_act_scan, n, turn,
834 pci171x_ai_cancel(dev, s);
836 COMEDI_CB_EOA | COMEDI_CB_ERROR;
837 comedi_event(dev, s);
840 comedi_buf_put(s->async, sampl & 0x0fff);
842 comedi_buf_put(s->async,
843 inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
846 if (j >= devpriv->ai_n_chan) {
848 devpriv->ai_act_scan++;
851 s->async->cur_chan = j;
856 ==============================================================================
858 static void interrupt_pci1710_half_fifo(void *d)
860 struct comedi_device *dev = d;
861 const struct boardtype *this_board = comedi_board(dev);
862 struct pci1710_private *devpriv = dev->private;
863 struct comedi_subdevice *s = &dev->subdevices[0];
866 m = inw(dev->iobase + PCI171x_STATUS);
867 if (!(m & Status_FH)) {
868 printk("comedi%d: A/D FIFO not half full! (%4x)\n",
870 pci171x_ai_cancel(dev, s);
871 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
872 comedi_event(dev, s);
877 ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
879 pci171x_ai_cancel(dev, s);
880 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
881 comedi_event(dev, s);
885 samplesinbuf = this_board->fifo_half_size;
886 if (samplesinbuf * sizeof(short) >= devpriv->ai_data_len) {
887 m = devpriv->ai_data_len / sizeof(short);
888 if (move_block_from_fifo(dev, s, m, 0))
894 if (move_block_from_fifo(dev, s, samplesinbuf, 1))
898 if (!devpriv->neverending_ai)
899 if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data
901 pci171x_ai_cancel(dev, s);
902 s->async->events |= COMEDI_CB_EOA;
903 comedi_event(dev, s);
906 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
908 comedi_event(dev, s);
912 ==============================================================================
914 static irqreturn_t interrupt_service_pci1710(int irq, void *d)
916 struct comedi_device *dev = d;
917 struct pci1710_private *devpriv = dev->private;
919 if (!dev->attached) /* is device attached? */
920 return IRQ_NONE; /* no, exit */
921 /* is this interrupt from our board? */
922 if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))
923 return IRQ_NONE; /* no, exit */
925 if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */
927 devpriv->CntrlReg &= Control_CNT0;
928 devpriv->CntrlReg |= Control_SW; /* set software trigger */
929 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
930 devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
931 outb(0, dev->iobase + PCI171x_CLRFIFO);
932 outb(0, dev->iobase + PCI171x_CLRINT);
933 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
934 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
936 start_pacer(dev, 1, devpriv->ai_et_div1, devpriv->ai_et_div2);
939 if (devpriv->ai_eos) { /* We use FIFO half full INT or not? */
940 interrupt_pci1710_every_sample(d);
942 interrupt_pci1710_half_fifo(d);
948 ==============================================================================
950 static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev,
951 struct comedi_subdevice *s)
953 const struct boardtype *this_board = comedi_board(dev);
954 struct pci1710_private *devpriv = dev->private;
955 unsigned int divisor1 = 0, divisor2 = 0;
958 start_pacer(dev, -1, 0, 0); /* stop pacer */
960 seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
964 setup_channel_list(dev, s, devpriv->ai_chanlist,
965 devpriv->ai_n_chan, seglen);
967 outb(0, dev->iobase + PCI171x_CLRFIFO);
968 outb(0, dev->iobase + PCI171x_CLRINT);
970 devpriv->ai_do = mode;
972 devpriv->ai_act_scan = 0;
973 s->async->cur_chan = 0;
974 devpriv->ai_buf_ptr = 0;
975 devpriv->neverending_ai = 0;
977 devpriv->CntrlReg &= Control_CNT0;
978 /* don't we want wake up every scan? devpriv->ai_eos=1; */
979 if ((devpriv->ai_flags & TRIG_WAKE_EOS)) {
982 devpriv->CntrlReg |= Control_ONEFH;
986 if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1))
987 devpriv->neverending_ai = 1;
988 /* well, user want neverending */
990 devpriv->neverending_ai = 0;
995 if (devpriv->ai_timer1 < this_board->ai_ns_min)
996 devpriv->ai_timer1 = this_board->ai_ns_min;
997 devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
999 devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
1000 devpriv->CntrlReg &=
1001 ~(Control_PACER | Control_ONEFH | Control_GATE);
1002 devpriv->CntrlReg |= Control_EXT;
1007 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base,
1008 &divisor1, &divisor2,
1009 &devpriv->ai_timer1,
1011 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
1014 start_pacer(dev, mode, divisor1, divisor2);
1016 devpriv->ai_et_div1 = divisor1;
1017 devpriv->ai_et_div2 = divisor2;
1021 devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
1022 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
1030 ==============================================================================
1032 static int pci171x_ai_cmdtest(struct comedi_device *dev,
1033 struct comedi_subdevice *s,
1034 struct comedi_cmd *cmd)
1036 const struct boardtype *this_board = comedi_board(dev);
1037 struct pci1710_private *devpriv = dev->private;
1040 unsigned int divisor1 = 0, divisor2 = 0;
1042 /* Step 1 : check if triggers are trivially valid */
1044 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
1045 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
1046 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
1047 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
1048 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
1053 /* step 2a: make sure trigger sources are unique */
1055 err |= cfc_check_trigger_is_unique(cmd->start_src);
1056 err |= cfc_check_trigger_is_unique(cmd->convert_src);
1057 err |= cfc_check_trigger_is_unique(cmd->stop_src);
1059 /* step 2b: and mutually compatible */
1064 /* Step 3: check if arguments are trivially valid */
1066 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
1067 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
1069 if (cmd->convert_src == TRIG_TIMER)
1070 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
1071 this_board->ai_ns_min);
1072 else /* TRIG_FOLLOW */
1073 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
1075 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
1077 if (cmd->stop_src == TRIG_COUNT)
1078 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
1079 else /* TRIG_NONE */
1080 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
1085 /* step 4: fix up any arguments */
1087 if (cmd->convert_src == TRIG_TIMER) {
1088 tmp = cmd->convert_arg;
1089 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base,
1090 &divisor1, &divisor2,
1091 &cmd->convert_arg, cmd->flags);
1092 if (cmd->convert_arg < this_board->ai_ns_min)
1093 cmd->convert_arg = this_board->ai_ns_min;
1094 if (tmp != cmd->convert_arg)
1101 /* step 5: complain about special chanlist considerations */
1103 if (cmd->chanlist) {
1104 if (!check_channel_list(dev, s, cmd->chanlist,
1106 return 5; /* incorrect channels list */
1113 ==============================================================================
1115 static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1117 struct pci1710_private *devpriv = dev->private;
1118 struct comedi_cmd *cmd = &s->async->cmd;
1120 devpriv->ai_n_chan = cmd->chanlist_len;
1121 devpriv->ai_chanlist = cmd->chanlist;
1122 devpriv->ai_flags = cmd->flags;
1123 devpriv->ai_data_len = s->async->prealloc_bufsz;
1124 devpriv->ai_timer1 = 0;
1125 devpriv->ai_timer2 = 0;
1127 if (cmd->stop_src == TRIG_COUNT)
1128 devpriv->ai_scans = cmd->stop_arg;
1130 devpriv->ai_scans = 0;
1133 if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 2, 3 */
1134 if (cmd->convert_src == TRIG_TIMER) { /* mode 1 and 2 */
1135 devpriv->ai_timer1 = cmd->convert_arg;
1136 return pci171x_ai_docmd_and_mode(cmd->start_src ==
1137 TRIG_EXT ? 2 : 1, dev,
1140 if (cmd->convert_src == TRIG_EXT) { /* mode 3 */
1141 return pci171x_ai_docmd_and_mode(3, dev, s);
1149 ==============================================================================
1151 static int pci171x_reset(struct comedi_device *dev)
1153 const struct boardtype *this_board = comedi_board(dev);
1154 struct pci1710_private *devpriv = dev->private;
1156 outw(0x30, dev->iobase + PCI171x_CNTCTRL);
1157 devpriv->CntrlReg = Control_SW | Control_CNT0; /* Software trigger, CNT0=external */
1158 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */
1159 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
1160 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
1161 start_pacer(dev, -1, 0, 0); /* stop 8254 */
1162 devpriv->da_ranges = 0;
1163 if (this_board->n_aochan) {
1164 outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); /* set DACs to 0..5V */
1165 outw(0, dev->iobase + PCI171x_DA1); /* set DA outputs to 0V */
1166 devpriv->ao_data[0] = 0x0000;
1167 if (this_board->n_aochan > 1) {
1168 outw(0, dev->iobase + PCI171x_DA2);
1169 devpriv->ao_data[1] = 0x0000;
1172 outw(0, dev->iobase + PCI171x_DO); /* digital outputs to 0 */
1173 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
1174 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
1180 ==============================================================================
1182 static int pci1720_reset(struct comedi_device *dev)
1184 struct pci1710_private *devpriv = dev->private;
1186 outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT); /* set synchronous output mode */
1187 devpriv->da_ranges = 0xAA;
1188 outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE); /* set all ranges to +/-5V */
1189 outw(0x0800, dev->iobase + PCI1720_DA0); /* set outputs to 0V */
1190 outw(0x0800, dev->iobase + PCI1720_DA1);
1191 outw(0x0800, dev->iobase + PCI1720_DA2);
1192 outw(0x0800, dev->iobase + PCI1720_DA3);
1193 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
1194 devpriv->ao_data[0] = 0x0800;
1195 devpriv->ao_data[1] = 0x0800;
1196 devpriv->ao_data[2] = 0x0800;
1197 devpriv->ao_data[3] = 0x0800;
1202 ==============================================================================
1204 static int pci1710_reset(struct comedi_device *dev)
1206 const struct boardtype *this_board = comedi_board(dev);
1208 switch (this_board->cardtype) {
1210 return pci1720_reset(dev);
1212 return pci171x_reset(dev);
1216 static int pci1710_auto_attach(struct comedi_device *dev,
1217 unsigned long context)
1219 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1220 const struct boardtype *this_board = NULL;
1221 struct pci1710_private *devpriv;
1222 struct comedi_subdevice *s;
1223 int ret, subdev, n_subdevices;
1225 if (context < ARRAY_SIZE(boardtypes))
1226 this_board = &boardtypes[context];
1229 dev->board_ptr = this_board;
1230 dev->board_name = this_board->name;
1232 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1236 ret = comedi_pci_enable(dev);
1239 dev->iobase = pci_resource_start(pcidev, 2);
1242 if (this_board->n_aichan)
1244 if (this_board->n_aochan)
1246 if (this_board->n_dichan)
1248 if (this_board->n_dochan)
1250 if (this_board->n_counter)
1253 ret = comedi_alloc_subdevices(dev, n_subdevices);
1259 if (this_board->have_irq && pcidev->irq) {
1260 ret = request_irq(pcidev->irq, interrupt_service_pci1710,
1261 IRQF_SHARED, dev->board_name, dev);
1263 dev->irq = pcidev->irq;
1268 if (this_board->n_aichan) {
1269 s = &dev->subdevices[subdev];
1270 dev->read_subdev = s;
1271 s->type = COMEDI_SUBD_AI;
1272 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
1273 if (this_board->n_aichand)
1274 s->subdev_flags |= SDF_DIFF;
1275 s->n_chan = this_board->n_aichan;
1276 s->maxdata = this_board->ai_maxdata;
1277 s->len_chanlist = this_board->n_aichan;
1278 s->range_table = this_board->rangelist_ai;
1279 s->cancel = pci171x_ai_cancel;
1280 s->insn_read = pci171x_insn_read_ai;
1282 s->subdev_flags |= SDF_CMD_READ;
1283 s->do_cmdtest = pci171x_ai_cmdtest;
1284 s->do_cmd = pci171x_ai_cmd;
1286 devpriv->i8254_osc_base = I8254_OSC_BASE_10MHZ;
1290 if (this_board->n_aochan) {
1291 s = &dev->subdevices[subdev];
1292 s->type = COMEDI_SUBD_AO;
1293 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1294 s->n_chan = this_board->n_aochan;
1295 s->maxdata = this_board->ao_maxdata;
1296 s->len_chanlist = this_board->n_aochan;
1297 s->range_table = this_board->rangelist_ao;
1298 switch (this_board->cardtype) {
1300 s->insn_write = pci1720_insn_write_ao;
1303 s->insn_write = pci171x_insn_write_ao;
1306 s->insn_read = pci171x_insn_read_ao;
1310 if (this_board->n_dichan) {
1311 s = &dev->subdevices[subdev];
1312 s->type = COMEDI_SUBD_DI;
1313 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
1314 s->n_chan = this_board->n_dichan;
1316 s->len_chanlist = this_board->n_dichan;
1317 s->range_table = &range_digital;
1318 s->insn_bits = pci171x_insn_bits_di;
1322 if (this_board->n_dochan) {
1323 s = &dev->subdevices[subdev];
1324 s->type = COMEDI_SUBD_DO;
1325 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1326 s->n_chan = this_board->n_dochan;
1328 s->len_chanlist = this_board->n_dochan;
1329 s->range_table = &range_digital;
1330 s->insn_bits = pci171x_insn_bits_do;
1334 if (this_board->n_counter) {
1335 s = &dev->subdevices[subdev];
1336 s->type = COMEDI_SUBD_COUNTER;
1337 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1338 s->n_chan = this_board->n_counter;
1339 s->len_chanlist = this_board->n_counter;
1340 s->maxdata = 0xffff;
1341 s->range_table = &range_unknown;
1342 s->insn_read = pci171x_insn_counter_read;
1343 s->insn_write = pci171x_insn_counter_write;
1344 s->insn_config = pci171x_insn_counter_config;
1348 dev_info(dev->class_dev, "%s attached, irq %sabled\n",
1349 dev->board_name, dev->irq ? "en" : "dis");
1354 static void pci1710_detach(struct comedi_device *dev)
1359 free_irq(dev->irq, dev);
1360 comedi_pci_disable(dev);
1363 static struct comedi_driver adv_pci1710_driver = {
1364 .driver_name = "adv_pci1710",
1365 .module = THIS_MODULE,
1366 .auto_attach = pci1710_auto_attach,
1367 .detach = pci1710_detach,
1370 static int adv_pci1710_pci_probe(struct pci_dev *dev,
1371 const struct pci_device_id *id)
1373 return comedi_pci_auto_config(dev, &adv_pci1710_driver,
1377 static DEFINE_PCI_DEVICE_TABLE(adv_pci1710_pci_table) = {
1379 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1380 PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050),
1381 .driver_data = BOARD_PCI1710,
1383 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1384 PCI_VENDOR_ID_ADVANTECH, 0x0000),
1385 .driver_data = BOARD_PCI1710,
1387 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1388 PCI_VENDOR_ID_ADVANTECH, 0xb100),
1389 .driver_data = BOARD_PCI1710,
1391 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1392 PCI_VENDOR_ID_ADVANTECH, 0xb200),
1393 .driver_data = BOARD_PCI1710,
1395 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1396 PCI_VENDOR_ID_ADVANTECH, 0xc100),
1397 .driver_data = BOARD_PCI1710,
1399 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1400 PCI_VENDOR_ID_ADVANTECH, 0xc200),
1401 .driver_data = BOARD_PCI1710,
1403 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd100),
1404 .driver_data = BOARD_PCI1710,
1406 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1407 PCI_VENDOR_ID_ADVANTECH, 0x0002),
1408 .driver_data = BOARD_PCI1710HG,
1410 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1411 PCI_VENDOR_ID_ADVANTECH, 0xb102),
1412 .driver_data = BOARD_PCI1710HG,
1414 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1415 PCI_VENDOR_ID_ADVANTECH, 0xb202),
1416 .driver_data = BOARD_PCI1710HG,
1418 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1419 PCI_VENDOR_ID_ADVANTECH, 0xc102),
1420 .driver_data = BOARD_PCI1710HG,
1422 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1423 PCI_VENDOR_ID_ADVANTECH, 0xc202),
1424 .driver_data = BOARD_PCI1710HG,
1426 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd102),
1427 .driver_data = BOARD_PCI1710HG,
1429 { PCI_VDEVICE(ADVANTECH, 0x1711), BOARD_PCI1711 },
1430 { PCI_VDEVICE(ADVANTECH, 0x1713), BOARD_PCI1713 },
1431 { PCI_VDEVICE(ADVANTECH, 0x1720), BOARD_PCI1720 },
1432 { PCI_VDEVICE(ADVANTECH, 0x1731), BOARD_PCI1731 },
1435 MODULE_DEVICE_TABLE(pci, adv_pci1710_pci_table);
1437 static struct pci_driver adv_pci1710_pci_driver = {
1438 .name = "adv_pci1710",
1439 .id_table = adv_pci1710_pci_table,
1440 .probe = adv_pci1710_pci_probe,
1441 .remove = comedi_pci_auto_unconfig,
1443 module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver);
1445 MODULE_AUTHOR("Comedi http://www.comedi.org");
1446 MODULE_DESCRIPTION("Comedi low-level driver");
1447 MODULE_LICENSE("GPL");