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/interrupt.h>
46 #include "../comedidev.h"
48 #include "comedi_fc.h"
50 #include "amcc_s5933.h"
52 #define PCI171x_PARANOIDCHECK /* if defined, then is used code which control
53 * correct channel number on every 12 bit
56 #define PCI_VENDOR_ID_ADVANTECH 0x13fe
58 /* hardware types of the cards */
59 #define TYPE_PCI171X 0
60 #define TYPE_PCI1713 2
61 #define TYPE_PCI1720 3
63 #define IORANGE_171x 32
64 #define IORANGE_1720 16
66 #define PCI171x_AD_DATA 0 /* R: A/D data */
67 #define PCI171x_SOFTTRG 0 /* W: soft trigger for A/D */
68 #define PCI171x_RANGE 2 /* W: A/D gain/range register */
69 #define PCI171x_MUX 4 /* W: A/D multiplexor control */
70 #define PCI171x_STATUS 6 /* R: status register */
71 #define PCI171x_CONTROL 6 /* W: control register */
72 #define PCI171x_CLRINT 8 /* W: clear interrupts request */
73 #define PCI171x_CLRFIFO 9 /* W: clear FIFO */
74 #define PCI171x_DA1 10 /* W: D/A register */
75 #define PCI171x_DA2 12 /* W: D/A register */
76 #define PCI171x_DAREF 14 /* W: D/A reference control */
77 #define PCI171x_DI 16 /* R: digi inputs */
78 #define PCI171x_DO 16 /* R: digi inputs */
79 #define PCI171x_CNT0 24 /* R/W: 8254 counter 0 */
80 #define PCI171x_CNT1 26 /* R/W: 8254 counter 1 */
81 #define PCI171x_CNT2 28 /* R/W: 8254 counter 2 */
82 #define PCI171x_CNTCTRL 30 /* W: 8254 counter control */
84 /* upper bits from status register (PCI171x_STATUS) (lower is same with control
86 #define Status_FE 0x0100 /* 1=FIFO is empty */
87 #define Status_FH 0x0200 /* 1=FIFO is half full */
88 #define Status_FF 0x0400 /* 1=FIFO is full, fatal error */
89 #define Status_IRQ 0x0800 /* 1=IRQ occurred */
90 /* bits from control register (PCI171x_CONTROL) */
91 #define Control_CNT0 0x0040 /* 1=CNT0 have external source,
92 * 0=have internal 100kHz source */
93 #define Control_ONEFH 0x0020 /* 1=IRQ on FIFO is half full, 0=every sample */
94 #define Control_IRQEN 0x0010 /* 1=enable IRQ */
95 #define Control_GATE 0x0008 /* 1=enable external trigger GATE (8254?) */
96 #define Control_EXT 0x0004 /* 1=external trigger source */
97 #define Control_PACER 0x0002 /* 1=enable internal 8254 trigger source */
98 #define Control_SW 0x0001 /* 1=enable software trigger source */
99 /* bits from counter control register (PCI171x_CNTCTRL) */
100 #define Counter_BCD 0x0001 /* 0 = binary counter, 1 = BCD counter */
101 #define Counter_M0 0x0002 /* M0-M2 select modes 0-5 */
102 #define Counter_M1 0x0004 /* 000 = mode 0, 010 = mode 2 ... */
103 #define Counter_M2 0x0008
104 #define Counter_RW0 0x0010 /* RW0/RW1 select read/write mode */
105 #define Counter_RW1 0x0020
106 #define Counter_SC0 0x0040 /* Select Counter. Only 00 or 11 may */
107 #define Counter_SC1 0x0080 /* be used, 00 for CNT0,
108 * 11 for read-back command */
110 #define PCI1720_DA0 0 /* W: D/A register 0 */
111 #define PCI1720_DA1 2 /* W: D/A register 1 */
112 #define PCI1720_DA2 4 /* W: D/A register 2 */
113 #define PCI1720_DA3 6 /* W: D/A register 3 */
114 #define PCI1720_RANGE 8 /* R/W: D/A range register */
115 #define PCI1720_SYNCOUT 9 /* W: D/A synchronized output register */
116 #define PCI1720_SYNCONT 15 /* R/W: D/A synchronized control */
118 /* D/A synchronized control (PCI1720_SYNCONT) */
119 #define Syncont_SC0 1 /* set synchronous output mode */
121 static const struct comedi_lrange range_pci1710_3 = { 9, {
134 static const char range_codes_pci1710_3[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
135 0x10, 0x11, 0x12, 0x13 };
137 static const struct comedi_lrange range_pci1710hg = { 12, {
153 static const char range_codes_pci1710hg[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
154 0x05, 0x06, 0x07, 0x10, 0x11,
157 static const struct comedi_lrange range_pci17x1 = { 5, {
166 static const char range_codes_pci17x1[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
168 static const struct comedi_lrange range_pci1720 = { 4, {
176 static const struct comedi_lrange range_pci171x_da = { 2, {
183 const char *name; /* board name */
185 int iorange; /* I/O range len */
186 char have_irq; /* 1=card support IRQ */
187 char cardtype; /* 0=1710& co. 2=1713, ... */
188 int n_aichan; /* num of A/D chans */
189 int n_aichand; /* num of A/D chans in diff mode */
190 int n_aochan; /* num of D/A chans */
191 int n_dichan; /* num of DI chans */
192 int n_dochan; /* num of DO chans */
193 int n_counter; /* num of counters */
194 int ai_maxdata; /* resolution of A/D */
195 int ao_maxdata; /* resolution of D/A */
196 const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */
197 const char *rangecode_ai; /* range codes for programming */
198 const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */
199 unsigned int ai_ns_min; /* max sample speed of card v ns */
200 unsigned int fifo_half_size; /* size of FIFO/2 */
203 static const struct boardtype boardtypes[] = {
207 .iorange = IORANGE_171x,
209 .cardtype = TYPE_PCI171X,
216 .ai_maxdata = 0x0fff,
217 .ao_maxdata = 0x0fff,
218 .rangelist_ai = &range_pci1710_3,
219 .rangecode_ai = range_codes_pci1710_3,
220 .rangelist_ao = &range_pci171x_da,
222 .fifo_half_size = 2048,
226 .iorange = IORANGE_171x,
228 .cardtype = TYPE_PCI171X,
235 .ai_maxdata = 0x0fff,
236 .ao_maxdata = 0x0fff,
237 .rangelist_ai = &range_pci1710hg,
238 .rangecode_ai = range_codes_pci1710hg,
239 .rangelist_ao = &range_pci171x_da,
241 .fifo_half_size = 2048,
245 .iorange = IORANGE_171x,
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,
263 .iorange = IORANGE_171x,
265 .cardtype = TYPE_PCI1713,
268 .ai_maxdata = 0x0fff,
269 .rangelist_ai = &range_pci1710_3,
270 .rangecode_ai = range_codes_pci1710_3,
272 .fifo_half_size = 2048,
276 .iorange = IORANGE_1720,
277 .cardtype = TYPE_PCI1720,
279 .ao_maxdata = 0x0fff,
280 .rangelist_ao = &range_pci1720,
284 .iorange = IORANGE_171x,
286 .cardtype = TYPE_PCI171X,
290 .ai_maxdata = 0x0fff,
291 .rangelist_ai = &range_pci17x1,
292 .rangecode_ai = range_codes_pci17x1,
294 .fifo_half_size = 512,
298 struct pci1710_private {
299 char neverending_ai; /* we do unlimited AI */
300 unsigned int CntrlReg; /* Control register */
301 unsigned int i8254_osc_base; /* frequence of onboard oscilator */
302 unsigned int ai_do; /* what do AI? 0=nothing, 1 to 4 mode */
303 unsigned int ai_act_scan; /* how many scans we finished */
304 unsigned int ai_act_chan; /* actual position in actual scan */
305 unsigned int ai_buf_ptr; /* data buffer ptr in samples */
306 unsigned char ai_eos; /* 1=EOS wake up */
308 unsigned int ai_et_CntrlReg;
309 unsigned int ai_et_MuxVal;
310 unsigned int ai_et_div1, ai_et_div2;
311 unsigned int act_chanlist[32]; /* list of scaned channel */
312 unsigned char act_chanlist_len; /* len of scanlist */
313 unsigned char act_chanlist_pos; /* actual position in MUX list */
314 unsigned char da_ranges; /* copy of D/A outpit range register */
315 unsigned int ai_scans; /* len of scanlist */
316 unsigned int ai_n_chan; /* how many channels is measured */
317 unsigned int *ai_chanlist; /* actaul chanlist */
318 unsigned int ai_flags; /* flaglist */
319 unsigned int ai_data_len; /* len of data buffer */
320 short *ai_data; /* data buffer */
321 unsigned int ai_timer1; /* timers */
322 unsigned int ai_timer2;
323 short ao_data[4]; /* data output buffer */
324 unsigned int cnt0_write_wait; /* after a write, wait for update of the
328 /* used for gain list programming */
329 static const unsigned int muxonechan[] = {
330 0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707,
331 0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f,
332 0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717,
333 0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f
337 ==============================================================================
338 Check if channel list from user is builded correctly
339 If it's ok, then program scan/gain logic.
340 This works for all cards.
342 static int check_channel_list(struct comedi_device *dev,
343 struct comedi_subdevice *s,
344 unsigned int *chanlist, unsigned int n_chan)
346 unsigned int chansegment[32];
347 unsigned int i, nowmustbechan, seglen, segpos;
349 /* correct channel and range number check itself comedi/range.c */
351 comedi_error(dev, "range/channel list is empty!");
356 return 1; /* seglen=1 */
358 chansegment[0] = chanlist[0]; /* first channel is every time ok */
359 for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {
360 if (chanlist[0] == chanlist[i])
361 break; /* we detected a loop, stop */
362 if ((CR_CHAN(chanlist[i]) & 1) &&
363 (CR_AREF(chanlist[i]) == AREF_DIFF)) {
364 comedi_error(dev, "Odd channel cannot be differential input!\n");
367 nowmustbechan = (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
368 if (CR_AREF(chansegment[i - 1]) == AREF_DIFF)
369 nowmustbechan = (nowmustbechan + 1) % s->n_chan;
370 if (nowmustbechan != CR_CHAN(chanlist[i])) {
371 printk("channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
372 i, CR_CHAN(chanlist[i]), nowmustbechan,
373 CR_CHAN(chanlist[0]));
376 chansegment[i] = chanlist[i]; /* next correct channel in list */
379 for (i = 0, segpos = 0; i < n_chan; i++) {
380 if (chanlist[i] != chansegment[i % seglen]) {
381 printk("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
382 i, CR_CHAN(chansegment[i]),
383 CR_RANGE(chansegment[i]),
384 CR_AREF(chansegment[i]),
385 CR_CHAN(chanlist[i % seglen]),
386 CR_RANGE(chanlist[i % seglen]),
387 CR_AREF(chansegment[i % seglen]));
394 static void setup_channel_list(struct comedi_device *dev,
395 struct comedi_subdevice *s,
396 unsigned int *chanlist, unsigned int n_chan,
399 const struct boardtype *this_board = comedi_board(dev);
400 struct pci1710_private *devpriv = dev->private;
401 unsigned int i, range, chanprog;
403 devpriv->act_chanlist_len = seglen;
404 devpriv->act_chanlist_pos = 0;
406 for (i = 0; i < seglen; i++) { /* store range list to card */
407 chanprog = muxonechan[CR_CHAN(chanlist[i])];
408 outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */
409 range = this_board->rangecode_ai[CR_RANGE(chanlist[i])];
410 if (CR_AREF(chanlist[i]) == AREF_DIFF)
412 outw(range, dev->iobase + PCI171x_RANGE); /* select gain */
413 #ifdef PCI171x_PARANOIDCHECK
414 devpriv->act_chanlist[i] =
415 (CR_CHAN(chanlist[i]) << 12) & 0xf000;
418 #ifdef PCI171x_PARANOIDCHECK
419 for ( ; i < n_chan; i++) { /* store remainder of channel list */
420 devpriv->act_chanlist[i] =
421 (CR_CHAN(chanlist[i]) << 12) & 0xf000;
425 devpriv->ai_et_MuxVal =
426 CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
427 /* select channel interval to scan */
428 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
432 ==============================================================================
434 static int pci171x_insn_read_ai(struct comedi_device *dev,
435 struct comedi_subdevice *s,
436 struct comedi_insn *insn, unsigned int *data)
438 struct pci1710_private *devpriv = dev->private;
440 #ifdef PCI171x_PARANOIDCHECK
441 const struct boardtype *this_board = comedi_board(dev);
445 devpriv->CntrlReg &= Control_CNT0;
446 devpriv->CntrlReg |= Control_SW; /* set software trigger */
447 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
448 outb(0, dev->iobase + PCI171x_CLRFIFO);
449 outb(0, dev->iobase + PCI171x_CLRINT);
451 setup_channel_list(dev, s, &insn->chanspec, 1, 1);
453 for (n = 0; n < insn->n; n++) {
454 outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */
458 if (!(inw(dev->iobase + PCI171x_STATUS) & Status_FE))
461 comedi_error(dev, "A/D insn timeout");
462 outb(0, dev->iobase + PCI171x_CLRFIFO);
463 outb(0, dev->iobase + PCI171x_CLRINT);
468 #ifdef PCI171x_PARANOIDCHECK
469 idata = inw(dev->iobase + PCI171x_AD_DATA);
470 if (this_board->cardtype != TYPE_PCI1713)
471 if ((idata & 0xf000) != devpriv->act_chanlist[0]) {
472 comedi_error(dev, "A/D insn data droput!");
475 data[n] = idata & 0x0fff;
477 data[n] = inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff;
482 outb(0, dev->iobase + PCI171x_CLRFIFO);
483 outb(0, dev->iobase + PCI171x_CLRINT);
489 ==============================================================================
491 static int pci171x_insn_write_ao(struct comedi_device *dev,
492 struct comedi_subdevice *s,
493 struct comedi_insn *insn, unsigned int *data)
495 struct pci1710_private *devpriv = dev->private;
496 int n, chan, range, ofs;
498 chan = CR_CHAN(insn->chanspec);
499 range = CR_RANGE(insn->chanspec);
501 devpriv->da_ranges &= 0xfb;
502 devpriv->da_ranges |= (range << 2);
503 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
506 devpriv->da_ranges &= 0xfe;
507 devpriv->da_ranges |= range;
508 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
512 for (n = 0; n < insn->n; n++)
513 outw(data[n], dev->iobase + ofs);
515 devpriv->ao_data[chan] = data[n];
522 ==============================================================================
524 static int pci171x_insn_read_ao(struct comedi_device *dev,
525 struct comedi_subdevice *s,
526 struct comedi_insn *insn, unsigned int *data)
528 struct pci1710_private *devpriv = dev->private;
531 chan = CR_CHAN(insn->chanspec);
532 for (n = 0; n < insn->n; n++)
533 data[n] = devpriv->ao_data[chan];
539 ==============================================================================
541 static int pci171x_insn_bits_di(struct comedi_device *dev,
542 struct comedi_subdevice *s,
543 struct comedi_insn *insn, unsigned int *data)
545 data[1] = inw(dev->iobase + PCI171x_DI);
551 ==============================================================================
553 static int pci171x_insn_bits_do(struct comedi_device *dev,
554 struct comedi_subdevice *s,
555 struct comedi_insn *insn, unsigned int *data)
558 s->state &= ~data[0];
559 s->state |= (data[0] & data[1]);
560 outw(s->state, dev->iobase + PCI171x_DO);
568 ==============================================================================
570 static void start_pacer(struct comedi_device *dev, int mode,
571 unsigned int divisor1, unsigned int divisor2)
573 outw(0xb4, dev->iobase + PCI171x_CNTCTRL);
574 outw(0x74, dev->iobase + PCI171x_CNTCTRL);
577 outw(divisor2 & 0xff, dev->iobase + PCI171x_CNT2);
578 outw((divisor2 >> 8) & 0xff, dev->iobase + PCI171x_CNT2);
579 outw(divisor1 & 0xff, dev->iobase + PCI171x_CNT1);
580 outw((divisor1 >> 8) & 0xff, dev->iobase + PCI171x_CNT1);
585 ==============================================================================
587 static int pci171x_insn_counter_read(struct comedi_device *dev,
588 struct comedi_subdevice *s,
589 struct comedi_insn *insn,
592 unsigned int msb, lsb, ccntrl;
595 ccntrl = 0xD2; /* count only */
596 for (i = 0; i < insn->n; i++) {
597 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
599 lsb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
600 msb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
602 data[0] = lsb | (msb << 8);
609 ==============================================================================
611 static int pci171x_insn_counter_write(struct comedi_device *dev,
612 struct comedi_subdevice *s,
613 struct comedi_insn *insn,
616 struct pci1710_private *devpriv = dev->private;
617 uint msb, lsb, ccntrl, status;
619 lsb = data[0] & 0x00FF;
620 msb = (data[0] & 0xFF00) >> 8;
622 /* write lsb, then msb */
623 outw(lsb, dev->iobase + PCI171x_CNT0);
624 outw(msb, dev->iobase + PCI171x_CNT0);
626 if (devpriv->cnt0_write_wait) {
627 /* wait for the new count to be loaded */
630 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
631 status = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
632 } while (status & 0x40);
639 ==============================================================================
641 static int pci171x_insn_counter_config(struct comedi_device *dev,
642 struct comedi_subdevice *s,
643 struct comedi_insn *insn,
647 /* This doesn't work like a normal Comedi counter config */
648 struct pci1710_private *devpriv = dev->private;
651 devpriv->cnt0_write_wait = data[0] & 0x20;
653 /* internal or external clock? */
654 if (!(data[0] & 0x10)) { /* internal */
655 devpriv->CntrlReg &= ~Control_CNT0;
657 devpriv->CntrlReg |= Control_CNT0;
659 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
662 ccntrl |= Counter_M0;
664 ccntrl |= Counter_M1;
666 ccntrl |= Counter_M2;
668 ccntrl |= Counter_BCD;
669 ccntrl |= Counter_RW0; /* set read/write mode */
670 ccntrl |= Counter_RW1;
671 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
678 ==============================================================================
680 static int pci1720_insn_write_ao(struct comedi_device *dev,
681 struct comedi_subdevice *s,
682 struct comedi_insn *insn, unsigned int *data)
684 struct pci1710_private *devpriv = dev->private;
685 int n, rangereg, chan;
687 chan = CR_CHAN(insn->chanspec);
688 rangereg = devpriv->da_ranges & (~(0x03 << (chan << 1)));
689 rangereg |= (CR_RANGE(insn->chanspec) << (chan << 1));
690 if (rangereg != devpriv->da_ranges) {
691 outb(rangereg, dev->iobase + PCI1720_RANGE);
692 devpriv->da_ranges = rangereg;
695 for (n = 0; n < insn->n; n++) {
696 outw(data[n], dev->iobase + PCI1720_DA0 + (chan << 1));
697 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
700 devpriv->ao_data[chan] = data[n];
706 ==============================================================================
708 static int pci171x_ai_cancel(struct comedi_device *dev,
709 struct comedi_subdevice *s)
711 const struct boardtype *this_board = comedi_board(dev);
712 struct pci1710_private *devpriv = dev->private;
714 switch (this_board->cardtype) {
716 devpriv->CntrlReg &= Control_CNT0;
717 devpriv->CntrlReg |= Control_SW;
719 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */
720 start_pacer(dev, -1, 0, 0);
721 outb(0, dev->iobase + PCI171x_CLRFIFO);
722 outb(0, dev->iobase + PCI171x_CLRINT);
727 devpriv->ai_act_scan = 0;
728 s->async->cur_chan = 0;
729 devpriv->ai_buf_ptr = 0;
730 devpriv->neverending_ai = 0;
736 ==============================================================================
738 static void interrupt_pci1710_every_sample(void *d)
740 struct comedi_device *dev = d;
741 struct pci1710_private *devpriv = dev->private;
742 struct comedi_subdevice *s = &dev->subdevices[0];
744 #ifdef PCI171x_PARANOIDCHECK
745 const struct boardtype *this_board = comedi_board(dev);
749 m = inw(dev->iobase + PCI171x_STATUS);
751 printk("comedi%d: A/D FIFO empty (%4x)\n", dev->minor, m);
752 pci171x_ai_cancel(dev, s);
753 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
754 comedi_event(dev, s);
759 ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
761 pci171x_ai_cancel(dev, s);
762 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
763 comedi_event(dev, s);
767 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
769 for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
770 #ifdef PCI171x_PARANOIDCHECK
771 sampl = inw(dev->iobase + PCI171x_AD_DATA);
772 if (this_board->cardtype != TYPE_PCI1713)
773 if ((sampl & 0xf000) !=
774 devpriv->act_chanlist[s->async->cur_chan]) {
776 ("comedi: A/D data dropout: received data from channel %d, expected %d!\n",
777 (sampl & 0xf000) >> 12,
780 async->cur_chan] & 0xf000) >>
782 pci171x_ai_cancel(dev, s);
784 COMEDI_CB_EOA | COMEDI_CB_ERROR;
785 comedi_event(dev, s);
788 comedi_buf_put(s->async, sampl & 0x0fff);
790 comedi_buf_put(s->async,
791 inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
793 ++s->async->cur_chan;
795 if (s->async->cur_chan >= devpriv->ai_n_chan)
796 s->async->cur_chan = 0;
799 if (s->async->cur_chan == 0) { /* one scan done */
800 devpriv->ai_act_scan++;
801 if ((!devpriv->neverending_ai) &&
802 (devpriv->ai_act_scan >= devpriv->ai_scans)) {
803 /* all data sampled */
804 pci171x_ai_cancel(dev, s);
805 s->async->events |= COMEDI_CB_EOA;
806 comedi_event(dev, s);
812 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
814 comedi_event(dev, s);
818 ==============================================================================
820 static int move_block_from_fifo(struct comedi_device *dev,
821 struct comedi_subdevice *s, int n, int turn)
823 struct pci1710_private *devpriv = dev->private;
825 #ifdef PCI171x_PARANOIDCHECK
826 const struct boardtype *this_board = comedi_board(dev);
830 j = s->async->cur_chan;
831 for (i = 0; i < n; i++) {
832 #ifdef PCI171x_PARANOIDCHECK
833 sampl = inw(dev->iobase + PCI171x_AD_DATA);
834 if (this_board->cardtype != TYPE_PCI1713)
835 if ((sampl & 0xf000) != devpriv->act_chanlist[j]) {
837 ("comedi%d: A/D FIFO data dropout: received data from channel %d, expected %d! (%d/%d/%d/%d/%d/%4x)\n",
838 dev->minor, (sampl & 0xf000) >> 12,
839 (devpriv->act_chanlist[j] & 0xf000) >> 12,
840 i, j, devpriv->ai_act_scan, n, turn,
842 pci171x_ai_cancel(dev, s);
844 COMEDI_CB_EOA | COMEDI_CB_ERROR;
845 comedi_event(dev, s);
848 comedi_buf_put(s->async, sampl & 0x0fff);
850 comedi_buf_put(s->async,
851 inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
854 if (j >= devpriv->ai_n_chan) {
856 devpriv->ai_act_scan++;
859 s->async->cur_chan = j;
864 ==============================================================================
866 static void interrupt_pci1710_half_fifo(void *d)
868 struct comedi_device *dev = d;
869 const struct boardtype *this_board = comedi_board(dev);
870 struct pci1710_private *devpriv = dev->private;
871 struct comedi_subdevice *s = &dev->subdevices[0];
874 m = inw(dev->iobase + PCI171x_STATUS);
875 if (!(m & Status_FH)) {
876 printk("comedi%d: A/D FIFO not half full! (%4x)\n",
878 pci171x_ai_cancel(dev, s);
879 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
880 comedi_event(dev, s);
885 ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
887 pci171x_ai_cancel(dev, s);
888 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
889 comedi_event(dev, s);
893 samplesinbuf = this_board->fifo_half_size;
894 if (samplesinbuf * sizeof(short) >= devpriv->ai_data_len) {
895 m = devpriv->ai_data_len / sizeof(short);
896 if (move_block_from_fifo(dev, s, m, 0))
902 if (move_block_from_fifo(dev, s, samplesinbuf, 1))
906 if (!devpriv->neverending_ai)
907 if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data
909 pci171x_ai_cancel(dev, s);
910 s->async->events |= COMEDI_CB_EOA;
911 comedi_event(dev, s);
914 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
916 comedi_event(dev, s);
920 ==============================================================================
922 static irqreturn_t interrupt_service_pci1710(int irq, void *d)
924 struct comedi_device *dev = d;
925 struct pci1710_private *devpriv = dev->private;
927 if (!dev->attached) /* is device attached? */
928 return IRQ_NONE; /* no, exit */
929 /* is this interrupt from our board? */
930 if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))
931 return IRQ_NONE; /* no, exit */
933 if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */
935 devpriv->CntrlReg &= Control_CNT0;
936 devpriv->CntrlReg |= Control_SW; /* set software trigger */
937 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
938 devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
939 outb(0, dev->iobase + PCI171x_CLRFIFO);
940 outb(0, dev->iobase + PCI171x_CLRINT);
941 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
942 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
944 start_pacer(dev, 1, devpriv->ai_et_div1, devpriv->ai_et_div2);
947 if (devpriv->ai_eos) { /* We use FIFO half full INT or not? */
948 interrupt_pci1710_every_sample(d);
950 interrupt_pci1710_half_fifo(d);
956 ==============================================================================
958 static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev,
959 struct comedi_subdevice *s)
961 const struct boardtype *this_board = comedi_board(dev);
962 struct pci1710_private *devpriv = dev->private;
963 unsigned int divisor1 = 0, divisor2 = 0;
966 start_pacer(dev, -1, 0, 0); /* stop pacer */
968 seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
972 setup_channel_list(dev, s, devpriv->ai_chanlist,
973 devpriv->ai_n_chan, seglen);
975 outb(0, dev->iobase + PCI171x_CLRFIFO);
976 outb(0, dev->iobase + PCI171x_CLRINT);
978 devpriv->ai_do = mode;
980 devpriv->ai_act_scan = 0;
981 s->async->cur_chan = 0;
982 devpriv->ai_buf_ptr = 0;
983 devpriv->neverending_ai = 0;
985 devpriv->CntrlReg &= Control_CNT0;
986 /* don't we want wake up every scan? devpriv->ai_eos=1; */
987 if ((devpriv->ai_flags & TRIG_WAKE_EOS)) {
990 devpriv->CntrlReg |= Control_ONEFH;
994 if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1))
995 devpriv->neverending_ai = 1;
996 /* well, user want neverending */
998 devpriv->neverending_ai = 0;
1003 if (devpriv->ai_timer1 < this_board->ai_ns_min)
1004 devpriv->ai_timer1 = this_board->ai_ns_min;
1005 devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
1007 devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
1008 devpriv->CntrlReg &=
1009 ~(Control_PACER | Control_ONEFH | Control_GATE);
1010 devpriv->CntrlReg |= Control_EXT;
1015 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
1016 &divisor2, &devpriv->ai_timer1,
1017 devpriv->ai_flags & TRIG_ROUND_MASK);
1018 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
1021 start_pacer(dev, mode, divisor1, divisor2);
1023 devpriv->ai_et_div1 = divisor1;
1024 devpriv->ai_et_div2 = divisor2;
1028 devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
1029 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
1037 ==============================================================================
1039 static int pci171x_ai_cmdtest(struct comedi_device *dev,
1040 struct comedi_subdevice *s,
1041 struct comedi_cmd *cmd)
1043 const struct boardtype *this_board = comedi_board(dev);
1044 struct pci1710_private *devpriv = dev->private;
1047 unsigned int divisor1 = 0, divisor2 = 0;
1049 /* Step 1 : check if triggers are trivially valid */
1051 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
1052 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
1053 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
1054 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
1055 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
1060 /* step 2a: make sure trigger sources are unique */
1062 err |= cfc_check_trigger_is_unique(cmd->start_src);
1063 err |= cfc_check_trigger_is_unique(cmd->convert_src);
1064 err |= cfc_check_trigger_is_unique(cmd->stop_src);
1066 /* step 2b: and mutually compatible */
1071 /* step 3: make sure arguments are trivially compatible */
1073 if (cmd->start_arg != 0) {
1078 if (cmd->scan_begin_arg != 0) {
1079 cmd->scan_begin_arg = 0;
1083 if (cmd->convert_src == TRIG_TIMER) {
1084 if (cmd->convert_arg < this_board->ai_ns_min) {
1085 cmd->convert_arg = this_board->ai_ns_min;
1088 } else { /* TRIG_FOLLOW */
1089 if (cmd->convert_arg != 0) {
1090 cmd->convert_arg = 0;
1095 if (cmd->scan_end_arg != cmd->chanlist_len) {
1096 cmd->scan_end_arg = cmd->chanlist_len;
1099 if (cmd->stop_src == TRIG_COUNT) {
1100 if (!cmd->stop_arg) {
1104 } else { /* TRIG_NONE */
1105 if (cmd->stop_arg != 0) {
1114 /* step 4: fix up any arguments */
1116 if (cmd->convert_src == TRIG_TIMER) {
1117 tmp = cmd->convert_arg;
1118 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
1119 &divisor2, &cmd->convert_arg,
1120 cmd->flags & TRIG_ROUND_MASK);
1121 if (cmd->convert_arg < this_board->ai_ns_min)
1122 cmd->convert_arg = this_board->ai_ns_min;
1123 if (tmp != cmd->convert_arg)
1130 /* step 5: complain about special chanlist considerations */
1132 if (cmd->chanlist) {
1133 if (!check_channel_list(dev, s, cmd->chanlist,
1135 return 5; /* incorrect channels list */
1142 ==============================================================================
1144 static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1146 struct pci1710_private *devpriv = dev->private;
1147 struct comedi_cmd *cmd = &s->async->cmd;
1149 devpriv->ai_n_chan = cmd->chanlist_len;
1150 devpriv->ai_chanlist = cmd->chanlist;
1151 devpriv->ai_flags = cmd->flags;
1152 devpriv->ai_data_len = s->async->prealloc_bufsz;
1153 devpriv->ai_data = s->async->prealloc_buf;
1154 devpriv->ai_timer1 = 0;
1155 devpriv->ai_timer2 = 0;
1157 if (cmd->stop_src == TRIG_COUNT)
1158 devpriv->ai_scans = cmd->stop_arg;
1160 devpriv->ai_scans = 0;
1163 if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 2, 3 */
1164 if (cmd->convert_src == TRIG_TIMER) { /* mode 1 and 2 */
1165 devpriv->ai_timer1 = cmd->convert_arg;
1166 return pci171x_ai_docmd_and_mode(cmd->start_src ==
1167 TRIG_EXT ? 2 : 1, dev,
1170 if (cmd->convert_src == TRIG_EXT) { /* mode 3 */
1171 return pci171x_ai_docmd_and_mode(3, dev, s);
1179 ==============================================================================
1181 static int pci171x_reset(struct comedi_device *dev)
1183 const struct boardtype *this_board = comedi_board(dev);
1184 struct pci1710_private *devpriv = dev->private;
1186 outw(0x30, dev->iobase + PCI171x_CNTCTRL);
1187 devpriv->CntrlReg = Control_SW | Control_CNT0; /* Software trigger, CNT0=external */
1188 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */
1189 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
1190 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
1191 start_pacer(dev, -1, 0, 0); /* stop 8254 */
1192 devpriv->da_ranges = 0;
1193 if (this_board->n_aochan) {
1194 outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); /* set DACs to 0..5V */
1195 outw(0, dev->iobase + PCI171x_DA1); /* set DA outputs to 0V */
1196 devpriv->ao_data[0] = 0x0000;
1197 if (this_board->n_aochan > 1) {
1198 outw(0, dev->iobase + PCI171x_DA2);
1199 devpriv->ao_data[1] = 0x0000;
1202 outw(0, dev->iobase + PCI171x_DO); /* digital outputs to 0 */
1203 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
1204 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
1210 ==============================================================================
1212 static int pci1720_reset(struct comedi_device *dev)
1214 struct pci1710_private *devpriv = dev->private;
1216 outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT); /* set synchronous output mode */
1217 devpriv->da_ranges = 0xAA;
1218 outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE); /* set all ranges to +/-5V */
1219 outw(0x0800, dev->iobase + PCI1720_DA0); /* set outputs to 0V */
1220 outw(0x0800, dev->iobase + PCI1720_DA1);
1221 outw(0x0800, dev->iobase + PCI1720_DA2);
1222 outw(0x0800, dev->iobase + PCI1720_DA3);
1223 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
1224 devpriv->ao_data[0] = 0x0800;
1225 devpriv->ao_data[1] = 0x0800;
1226 devpriv->ao_data[2] = 0x0800;
1227 devpriv->ao_data[3] = 0x0800;
1232 ==============================================================================
1234 static int pci1710_reset(struct comedi_device *dev)
1236 const struct boardtype *this_board = comedi_board(dev);
1238 switch (this_board->cardtype) {
1240 return pci1720_reset(dev);
1242 return pci171x_reset(dev);
1246 static const void *pci1710_find_boardinfo(struct comedi_device *dev,
1247 struct pci_dev *pcidev)
1249 const struct boardtype *this_board;
1252 for (i = 0; i < ARRAY_SIZE(boardtypes); i++) {
1253 this_board = &boardtypes[i];
1254 if (pcidev->device == this_board->device_id)
1260 static int pci1710_attach_pci(struct comedi_device *dev,
1261 struct pci_dev *pcidev)
1263 const struct boardtype *this_board;
1264 struct pci1710_private *devpriv;
1265 struct comedi_subdevice *s;
1266 int ret, subdev, n_subdevices;
1268 comedi_set_hw_dev(dev, &pcidev->dev);
1270 this_board = pci1710_find_boardinfo(dev, pcidev);
1273 dev->board_ptr = this_board;
1274 dev->board_name = this_board->name;
1276 ret = alloc_private(dev, sizeof(*devpriv));
1279 devpriv = dev->private;
1281 ret = comedi_pci_enable(pcidev, dev->board_name);
1284 dev->iobase = pci_resource_start(pcidev, 2);
1287 if (this_board->n_aichan)
1289 if (this_board->n_aochan)
1291 if (this_board->n_dichan)
1293 if (this_board->n_dochan)
1295 if (this_board->n_counter)
1298 ret = comedi_alloc_subdevices(dev, n_subdevices);
1304 if (this_board->have_irq && pcidev->irq) {
1305 ret = request_irq(pcidev->irq, interrupt_service_pci1710,
1306 IRQF_SHARED, dev->board_name, dev);
1308 dev->irq = pcidev->irq;
1313 if (this_board->n_aichan) {
1314 s = &dev->subdevices[subdev];
1315 dev->read_subdev = s;
1316 s->type = COMEDI_SUBD_AI;
1317 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
1318 if (this_board->n_aichand)
1319 s->subdev_flags |= SDF_DIFF;
1320 s->n_chan = this_board->n_aichan;
1321 s->maxdata = this_board->ai_maxdata;
1322 s->len_chanlist = this_board->n_aichan;
1323 s->range_table = this_board->rangelist_ai;
1324 s->cancel = pci171x_ai_cancel;
1325 s->insn_read = pci171x_insn_read_ai;
1327 s->subdev_flags |= SDF_CMD_READ;
1328 s->do_cmdtest = pci171x_ai_cmdtest;
1329 s->do_cmd = pci171x_ai_cmd;
1331 devpriv->i8254_osc_base = 100; /* 100ns=10MHz */
1335 if (this_board->n_aochan) {
1336 s = &dev->subdevices[subdev];
1337 s->type = COMEDI_SUBD_AO;
1338 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1339 s->n_chan = this_board->n_aochan;
1340 s->maxdata = this_board->ao_maxdata;
1341 s->len_chanlist = this_board->n_aochan;
1342 s->range_table = this_board->rangelist_ao;
1343 switch (this_board->cardtype) {
1345 s->insn_write = pci1720_insn_write_ao;
1348 s->insn_write = pci171x_insn_write_ao;
1351 s->insn_read = pci171x_insn_read_ao;
1355 if (this_board->n_dichan) {
1356 s = &dev->subdevices[subdev];
1357 s->type = COMEDI_SUBD_DI;
1358 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
1359 s->n_chan = this_board->n_dichan;
1361 s->len_chanlist = this_board->n_dichan;
1362 s->range_table = &range_digital;
1363 s->io_bits = 0; /* all bits input */
1364 s->insn_bits = pci171x_insn_bits_di;
1368 if (this_board->n_dochan) {
1369 s = &dev->subdevices[subdev];
1370 s->type = COMEDI_SUBD_DO;
1371 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1372 s->n_chan = this_board->n_dochan;
1374 s->len_chanlist = this_board->n_dochan;
1375 s->range_table = &range_digital;
1376 /* all bits output */
1377 s->io_bits = (1 << this_board->n_dochan) - 1;
1379 s->insn_bits = pci171x_insn_bits_do;
1383 if (this_board->n_counter) {
1384 s = &dev->subdevices[subdev];
1385 s->type = COMEDI_SUBD_COUNTER;
1386 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1387 s->n_chan = this_board->n_counter;
1388 s->len_chanlist = this_board->n_counter;
1389 s->maxdata = 0xffff;
1390 s->range_table = &range_unknown;
1391 s->insn_read = pci171x_insn_counter_read;
1392 s->insn_write = pci171x_insn_counter_write;
1393 s->insn_config = pci171x_insn_counter_config;
1397 dev_info(dev->class_dev, "%s attached, irq %sabled\n",
1398 dev->board_name, dev->irq ? "en" : "dis");
1403 static void pci1710_detach(struct comedi_device *dev)
1405 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1410 free_irq(dev->irq, dev);
1413 comedi_pci_disable(pcidev);
1417 static struct comedi_driver adv_pci1710_driver = {
1418 .driver_name = "adv_pci1710",
1419 .module = THIS_MODULE,
1420 .attach_pci = pci1710_attach_pci,
1421 .detach = pci1710_detach,
1424 static int __devinit adv_pci1710_pci_probe(struct pci_dev *dev,
1425 const struct pci_device_id *ent)
1427 return comedi_pci_auto_config(dev, &adv_pci1710_driver);
1430 static void __devexit adv_pci1710_pci_remove(struct pci_dev *dev)
1432 comedi_pci_auto_unconfig(dev);
1435 static DEFINE_PCI_DEVICE_TABLE(adv_pci1710_pci_table) = {
1436 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1710) },
1437 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1711) },
1438 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1713) },
1439 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1720) },
1440 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1731) },
1443 MODULE_DEVICE_TABLE(pci, adv_pci1710_pci_table);
1445 static struct pci_driver adv_pci1710_pci_driver = {
1446 .name = "adv_pci1710",
1447 .id_table = adv_pci1710_pci_table,
1448 .probe = adv_pci1710_pci_probe,
1449 .remove = __devexit_p(adv_pci1710_pci_remove),
1451 module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver);
1453 MODULE_AUTHOR("Comedi http://www.comedi.org");
1454 MODULE_DESCRIPTION("Comedi low-level driver");
1455 MODULE_LICENSE("GPL");