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"
49 #include "amcc_s5933.h"
51 #define PCI171x_PARANOIDCHECK /* if defined, then is used code which control
52 * correct channel number on every 12 bit
55 #undef PCI171X_EXTDEBUG
57 #define DRV_NAME "adv_pci1710"
60 #ifdef PCI171X_EXTDEBUG
61 #define DPRINTK(fmt, args...) printk(fmt, ## args)
63 #define DPRINTK(fmt, args...)
66 #define PCI_VENDOR_ID_ADVANTECH 0x13fe
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 static const struct comedi_lrange range_pci1710hg = { 12, {
163 static const char range_codes_pci1710hg[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
164 0x05, 0x06, 0x07, 0x10, 0x11,
167 static const struct comedi_lrange range_pci17x1 = { 5, {
176 static const char range_codes_pci17x1[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
178 static const struct comedi_lrange range_pci1720 = { 4, {
186 static const struct comedi_lrange range_pci171x_da = { 2, {
193 const char *name; /* board name */
195 int iorange; /* I/O range len */
196 char have_irq; /* 1=card support IRQ */
197 char cardtype; /* 0=1710& co. 2=1713, ... */
198 int n_aichan; /* num of A/D chans */
199 int n_aichand; /* num of A/D chans in diff mode */
200 int n_aochan; /* num of D/A chans */
201 int n_dichan; /* num of DI chans */
202 int n_dochan; /* num of DO chans */
203 int n_counter; /* num of counters */
204 int ai_maxdata; /* resolution of A/D */
205 int ao_maxdata; /* resolution of D/A */
206 const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */
207 const char *rangecode_ai; /* range codes for programming */
208 const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */
209 unsigned int ai_ns_min; /* max sample speed of card v ns */
210 unsigned int fifo_half_size; /* size of FIFO/2 */
213 static const struct boardtype boardtypes[] = {
215 IORANGE_171x, 1, TYPE_PCI171X,
216 16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff,
217 &range_pci1710_3, range_codes_pci1710_3,
220 {"pci1710hg", 0x1710,
221 IORANGE_171x, 1, TYPE_PCI171X,
222 16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff,
223 &range_pci1710hg, range_codes_pci1710hg,
227 IORANGE_171x, 1, TYPE_PCI171X,
228 16, 0, 2, 16, 16, 1, 0x0fff, 0x0fff,
229 &range_pci17x1, range_codes_pci17x1, &range_pci171x_da,
232 IORANGE_171x, 1, TYPE_PCI1713,
233 32, 16, 0, 0, 0, 0, 0x0fff, 0x0000,
234 &range_pci1710_3, range_codes_pci1710_3, NULL,
237 IORANGE_1720, 0, TYPE_PCI1720,
238 0, 0, 4, 0, 0, 0, 0x0000, 0x0fff,
239 NULL, NULL, &range_pci1720,
242 IORANGE_171x, 1, TYPE_PCI171X,
243 16, 0, 0, 16, 16, 0, 0x0fff, 0x0000,
244 &range_pci17x1, range_codes_pci17x1, NULL,
246 /* dummy entry corresponding to driver name */
250 struct pci1710_private {
251 char valid; /* card is usable */
252 char neverending_ai; /* we do unlimited AI */
253 unsigned int CntrlReg; /* Control register */
254 unsigned int i8254_osc_base; /* frequence of onboard oscilator */
255 unsigned int ai_do; /* what do AI? 0=nothing, 1 to 4 mode */
256 unsigned int ai_act_scan; /* how many scans we finished */
257 unsigned int ai_act_chan; /* actual position in actual scan */
258 unsigned int ai_buf_ptr; /* data buffer ptr in samples */
259 unsigned char ai_eos; /* 1=EOS wake up */
261 unsigned int ai_et_CntrlReg;
262 unsigned int ai_et_MuxVal;
263 unsigned int ai_et_div1, ai_et_div2;
264 unsigned int act_chanlist[32]; /* list of scaned channel */
265 unsigned char act_chanlist_len; /* len of scanlist */
266 unsigned char act_chanlist_pos; /* actual position in MUX list */
267 unsigned char da_ranges; /* copy of D/A outpit range register */
268 unsigned int ai_scans; /* len of scanlist */
269 unsigned int ai_n_chan; /* how many channels is measured */
270 unsigned int *ai_chanlist; /* actaul chanlist */
271 unsigned int ai_flags; /* flaglist */
272 unsigned int ai_data_len; /* len of data buffer */
273 short *ai_data; /* data buffer */
274 unsigned int ai_timer1; /* timers */
275 unsigned int ai_timer2;
276 short ao_data[4]; /* data output buffer */
277 unsigned int cnt0_write_wait; /* after a write, wait for update of the
281 #define devpriv ((struct pci1710_private *)dev->private)
282 #define this_board ((const struct boardtype *)dev->board_ptr)
285 ==============================================================================
288 static int check_channel_list(struct comedi_device *dev,
289 struct comedi_subdevice *s,
290 unsigned int *chanlist, unsigned int n_chan);
291 static void setup_channel_list(struct comedi_device *dev,
292 struct comedi_subdevice *s,
293 unsigned int *chanlist, unsigned int n_chan,
294 unsigned int seglen);
295 static void start_pacer(struct comedi_device *dev, int mode,
296 unsigned int divisor1, unsigned int divisor2);
297 static int pci1710_reset(struct comedi_device *dev);
298 static int pci171x_ai_cancel(struct comedi_device *dev,
299 struct comedi_subdevice *s);
301 /* used for gain list programming */
302 static const unsigned int muxonechan[] = {
303 0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707,
304 0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f,
305 0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717,
306 0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f
310 ==============================================================================
312 static int pci171x_insn_read_ai(struct comedi_device *dev,
313 struct comedi_subdevice *s,
314 struct comedi_insn *insn, unsigned int *data)
317 #ifdef PCI171x_PARANOIDCHECK
321 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_insn_read_ai(...)\n");
322 devpriv->CntrlReg &= Control_CNT0;
323 devpriv->CntrlReg |= Control_SW; /* set software trigger */
324 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
325 outb(0, dev->iobase + PCI171x_CLRFIFO);
326 outb(0, dev->iobase + PCI171x_CLRINT);
328 setup_channel_list(dev, s, &insn->chanspec, 1, 1);
330 DPRINTK("adv_pci1710 A ST=%4x IO=%x\n",
331 inw(dev->iobase + PCI171x_STATUS),
332 dev->iobase + PCI171x_STATUS);
333 for (n = 0; n < insn->n; n++) {
334 outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */
335 DPRINTK("adv_pci1710 B n=%d ST=%4x\n", n,
336 inw(dev->iobase + PCI171x_STATUS));
338 DPRINTK("adv_pci1710 C n=%d ST=%4x\n", n,
339 inw(dev->iobase + PCI171x_STATUS));
342 if (!(inw(dev->iobase + PCI171x_STATUS) & Status_FE))
345 DPRINTK("adv_pci1710 D n=%d tm=%d ST=%4x\n", n,
347 inw(dev->iobase + PCI171x_STATUS));
349 comedi_error(dev, "A/D insn timeout");
350 outb(0, dev->iobase + PCI171x_CLRFIFO);
351 outb(0, dev->iobase + PCI171x_CLRINT);
354 ("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n",
359 #ifdef PCI171x_PARANOIDCHECK
360 idata = inw(dev->iobase + PCI171x_AD_DATA);
361 if (this_board->cardtype != TYPE_PCI1713)
362 if ((idata & 0xf000) != devpriv->act_chanlist[0]) {
363 comedi_error(dev, "A/D insn data droput!");
366 data[n] = idata & 0x0fff;
368 data[n] = inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff;
373 outb(0, dev->iobase + PCI171x_CLRFIFO);
374 outb(0, dev->iobase + PCI171x_CLRINT);
376 DPRINTK("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n", n);
381 ==============================================================================
383 static int pci171x_insn_write_ao(struct comedi_device *dev,
384 struct comedi_subdevice *s,
385 struct comedi_insn *insn, unsigned int *data)
387 int n, chan, range, ofs;
389 chan = CR_CHAN(insn->chanspec);
390 range = CR_RANGE(insn->chanspec);
392 devpriv->da_ranges &= 0xfb;
393 devpriv->da_ranges |= (range << 2);
394 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
397 devpriv->da_ranges &= 0xfe;
398 devpriv->da_ranges |= range;
399 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
403 for (n = 0; n < insn->n; n++)
404 outw(data[n], dev->iobase + ofs);
406 devpriv->ao_data[chan] = data[n];
413 ==============================================================================
415 static int pci171x_insn_read_ao(struct comedi_device *dev,
416 struct comedi_subdevice *s,
417 struct comedi_insn *insn, unsigned int *data)
421 chan = CR_CHAN(insn->chanspec);
422 for (n = 0; n < insn->n; n++)
423 data[n] = devpriv->ao_data[chan];
429 ==============================================================================
431 static int pci171x_insn_bits_di(struct comedi_device *dev,
432 struct comedi_subdevice *s,
433 struct comedi_insn *insn, unsigned int *data)
435 data[1] = inw(dev->iobase + PCI171x_DI);
441 ==============================================================================
443 static int pci171x_insn_bits_do(struct comedi_device *dev,
444 struct comedi_subdevice *s,
445 struct comedi_insn *insn, unsigned int *data)
448 s->state &= ~data[0];
449 s->state |= (data[0] & data[1]);
450 outw(s->state, dev->iobase + PCI171x_DO);
458 ==============================================================================
460 static int pci171x_insn_counter_read(struct comedi_device *dev,
461 struct comedi_subdevice *s,
462 struct comedi_insn *insn,
465 unsigned int msb, lsb, ccntrl;
468 ccntrl = 0xD2; /* count only */
469 for (i = 0; i < insn->n; i++) {
470 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
472 lsb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
473 msb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
475 data[0] = lsb | (msb << 8);
482 ==============================================================================
484 static int pci171x_insn_counter_write(struct comedi_device *dev,
485 struct comedi_subdevice *s,
486 struct comedi_insn *insn,
489 uint msb, lsb, ccntrl, status;
491 lsb = data[0] & 0x00FF;
492 msb = (data[0] & 0xFF00) >> 8;
494 /* write lsb, then msb */
495 outw(lsb, dev->iobase + PCI171x_CNT0);
496 outw(msb, dev->iobase + PCI171x_CNT0);
498 if (devpriv->cnt0_write_wait) {
499 /* wait for the new count to be loaded */
502 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
503 status = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
504 } while (status & 0x40);
511 ==============================================================================
513 static int pci171x_insn_counter_config(struct comedi_device *dev,
514 struct comedi_subdevice *s,
515 struct comedi_insn *insn,
519 /* This doesn't work like a normal Comedi counter config */
522 devpriv->cnt0_write_wait = data[0] & 0x20;
524 /* internal or external clock? */
525 if (!(data[0] & 0x10)) { /* internal */
526 devpriv->CntrlReg &= ~Control_CNT0;
528 devpriv->CntrlReg |= Control_CNT0;
530 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
533 ccntrl |= Counter_M0;
535 ccntrl |= Counter_M1;
537 ccntrl |= Counter_M2;
539 ccntrl |= Counter_BCD;
540 ccntrl |= Counter_RW0; /* set read/write mode */
541 ccntrl |= Counter_RW1;
542 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
549 ==============================================================================
551 static int pci1720_insn_write_ao(struct comedi_device *dev,
552 struct comedi_subdevice *s,
553 struct comedi_insn *insn, unsigned int *data)
555 int n, rangereg, chan;
557 chan = CR_CHAN(insn->chanspec);
558 rangereg = devpriv->da_ranges & (~(0x03 << (chan << 1)));
559 rangereg |= (CR_RANGE(insn->chanspec) << (chan << 1));
560 if (rangereg != devpriv->da_ranges) {
561 outb(rangereg, dev->iobase + PCI1720_RANGE);
562 devpriv->da_ranges = rangereg;
565 for (n = 0; n < insn->n; n++) {
566 outw(data[n], dev->iobase + PCI1720_DA0 + (chan << 1));
567 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
570 devpriv->ao_data[chan] = data[n];
576 ==============================================================================
578 static void interrupt_pci1710_every_sample(void *d)
580 struct comedi_device *dev = d;
581 struct comedi_subdevice *s = dev->subdevices + 0;
583 #ifdef PCI171x_PARANOIDCHECK
587 DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_every_sample(...)\n");
588 m = inw(dev->iobase + PCI171x_STATUS);
590 printk("comedi%d: A/D FIFO empty (%4x)\n", dev->minor, m);
591 pci171x_ai_cancel(dev, s);
592 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
593 comedi_event(dev, s);
598 ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
600 pci171x_ai_cancel(dev, s);
601 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
602 comedi_event(dev, s);
606 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
609 for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
610 #ifdef PCI171x_PARANOIDCHECK
611 sampl = inw(dev->iobase + PCI171x_AD_DATA);
612 DPRINTK("%04x:", sampl);
613 if (this_board->cardtype != TYPE_PCI1713)
614 if ((sampl & 0xf000) !=
615 devpriv->act_chanlist[s->async->cur_chan]) {
617 ("comedi: A/D data dropout: received data from channel %d, expected %d!\n",
618 (sampl & 0xf000) >> 12,
621 async->cur_chan] & 0xf000) >>
623 pci171x_ai_cancel(dev, s);
625 COMEDI_CB_EOA | COMEDI_CB_ERROR;
626 comedi_event(dev, s);
629 DPRINTK("%8d %2d %8d~", s->async->buf_int_ptr,
630 s->async->cur_chan, s->async->buf_int_count);
631 comedi_buf_put(s->async, sampl & 0x0fff);
633 comedi_buf_put(s->async,
634 inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
636 ++s->async->cur_chan;
638 if (s->async->cur_chan >= devpriv->ai_n_chan)
639 s->async->cur_chan = 0;
642 if (s->async->cur_chan == 0) { /* one scan done */
643 devpriv->ai_act_scan++;
645 ("adv_pci1710 EDBG: EOS1 bic %d bip %d buc %d bup %d\n",
646 s->async->buf_int_count, s->async->buf_int_ptr,
647 s->async->buf_user_count, s->async->buf_user_ptr);
648 DPRINTK("adv_pci1710 EDBG: EOS2\n");
649 if ((!devpriv->neverending_ai) &&
650 (devpriv->ai_act_scan >= devpriv->ai_scans)) {
651 /* all data sampled */
652 pci171x_ai_cancel(dev, s);
653 s->async->events |= COMEDI_CB_EOA;
654 comedi_event(dev, s);
660 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
661 DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_every_sample(...)\n");
663 comedi_event(dev, s);
667 ==============================================================================
669 static int move_block_from_fifo(struct comedi_device *dev,
670 struct comedi_subdevice *s, int n, int turn)
673 #ifdef PCI171x_PARANOIDCHECK
676 DPRINTK("adv_pci1710 EDBG: BGN: move_block_from_fifo(...,%d,%d)\n", n,
678 j = s->async->cur_chan;
679 for (i = 0; i < n; i++) {
680 #ifdef PCI171x_PARANOIDCHECK
681 sampl = inw(dev->iobase + PCI171x_AD_DATA);
682 if (this_board->cardtype != TYPE_PCI1713)
683 if ((sampl & 0xf000) != devpriv->act_chanlist[j]) {
685 ("comedi%d: A/D FIFO data dropout: received data from channel %d, expected %d! (%d/%d/%d/%d/%d/%4x)\n",
686 dev->minor, (sampl & 0xf000) >> 12,
687 (devpriv->act_chanlist[j] & 0xf000) >> 12,
688 i, j, devpriv->ai_act_scan, n, turn,
690 pci171x_ai_cancel(dev, s);
692 COMEDI_CB_EOA | COMEDI_CB_ERROR;
693 comedi_event(dev, s);
696 comedi_buf_put(s->async, sampl & 0x0fff);
698 comedi_buf_put(s->async,
699 inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
702 if (j >= devpriv->ai_n_chan) {
704 devpriv->ai_act_scan++;
707 s->async->cur_chan = j;
708 DPRINTK("adv_pci1710 EDBG: END: move_block_from_fifo(...)\n");
713 ==============================================================================
715 static void interrupt_pci1710_half_fifo(void *d)
717 struct comedi_device *dev = d;
718 struct comedi_subdevice *s = dev->subdevices + 0;
721 DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_half_fifo(...)\n");
722 m = inw(dev->iobase + PCI171x_STATUS);
723 if (!(m & Status_FH)) {
724 printk("comedi%d: A/D FIFO not half full! (%4x)\n",
726 pci171x_ai_cancel(dev, s);
727 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
728 comedi_event(dev, s);
733 ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
735 pci171x_ai_cancel(dev, s);
736 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
737 comedi_event(dev, s);
741 samplesinbuf = this_board->fifo_half_size;
742 if (samplesinbuf * sizeof(short) >= devpriv->ai_data_len) {
743 m = devpriv->ai_data_len / sizeof(short);
744 if (move_block_from_fifo(dev, s, m, 0))
750 if (move_block_from_fifo(dev, s, samplesinbuf, 1))
754 if (!devpriv->neverending_ai)
755 if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data
757 pci171x_ai_cancel(dev, s);
758 s->async->events |= COMEDI_CB_EOA;
759 comedi_event(dev, s);
762 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
763 DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_half_fifo(...)\n");
765 comedi_event(dev, s);
769 ==============================================================================
771 static irqreturn_t interrupt_service_pci1710(int irq, void *d)
773 struct comedi_device *dev = d;
775 DPRINTK("adv_pci1710 EDBG: BGN: interrupt_service_pci1710(%d,...)\n",
777 if (!dev->attached) /* is device attached? */
778 return IRQ_NONE; /* no, exit */
779 /* is this interrupt from our board? */
780 if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))
781 return IRQ_NONE; /* no, exit */
783 DPRINTK("adv_pci1710 EDBG: interrupt_service_pci1710() ST: %4x\n",
784 inw(dev->iobase + PCI171x_STATUS));
786 if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */
788 devpriv->CntrlReg &= Control_CNT0;
789 devpriv->CntrlReg |= Control_SW; /* set software trigger */
790 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
791 devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
792 outb(0, dev->iobase + PCI171x_CLRFIFO);
793 outb(0, dev->iobase + PCI171x_CLRINT);
794 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
795 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
797 start_pacer(dev, 1, devpriv->ai_et_div1, devpriv->ai_et_div2);
800 if (devpriv->ai_eos) { /* We use FIFO half full INT or not? */
801 interrupt_pci1710_every_sample(d);
803 interrupt_pci1710_half_fifo(d);
805 DPRINTK("adv_pci1710 EDBG: END: interrupt_service_pci1710(...)\n");
810 ==============================================================================
812 static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev,
813 struct comedi_subdevice *s)
815 unsigned int divisor1 = 0, divisor2 = 0;
818 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_docmd_and_mode(%d,...)\n",
820 start_pacer(dev, -1, 0, 0); /* stop pacer */
822 seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
826 setup_channel_list(dev, s, devpriv->ai_chanlist,
827 devpriv->ai_n_chan, seglen);
829 outb(0, dev->iobase + PCI171x_CLRFIFO);
830 outb(0, dev->iobase + PCI171x_CLRINT);
832 devpriv->ai_do = mode;
834 devpriv->ai_act_scan = 0;
835 s->async->cur_chan = 0;
836 devpriv->ai_buf_ptr = 0;
837 devpriv->neverending_ai = 0;
839 devpriv->CntrlReg &= Control_CNT0;
840 /* don't we want wake up every scan? devpriv->ai_eos=1; */
841 if ((devpriv->ai_flags & TRIG_WAKE_EOS)) {
844 devpriv->CntrlReg |= Control_ONEFH;
848 if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1))
849 devpriv->neverending_ai = 1;
850 /* well, user want neverending */
852 devpriv->neverending_ai = 0;
857 if (devpriv->ai_timer1 < this_board->ai_ns_min)
858 devpriv->ai_timer1 = this_board->ai_ns_min;
859 devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
861 devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
863 ~(Control_PACER | Control_ONEFH | Control_GATE);
864 devpriv->CntrlReg |= Control_EXT;
869 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
870 &divisor2, &devpriv->ai_timer1,
871 devpriv->ai_flags & TRIG_ROUND_MASK);
873 ("adv_pci1710 EDBG: OSC base=%u div1=%u div2=%u timer=%u\n",
874 devpriv->i8254_osc_base, divisor1, divisor2,
876 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
879 start_pacer(dev, mode, divisor1, divisor2);
881 devpriv->ai_et_div1 = divisor1;
882 devpriv->ai_et_div2 = divisor2;
886 devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
887 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
891 DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_docmd_and_mode(...)\n");
895 #ifdef PCI171X_EXTDEBUG
897 ==============================================================================
899 static void pci171x_cmdtest_out(int e, struct comedi_cmd *cmd)
901 printk("adv_pci1710 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e,
902 cmd->start_src, cmd->scan_begin_src, cmd->convert_src);
903 printk("adv_pci1710 e=%d startarg=%d scanarg=%d convarg=%d\n", e,
904 cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg);
905 printk("adv_pci1710 e=%d stopsrc=%x scanend=%x\n", e, cmd->stop_src,
907 printk("adv_pci1710 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n",
908 e, cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len);
913 ==============================================================================
915 static int pci171x_ai_cmdtest(struct comedi_device *dev,
916 struct comedi_subdevice *s,
917 struct comedi_cmd *cmd)
921 unsigned int divisor1 = 0, divisor2 = 0;
923 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...)\n");
924 #ifdef PCI171X_EXTDEBUG
925 pci171x_cmdtest_out(-1, cmd);
927 /* step 1: make sure trigger sources are trivially valid */
929 tmp = cmd->start_src;
930 cmd->start_src &= TRIG_NOW | TRIG_EXT;
931 if (!cmd->start_src || tmp != cmd->start_src)
934 tmp = cmd->scan_begin_src;
935 cmd->scan_begin_src &= TRIG_FOLLOW;
936 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
939 tmp = cmd->convert_src;
940 cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
941 if (!cmd->convert_src || tmp != cmd->convert_src)
944 tmp = cmd->scan_end_src;
945 cmd->scan_end_src &= TRIG_COUNT;
946 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
950 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
951 if (!cmd->stop_src || tmp != cmd->stop_src)
955 #ifdef PCI171X_EXTDEBUG
956 pci171x_cmdtest_out(1, cmd);
959 "adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=1\n",
964 /* step2: make sure trigger srcs are unique and mutually compatible */
966 if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) {
967 cmd->start_src = TRIG_NOW;
971 if (cmd->scan_begin_src != TRIG_FOLLOW) {
972 cmd->scan_begin_src = TRIG_FOLLOW;
976 if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
979 if (cmd->scan_end_src != TRIG_COUNT) {
980 cmd->scan_end_src = TRIG_COUNT;
984 if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
988 #ifdef PCI171X_EXTDEBUG
989 pci171x_cmdtest_out(2, cmd);
992 "adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=2\n",
997 /* step 3: make sure arguments are trivially compatible */
999 if (cmd->start_arg != 0) {
1004 if (cmd->scan_begin_arg != 0) {
1005 cmd->scan_begin_arg = 0;
1009 if (cmd->convert_src == TRIG_TIMER) {
1010 if (cmd->convert_arg < this_board->ai_ns_min) {
1011 cmd->convert_arg = this_board->ai_ns_min;
1014 } else { /* TRIG_FOLLOW */
1015 if (cmd->convert_arg != 0) {
1016 cmd->convert_arg = 0;
1021 if (cmd->scan_end_arg != cmd->chanlist_len) {
1022 cmd->scan_end_arg = cmd->chanlist_len;
1025 if (cmd->stop_src == TRIG_COUNT) {
1026 if (!cmd->stop_arg) {
1030 } else { /* TRIG_NONE */
1031 if (cmd->stop_arg != 0) {
1038 #ifdef PCI171X_EXTDEBUG
1039 pci171x_cmdtest_out(3, cmd);
1042 "adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=3\n",
1047 /* step 4: fix up any arguments */
1049 if (cmd->convert_src == TRIG_TIMER) {
1050 tmp = cmd->convert_arg;
1051 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
1052 &divisor2, &cmd->convert_arg,
1053 cmd->flags & TRIG_ROUND_MASK);
1054 if (cmd->convert_arg < this_board->ai_ns_min)
1055 cmd->convert_arg = this_board->ai_ns_min;
1056 if (tmp != cmd->convert_arg)
1062 ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=4\n",
1067 /* step 5: complain about special chanlist considerations */
1069 if (cmd->chanlist) {
1070 if (!check_channel_list(dev, s, cmd->chanlist,
1072 return 5; /* incorrect channels list */
1075 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) ret=0\n");
1080 ==============================================================================
1082 static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1084 struct comedi_cmd *cmd = &s->async->cmd;
1086 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmd(...)\n");
1087 devpriv->ai_n_chan = cmd->chanlist_len;
1088 devpriv->ai_chanlist = cmd->chanlist;
1089 devpriv->ai_flags = cmd->flags;
1090 devpriv->ai_data_len = s->async->prealloc_bufsz;
1091 devpriv->ai_data = s->async->prealloc_buf;
1092 devpriv->ai_timer1 = 0;
1093 devpriv->ai_timer2 = 0;
1095 if (cmd->stop_src == TRIG_COUNT)
1096 devpriv->ai_scans = cmd->stop_arg;
1098 devpriv->ai_scans = 0;
1101 if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 2, 3 */
1102 if (cmd->convert_src == TRIG_TIMER) { /* mode 1 and 2 */
1103 devpriv->ai_timer1 = cmd->convert_arg;
1104 return pci171x_ai_docmd_and_mode(cmd->start_src ==
1105 TRIG_EXT ? 2 : 1, dev,
1108 if (cmd->convert_src == TRIG_EXT) { /* mode 3 */
1109 return pci171x_ai_docmd_and_mode(3, dev, s);
1117 ==============================================================================
1118 Check if channel list from user is builded correctly
1119 If it's ok, then program scan/gain logic.
1120 This works for all cards.
1122 static int check_channel_list(struct comedi_device *dev,
1123 struct comedi_subdevice *s,
1124 unsigned int *chanlist, unsigned int n_chan)
1126 unsigned int chansegment[32];
1127 unsigned int i, nowmustbechan, seglen, segpos;
1129 DPRINTK("adv_pci1710 EDBG: check_channel_list(...,%d)\n", n_chan);
1130 /* correct channel and range number check itself comedi/range.c */
1132 comedi_error(dev, "range/channel list is empty!");
1137 return 1; /* seglen=1 */
1139 chansegment[0] = chanlist[0]; /* first channel is every time ok */
1140 for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {
1141 if (chanlist[0] == chanlist[i])
1142 break; /* we detected a loop, stop */
1143 if ((CR_CHAN(chanlist[i]) & 1) &&
1144 (CR_AREF(chanlist[i]) == AREF_DIFF)) {
1145 comedi_error(dev, "Odd channel cannot be differential input!\n");
1148 nowmustbechan = (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
1149 if (CR_AREF(chansegment[i - 1]) == AREF_DIFF)
1150 nowmustbechan = (nowmustbechan + 1) % s->n_chan;
1151 if (nowmustbechan != CR_CHAN(chanlist[i])) {
1152 printk("channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
1153 i, CR_CHAN(chanlist[i]), nowmustbechan,
1154 CR_CHAN(chanlist[0]));
1157 chansegment[i] = chanlist[i]; /* next correct channel in list */
1160 for (i = 0, segpos = 0; i < n_chan; i++) {
1161 if (chanlist[i] != chansegment[i % seglen]) {
1162 printk("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
1163 i, CR_CHAN(chansegment[i]),
1164 CR_RANGE(chansegment[i]),
1165 CR_AREF(chansegment[i]),
1166 CR_CHAN(chanlist[i % seglen]),
1167 CR_RANGE(chanlist[i % seglen]),
1168 CR_AREF(chansegment[i % seglen]));
1175 static void setup_channel_list(struct comedi_device *dev,
1176 struct comedi_subdevice *s,
1177 unsigned int *chanlist, unsigned int n_chan,
1178 unsigned int seglen)
1180 unsigned int i, range, chanprog;
1182 DPRINTK("adv_pci1710 EDBG: setup_channel_list(...,%d,%d)\n", n_chan,
1184 devpriv->act_chanlist_len = seglen;
1185 devpriv->act_chanlist_pos = 0;
1187 DPRINTK("SegLen: %d\n", seglen);
1188 for (i = 0; i < seglen; i++) { /* store range list to card */
1189 chanprog = muxonechan[CR_CHAN(chanlist[i])];
1190 outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */
1191 range = this_board->rangecode_ai[CR_RANGE(chanlist[i])];
1192 if (CR_AREF(chanlist[i]) == AREF_DIFF)
1194 outw(range, dev->iobase + PCI171x_RANGE); /* select gain */
1195 #ifdef PCI171x_PARANOIDCHECK
1196 devpriv->act_chanlist[i] =
1197 (CR_CHAN(chanlist[i]) << 12) & 0xf000;
1199 DPRINTK("GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range,
1200 devpriv->act_chanlist[i]);
1202 #ifdef PCI171x_PARANOIDCHECK
1203 for ( ; i < n_chan; i++) { /* store remainder of channel list */
1204 devpriv->act_chanlist[i] =
1205 (CR_CHAN(chanlist[i]) << 12) & 0xf000;
1209 devpriv->ai_et_MuxVal =
1210 CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
1211 /* select channel interval to scan */
1212 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
1213 DPRINTK("MUX: %4x L%4x.H%4x\n",
1214 CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8),
1215 CR_CHAN(chanlist[0]), CR_CHAN(chanlist[seglen - 1]));
1219 ==============================================================================
1221 static void start_pacer(struct comedi_device *dev, int mode,
1222 unsigned int divisor1, unsigned int divisor2)
1224 DPRINTK("adv_pci1710 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode,
1225 divisor1, divisor2);
1226 outw(0xb4, dev->iobase + PCI171x_CNTCTRL);
1227 outw(0x74, dev->iobase + PCI171x_CNTCTRL);
1230 outw(divisor2 & 0xff, dev->iobase + PCI171x_CNT2);
1231 outw((divisor2 >> 8) & 0xff, dev->iobase + PCI171x_CNT2);
1232 outw(divisor1 & 0xff, dev->iobase + PCI171x_CNT1);
1233 outw((divisor1 >> 8) & 0xff, dev->iobase + PCI171x_CNT1);
1235 DPRINTK("adv_pci1710 EDBG: END: start_pacer(...)\n");
1239 ==============================================================================
1241 static int pci171x_ai_cancel(struct comedi_device *dev,
1242 struct comedi_subdevice *s)
1244 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cancel(...)\n");
1246 switch (this_board->cardtype) {
1248 devpriv->CntrlReg &= Control_CNT0;
1249 devpriv->CntrlReg |= Control_SW;
1251 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */
1252 start_pacer(dev, -1, 0, 0);
1253 outb(0, dev->iobase + PCI171x_CLRFIFO);
1254 outb(0, dev->iobase + PCI171x_CLRINT);
1259 devpriv->ai_act_scan = 0;
1260 s->async->cur_chan = 0;
1261 devpriv->ai_buf_ptr = 0;
1262 devpriv->neverending_ai = 0;
1264 DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_cancel(...)\n");
1269 ==============================================================================
1271 static int pci171x_reset(struct comedi_device *dev)
1273 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_reset(...)\n");
1274 outw(0x30, dev->iobase + PCI171x_CNTCTRL);
1275 devpriv->CntrlReg = Control_SW | Control_CNT0; /* Software trigger, CNT0=external */
1276 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */
1277 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
1278 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
1279 start_pacer(dev, -1, 0, 0); /* stop 8254 */
1280 devpriv->da_ranges = 0;
1281 if (this_board->n_aochan) {
1282 outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); /* set DACs to 0..5V */
1283 outw(0, dev->iobase + PCI171x_DA1); /* set DA outputs to 0V */
1284 devpriv->ao_data[0] = 0x0000;
1285 if (this_board->n_aochan > 1) {
1286 outw(0, dev->iobase + PCI171x_DA2);
1287 devpriv->ao_data[1] = 0x0000;
1290 outw(0, dev->iobase + PCI171x_DO); /* digital outputs to 0 */
1291 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
1292 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
1294 DPRINTK("adv_pci1710 EDBG: END: pci171x_reset(...)\n");
1299 ==============================================================================
1301 static int pci1720_reset(struct comedi_device *dev)
1303 DPRINTK("adv_pci1710 EDBG: BGN: pci1720_reset(...)\n");
1304 outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT); /* set synchronous output mode */
1305 devpriv->da_ranges = 0xAA;
1306 outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE); /* set all ranges to +/-5V */
1307 outw(0x0800, dev->iobase + PCI1720_DA0); /* set outputs to 0V */
1308 outw(0x0800, dev->iobase + PCI1720_DA1);
1309 outw(0x0800, dev->iobase + PCI1720_DA2);
1310 outw(0x0800, dev->iobase + PCI1720_DA3);
1311 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
1312 devpriv->ao_data[0] = 0x0800;
1313 devpriv->ao_data[1] = 0x0800;
1314 devpriv->ao_data[2] = 0x0800;
1315 devpriv->ao_data[3] = 0x0800;
1316 DPRINTK("adv_pci1710 EDBG: END: pci1720_reset(...)\n");
1321 ==============================================================================
1323 static int pci1710_reset(struct comedi_device *dev)
1325 DPRINTK("adv_pci1710 EDBG: BGN: pci1710_reset(...)\n");
1326 switch (this_board->cardtype) {
1328 return pci1720_reset(dev);
1330 return pci171x_reset(dev);
1332 DPRINTK("adv_pci1710 EDBG: END: pci1710_reset(...)\n");
1335 static struct pci_dev *pci1710_find_pci_dev(struct comedi_device *dev,
1336 struct comedi_devconfig *it)
1338 struct pci_dev *pcidev = NULL;
1339 int bus = it->options[0];
1340 int slot = it->options[1];
1341 int board_index = this_board - boardtypes;
1344 for_each_pci_dev(pcidev) {
1346 if (bus != pcidev->bus->number ||
1347 slot != PCI_SLOT(pcidev->devfn))
1350 if (pcidev->vendor != PCI_VENDOR_ID_ADVANTECH)
1352 if (pci_is_enabled(pcidev))
1355 if (strcmp(this_board->name, DRV_NAME) == 0) {
1356 for (i = 0; i < ARRAY_SIZE(boardtypes); ++i) {
1357 if (pcidev->device == boardtypes[i].device_id) {
1362 if (i == ARRAY_SIZE(boardtypes))
1365 if (pcidev->device != boardtypes[board_index].device_id)
1368 dev->board_ptr = &boardtypes[board_index];
1371 dev_err(dev->class_dev,
1372 "No supported board found! (req. bus %d, slot %d)\n",
1377 static int pci1710_attach(struct comedi_device *dev,
1378 struct comedi_devconfig *it)
1380 struct pci_dev *pcidev;
1381 struct comedi_subdevice *s;
1382 int ret, subdev, n_subdevices;
1385 dev_info(dev->class_dev, DRV_NAME ": attach\n");
1387 ret = alloc_private(dev, sizeof(struct pci1710_private));
1391 pcidev = pci1710_find_pci_dev(dev, it);
1394 comedi_set_hw_dev(dev, &pcidev->dev);
1396 ret = comedi_pci_enable(pcidev, DRV_NAME);
1400 dev->iobase = pci_resource_start(pcidev, 2);
1403 dev->board_name = this_board->name;
1406 if (this_board->n_aichan)
1408 if (this_board->n_aochan)
1410 if (this_board->n_dichan)
1412 if (this_board->n_dochan)
1414 if (this_board->n_counter)
1417 ret = comedi_alloc_subdevices(dev, n_subdevices);
1423 if (this_board->have_irq) {
1425 if (request_irq(irq, interrupt_service_pci1710,
1426 IRQF_SHARED, "Advantech PCI-1710",
1428 dev_dbg(dev->class_dev,
1429 "unable to allocate IRQ %d, DISABLING IT",
1431 irq = 0; /* Can't use IRQ */
1433 dev_dbg(dev->class_dev, "irq=%u", irq);
1436 dev_dbg(dev->class_dev, "IRQ disabled");
1445 if (this_board->n_aichan) {
1446 s = dev->subdevices + subdev;
1447 dev->read_subdev = s;
1448 s->type = COMEDI_SUBD_AI;
1449 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
1450 if (this_board->n_aichand)
1451 s->subdev_flags |= SDF_DIFF;
1452 s->n_chan = this_board->n_aichan;
1453 s->maxdata = this_board->ai_maxdata;
1454 s->len_chanlist = this_board->n_aichan;
1455 s->range_table = this_board->rangelist_ai;
1456 s->cancel = pci171x_ai_cancel;
1457 s->insn_read = pci171x_insn_read_ai;
1459 s->subdev_flags |= SDF_CMD_READ;
1460 s->do_cmdtest = pci171x_ai_cmdtest;
1461 s->do_cmd = pci171x_ai_cmd;
1463 devpriv->i8254_osc_base = 100; /* 100ns=10MHz */
1467 if (this_board->n_aochan) {
1468 s = dev->subdevices + subdev;
1469 s->type = COMEDI_SUBD_AO;
1470 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1471 s->n_chan = this_board->n_aochan;
1472 s->maxdata = this_board->ao_maxdata;
1473 s->len_chanlist = this_board->n_aochan;
1474 s->range_table = this_board->rangelist_ao;
1475 switch (this_board->cardtype) {
1477 s->insn_write = pci1720_insn_write_ao;
1480 s->insn_write = pci171x_insn_write_ao;
1483 s->insn_read = pci171x_insn_read_ao;
1487 if (this_board->n_dichan) {
1488 s = dev->subdevices + subdev;
1489 s->type = COMEDI_SUBD_DI;
1490 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
1491 s->n_chan = this_board->n_dichan;
1493 s->len_chanlist = this_board->n_dichan;
1494 s->range_table = &range_digital;
1495 s->io_bits = 0; /* all bits input */
1496 s->insn_bits = pci171x_insn_bits_di;
1500 if (this_board->n_dochan) {
1501 s = dev->subdevices + subdev;
1502 s->type = COMEDI_SUBD_DO;
1503 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1504 s->n_chan = this_board->n_dochan;
1506 s->len_chanlist = this_board->n_dochan;
1507 s->range_table = &range_digital;
1508 /* all bits output */
1509 s->io_bits = (1 << this_board->n_dochan) - 1;
1511 s->insn_bits = pci171x_insn_bits_do;
1515 if (this_board->n_counter) {
1516 s = dev->subdevices + subdev;
1517 s->type = COMEDI_SUBD_COUNTER;
1518 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1519 s->n_chan = this_board->n_counter;
1520 s->len_chanlist = this_board->n_counter;
1521 s->maxdata = 0xffff;
1522 s->range_table = &range_unknown;
1523 s->insn_read = pci171x_insn_counter_read;
1524 s->insn_write = pci171x_insn_counter_write;
1525 s->insn_config = pci171x_insn_counter_config;
1534 static void pci1710_detach(struct comedi_device *dev)
1536 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1542 free_irq(dev->irq, dev);
1546 comedi_pci_disable(pcidev);
1547 pci_dev_put(pcidev);
1551 static struct comedi_driver adv_pci1710_driver = {
1552 .driver_name = "adv_pci1710",
1553 .module = THIS_MODULE,
1554 .attach = pci1710_attach,
1555 .detach = pci1710_detach,
1556 .num_names = ARRAY_SIZE(boardtypes),
1557 .board_name = &boardtypes[0].name,
1558 .offset = sizeof(struct boardtype),
1561 static int __devinit adv_pci1710_pci_probe(struct pci_dev *dev,
1562 const struct pci_device_id *ent)
1564 return comedi_pci_auto_config(dev, &adv_pci1710_driver);
1567 static void __devexit adv_pci1710_pci_remove(struct pci_dev *dev)
1569 comedi_pci_auto_unconfig(dev);
1572 static DEFINE_PCI_DEVICE_TABLE(adv_pci1710_pci_table) = {
1573 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1710) },
1574 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1711) },
1575 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1713) },
1576 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1720) },
1577 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1731) },
1580 MODULE_DEVICE_TABLE(pci, adv_pci1710_pci_table);
1582 static struct pci_driver adv_pci1710_pci_driver = {
1583 .name = "adv_pci1710",
1584 .id_table = adv_pci1710_pci_table,
1585 .probe = adv_pci1710_pci_probe,
1586 .remove = __devexit_p(adv_pci1710_pci_remove),
1588 module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver);
1590 MODULE_AUTHOR("Comedi http://www.comedi.org");
1591 MODULE_DESCRIPTION("Comedi low-level driver");
1592 MODULE_LICENSE("GPL");