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_pci.h"
51 #include "amcc_s5933.h"
53 #define PCI171x_PARANOIDCHECK /* if defined, then is used code which control correct channel number on every 12 bit sample */
55 #undef PCI171X_EXTDEBUG
57 #define DRV_NAME "adv_pci1710"
60 #ifdef PCI171X_EXTDEBUG
61 #define DPRINTK(fmt, args...) rt_printk(fmt, ## args)
63 #define DPRINTK(fmt, args...)
66 /* hardware types of the cards */
67 #define TYPE_PCI171X 0
68 #define TYPE_PCI1713 2
69 #define TYPE_PCI1720 3
71 #define IORANGE_171x 32
72 #define IORANGE_1720 16
74 #define PCI171x_AD_DATA 0 /* R: A/D data */
75 #define PCI171x_SOFTTRG 0 /* W: soft trigger for A/D */
76 #define PCI171x_RANGE 2 /* W: A/D gain/range register */
77 #define PCI171x_MUX 4 /* W: A/D multiplexor control */
78 #define PCI171x_STATUS 6 /* R: status register */
79 #define PCI171x_CONTROL 6 /* W: control register */
80 #define PCI171x_CLRINT 8 /* W: clear interrupts request */
81 #define PCI171x_CLRFIFO 9 /* W: clear FIFO */
82 #define PCI171x_DA1 10 /* W: D/A register */
83 #define PCI171x_DA2 12 /* W: D/A register */
84 #define PCI171x_DAREF 14 /* W: D/A reference control */
85 #define PCI171x_DI 16 /* R: digi inputs */
86 #define PCI171x_DO 16 /* R: digi inputs */
87 #define PCI171x_CNT0 24 /* R/W: 8254 couter 0 */
88 #define PCI171x_CNT1 26 /* R/W: 8254 couter 1 */
89 #define PCI171x_CNT2 28 /* R/W: 8254 couter 2 */
90 #define PCI171x_CNTCTRL 30 /* W: 8254 counter control */
92 /* upper bits from status register (PCI171x_STATUS) (lower is same woth control reg) */
93 #define Status_FE 0x0100 /* 1=FIFO is empty */
94 #define Status_FH 0x0200 /* 1=FIFO is half full */
95 #define Status_FF 0x0400 /* 1=FIFO is full, fatal error */
96 #define Status_IRQ 0x0800 /* 1=IRQ occured */
97 /* bits from control register (PCI171x_CONTROL) */
98 #define Control_CNT0 0x0040 /* 1=CNT0 have external source, 0=have internal 100kHz source */
99 #define Control_ONEFH 0x0020 /* 1=IRQ on FIFO is half full, 0=every sample */
100 #define Control_IRQEN 0x0010 /* 1=enable IRQ */
101 #define Control_GATE 0x0008 /* 1=enable external trigger GATE (8254?) */
102 #define Control_EXT 0x0004 /* 1=external trigger source */
103 #define Control_PACER 0x0002 /* 1=enable internal 8254 trigger source */
104 #define Control_SW 0x0001 /* 1=enable software trigger source */
105 /* bits from counter control register (PCI171x_CNTCTRL) */
106 #define Counter_BCD 0x0001 /* 0 = binary counter, 1 = BCD counter */
107 #define Counter_M0 0x0002 /* M0-M2 select modes 0-5 */
108 #define Counter_M1 0x0004 /* 000 = mode 0, 010 = mode 2 ... */
109 #define Counter_M2 0x0008
110 #define Counter_RW0 0x0010 /* RW0/RW1 select read/write mode */
111 #define Counter_RW1 0x0020
112 #define Counter_SC0 0x0040 /* Select Counter. Only 00 or 11 may */
113 #define Counter_SC1 0x0080 /* be used, 00 for CNT0, 11 for read-back command */
115 #define PCI1720_DA0 0 /* W: D/A register 0 */
116 #define PCI1720_DA1 2 /* W: D/A register 1 */
117 #define PCI1720_DA2 4 /* W: D/A register 2 */
118 #define PCI1720_DA3 6 /* W: D/A register 3 */
119 #define PCI1720_RANGE 8 /* R/W: D/A range register */
120 #define PCI1720_SYNCOUT 9 /* W: D/A synchronized output register */
121 #define PCI1720_SYNCONT 15 /* R/W: D/A synchronized control */
123 /* D/A synchronized control (PCI1720_SYNCONT) */
124 #define Syncont_SC0 1 /* set synchronous output mode */
126 static const struct comedi_lrange range_pci1710_3 = { 9, {
139 static const char range_codes_pci1710_3[] =
140 { 0x00, 0x01, 0x02, 0x03, 0x04, 0x10, 0x11, 0x12, 0x13 };
142 static const struct comedi_lrange range_pci1710hg = { 12, {
158 static const char range_codes_pci1710hg[] =
159 { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12,
162 static const struct comedi_lrange range_pci17x1 = { 5, {
171 static const char range_codes_pci17x1[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
173 static const struct comedi_lrange range_pci1720 = { 4, {
181 static const struct comedi_lrange range_pci171x_da = { 2, {
187 static int pci1710_attach(struct comedi_device *dev, struct comedi_devconfig *it);
188 static int pci1710_detach(struct comedi_device *dev);
191 const char *name; /* board name */
193 int iorange; /* I/O range len */
194 char have_irq; /* 1=card support IRQ */
195 char cardtype; /* 0=1710& co. 2=1713, ... */
196 int n_aichan; /* num of A/D chans */
197 int n_aichand; /* num of A/D chans in diff mode */
198 int n_aochan; /* num of D/A chans */
199 int n_dichan; /* num of DI chans */
200 int n_dochan; /* num of DO chans */
201 int n_counter; /* num of counters */
202 int ai_maxdata; /* resolution of A/D */
203 int ao_maxdata; /* resolution of D/A */
204 const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */
205 const char *rangecode_ai; /* range codes for programming */
206 const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */
207 unsigned int ai_ns_min; /* max sample speed of card v ns */
208 unsigned int fifo_half_size; /* size of FIFO/2 */
211 static DEFINE_PCI_DEVICE_TABLE(pci1710_pci_table) = {
212 {PCI_VENDOR_ID_ADVANTECH, 0x1710, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
213 {PCI_VENDOR_ID_ADVANTECH, 0x1711, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
214 {PCI_VENDOR_ID_ADVANTECH, 0x1713, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
215 {PCI_VENDOR_ID_ADVANTECH, 0x1720, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
216 {PCI_VENDOR_ID_ADVANTECH, 0x1731, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
220 MODULE_DEVICE_TABLE(pci, pci1710_pci_table);
222 static const struct boardtype boardtypes[] = {
224 IORANGE_171x, 1, TYPE_PCI171X,
225 16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff,
226 &range_pci1710_3, range_codes_pci1710_3,
229 {"pci1710hg", 0x1710,
230 IORANGE_171x, 1, TYPE_PCI171X,
231 16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff,
232 &range_pci1710hg, range_codes_pci1710hg,
236 IORANGE_171x, 1, TYPE_PCI171X,
237 16, 0, 2, 16, 16, 1, 0x0fff, 0x0fff,
238 &range_pci17x1, range_codes_pci17x1, &range_pci171x_da,
241 IORANGE_171x, 1, TYPE_PCI1713,
242 32, 16, 0, 0, 0, 0, 0x0fff, 0x0000,
243 &range_pci1710_3, range_codes_pci1710_3, NULL,
246 IORANGE_1720, 0, TYPE_PCI1720,
247 0, 0, 4, 0, 0, 0, 0x0000, 0x0fff,
248 NULL, NULL, &range_pci1720,
251 IORANGE_171x, 1, TYPE_PCI171X,
252 16, 0, 0, 16, 16, 0, 0x0fff, 0x0000,
253 &range_pci17x1, range_codes_pci17x1, NULL,
255 /* dummy entry corresponding to driver name */
259 #define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype))
261 static struct comedi_driver driver_pci1710 = {
262 .driver_name = DRV_NAME,
263 .module = THIS_MODULE,
264 .attach = pci1710_attach,
265 .detach = pci1710_detach,
266 .num_names = n_boardtypes,
267 .board_name = &boardtypes[0].name,
268 .offset = sizeof(struct boardtype),
271 struct pci1710_private {
272 struct pci_dev *pcidev; /* ptr to PCI device */
273 char valid; /* card is usable */
274 char neverending_ai; /* we do unlimited AI */
275 unsigned int CntrlReg; /* Control register */
276 unsigned int i8254_osc_base; /* frequence of onboard oscilator */
277 unsigned int ai_do; /* what do AI? 0=nothing, 1 to 4 mode */
278 unsigned int ai_act_scan; /* how many scans we finished */
279 unsigned int ai_act_chan; /* actual position in actual scan */
280 unsigned int ai_buf_ptr; /* data buffer ptr in samples */
281 unsigned char ai_eos; /* 1=EOS wake up */
283 unsigned int ai_et_CntrlReg;
284 unsigned int ai_et_MuxVal;
285 unsigned int ai_et_div1, ai_et_div2;
286 unsigned int act_chanlist[32]; /* list of scaned channel */
287 unsigned char act_chanlist_len; /* len of scanlist */
288 unsigned char act_chanlist_pos; /* actual position in MUX list */
289 unsigned char da_ranges; /* copy of D/A outpit range register */
290 unsigned int ai_scans; /* len of scanlist */
291 unsigned int ai_n_chan; /* how many channels is measured */
292 unsigned int *ai_chanlist; /* actaul chanlist */
293 unsigned int ai_flags; /* flaglist */
294 unsigned int ai_data_len; /* len of data buffer */
295 short *ai_data; /* data buffer */
296 unsigned int ai_timer1; /* timers */
297 unsigned int ai_timer2;
298 short ao_data[4]; /* data output buffer */
299 unsigned int cnt0_write_wait; /* after a write, wait for update of the internal state */
302 #define devpriv ((struct pci1710_private *)dev->private)
303 #define this_board ((const struct boardtype *)dev->board_ptr)
306 ==============================================================================
309 static int check_channel_list(struct comedi_device *dev, struct comedi_subdevice *s,
310 unsigned int *chanlist, unsigned int n_chan);
311 static void setup_channel_list(struct comedi_device *dev, struct comedi_subdevice *s,
312 unsigned int *chanlist, unsigned int n_chan, unsigned int seglen);
313 static void start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1,
314 unsigned int divisor2);
315 static int pci1710_reset(struct comedi_device *dev);
316 static int pci171x_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
318 static const unsigned int muxonechan[] = { 0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707, /* used for gain list programming */
319 0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f,
320 0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717,
321 0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f
325 ==============================================================================
327 static int pci171x_insn_read_ai(struct comedi_device *dev, struct comedi_subdevice *s,
328 struct comedi_insn *insn, unsigned int *data)
331 #ifdef PCI171x_PARANOIDCHECK
335 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_insn_read_ai(...)\n");
336 devpriv->CntrlReg &= Control_CNT0;
337 devpriv->CntrlReg |= Control_SW; /* set software trigger */
338 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
339 outb(0, dev->iobase + PCI171x_CLRFIFO);
340 outb(0, dev->iobase + PCI171x_CLRINT);
342 setup_channel_list(dev, s, &insn->chanspec, 1, 1);
344 DPRINTK("adv_pci1710 A ST=%4x IO=%x\n",
345 inw(dev->iobase + PCI171x_STATUS),
346 dev->iobase + PCI171x_STATUS);
347 for (n = 0; n < insn->n; n++) {
348 outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */
349 DPRINTK("adv_pci1710 B n=%d ST=%4x\n", n,
350 inw(dev->iobase + PCI171x_STATUS));
351 /* comedi_udelay(1); */
352 DPRINTK("adv_pci1710 C n=%d ST=%4x\n", n,
353 inw(dev->iobase + PCI171x_STATUS));
356 if (!(inw(dev->iobase + PCI171x_STATUS) & Status_FE))
359 DPRINTK("adv_pci1710 D n=%d tm=%d ST=%4x\n", n,
361 inw(dev->iobase + PCI171x_STATUS));
363 comedi_error(dev, "A/D insn timeout");
364 outb(0, dev->iobase + PCI171x_CLRFIFO);
365 outb(0, dev->iobase + PCI171x_CLRINT);
367 DPRINTK("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n", n);
371 #ifdef PCI171x_PARANOIDCHECK
372 idata = inw(dev->iobase + PCI171x_AD_DATA);
373 if (this_board->cardtype != TYPE_PCI1713)
374 if ((idata & 0xf000) != devpriv->act_chanlist[0]) {
375 comedi_error(dev, "A/D insn data droput!");
378 data[n] = idata & 0x0fff;
380 data[n] = inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff;
385 outb(0, dev->iobase + PCI171x_CLRFIFO);
386 outb(0, dev->iobase + PCI171x_CLRINT);
388 DPRINTK("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n", n);
393 ==============================================================================
395 static int pci171x_insn_write_ao(struct comedi_device *dev, struct comedi_subdevice *s,
396 struct comedi_insn *insn, unsigned int *data)
398 int n, chan, range, ofs;
400 chan = CR_CHAN(insn->chanspec);
401 range = CR_RANGE(insn->chanspec);
403 devpriv->da_ranges &= 0xfb;
404 devpriv->da_ranges |= (range << 2);
405 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
408 devpriv->da_ranges &= 0xfe;
409 devpriv->da_ranges |= range;
410 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
414 for (n = 0; n < insn->n; n++)
415 outw(data[n], dev->iobase + ofs);
417 devpriv->ao_data[chan] = data[n];
424 ==============================================================================
426 static int pci171x_insn_read_ao(struct comedi_device *dev, struct comedi_subdevice *s,
427 struct comedi_insn *insn, unsigned int *data)
431 chan = CR_CHAN(insn->chanspec);
432 for (n = 0; n < insn->n; n++)
433 data[n] = devpriv->ao_data[chan];
439 ==============================================================================
441 static int pci171x_insn_bits_di(struct comedi_device *dev, struct comedi_subdevice *s,
442 struct comedi_insn *insn, unsigned int *data)
444 data[1] = inw(dev->iobase + PCI171x_DI);
450 ==============================================================================
452 static int pci171x_insn_bits_do(struct comedi_device *dev, struct comedi_subdevice *s,
453 struct comedi_insn *insn, unsigned int *data)
456 s->state &= ~data[0];
457 s->state |= (data[0] & data[1]);
458 outw(s->state, dev->iobase + PCI171x_DO);
466 ==============================================================================
468 static int pci171x_insn_counter_read(struct comedi_device *dev, struct comedi_subdevice *s,
469 struct comedi_insn *insn, unsigned int *data)
471 unsigned int msb, lsb, ccntrl;
474 ccntrl = 0xD2; /* count only */
475 for (i = 0; i < insn->n; i++) {
476 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
478 lsb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
479 msb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
481 data[0] = lsb | (msb << 8);
488 ==============================================================================
490 static int pci171x_insn_counter_write(struct comedi_device *dev, struct comedi_subdevice *s,
491 struct comedi_insn *insn, unsigned int *data)
493 uint msb, lsb, ccntrl, status;
495 lsb = data[0] & 0x00FF;
496 msb = (data[0] & 0xFF00) >> 8;
498 /* write lsb, then msb */
499 outw(lsb, dev->iobase + PCI171x_CNT0);
500 outw(msb, dev->iobase + PCI171x_CNT0);
502 if (devpriv->cnt0_write_wait) {
503 /* wait for the new count to be loaded */
506 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
507 status = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
508 } while (status & 0x40);
515 ==============================================================================
517 static int pci171x_insn_counter_config(struct comedi_device *dev,
518 struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data)
521 /* This doesn't work like a normal Comedi counter config */
524 devpriv->cnt0_write_wait = data[0] & 0x20;
526 /* internal or external clock? */
527 if (!(data[0] & 0x10)) { /* internal */
528 devpriv->CntrlReg &= ~Control_CNT0;
530 devpriv->CntrlReg |= Control_CNT0;
532 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
535 ccntrl |= Counter_M0;
537 ccntrl |= Counter_M1;
539 ccntrl |= Counter_M2;
541 ccntrl |= Counter_BCD;
542 ccntrl |= Counter_RW0; /* set read/write mode */
543 ccntrl |= Counter_RW1;
544 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
551 ==============================================================================
553 static int pci1720_insn_write_ao(struct comedi_device *dev, struct comedi_subdevice *s,
554 struct comedi_insn *insn, unsigned int *data)
556 int n, rangereg, chan;
558 chan = CR_CHAN(insn->chanspec);
559 rangereg = devpriv->da_ranges & (~(0x03 << (chan << 1)));
560 rangereg |= (CR_RANGE(insn->chanspec) << (chan << 1));
561 if (rangereg != devpriv->da_ranges) {
562 outb(rangereg, dev->iobase + PCI1720_RANGE);
563 devpriv->da_ranges = rangereg;
566 for (n = 0; n < insn->n; n++) {
567 outw(data[n], dev->iobase + PCI1720_DA0 + (chan << 1));
568 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
571 devpriv->ao_data[chan] = data[n];
577 ==============================================================================
579 static void interrupt_pci1710_every_sample(void *d)
581 struct comedi_device *dev = d;
582 struct comedi_subdevice *s = dev->subdevices + 0;
584 #ifdef PCI171x_PARANOIDCHECK
588 DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_every_sample(...)\n");
589 m = inw(dev->iobase + PCI171x_STATUS);
591 rt_printk("comedi%d: A/D FIFO empty (%4x)\n", dev->minor, m);
592 pci171x_ai_cancel(dev, s);
593 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
594 comedi_event(dev, s);
599 ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
601 pci171x_ai_cancel(dev, s);
602 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
603 comedi_event(dev, s);
607 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
610 for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
611 #ifdef PCI171x_PARANOIDCHECK
612 sampl = inw(dev->iobase + PCI171x_AD_DATA);
613 DPRINTK("%04x:", sampl);
614 if (this_board->cardtype != TYPE_PCI1713)
615 if ((sampl & 0xf000) !=
616 devpriv->act_chanlist[s->async->cur_chan]) {
618 ("comedi: A/D data dropout: received data from channel %d, expected %d!\n",
619 (sampl & 0xf000) >> 12,
620 (devpriv->act_chanlist[s->async->
621 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++;
644 DPRINTK("adv_pci1710 EDBG: EOS1 bic %d bip %d buc %d bup %d\n", s->async->buf_int_count, s->async->buf_int_ptr, s->async->buf_user_count, s->async->buf_user_ptr);
645 DPRINTK("adv_pci1710 EDBG: EOS2\n");
646 if ((!devpriv->neverending_ai) && (devpriv->ai_act_scan >= devpriv->ai_scans)) { /* all data sampled */
647 pci171x_ai_cancel(dev, s);
648 s->async->events |= COMEDI_CB_EOA;
649 comedi_event(dev, s);
655 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
656 DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_every_sample(...)\n");
658 comedi_event(dev, s);
662 ==============================================================================
664 static int move_block_from_fifo(struct comedi_device *dev, struct comedi_subdevice *s,
668 #ifdef PCI171x_PARANOIDCHECK
671 DPRINTK("adv_pci1710 EDBG: BGN: move_block_from_fifo(...,%d,%d)\n", n,
673 j = s->async->cur_chan;
674 for (i = 0; i < n; i++) {
675 #ifdef PCI171x_PARANOIDCHECK
676 sampl = inw(dev->iobase + PCI171x_AD_DATA);
677 if (this_board->cardtype != TYPE_PCI1713)
678 if ((sampl & 0xf000) != devpriv->act_chanlist[j]) {
680 ("comedi%d: A/D FIFO data dropout: received data from channel %d, expected %d! (%d/%d/%d/%d/%d/%4x)\n",
681 dev->minor, (sampl & 0xf000) >> 12,
683 act_chanlist[j] & 0xf000) >> 12,
684 i, j, devpriv->ai_act_scan, n, turn,
686 pci171x_ai_cancel(dev, s);
688 COMEDI_CB_EOA | COMEDI_CB_ERROR;
689 comedi_event(dev, s);
692 comedi_buf_put(s->async, sampl & 0x0fff);
694 comedi_buf_put(s->async,
695 inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
698 if (j >= devpriv->ai_n_chan) {
700 devpriv->ai_act_scan++;
703 DPRINTK("adv_pci1710 EDBG: END: move_block_from_fifo(...)\n");
708 ==============================================================================
710 static void interrupt_pci1710_half_fifo(void *d)
712 struct comedi_device *dev = d;
713 struct comedi_subdevice *s = dev->subdevices + 0;
716 DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_half_fifo(...)\n");
717 m = inw(dev->iobase + PCI171x_STATUS);
718 if (!(m & Status_FH)) {
719 rt_printk("comedi%d: A/D FIFO not half full! (%4x)\n",
721 pci171x_ai_cancel(dev, s);
722 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
723 comedi_event(dev, s);
728 ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
730 pci171x_ai_cancel(dev, s);
731 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
732 comedi_event(dev, s);
736 samplesinbuf = this_board->fifo_half_size;
737 if (samplesinbuf * sizeof(short) >= devpriv->ai_data_len) {
738 m = devpriv->ai_data_len / sizeof(short);
739 if (move_block_from_fifo(dev, s, m, 0))
745 if (move_block_from_fifo(dev, s, samplesinbuf, 1))
749 if (!devpriv->neverending_ai)
750 if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data sampled */
751 pci171x_ai_cancel(dev, s);
752 s->async->events |= COMEDI_CB_EOA;
753 comedi_event(dev, s);
756 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
757 DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_half_fifo(...)\n");
759 comedi_event(dev, s);
763 ==============================================================================
765 static irqreturn_t interrupt_service_pci1710(int irq, void *d)
767 struct comedi_device *dev = d;
769 DPRINTK("adv_pci1710 EDBG: BGN: interrupt_service_pci1710(%d,...)\n",
771 if (!dev->attached) /* is device attached? */
772 return IRQ_NONE; /* no, exit */
774 if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ)) /* is this interrupt from our board? */
775 return IRQ_NONE; /* no, exit */
777 DPRINTK("adv_pci1710 EDBG: interrupt_service_pci1710() ST: %4x\n",
778 inw(dev->iobase + PCI171x_STATUS));
780 if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */
782 devpriv->CntrlReg &= Control_CNT0;
783 devpriv->CntrlReg |= Control_SW; /* set software trigger */
784 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
785 devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
786 outb(0, dev->iobase + PCI171x_CLRFIFO);
787 outb(0, dev->iobase + PCI171x_CLRINT);
788 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
789 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
791 start_pacer(dev, 1, devpriv->ai_et_div1, devpriv->ai_et_div2);
794 if (devpriv->ai_eos) { /* We use FIFO half full INT or not? */
795 interrupt_pci1710_every_sample(d);
797 interrupt_pci1710_half_fifo(d);
799 DPRINTK("adv_pci1710 EDBG: END: interrupt_service_pci1710(...)\n");
804 ==============================================================================
806 static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev,
807 struct comedi_subdevice *s)
809 unsigned int divisor1, divisor2;
812 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_docmd_and_mode(%d,...)\n",
814 start_pacer(dev, -1, 0, 0); /* stop pacer */
816 seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
820 setup_channel_list(dev, s, devpriv->ai_chanlist,
821 devpriv->ai_n_chan, seglen);
823 outb(0, dev->iobase + PCI171x_CLRFIFO);
824 outb(0, dev->iobase + PCI171x_CLRINT);
826 devpriv->ai_do = mode;
828 devpriv->ai_act_scan = 0;
829 s->async->cur_chan = 0;
830 devpriv->ai_buf_ptr = 0;
831 devpriv->neverending_ai = 0;
833 devpriv->CntrlReg &= Control_CNT0;
834 if ((devpriv->ai_flags & TRIG_WAKE_EOS)) { /* don't we want wake up every scan? devpriv->ai_eos=1; */
837 devpriv->CntrlReg |= Control_ONEFH;
841 if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1)) {
842 devpriv->neverending_ai = 1;
843 } /* well, user want neverending */
845 devpriv->neverending_ai = 0;
850 if (devpriv->ai_timer1 < this_board->ai_ns_min)
851 devpriv->ai_timer1 = this_board->ai_ns_min;
852 devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
854 devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
856 ~(Control_PACER | Control_ONEFH | Control_GATE);
857 devpriv->CntrlReg |= Control_EXT;
862 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
863 &divisor2, &devpriv->ai_timer1,
864 devpriv->ai_flags & TRIG_ROUND_MASK);
865 DPRINTK("adv_pci1710 EDBG: OSC base=%u div1=%u div2=%u timer=%u\n", devpriv->i8254_osc_base, divisor1, divisor2, devpriv->ai_timer1);
866 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
869 start_pacer(dev, mode, divisor1, divisor2);
871 devpriv->ai_et_div1 = divisor1;
872 devpriv->ai_et_div2 = divisor2;
876 devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
877 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
881 DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_docmd_and_mode(...)\n");
885 #ifdef PCI171X_EXTDEBUG
887 ==============================================================================
889 static void pci171x_cmdtest_out(int e, struct comedi_cmd *cmd)
891 rt_printk("adv_pci1710 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e,
892 cmd->start_src, cmd->scan_begin_src, cmd->convert_src);
893 rt_printk("adv_pci1710 e=%d startarg=%d scanarg=%d convarg=%d\n", e,
894 cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg);
895 rt_printk("adv_pci1710 e=%d stopsrc=%x scanend=%x\n", e, cmd->stop_src,
897 rt_printk("adv_pci1710 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n",
898 e, cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len);
903 ==============================================================================
905 static int pci171x_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
906 struct comedi_cmd *cmd)
909 int tmp, divisor1, divisor2;
911 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...)\n");
912 #ifdef PCI171X_EXTDEBUG
913 pci171x_cmdtest_out(-1, cmd);
915 /* step 1: make sure trigger sources are trivially valid */
917 tmp = cmd->start_src;
918 cmd->start_src &= TRIG_NOW | TRIG_EXT;
919 if (!cmd->start_src || tmp != cmd->start_src)
922 tmp = cmd->scan_begin_src;
923 cmd->scan_begin_src &= TRIG_FOLLOW;
924 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
927 tmp = cmd->convert_src;
928 cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
929 if (!cmd->convert_src || tmp != cmd->convert_src)
932 tmp = cmd->scan_end_src;
933 cmd->scan_end_src &= TRIG_COUNT;
934 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
938 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
939 if (!cmd->stop_src || tmp != cmd->stop_src)
943 #ifdef PCI171X_EXTDEBUG
944 pci171x_cmdtest_out(1, cmd);
946 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=1\n", err);
950 /* step 2: make sure trigger sources are unique and mutually compatible */
952 if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) {
953 cmd->start_src = TRIG_NOW;
957 if (cmd->scan_begin_src != TRIG_FOLLOW) {
958 cmd->scan_begin_src = TRIG_FOLLOW;
962 if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
965 if (cmd->scan_end_src != TRIG_COUNT) {
966 cmd->scan_end_src = TRIG_COUNT;
970 if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
974 #ifdef PCI171X_EXTDEBUG
975 pci171x_cmdtest_out(2, cmd);
977 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=2\n", err);
981 /* step 3: make sure arguments are trivially compatible */
983 if (cmd->start_arg != 0) {
988 if (cmd->scan_begin_arg != 0) {
989 cmd->scan_begin_arg = 0;
993 if (cmd->convert_src == TRIG_TIMER) {
994 if (cmd->convert_arg < this_board->ai_ns_min) {
995 cmd->convert_arg = this_board->ai_ns_min;
998 } else { /* TRIG_FOLLOW */
999 if (cmd->convert_arg != 0) {
1000 cmd->convert_arg = 0;
1005 if (!cmd->chanlist_len) {
1006 cmd->chanlist_len = 1;
1009 if (cmd->chanlist_len > this_board->n_aichan) {
1010 cmd->chanlist_len = this_board->n_aichan;
1013 if (cmd->scan_end_arg != cmd->chanlist_len) {
1014 cmd->scan_end_arg = cmd->chanlist_len;
1017 if (cmd->stop_src == TRIG_COUNT) {
1018 if (!cmd->stop_arg) {
1022 } else { /* TRIG_NONE */
1023 if (cmd->stop_arg != 0) {
1030 #ifdef PCI171X_EXTDEBUG
1031 pci171x_cmdtest_out(3, cmd);
1033 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=3\n", err);
1037 /* step 4: fix up any arguments */
1039 if (cmd->convert_src == TRIG_TIMER) {
1040 tmp = cmd->convert_arg;
1041 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
1042 &divisor2, &cmd->convert_arg,
1043 cmd->flags & TRIG_ROUND_MASK);
1044 if (cmd->convert_arg < this_board->ai_ns_min)
1045 cmd->convert_arg = this_board->ai_ns_min;
1046 if (tmp != cmd->convert_arg)
1051 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=4\n", err);
1055 /* step 5: complain about special chanlist considerations */
1057 if (cmd->chanlist) {
1058 if (!check_channel_list(dev, s, cmd->chanlist,
1060 return 5; /* incorrect channels list */
1063 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) ret=0\n");
1068 ==============================================================================
1070 static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1072 struct comedi_cmd *cmd = &s->async->cmd;
1074 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmd(...)\n");
1075 devpriv->ai_n_chan = cmd->chanlist_len;
1076 devpriv->ai_chanlist = cmd->chanlist;
1077 devpriv->ai_flags = cmd->flags;
1078 devpriv->ai_data_len = s->async->prealloc_bufsz;
1079 devpriv->ai_data = s->async->prealloc_buf;
1080 devpriv->ai_timer1 = 0;
1081 devpriv->ai_timer2 = 0;
1083 if (cmd->stop_src == TRIG_COUNT) {
1084 devpriv->ai_scans = cmd->stop_arg;
1086 devpriv->ai_scans = 0;
1089 if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 2, 3 */
1090 if (cmd->convert_src == TRIG_TIMER) { /* mode 1 and 2 */
1091 devpriv->ai_timer1 = cmd->convert_arg;
1092 return pci171x_ai_docmd_and_mode(cmd->start_src ==
1093 TRIG_EXT ? 2 : 1, dev, s);
1095 if (cmd->convert_src == TRIG_EXT) { /* mode 3 */
1096 return pci171x_ai_docmd_and_mode(3, dev, s);
1104 ==============================================================================
1105 Check if channel list from user is builded correctly
1106 If it's ok, then program scan/gain logic.
1107 This works for all cards.
1109 static int check_channel_list(struct comedi_device *dev, struct comedi_subdevice *s,
1110 unsigned int *chanlist, unsigned int n_chan)
1112 unsigned int chansegment[32];
1113 unsigned int i, nowmustbechan, seglen, segpos;
1115 DPRINTK("adv_pci1710 EDBG: check_channel_list(...,%d)\n", n_chan);
1116 /* correct channel and range number check itself comedi/range.c */
1118 comedi_error(dev, "range/channel list is empty!");
1123 chansegment[0] = chanlist[0]; /* first channel is everytime ok */
1124 for (i = 1, seglen = 1; i < n_chan; i++, seglen++) { /* build part of chanlist */
1125 /* rt_printk("%d. %d %d\n",i,CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
1126 if (chanlist[0] == chanlist[i])
1127 break; /* we detect loop, this must by finish */
1128 if (CR_CHAN(chanlist[i]) & 1) /* odd channel cann't by differencial */
1129 if (CR_AREF(chanlist[i]) == AREF_DIFF) {
1131 "Odd channel can't be differential input!\n");
1135 (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
1136 if (CR_AREF(chansegment[i - 1]) == AREF_DIFF)
1137 nowmustbechan = (nowmustbechan + 1) % s->n_chan;
1138 if (nowmustbechan != CR_CHAN(chanlist[i])) { /* channel list isn't continous :-( */
1140 ("channel list must be continous! chanlist[%i]=%d but must be %d or %d!\n",
1141 i, CR_CHAN(chanlist[i]), nowmustbechan,
1142 CR_CHAN(chanlist[0]));
1145 chansegment[i] = chanlist[i]; /* well, this is next correct channel in list */
1148 for (i = 0, segpos = 0; i < n_chan; i++) { /* check whole chanlist */
1149 /* rt_printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
1150 if (chanlist[i] != chansegment[i % seglen]) {
1152 ("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
1153 i, CR_CHAN(chansegment[i]),
1154 CR_RANGE(chansegment[i]),
1155 CR_AREF(chansegment[i]),
1156 CR_CHAN(chanlist[i % seglen]),
1157 CR_RANGE(chanlist[i % seglen]),
1158 CR_AREF(chansegment[i % seglen]));
1159 return 0; /* chan/gain list is strange */
1168 static void setup_channel_list(struct comedi_device *dev, struct comedi_subdevice *s,
1169 unsigned int *chanlist, unsigned int n_chan, unsigned int seglen)
1171 unsigned int i, range, chanprog;
1173 DPRINTK("adv_pci1710 EDBG: setup_channel_list(...,%d,%d)\n", n_chan,
1175 devpriv->act_chanlist_len = seglen;
1176 devpriv->act_chanlist_pos = 0;
1178 DPRINTK("SegLen: %d\n", seglen);
1179 for (i = 0; i < seglen; i++) { /* store range list to card */
1180 chanprog = muxonechan[CR_CHAN(chanlist[i])];
1181 outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */
1182 range = this_board->rangecode_ai[CR_RANGE(chanlist[i])];
1183 if (CR_AREF(chanlist[i]) == AREF_DIFF)
1185 outw(range, dev->iobase + PCI171x_RANGE); /* select gain */
1186 #ifdef PCI171x_PARANOIDCHECK
1187 devpriv->act_chanlist[i] =
1188 (CR_CHAN(chanlist[i]) << 12) & 0xf000;
1190 DPRINTK("GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range,
1191 devpriv->act_chanlist[i]);
1194 devpriv->ai_et_MuxVal =
1195 CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
1196 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX); /* select channel interval to scan */
1197 DPRINTK("MUX: %4x L%4x.H%4x\n",
1198 CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8),
1199 CR_CHAN(chanlist[0]), CR_CHAN(chanlist[seglen - 1]));
1203 ==============================================================================
1205 static void start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1,
1206 unsigned int divisor2)
1208 DPRINTK("adv_pci1710 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode,
1209 divisor1, divisor2);
1210 outw(0xb4, dev->iobase + PCI171x_CNTCTRL);
1211 outw(0x74, dev->iobase + PCI171x_CNTCTRL);
1214 outw(divisor2 & 0xff, dev->iobase + PCI171x_CNT2);
1215 outw((divisor2 >> 8) & 0xff, dev->iobase + PCI171x_CNT2);
1216 outw(divisor1 & 0xff, dev->iobase + PCI171x_CNT1);
1217 outw((divisor1 >> 8) & 0xff, dev->iobase + PCI171x_CNT1);
1219 DPRINTK("adv_pci1710 EDBG: END: start_pacer(...)\n");
1223 ==============================================================================
1225 static int pci171x_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
1227 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cancel(...)\n");
1229 switch (this_board->cardtype) {
1231 devpriv->CntrlReg &= Control_CNT0;
1232 devpriv->CntrlReg |= Control_SW;
1234 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */
1235 start_pacer(dev, -1, 0, 0);
1236 outb(0, dev->iobase + PCI171x_CLRFIFO);
1237 outb(0, dev->iobase + PCI171x_CLRINT);
1242 devpriv->ai_act_scan = 0;
1243 s->async->cur_chan = 0;
1244 devpriv->ai_buf_ptr = 0;
1245 devpriv->neverending_ai = 0;
1247 DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_cancel(...)\n");
1252 ==============================================================================
1254 static int pci171x_reset(struct comedi_device *dev)
1256 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_reset(...)\n");
1257 outw(0x30, dev->iobase + PCI171x_CNTCTRL);
1258 devpriv->CntrlReg = Control_SW | Control_CNT0; /* Software trigger, CNT0=external */
1259 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */
1260 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
1261 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
1262 start_pacer(dev, -1, 0, 0); /* stop 8254 */
1263 devpriv->da_ranges = 0;
1264 if (this_board->n_aochan) {
1265 outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); /* set DACs to 0..5V */
1266 outw(0, dev->iobase + PCI171x_DA1); /* set DA outputs to 0V */
1267 devpriv->ao_data[0] = 0x0000;
1268 if (this_board->n_aochan > 1) {
1269 outw(0, dev->iobase + PCI171x_DA2);
1270 devpriv->ao_data[1] = 0x0000;
1273 outw(0, dev->iobase + PCI171x_DO); /* digital outputs to 0 */
1274 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
1275 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
1277 DPRINTK("adv_pci1710 EDBG: END: pci171x_reset(...)\n");
1282 ==============================================================================
1284 static int pci1720_reset(struct comedi_device *dev)
1286 DPRINTK("adv_pci1710 EDBG: BGN: pci1720_reset(...)\n");
1287 outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT); /* set synchronous output mode */
1288 devpriv->da_ranges = 0xAA;
1289 outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE); /* set all ranges to +/-5V */
1290 outw(0x0800, dev->iobase + PCI1720_DA0); /* set outputs to 0V */
1291 outw(0x0800, dev->iobase + PCI1720_DA1);
1292 outw(0x0800, dev->iobase + PCI1720_DA2);
1293 outw(0x0800, dev->iobase + PCI1720_DA3);
1294 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
1295 devpriv->ao_data[0] = 0x0800;
1296 devpriv->ao_data[1] = 0x0800;
1297 devpriv->ao_data[2] = 0x0800;
1298 devpriv->ao_data[3] = 0x0800;
1299 DPRINTK("adv_pci1710 EDBG: END: pci1720_reset(...)\n");
1304 ==============================================================================
1306 static int pci1710_reset(struct comedi_device *dev)
1308 DPRINTK("adv_pci1710 EDBG: BGN: pci1710_reset(...)\n");
1309 switch (this_board->cardtype) {
1311 return pci1720_reset(dev);
1313 return pci171x_reset(dev);
1315 DPRINTK("adv_pci1710 EDBG: END: pci1710_reset(...)\n");
1319 ==============================================================================
1321 static int pci1710_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1323 struct comedi_subdevice *s;
1324 int ret, subdev, n_subdevices;
1326 unsigned long iobase;
1327 struct pci_dev *pcidev;
1328 int opt_bus, opt_slot;
1330 unsigned char pci_bus, pci_slot, pci_func;
1334 rt_printk("comedi%d: adv_pci1710: ", dev->minor);
1336 opt_bus = it->options[0];
1337 opt_slot = it->options[1];
1339 if ((ret = alloc_private(dev, sizeof(struct pci1710_private))) < 0) {
1340 rt_printk(" - Allocation failed!\n");
1344 /* Look for matching PCI device */
1345 errstr = "not found!";
1347 board_index = this_board - boardtypes;
1348 while (NULL != (pcidev = pci_get_device(PCI_VENDOR_ID_ADVANTECH,
1349 PCI_ANY_ID, pcidev))) {
1350 if(strcmp(this_board->name, DRV_NAME) == 0)
1352 for(i = 0; i < n_boardtypes; ++i)
1354 if(pcidev->device == boardtypes[i].device_id)
1360 if(i == n_boardtypes) continue;
1363 if(pcidev->device != boardtypes[board_index].device_id) continue;
1366 /* Found matching vendor/device. */
1367 if (opt_bus || opt_slot) {
1368 /* Check bus/slot. */
1369 if (opt_bus != pcidev->bus->number
1370 || opt_slot != PCI_SLOT(pcidev->devfn))
1371 continue; /* no match */
1374 * Look for device that isn't in use.
1375 * Enable PCI device and request regions.
1377 if (comedi_pci_enable(pcidev, DRV_NAME)) {
1378 errstr = "failed to enable PCI device and request regions!";
1381 /* fixup board_ptr in case we were using the dummy entry with the driver name */
1382 dev->board_ptr = &boardtypes[board_index];
1387 if (opt_bus || opt_slot) {
1388 rt_printk(" - Card at b:s %d:%d %s\n",
1389 opt_bus, opt_slot, errstr);
1391 rt_printk(" - Card %s\n", errstr);
1396 pci_bus = pcidev->bus->number;
1397 pci_slot = PCI_SLOT(pcidev->devfn);
1398 pci_func = PCI_FUNC(pcidev->devfn);
1400 iobase = pci_resource_start(pcidev, 2);
1402 rt_printk(", b:s:f=%d:%d:%d, io=0x%4lx", pci_bus, pci_slot, pci_func,
1405 dev->iobase = iobase;
1407 dev->board_name = this_board->name;
1408 devpriv->pcidev = pcidev;
1411 if (this_board->n_aichan)
1413 if (this_board->n_aochan)
1415 if (this_board->n_dichan)
1417 if (this_board->n_dochan)
1419 if (this_board->n_counter)
1422 if ((ret = alloc_subdevices(dev, n_subdevices)) < 0) {
1423 rt_printk(" - Allocation failed!\n");
1429 if (this_board->have_irq) {
1431 if (comedi_request_irq(irq, interrupt_service_pci1710,
1432 IRQF_SHARED, "Advantech PCI-1710",
1435 (", unable to allocate IRQ %d, DISABLING IT",
1437 irq = 0; /* Can't use IRQ */
1439 rt_printk(", irq=%u", irq);
1442 rt_printk(", IRQ disabled");
1454 if (this_board->n_aichan) {
1455 s = dev->subdevices + subdev;
1456 dev->read_subdev = s;
1457 s->type = COMEDI_SUBD_AI;
1458 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
1459 if (this_board->n_aichand)
1460 s->subdev_flags |= SDF_DIFF;
1461 s->n_chan = this_board->n_aichan;
1462 s->maxdata = this_board->ai_maxdata;
1463 s->len_chanlist = this_board->n_aichan;
1464 s->range_table = this_board->rangelist_ai;
1465 s->cancel = pci171x_ai_cancel;
1466 s->insn_read = pci171x_insn_read_ai;
1468 s->subdev_flags |= SDF_CMD_READ;
1469 s->do_cmdtest = pci171x_ai_cmdtest;
1470 s->do_cmd = pci171x_ai_cmd;
1472 devpriv->i8254_osc_base = 100; /* 100ns=10MHz */
1476 if (this_board->n_aochan) {
1477 s = dev->subdevices + subdev;
1478 s->type = COMEDI_SUBD_AO;
1479 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1480 s->n_chan = this_board->n_aochan;
1481 s->maxdata = this_board->ao_maxdata;
1482 s->len_chanlist = this_board->n_aochan;
1483 s->range_table = this_board->rangelist_ao;
1484 switch (this_board->cardtype) {
1486 s->insn_write = pci1720_insn_write_ao;
1489 s->insn_write = pci171x_insn_write_ao;
1492 s->insn_read = pci171x_insn_read_ao;
1496 if (this_board->n_dichan) {
1497 s = dev->subdevices + subdev;
1498 s->type = COMEDI_SUBD_DI;
1499 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
1500 s->n_chan = this_board->n_dichan;
1502 s->len_chanlist = this_board->n_dichan;
1503 s->range_table = &range_digital;
1504 s->io_bits = 0; /* all bits input */
1505 s->insn_bits = pci171x_insn_bits_di;
1509 if (this_board->n_dochan) {
1510 s = dev->subdevices + subdev;
1511 s->type = COMEDI_SUBD_DO;
1512 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1513 s->n_chan = this_board->n_dochan;
1515 s->len_chanlist = this_board->n_dochan;
1516 s->range_table = &range_digital;
1517 s->io_bits = (1 << this_board->n_dochan) - 1; /* all bits output */
1519 s->insn_bits = pci171x_insn_bits_do;
1523 if (this_board->n_counter) {
1524 s = dev->subdevices + subdev;
1525 s->type = COMEDI_SUBD_COUNTER;
1526 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1527 s->n_chan = this_board->n_counter;
1528 s->len_chanlist = this_board->n_counter;
1529 s->maxdata = 0xffff;
1530 s->range_table = &range_unknown;
1531 s->insn_read = pci171x_insn_counter_read;
1532 s->insn_write = pci171x_insn_counter_write;
1533 s->insn_config = pci171x_insn_counter_config;
1543 ==============================================================================
1545 static int pci1710_detach(struct comedi_device *dev)
1552 comedi_free_irq(dev->irq, dev);
1553 if (devpriv->pcidev) {
1555 comedi_pci_disable(devpriv->pcidev);
1557 pci_dev_put(devpriv->pcidev);
1565 ==============================================================================
1567 COMEDI_PCI_INITCLEANUP(driver_pci1710, pci1710_pci_table);
1569 ==============================================================================