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/pci.h>
45 #include <linux/interrupt.h>
47 #include "../comedidev.h"
49 #include "comedi_fc.h"
51 #include "amcc_s5933.h"
54 * The pci1710 and pci1710hg boards have the same device id!
56 * The only difference between these boards is in the
57 * supported analog input ranges.
59 * #define this if your card is a pci1710hg and you need the
60 * correct ranges reported to user space.
62 #undef USE_PCI1710HG_RANGE
64 #define PCI171x_PARANOIDCHECK /* if defined, then is used code which control
65 * correct channel number on every 12 bit
68 /* hardware types of the cards */
69 #define TYPE_PCI171X 0
70 #define TYPE_PCI1713 2
71 #define TYPE_PCI1720 3
73 #define IORANGE_171x 32
74 #define IORANGE_1720 16
76 #define PCI171x_AD_DATA 0 /* R: A/D data */
77 #define PCI171x_SOFTTRG 0 /* W: soft trigger for A/D */
78 #define PCI171x_RANGE 2 /* W: A/D gain/range register */
79 #define PCI171x_MUX 4 /* W: A/D multiplexor control */
80 #define PCI171x_STATUS 6 /* R: status register */
81 #define PCI171x_CONTROL 6 /* W: control register */
82 #define PCI171x_CLRINT 8 /* W: clear interrupts request */
83 #define PCI171x_CLRFIFO 9 /* W: clear FIFO */
84 #define PCI171x_DA1 10 /* W: D/A register */
85 #define PCI171x_DA2 12 /* W: D/A register */
86 #define PCI171x_DAREF 14 /* W: D/A reference control */
87 #define PCI171x_DI 16 /* R: digi inputs */
88 #define PCI171x_DO 16 /* R: digi inputs */
89 #define PCI171x_CNT0 24 /* R/W: 8254 counter 0 */
90 #define PCI171x_CNT1 26 /* R/W: 8254 counter 1 */
91 #define PCI171x_CNT2 28 /* R/W: 8254 counter 2 */
92 #define PCI171x_CNTCTRL 30 /* W: 8254 counter control */
94 /* upper bits from status register (PCI171x_STATUS) (lower is same with control
96 #define Status_FE 0x0100 /* 1=FIFO is empty */
97 #define Status_FH 0x0200 /* 1=FIFO is half full */
98 #define Status_FF 0x0400 /* 1=FIFO is full, fatal error */
99 #define Status_IRQ 0x0800 /* 1=IRQ occurred */
100 /* bits from control register (PCI171x_CONTROL) */
101 #define Control_CNT0 0x0040 /* 1=CNT0 have external source,
102 * 0=have internal 100kHz source */
103 #define Control_ONEFH 0x0020 /* 1=IRQ on FIFO is half full, 0=every sample */
104 #define Control_IRQEN 0x0010 /* 1=enable IRQ */
105 #define Control_GATE 0x0008 /* 1=enable external trigger GATE (8254?) */
106 #define Control_EXT 0x0004 /* 1=external trigger source */
107 #define Control_PACER 0x0002 /* 1=enable internal 8254 trigger source */
108 #define Control_SW 0x0001 /* 1=enable software trigger source */
109 /* bits from counter control register (PCI171x_CNTCTRL) */
110 #define Counter_BCD 0x0001 /* 0 = binary counter, 1 = BCD counter */
111 #define Counter_M0 0x0002 /* M0-M2 select modes 0-5 */
112 #define Counter_M1 0x0004 /* 000 = mode 0, 010 = mode 2 ... */
113 #define Counter_M2 0x0008
114 #define Counter_RW0 0x0010 /* RW0/RW1 select read/write mode */
115 #define Counter_RW1 0x0020
116 #define Counter_SC0 0x0040 /* Select Counter. Only 00 or 11 may */
117 #define Counter_SC1 0x0080 /* be used, 00 for CNT0,
118 * 11 for read-back command */
120 #define PCI1720_DA0 0 /* W: D/A register 0 */
121 #define PCI1720_DA1 2 /* W: D/A register 1 */
122 #define PCI1720_DA2 4 /* W: D/A register 2 */
123 #define PCI1720_DA3 6 /* W: D/A register 3 */
124 #define PCI1720_RANGE 8 /* R/W: D/A range register */
125 #define PCI1720_SYNCOUT 9 /* W: D/A synchronized output register */
126 #define PCI1720_SYNCONT 15 /* R/W: D/A synchronized control */
128 /* D/A synchronized control (PCI1720_SYNCONT) */
129 #define Syncont_SC0 1 /* set synchronous output mode */
131 static const struct comedi_lrange range_pci1710_3 = { 9, {
144 static const char range_codes_pci1710_3[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
145 0x10, 0x11, 0x12, 0x13 };
147 #ifdef USE_PCI1710HG_RANGE
148 static const struct comedi_lrange range_pci1710hg = { 12, {
164 static const char range_codes_pci1710hg[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
165 0x05, 0x06, 0x07, 0x10, 0x11,
167 #endif /* USE_PCI1710HG_RANGE */
169 static const struct comedi_lrange range_pci17x1 = { 5, {
178 static const char range_codes_pci17x1[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
180 static const struct comedi_lrange range_pci1720 = { 4, {
188 static const struct comedi_lrange range_pci171x_da = { 2, {
194 enum pci1710_boardid {
203 const char *name; /* board name */
204 int iorange; /* I/O range len */
205 char have_irq; /* 1=card support IRQ */
206 char cardtype; /* 0=1710& co. 2=1713, ... */
207 int n_aichan; /* num of A/D chans */
208 int n_aichand; /* num of A/D chans in diff mode */
209 int n_aochan; /* num of D/A chans */
210 int n_dichan; /* num of DI chans */
211 int n_dochan; /* num of DO chans */
212 int n_counter; /* num of counters */
213 int ai_maxdata; /* resolution of A/D */
214 int ao_maxdata; /* resolution of D/A */
215 const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */
216 const char *rangecode_ai; /* range codes for programming */
217 const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */
218 unsigned int ai_ns_min; /* max sample speed of card v ns */
219 unsigned int fifo_half_size; /* size of FIFO/2 */
222 static const struct boardtype boardtypes[] = {
225 .iorange = IORANGE_171x,
227 .cardtype = TYPE_PCI171X,
234 .ai_maxdata = 0x0fff,
235 .ao_maxdata = 0x0fff,
236 #ifndef USE_PCI1710HG_RANGE
237 .rangelist_ai = &range_pci1710_3,
238 .rangecode_ai = range_codes_pci1710_3,
240 .rangelist_ai = &range_pci1710hg,
241 .rangecode_ai = range_codes_pci1710hg,
243 .rangelist_ao = &range_pci171x_da,
245 .fifo_half_size = 2048,
249 .iorange = IORANGE_171x,
251 .cardtype = TYPE_PCI171X,
257 .ai_maxdata = 0x0fff,
258 .ao_maxdata = 0x0fff,
259 .rangelist_ai = &range_pci17x1,
260 .rangecode_ai = range_codes_pci17x1,
261 .rangelist_ao = &range_pci171x_da,
263 .fifo_half_size = 512,
267 .iorange = IORANGE_171x,
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 .iorange = IORANGE_1720,
281 .cardtype = TYPE_PCI1720,
283 .ao_maxdata = 0x0fff,
284 .rangelist_ao = &range_pci1720,
288 .iorange = IORANGE_171x,
290 .cardtype = TYPE_PCI171X,
294 .ai_maxdata = 0x0fff,
295 .rangelist_ai = &range_pci17x1,
296 .rangecode_ai = range_codes_pci17x1,
298 .fifo_half_size = 512,
302 struct pci1710_private {
303 char neverending_ai; /* we do unlimited AI */
304 unsigned int CntrlReg; /* Control register */
305 unsigned int i8254_osc_base; /* frequence of onboard oscilator */
306 unsigned int ai_do; /* what do AI? 0=nothing, 1 to 4 mode */
307 unsigned int ai_act_scan; /* how many scans we finished */
308 unsigned int ai_act_chan; /* actual position in actual scan */
309 unsigned int ai_buf_ptr; /* data buffer ptr in samples */
310 unsigned char ai_eos; /* 1=EOS wake up */
312 unsigned int ai_et_CntrlReg;
313 unsigned int ai_et_MuxVal;
314 unsigned int ai_et_div1, ai_et_div2;
315 unsigned int act_chanlist[32]; /* list of scaned channel */
316 unsigned char act_chanlist_len; /* len of scanlist */
317 unsigned char act_chanlist_pos; /* actual position in MUX list */
318 unsigned char da_ranges; /* copy of D/A outpit range register */
319 unsigned int ai_scans; /* len of scanlist */
320 unsigned int ai_n_chan; /* how many channels is measured */
321 unsigned int *ai_chanlist; /* actaul chanlist */
322 unsigned int ai_flags; /* flaglist */
323 unsigned int ai_data_len; /* len of data buffer */
324 short *ai_data; /* data buffer */
325 unsigned int ai_timer1; /* timers */
326 unsigned int ai_timer2;
327 short ao_data[4]; /* data output buffer */
328 unsigned int cnt0_write_wait; /* after a write, wait for update of the
332 /* used for gain list programming */
333 static const unsigned int muxonechan[] = {
334 0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707,
335 0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f,
336 0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717,
337 0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f
341 ==============================================================================
342 Check if channel list from user is builded correctly
343 If it's ok, then program scan/gain logic.
344 This works for all cards.
346 static int check_channel_list(struct comedi_device *dev,
347 struct comedi_subdevice *s,
348 unsigned int *chanlist, unsigned int n_chan)
350 unsigned int chansegment[32];
351 unsigned int i, nowmustbechan, seglen, segpos;
353 /* correct channel and range number check itself comedi/range.c */
355 comedi_error(dev, "range/channel list is empty!");
360 return 1; /* seglen=1 */
362 chansegment[0] = chanlist[0]; /* first channel is every time ok */
363 for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {
364 if (chanlist[0] == chanlist[i])
365 break; /* we detected a loop, stop */
366 if ((CR_CHAN(chanlist[i]) & 1) &&
367 (CR_AREF(chanlist[i]) == AREF_DIFF)) {
368 comedi_error(dev, "Odd channel cannot be differential input!\n");
371 nowmustbechan = (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
372 if (CR_AREF(chansegment[i - 1]) == AREF_DIFF)
373 nowmustbechan = (nowmustbechan + 1) % s->n_chan;
374 if (nowmustbechan != CR_CHAN(chanlist[i])) {
375 printk("channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
376 i, CR_CHAN(chanlist[i]), nowmustbechan,
377 CR_CHAN(chanlist[0]));
380 chansegment[i] = chanlist[i]; /* next correct channel in list */
383 for (i = 0, segpos = 0; i < n_chan; i++) {
384 if (chanlist[i] != chansegment[i % seglen]) {
385 printk("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
386 i, CR_CHAN(chansegment[i]),
387 CR_RANGE(chansegment[i]),
388 CR_AREF(chansegment[i]),
389 CR_CHAN(chanlist[i % seglen]),
390 CR_RANGE(chanlist[i % seglen]),
391 CR_AREF(chansegment[i % seglen]));
398 static void setup_channel_list(struct comedi_device *dev,
399 struct comedi_subdevice *s,
400 unsigned int *chanlist, unsigned int n_chan,
403 const struct boardtype *this_board = comedi_board(dev);
404 struct pci1710_private *devpriv = dev->private;
405 unsigned int i, range, chanprog;
407 devpriv->act_chanlist_len = seglen;
408 devpriv->act_chanlist_pos = 0;
410 for (i = 0; i < seglen; i++) { /* store range list to card */
411 chanprog = muxonechan[CR_CHAN(chanlist[i])];
412 outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */
413 range = this_board->rangecode_ai[CR_RANGE(chanlist[i])];
414 if (CR_AREF(chanlist[i]) == AREF_DIFF)
416 outw(range, dev->iobase + PCI171x_RANGE); /* select gain */
417 #ifdef PCI171x_PARANOIDCHECK
418 devpriv->act_chanlist[i] =
419 (CR_CHAN(chanlist[i]) << 12) & 0xf000;
422 #ifdef PCI171x_PARANOIDCHECK
423 for ( ; i < n_chan; i++) { /* store remainder of channel list */
424 devpriv->act_chanlist[i] =
425 (CR_CHAN(chanlist[i]) << 12) & 0xf000;
429 devpriv->ai_et_MuxVal =
430 CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
431 /* select channel interval to scan */
432 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
436 ==============================================================================
438 static int pci171x_insn_read_ai(struct comedi_device *dev,
439 struct comedi_subdevice *s,
440 struct comedi_insn *insn, unsigned int *data)
442 struct pci1710_private *devpriv = dev->private;
444 #ifdef PCI171x_PARANOIDCHECK
445 const struct boardtype *this_board = comedi_board(dev);
449 devpriv->CntrlReg &= Control_CNT0;
450 devpriv->CntrlReg |= Control_SW; /* set software trigger */
451 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
452 outb(0, dev->iobase + PCI171x_CLRFIFO);
453 outb(0, dev->iobase + PCI171x_CLRINT);
455 setup_channel_list(dev, s, &insn->chanspec, 1, 1);
457 for (n = 0; n < insn->n; n++) {
458 outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */
462 if (!(inw(dev->iobase + PCI171x_STATUS) & Status_FE))
465 comedi_error(dev, "A/D insn timeout");
466 outb(0, dev->iobase + PCI171x_CLRFIFO);
467 outb(0, dev->iobase + PCI171x_CLRINT);
472 #ifdef PCI171x_PARANOIDCHECK
473 idata = inw(dev->iobase + PCI171x_AD_DATA);
474 if (this_board->cardtype != TYPE_PCI1713)
475 if ((idata & 0xf000) != devpriv->act_chanlist[0]) {
476 comedi_error(dev, "A/D insn data droput!");
479 data[n] = idata & 0x0fff;
481 data[n] = inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff;
486 outb(0, dev->iobase + PCI171x_CLRFIFO);
487 outb(0, dev->iobase + PCI171x_CLRINT);
493 ==============================================================================
495 static int pci171x_insn_write_ao(struct comedi_device *dev,
496 struct comedi_subdevice *s,
497 struct comedi_insn *insn, unsigned int *data)
499 struct pci1710_private *devpriv = dev->private;
500 int n, chan, range, ofs;
502 chan = CR_CHAN(insn->chanspec);
503 range = CR_RANGE(insn->chanspec);
505 devpriv->da_ranges &= 0xfb;
506 devpriv->da_ranges |= (range << 2);
507 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
510 devpriv->da_ranges &= 0xfe;
511 devpriv->da_ranges |= range;
512 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
516 for (n = 0; n < insn->n; n++)
517 outw(data[n], dev->iobase + ofs);
519 devpriv->ao_data[chan] = data[n];
526 ==============================================================================
528 static int pci171x_insn_read_ao(struct comedi_device *dev,
529 struct comedi_subdevice *s,
530 struct comedi_insn *insn, unsigned int *data)
532 struct pci1710_private *devpriv = dev->private;
535 chan = CR_CHAN(insn->chanspec);
536 for (n = 0; n < insn->n; n++)
537 data[n] = devpriv->ao_data[chan];
543 ==============================================================================
545 static int pci171x_insn_bits_di(struct comedi_device *dev,
546 struct comedi_subdevice *s,
547 struct comedi_insn *insn, unsigned int *data)
549 data[1] = inw(dev->iobase + PCI171x_DI);
555 ==============================================================================
557 static int pci171x_insn_bits_do(struct comedi_device *dev,
558 struct comedi_subdevice *s,
559 struct comedi_insn *insn, unsigned int *data)
562 s->state &= ~data[0];
563 s->state |= (data[0] & data[1]);
564 outw(s->state, dev->iobase + PCI171x_DO);
572 ==============================================================================
574 static void start_pacer(struct comedi_device *dev, int mode,
575 unsigned int divisor1, unsigned int divisor2)
577 outw(0xb4, dev->iobase + PCI171x_CNTCTRL);
578 outw(0x74, dev->iobase + PCI171x_CNTCTRL);
581 outw(divisor2 & 0xff, dev->iobase + PCI171x_CNT2);
582 outw((divisor2 >> 8) & 0xff, dev->iobase + PCI171x_CNT2);
583 outw(divisor1 & 0xff, dev->iobase + PCI171x_CNT1);
584 outw((divisor1 >> 8) & 0xff, dev->iobase + PCI171x_CNT1);
589 ==============================================================================
591 static int pci171x_insn_counter_read(struct comedi_device *dev,
592 struct comedi_subdevice *s,
593 struct comedi_insn *insn,
596 unsigned int msb, lsb, ccntrl;
599 ccntrl = 0xD2; /* count only */
600 for (i = 0; i < insn->n; i++) {
601 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
603 lsb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
604 msb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
606 data[0] = lsb | (msb << 8);
613 ==============================================================================
615 static int pci171x_insn_counter_write(struct comedi_device *dev,
616 struct comedi_subdevice *s,
617 struct comedi_insn *insn,
620 struct pci1710_private *devpriv = dev->private;
621 uint msb, lsb, ccntrl, status;
623 lsb = data[0] & 0x00FF;
624 msb = (data[0] & 0xFF00) >> 8;
626 /* write lsb, then msb */
627 outw(lsb, dev->iobase + PCI171x_CNT0);
628 outw(msb, dev->iobase + PCI171x_CNT0);
630 if (devpriv->cnt0_write_wait) {
631 /* wait for the new count to be loaded */
634 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
635 status = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
636 } while (status & 0x40);
643 ==============================================================================
645 static int pci171x_insn_counter_config(struct comedi_device *dev,
646 struct comedi_subdevice *s,
647 struct comedi_insn *insn,
651 /* This doesn't work like a normal Comedi counter config */
652 struct pci1710_private *devpriv = dev->private;
655 devpriv->cnt0_write_wait = data[0] & 0x20;
657 /* internal or external clock? */
658 if (!(data[0] & 0x10)) { /* internal */
659 devpriv->CntrlReg &= ~Control_CNT0;
661 devpriv->CntrlReg |= Control_CNT0;
663 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
666 ccntrl |= Counter_M0;
668 ccntrl |= Counter_M1;
670 ccntrl |= Counter_M2;
672 ccntrl |= Counter_BCD;
673 ccntrl |= Counter_RW0; /* set read/write mode */
674 ccntrl |= Counter_RW1;
675 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
682 ==============================================================================
684 static int pci1720_insn_write_ao(struct comedi_device *dev,
685 struct comedi_subdevice *s,
686 struct comedi_insn *insn, unsigned int *data)
688 struct pci1710_private *devpriv = dev->private;
689 int n, rangereg, chan;
691 chan = CR_CHAN(insn->chanspec);
692 rangereg = devpriv->da_ranges & (~(0x03 << (chan << 1)));
693 rangereg |= (CR_RANGE(insn->chanspec) << (chan << 1));
694 if (rangereg != devpriv->da_ranges) {
695 outb(rangereg, dev->iobase + PCI1720_RANGE);
696 devpriv->da_ranges = rangereg;
699 for (n = 0; n < insn->n; n++) {
700 outw(data[n], dev->iobase + PCI1720_DA0 + (chan << 1));
701 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
704 devpriv->ao_data[chan] = data[n];
710 ==============================================================================
712 static int pci171x_ai_cancel(struct comedi_device *dev,
713 struct comedi_subdevice *s)
715 const struct boardtype *this_board = comedi_board(dev);
716 struct pci1710_private *devpriv = dev->private;
718 switch (this_board->cardtype) {
720 devpriv->CntrlReg &= Control_CNT0;
721 devpriv->CntrlReg |= Control_SW;
723 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */
724 start_pacer(dev, -1, 0, 0);
725 outb(0, dev->iobase + PCI171x_CLRFIFO);
726 outb(0, dev->iobase + PCI171x_CLRINT);
731 devpriv->ai_act_scan = 0;
732 s->async->cur_chan = 0;
733 devpriv->ai_buf_ptr = 0;
734 devpriv->neverending_ai = 0;
740 ==============================================================================
742 static void interrupt_pci1710_every_sample(void *d)
744 struct comedi_device *dev = d;
745 struct pci1710_private *devpriv = dev->private;
746 struct comedi_subdevice *s = &dev->subdevices[0];
748 #ifdef PCI171x_PARANOIDCHECK
749 const struct boardtype *this_board = comedi_board(dev);
753 m = inw(dev->iobase + PCI171x_STATUS);
755 printk("comedi%d: A/D FIFO empty (%4x)\n", dev->minor, m);
756 pci171x_ai_cancel(dev, s);
757 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
758 comedi_event(dev, s);
763 ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
765 pci171x_ai_cancel(dev, s);
766 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
767 comedi_event(dev, s);
771 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
773 for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
774 #ifdef PCI171x_PARANOIDCHECK
775 sampl = inw(dev->iobase + PCI171x_AD_DATA);
776 if (this_board->cardtype != TYPE_PCI1713)
777 if ((sampl & 0xf000) !=
778 devpriv->act_chanlist[s->async->cur_chan]) {
780 ("comedi: A/D data dropout: received data from channel %d, expected %d!\n",
781 (sampl & 0xf000) >> 12,
784 async->cur_chan] & 0xf000) >>
786 pci171x_ai_cancel(dev, s);
788 COMEDI_CB_EOA | COMEDI_CB_ERROR;
789 comedi_event(dev, s);
792 comedi_buf_put(s->async, sampl & 0x0fff);
794 comedi_buf_put(s->async,
795 inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
797 ++s->async->cur_chan;
799 if (s->async->cur_chan >= devpriv->ai_n_chan)
800 s->async->cur_chan = 0;
803 if (s->async->cur_chan == 0) { /* one scan done */
804 devpriv->ai_act_scan++;
805 if ((!devpriv->neverending_ai) &&
806 (devpriv->ai_act_scan >= devpriv->ai_scans)) {
807 /* all data sampled */
808 pci171x_ai_cancel(dev, s);
809 s->async->events |= COMEDI_CB_EOA;
810 comedi_event(dev, s);
816 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
818 comedi_event(dev, s);
822 ==============================================================================
824 static int move_block_from_fifo(struct comedi_device *dev,
825 struct comedi_subdevice *s, int n, int turn)
827 struct pci1710_private *devpriv = dev->private;
829 #ifdef PCI171x_PARANOIDCHECK
830 const struct boardtype *this_board = comedi_board(dev);
834 j = s->async->cur_chan;
835 for (i = 0; i < n; i++) {
836 #ifdef PCI171x_PARANOIDCHECK
837 sampl = inw(dev->iobase + PCI171x_AD_DATA);
838 if (this_board->cardtype != TYPE_PCI1713)
839 if ((sampl & 0xf000) != devpriv->act_chanlist[j]) {
841 ("comedi%d: A/D FIFO data dropout: received data from channel %d, expected %d! (%d/%d/%d/%d/%d/%4x)\n",
842 dev->minor, (sampl & 0xf000) >> 12,
843 (devpriv->act_chanlist[j] & 0xf000) >> 12,
844 i, j, devpriv->ai_act_scan, n, turn,
846 pci171x_ai_cancel(dev, s);
848 COMEDI_CB_EOA | COMEDI_CB_ERROR;
849 comedi_event(dev, s);
852 comedi_buf_put(s->async, sampl & 0x0fff);
854 comedi_buf_put(s->async,
855 inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
858 if (j >= devpriv->ai_n_chan) {
860 devpriv->ai_act_scan++;
863 s->async->cur_chan = j;
868 ==============================================================================
870 static void interrupt_pci1710_half_fifo(void *d)
872 struct comedi_device *dev = d;
873 const struct boardtype *this_board = comedi_board(dev);
874 struct pci1710_private *devpriv = dev->private;
875 struct comedi_subdevice *s = &dev->subdevices[0];
878 m = inw(dev->iobase + PCI171x_STATUS);
879 if (!(m & Status_FH)) {
880 printk("comedi%d: A/D FIFO not half full! (%4x)\n",
882 pci171x_ai_cancel(dev, s);
883 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
884 comedi_event(dev, s);
889 ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
891 pci171x_ai_cancel(dev, s);
892 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
893 comedi_event(dev, s);
897 samplesinbuf = this_board->fifo_half_size;
898 if (samplesinbuf * sizeof(short) >= devpriv->ai_data_len) {
899 m = devpriv->ai_data_len / sizeof(short);
900 if (move_block_from_fifo(dev, s, m, 0))
906 if (move_block_from_fifo(dev, s, samplesinbuf, 1))
910 if (!devpriv->neverending_ai)
911 if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data
913 pci171x_ai_cancel(dev, s);
914 s->async->events |= COMEDI_CB_EOA;
915 comedi_event(dev, s);
918 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
920 comedi_event(dev, s);
924 ==============================================================================
926 static irqreturn_t interrupt_service_pci1710(int irq, void *d)
928 struct comedi_device *dev = d;
929 struct pci1710_private *devpriv = dev->private;
931 if (!dev->attached) /* is device attached? */
932 return IRQ_NONE; /* no, exit */
933 /* is this interrupt from our board? */
934 if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))
935 return IRQ_NONE; /* no, exit */
937 if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */
939 devpriv->CntrlReg &= Control_CNT0;
940 devpriv->CntrlReg |= Control_SW; /* set software trigger */
941 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
942 devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
943 outb(0, dev->iobase + PCI171x_CLRFIFO);
944 outb(0, dev->iobase + PCI171x_CLRINT);
945 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
946 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
948 start_pacer(dev, 1, devpriv->ai_et_div1, devpriv->ai_et_div2);
951 if (devpriv->ai_eos) { /* We use FIFO half full INT or not? */
952 interrupt_pci1710_every_sample(d);
954 interrupt_pci1710_half_fifo(d);
960 ==============================================================================
962 static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev,
963 struct comedi_subdevice *s)
965 const struct boardtype *this_board = comedi_board(dev);
966 struct pci1710_private *devpriv = dev->private;
967 unsigned int divisor1 = 0, divisor2 = 0;
970 start_pacer(dev, -1, 0, 0); /* stop pacer */
972 seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
976 setup_channel_list(dev, s, devpriv->ai_chanlist,
977 devpriv->ai_n_chan, seglen);
979 outb(0, dev->iobase + PCI171x_CLRFIFO);
980 outb(0, dev->iobase + PCI171x_CLRINT);
982 devpriv->ai_do = mode;
984 devpriv->ai_act_scan = 0;
985 s->async->cur_chan = 0;
986 devpriv->ai_buf_ptr = 0;
987 devpriv->neverending_ai = 0;
989 devpriv->CntrlReg &= Control_CNT0;
990 /* don't we want wake up every scan? devpriv->ai_eos=1; */
991 if ((devpriv->ai_flags & TRIG_WAKE_EOS)) {
994 devpriv->CntrlReg |= Control_ONEFH;
998 if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1))
999 devpriv->neverending_ai = 1;
1000 /* well, user want neverending */
1002 devpriv->neverending_ai = 0;
1007 if (devpriv->ai_timer1 < this_board->ai_ns_min)
1008 devpriv->ai_timer1 = this_board->ai_ns_min;
1009 devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
1011 devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
1012 devpriv->CntrlReg &=
1013 ~(Control_PACER | Control_ONEFH | Control_GATE);
1014 devpriv->CntrlReg |= Control_EXT;
1019 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
1020 &divisor2, &devpriv->ai_timer1,
1021 devpriv->ai_flags & TRIG_ROUND_MASK);
1022 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
1025 start_pacer(dev, mode, divisor1, divisor2);
1027 devpriv->ai_et_div1 = divisor1;
1028 devpriv->ai_et_div2 = divisor2;
1032 devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
1033 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
1041 ==============================================================================
1043 static int pci171x_ai_cmdtest(struct comedi_device *dev,
1044 struct comedi_subdevice *s,
1045 struct comedi_cmd *cmd)
1047 const struct boardtype *this_board = comedi_board(dev);
1048 struct pci1710_private *devpriv = dev->private;
1051 unsigned int divisor1 = 0, divisor2 = 0;
1053 /* Step 1 : check if triggers are trivially valid */
1055 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
1056 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
1057 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
1058 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
1059 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
1064 /* step 2a: make sure trigger sources are unique */
1066 err |= cfc_check_trigger_is_unique(cmd->start_src);
1067 err |= cfc_check_trigger_is_unique(cmd->convert_src);
1068 err |= cfc_check_trigger_is_unique(cmd->stop_src);
1070 /* step 2b: and mutually compatible */
1075 /* Step 3: check if arguments are trivially valid */
1077 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
1078 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
1080 if (cmd->convert_src == TRIG_TIMER)
1081 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
1082 this_board->ai_ns_min);
1083 else /* TRIG_FOLLOW */
1084 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
1086 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
1088 if (cmd->stop_src == TRIG_COUNT)
1089 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
1090 else /* TRIG_NONE */
1091 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
1096 /* step 4: fix up any arguments */
1098 if (cmd->convert_src == TRIG_TIMER) {
1099 tmp = cmd->convert_arg;
1100 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
1101 &divisor2, &cmd->convert_arg,
1102 cmd->flags & TRIG_ROUND_MASK);
1103 if (cmd->convert_arg < this_board->ai_ns_min)
1104 cmd->convert_arg = this_board->ai_ns_min;
1105 if (tmp != cmd->convert_arg)
1112 /* step 5: complain about special chanlist considerations */
1114 if (cmd->chanlist) {
1115 if (!check_channel_list(dev, s, cmd->chanlist,
1117 return 5; /* incorrect channels list */
1124 ==============================================================================
1126 static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1128 struct pci1710_private *devpriv = dev->private;
1129 struct comedi_cmd *cmd = &s->async->cmd;
1131 devpriv->ai_n_chan = cmd->chanlist_len;
1132 devpriv->ai_chanlist = cmd->chanlist;
1133 devpriv->ai_flags = cmd->flags;
1134 devpriv->ai_data_len = s->async->prealloc_bufsz;
1135 devpriv->ai_data = s->async->prealloc_buf;
1136 devpriv->ai_timer1 = 0;
1137 devpriv->ai_timer2 = 0;
1139 if (cmd->stop_src == TRIG_COUNT)
1140 devpriv->ai_scans = cmd->stop_arg;
1142 devpriv->ai_scans = 0;
1145 if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 2, 3 */
1146 if (cmd->convert_src == TRIG_TIMER) { /* mode 1 and 2 */
1147 devpriv->ai_timer1 = cmd->convert_arg;
1148 return pci171x_ai_docmd_and_mode(cmd->start_src ==
1149 TRIG_EXT ? 2 : 1, dev,
1152 if (cmd->convert_src == TRIG_EXT) { /* mode 3 */
1153 return pci171x_ai_docmd_and_mode(3, dev, s);
1161 ==============================================================================
1163 static int pci171x_reset(struct comedi_device *dev)
1165 const struct boardtype *this_board = comedi_board(dev);
1166 struct pci1710_private *devpriv = dev->private;
1168 outw(0x30, dev->iobase + PCI171x_CNTCTRL);
1169 devpriv->CntrlReg = Control_SW | Control_CNT0; /* Software trigger, CNT0=external */
1170 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */
1171 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
1172 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
1173 start_pacer(dev, -1, 0, 0); /* stop 8254 */
1174 devpriv->da_ranges = 0;
1175 if (this_board->n_aochan) {
1176 outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); /* set DACs to 0..5V */
1177 outw(0, dev->iobase + PCI171x_DA1); /* set DA outputs to 0V */
1178 devpriv->ao_data[0] = 0x0000;
1179 if (this_board->n_aochan > 1) {
1180 outw(0, dev->iobase + PCI171x_DA2);
1181 devpriv->ao_data[1] = 0x0000;
1184 outw(0, dev->iobase + PCI171x_DO); /* digital outputs to 0 */
1185 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
1186 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
1192 ==============================================================================
1194 static int pci1720_reset(struct comedi_device *dev)
1196 struct pci1710_private *devpriv = dev->private;
1198 outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT); /* set synchronous output mode */
1199 devpriv->da_ranges = 0xAA;
1200 outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE); /* set all ranges to +/-5V */
1201 outw(0x0800, dev->iobase + PCI1720_DA0); /* set outputs to 0V */
1202 outw(0x0800, dev->iobase + PCI1720_DA1);
1203 outw(0x0800, dev->iobase + PCI1720_DA2);
1204 outw(0x0800, dev->iobase + PCI1720_DA3);
1205 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
1206 devpriv->ao_data[0] = 0x0800;
1207 devpriv->ao_data[1] = 0x0800;
1208 devpriv->ao_data[2] = 0x0800;
1209 devpriv->ao_data[3] = 0x0800;
1214 ==============================================================================
1216 static int pci1710_reset(struct comedi_device *dev)
1218 const struct boardtype *this_board = comedi_board(dev);
1220 switch (this_board->cardtype) {
1222 return pci1720_reset(dev);
1224 return pci171x_reset(dev);
1228 static int pci1710_auto_attach(struct comedi_device *dev,
1229 unsigned long context)
1231 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1232 const struct boardtype *this_board = NULL;
1233 struct pci1710_private *devpriv;
1234 struct comedi_subdevice *s;
1235 int ret, subdev, n_subdevices;
1237 if (context < ARRAY_SIZE(boardtypes))
1238 this_board = &boardtypes[context];
1241 dev->board_ptr = this_board;
1242 dev->board_name = this_board->name;
1244 devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
1247 dev->private = devpriv;
1249 ret = comedi_pci_enable(pcidev, dev->board_name);
1252 dev->iobase = pci_resource_start(pcidev, 2);
1255 if (this_board->n_aichan)
1257 if (this_board->n_aochan)
1259 if (this_board->n_dichan)
1261 if (this_board->n_dochan)
1263 if (this_board->n_counter)
1266 ret = comedi_alloc_subdevices(dev, n_subdevices);
1272 if (this_board->have_irq && pcidev->irq) {
1273 ret = request_irq(pcidev->irq, interrupt_service_pci1710,
1274 IRQF_SHARED, dev->board_name, dev);
1276 dev->irq = pcidev->irq;
1281 if (this_board->n_aichan) {
1282 s = &dev->subdevices[subdev];
1283 dev->read_subdev = s;
1284 s->type = COMEDI_SUBD_AI;
1285 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
1286 if (this_board->n_aichand)
1287 s->subdev_flags |= SDF_DIFF;
1288 s->n_chan = this_board->n_aichan;
1289 s->maxdata = this_board->ai_maxdata;
1290 s->len_chanlist = this_board->n_aichan;
1291 s->range_table = this_board->rangelist_ai;
1292 s->cancel = pci171x_ai_cancel;
1293 s->insn_read = pci171x_insn_read_ai;
1295 s->subdev_flags |= SDF_CMD_READ;
1296 s->do_cmdtest = pci171x_ai_cmdtest;
1297 s->do_cmd = pci171x_ai_cmd;
1299 devpriv->i8254_osc_base = 100; /* 100ns=10MHz */
1303 if (this_board->n_aochan) {
1304 s = &dev->subdevices[subdev];
1305 s->type = COMEDI_SUBD_AO;
1306 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1307 s->n_chan = this_board->n_aochan;
1308 s->maxdata = this_board->ao_maxdata;
1309 s->len_chanlist = this_board->n_aochan;
1310 s->range_table = this_board->rangelist_ao;
1311 switch (this_board->cardtype) {
1313 s->insn_write = pci1720_insn_write_ao;
1316 s->insn_write = pci171x_insn_write_ao;
1319 s->insn_read = pci171x_insn_read_ao;
1323 if (this_board->n_dichan) {
1324 s = &dev->subdevices[subdev];
1325 s->type = COMEDI_SUBD_DI;
1326 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
1327 s->n_chan = this_board->n_dichan;
1329 s->len_chanlist = this_board->n_dichan;
1330 s->range_table = &range_digital;
1331 s->io_bits = 0; /* all bits input */
1332 s->insn_bits = pci171x_insn_bits_di;
1336 if (this_board->n_dochan) {
1337 s = &dev->subdevices[subdev];
1338 s->type = COMEDI_SUBD_DO;
1339 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1340 s->n_chan = this_board->n_dochan;
1342 s->len_chanlist = this_board->n_dochan;
1343 s->range_table = &range_digital;
1344 /* all bits output */
1345 s->io_bits = (1 << this_board->n_dochan) - 1;
1347 s->insn_bits = pci171x_insn_bits_do;
1351 if (this_board->n_counter) {
1352 s = &dev->subdevices[subdev];
1353 s->type = COMEDI_SUBD_COUNTER;
1354 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1355 s->n_chan = this_board->n_counter;
1356 s->len_chanlist = this_board->n_counter;
1357 s->maxdata = 0xffff;
1358 s->range_table = &range_unknown;
1359 s->insn_read = pci171x_insn_counter_read;
1360 s->insn_write = pci171x_insn_counter_write;
1361 s->insn_config = pci171x_insn_counter_config;
1365 dev_info(dev->class_dev, "%s attached, irq %sabled\n",
1366 dev->board_name, dev->irq ? "en" : "dis");
1371 static void pci1710_detach(struct comedi_device *dev)
1373 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1378 free_irq(dev->irq, dev);
1381 comedi_pci_disable(pcidev);
1385 static struct comedi_driver adv_pci1710_driver = {
1386 .driver_name = "adv_pci1710",
1387 .module = THIS_MODULE,
1388 .auto_attach = pci1710_auto_attach,
1389 .detach = pci1710_detach,
1392 static int adv_pci1710_pci_probe(struct pci_dev *dev,
1393 const struct pci_device_id *id)
1395 return comedi_pci_auto_config(dev, &adv_pci1710_driver,
1399 static DEFINE_PCI_DEVICE_TABLE(adv_pci1710_pci_table) = {
1400 { PCI_VDEVICE(ADVANTECH, 0x1710), BOARD_PCI1710 },
1401 { PCI_VDEVICE(ADVANTECH, 0x1711), BOARD_PCI1711 },
1402 { PCI_VDEVICE(ADVANTECH, 0x1713), BOARD_PCI1713 },
1403 { PCI_VDEVICE(ADVANTECH, 0x1720), BOARD_PCI1720 },
1404 { PCI_VDEVICE(ADVANTECH, 0x1731), BOARD_PCI1731 },
1407 MODULE_DEVICE_TABLE(pci, adv_pci1710_pci_table);
1409 static struct pci_driver adv_pci1710_pci_driver = {
1410 .name = "adv_pci1710",
1411 .id_table = adv_pci1710_pci_table,
1412 .probe = adv_pci1710_pci_probe,
1413 .remove = comedi_pci_auto_unconfig,
1415 module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver);
1417 MODULE_AUTHOR("Comedi http://www.comedi.org");
1418 MODULE_DESCRIPTION("Comedi low-level driver");
1419 MODULE_LICENSE("GPL");