staging: comedi: adv_pci1710: update the MODULE_DESCRIPTION
[firefly-linux-kernel-4.4.55.git] / drivers / staging / comedi / drivers / adv_pci1710.c
1 /*
2  * comedi/drivers/adv_pci1710.c
3  *
4  * Author: Michal Dobes <dobes@tesnet.cz>
5  *
6  * Thanks to ZhenGang Shang <ZhenGang.Shang@Advantech.com.cn>
7  * for testing and informations.
8  *
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
12  *
13  * Options:
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
17  *
18 */
19 /*
20 Driver: adv_pci1710
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,
26   PCI-1731
27 Status: works
28
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.
32
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
35 PCI driver.
36
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
41         device will be used.
42 */
43
44 #include <linux/module.h>
45 #include <linux/pci.h>
46 #include <linux/interrupt.h>
47
48 #include "../comedidev.h"
49
50 #include "comedi_fc.h"
51 #include "8253.h"
52 #include "amcc_s5933.h"
53
54 /* hardware types of the cards */
55 #define TYPE_PCI171X    0
56 #define TYPE_PCI1713    2
57 #define TYPE_PCI1720    3
58
59 #define PCI171x_AD_DATA  0      /* R:   A/D data */
60 #define PCI171x_SOFTTRG  0      /* W:   soft trigger for A/D */
61 #define PCI171x_RANGE    2      /* W:   A/D gain/range register */
62 #define PCI171x_MUX      4      /* W:   A/D multiplexor control */
63 #define PCI171x_STATUS   6      /* R:   status register */
64 #define PCI171x_CONTROL  6      /* W:   control register */
65 #define PCI171x_CLRINT   8      /* W:   clear interrupts request */
66 #define PCI171x_CLRFIFO  9      /* W:   clear FIFO */
67 #define PCI171x_DA1     10      /* W:   D/A register */
68 #define PCI171x_DA2     12      /* W:   D/A register */
69 #define PCI171x_DAREF   14      /* W:   D/A reference control */
70 #define PCI171x_DI      16      /* R:   digi inputs */
71 #define PCI171x_DO      16      /* R:   digi inputs */
72
73 #define PCI171X_TIMER_BASE      0x18
74
75 #define PCI171x_CNT0    24      /* R/W: 8254 counter 0 */
76 #define PCI171x_CNT1    26      /* R/W: 8254 counter 1 */
77 #define PCI171x_CNT2    28      /* R/W: 8254 counter 2 */
78 #define PCI171x_CNTCTRL 30      /* W:   8254 counter control */
79
80 /* upper bits from status register (PCI171x_STATUS) (lower is same with control
81  * reg) */
82 #define Status_FE       0x0100  /* 1=FIFO is empty */
83 #define Status_FH       0x0200  /* 1=FIFO is half full */
84 #define Status_FF       0x0400  /* 1=FIFO is full, fatal error */
85 #define Status_IRQ      0x0800  /* 1=IRQ occurred */
86 /* bits from control register (PCI171x_CONTROL) */
87 #define Control_CNT0    0x0040  /* 1=CNT0 have external source,
88                                  * 0=have internal 100kHz source */
89 #define Control_ONEFH   0x0020  /* 1=IRQ on FIFO is half full, 0=every sample */
90 #define Control_IRQEN   0x0010  /* 1=enable IRQ */
91 #define Control_GATE    0x0008  /* 1=enable external trigger GATE (8254?) */
92 #define Control_EXT     0x0004  /* 1=external trigger source */
93 #define Control_PACER   0x0002  /* 1=enable internal 8254 trigger source */
94 #define Control_SW      0x0001  /* 1=enable software trigger source */
95 /* bits from counter control register (PCI171x_CNTCTRL) */
96 #define Counter_BCD     0x0001  /* 0 = binary counter, 1 = BCD counter */
97 #define Counter_M0      0x0002  /* M0-M2 select modes 0-5 */
98 #define Counter_M1      0x0004  /* 000 = mode 0, 010 = mode 2 ... */
99 #define Counter_M2      0x0008
100 #define Counter_RW0     0x0010  /* RW0/RW1 select read/write mode */
101 #define Counter_RW1     0x0020
102 #define Counter_SC0     0x0040  /* Select Counter. Only 00 or 11 may */
103 #define Counter_SC1     0x0080  /* be used, 00 for CNT0,
104                                  * 11 for read-back command */
105
106 #define PCI1720_DA0      0      /* W:   D/A register 0 */
107 #define PCI1720_DA1      2      /* W:   D/A register 1 */
108 #define PCI1720_DA2      4      /* W:   D/A register 2 */
109 #define PCI1720_DA3      6      /* W:   D/A register 3 */
110 #define PCI1720_RANGE    8      /* R/W: D/A range register */
111 #define PCI1720_SYNCOUT  9      /* W:   D/A synchronized output register */
112 #define PCI1720_SYNCONT 15      /* R/W: D/A synchronized control */
113
114 /* D/A synchronized control (PCI1720_SYNCONT) */
115 #define Syncont_SC0      1      /* set synchronous output mode */
116
117 static const struct comedi_lrange range_pci1710_3 = {
118         9, {
119                 BIP_RANGE(5),
120                 BIP_RANGE(2.5),
121                 BIP_RANGE(1.25),
122                 BIP_RANGE(0.625),
123                 BIP_RANGE(10),
124                 UNI_RANGE(10),
125                 UNI_RANGE(5),
126                 UNI_RANGE(2.5),
127                 UNI_RANGE(1.25)
128         }
129 };
130
131 static const char range_codes_pci1710_3[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
132                                               0x10, 0x11, 0x12, 0x13 };
133
134 static const struct comedi_lrange range_pci1710hg = {
135         12, {
136                 BIP_RANGE(5),
137                 BIP_RANGE(0.5),
138                 BIP_RANGE(0.05),
139                 BIP_RANGE(0.005),
140                 BIP_RANGE(10),
141                 BIP_RANGE(1),
142                 BIP_RANGE(0.1),
143                 BIP_RANGE(0.01),
144                 UNI_RANGE(10),
145                 UNI_RANGE(1),
146                 UNI_RANGE(0.1),
147                 UNI_RANGE(0.01)
148         }
149 };
150
151 static const char range_codes_pci1710hg[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
152                                               0x05, 0x06, 0x07, 0x10, 0x11,
153                                               0x12, 0x13 };
154
155 static const struct comedi_lrange range_pci17x1 = {
156         5, {
157                 BIP_RANGE(10),
158                 BIP_RANGE(5),
159                 BIP_RANGE(2.5),
160                 BIP_RANGE(1.25),
161                 BIP_RANGE(0.625)
162         }
163 };
164
165 static const char range_codes_pci17x1[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
166
167 static const struct comedi_lrange range_pci1720 = {
168         4, {
169                 UNI_RANGE(5),
170                 UNI_RANGE(10),
171                 BIP_RANGE(5),
172                 BIP_RANGE(10)
173         }
174 };
175
176 static const struct comedi_lrange range_pci171x_da = {
177         2, {
178                 UNI_RANGE(5),
179                 UNI_RANGE(10)
180         }
181 };
182
183 enum pci1710_boardid {
184         BOARD_PCI1710,
185         BOARD_PCI1710HG,
186         BOARD_PCI1711,
187         BOARD_PCI1713,
188         BOARD_PCI1720,
189         BOARD_PCI1731,
190 };
191
192 struct boardtype {
193         const char *name;       /*  board name */
194         char cardtype;          /*  0=1710& co. 2=1713, ... */
195         int n_aichan;           /*  num of A/D chans */
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 has_irq:1;
200         unsigned int has_large_fifo:1;  /* 4K or 1K FIFO */
201         unsigned int has_diff_ai:1;
202         unsigned int has_ao:1;
203         unsigned int has_di_do:1;
204         unsigned int has_counter:1;
205 };
206
207 static const struct boardtype boardtypes[] = {
208         [BOARD_PCI1710] = {
209                 .name           = "pci1710",
210                 .cardtype       = TYPE_PCI171X,
211                 .n_aichan       = 16,
212                 .rangelist_ai   = &range_pci1710_3,
213                 .rangecode_ai   = range_codes_pci1710_3,
214                 .rangelist_ao   = &range_pci171x_da,
215                 .has_irq        = 1,
216                 .has_large_fifo = 1,
217                 .has_diff_ai    = 1,
218                 .has_ao         = 1,
219                 .has_di_do      = 1,
220                 .has_counter    = 1,
221         },
222         [BOARD_PCI1710HG] = {
223                 .name           = "pci1710hg",
224                 .cardtype       = TYPE_PCI171X,
225                 .n_aichan       = 16,
226                 .rangelist_ai   = &range_pci1710hg,
227                 .rangecode_ai   = range_codes_pci1710hg,
228                 .rangelist_ao   = &range_pci171x_da,
229                 .has_irq        = 1,
230                 .has_large_fifo = 1,
231                 .has_diff_ai    = 1,
232                 .has_ao         = 1,
233                 .has_di_do      = 1,
234                 .has_counter    = 1,
235         },
236         [BOARD_PCI1711] = {
237                 .name           = "pci1711",
238                 .cardtype       = TYPE_PCI171X,
239                 .n_aichan       = 16,
240                 .rangelist_ai   = &range_pci17x1,
241                 .rangecode_ai   = range_codes_pci17x1,
242                 .rangelist_ao   = &range_pci171x_da,
243                 .has_irq        = 1,
244                 .has_ao         = 1,
245                 .has_di_do      = 1,
246                 .has_counter    = 1,
247         },
248         [BOARD_PCI1713] = {
249                 .name           = "pci1713",
250                 .cardtype       = TYPE_PCI1713,
251                 .n_aichan       = 32,
252                 .rangelist_ai   = &range_pci1710_3,
253                 .rangecode_ai   = range_codes_pci1710_3,
254                 .has_irq        = 1,
255                 .has_large_fifo = 1,
256                 .has_diff_ai    = 1,
257         },
258         [BOARD_PCI1720] = {
259                 .name           = "pci1720",
260                 .cardtype       = TYPE_PCI1720,
261                 .rangelist_ao   = &range_pci1720,
262                 .has_ao         = 1,
263         },
264         [BOARD_PCI1731] = {
265                 .name           = "pci1731",
266                 .cardtype       = TYPE_PCI171X,
267                 .n_aichan       = 16,
268                 .rangelist_ai   = &range_pci17x1,
269                 .rangecode_ai   = range_codes_pci17x1,
270                 .has_irq        = 1,
271                 .has_di_do      = 1,
272         },
273 };
274
275 struct pci1710_private {
276         unsigned int max_samples;
277         unsigned int CntrlReg;  /*  Control register */
278         unsigned char ai_et;
279         unsigned int ai_et_CntrlReg;
280         unsigned int ai_et_MuxVal;
281         unsigned int next_divisor1;
282         unsigned int next_divisor2;
283         unsigned int divisor1;
284         unsigned int divisor2;
285         unsigned int act_chanlist[32];  /*  list of scanned channel */
286         unsigned char saved_seglen;     /* len of the non-repeating chanlist */
287         unsigned char da_ranges;        /*  copy of D/A outpit range register */
288         unsigned int cnt0_write_wait;   /* after a write, wait for update of the
289                                          * internal state */
290 };
291
292 /*  used for gain list programming */
293 static const unsigned int muxonechan[] = {
294         0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707,
295         0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f,
296         0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717,
297         0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f
298 };
299
300 static int pci171x_ai_dropout(struct comedi_device *dev,
301                               struct comedi_subdevice *s,
302                               unsigned int chan,
303                               unsigned int val)
304 {
305         const struct boardtype *board = dev->board_ptr;
306         struct pci1710_private *devpriv = dev->private;
307
308         if (board->cardtype != TYPE_PCI1713) {
309                 if ((val & 0xf000) != devpriv->act_chanlist[chan]) {
310                         dev_err(dev->class_dev,
311                                 "A/D data droput: received from channel %d, expected %d\n",
312                                 (val >> 12) & 0xf,
313                                 (devpriv->act_chanlist[chan] >> 12) & 0xf);
314                         return -ENODATA;
315                 }
316         }
317         return 0;
318 }
319
320 static int pci171x_ai_check_chanlist(struct comedi_device *dev,
321                                      struct comedi_subdevice *s,
322                                      struct comedi_cmd *cmd)
323 {
324         struct pci1710_private *devpriv = dev->private;
325         unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
326         unsigned int last_aref = CR_AREF(cmd->chanlist[0]);
327         unsigned int next_chan = (chan0 + 1) % s->n_chan;
328         unsigned int chansegment[32];
329         unsigned int seglen;
330         int i;
331
332         if (cmd->chanlist_len == 1) {
333                 devpriv->saved_seglen = cmd->chanlist_len;
334                 return 0;
335         }
336
337         /* first channel is always ok */
338         chansegment[0] = cmd->chanlist[0];
339
340         for (i = 1; i < cmd->chanlist_len; i++) {
341                 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
342                 unsigned int aref = CR_AREF(cmd->chanlist[i]);
343
344                 if (cmd->chanlist[0] == cmd->chanlist[i])
345                         break;  /*  we detected a loop, stop */
346
347                 if (aref == AREF_DIFF && (chan & 1)) {
348                         dev_err(dev->class_dev,
349                                 "Odd channel cannot be differential input!\n");
350                         return -EINVAL;
351                 }
352
353                 if (last_aref == AREF_DIFF)
354                         next_chan = (next_chan + 1) % s->n_chan;
355                 if (chan != next_chan) {
356                         dev_err(dev->class_dev,
357                                 "channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
358                                 i, chan, next_chan, chan0);
359                         return -EINVAL;
360                 }
361
362                 /* next correct channel in list */
363                 chansegment[i] = cmd->chanlist[i];
364                 last_aref = aref;
365         }
366         seglen = i;
367
368         for (i = 0; i < cmd->chanlist_len; i++) {
369                 if (cmd->chanlist[i] != chansegment[i % seglen]) {
370                         dev_err(dev->class_dev,
371                                 "bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
372                                 i, CR_CHAN(chansegment[i]),
373                                 CR_RANGE(chansegment[i]),
374                                 CR_AREF(chansegment[i]),
375                                 CR_CHAN(cmd->chanlist[i % seglen]),
376                                 CR_RANGE(cmd->chanlist[i % seglen]),
377                                 CR_AREF(chansegment[i % seglen]));
378                         return -EINVAL;
379                 }
380         }
381         devpriv->saved_seglen = seglen;
382
383         return 0;
384 }
385
386 static void setup_channel_list(struct comedi_device *dev,
387                                struct comedi_subdevice *s,
388                                unsigned int *chanlist, unsigned int n_chan,
389                                unsigned int seglen)
390 {
391         const struct boardtype *board = dev->board_ptr;
392         struct pci1710_private *devpriv = dev->private;
393         unsigned int i, range, chanprog;
394
395         for (i = 0; i < seglen; i++) {  /*  store range list to card */
396                 chanprog = muxonechan[CR_CHAN(chanlist[i])];
397                 outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */
398                 range = board->rangecode_ai[CR_RANGE(chanlist[i])];
399                 if (CR_AREF(chanlist[i]) == AREF_DIFF)
400                         range |= 0x0020;
401                 outw(range, dev->iobase + PCI171x_RANGE); /* select gain */
402                 devpriv->act_chanlist[i] =
403                         (CR_CHAN(chanlist[i]) << 12) & 0xf000;
404         }
405         for ( ; i < n_chan; i++) { /* store remainder of channel list */
406                 devpriv->act_chanlist[i] =
407                         (CR_CHAN(chanlist[i]) << 12) & 0xf000;
408         }
409
410         devpriv->ai_et_MuxVal =
411                 CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
412         /* select channel interval to scan */
413         outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
414 }
415
416 static int pci171x_ai_eoc(struct comedi_device *dev,
417                           struct comedi_subdevice *s,
418                           struct comedi_insn *insn,
419                           unsigned long context)
420 {
421         unsigned int status;
422
423         status = inw(dev->iobase + PCI171x_STATUS);
424         if ((status & Status_FE) == 0)
425                 return 0;
426         return -EBUSY;
427 }
428
429 static int pci171x_ai_insn_read(struct comedi_device *dev,
430                                 struct comedi_subdevice *s,
431                                 struct comedi_insn *insn,
432                                 unsigned int *data)
433 {
434         struct pci1710_private *devpriv = dev->private;
435         unsigned int chan = CR_CHAN(insn->chanspec);
436         int ret = 0;
437         int i;
438
439         devpriv->CntrlReg &= Control_CNT0;
440         devpriv->CntrlReg |= Control_SW;        /*  set software trigger */
441         outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
442         outb(0, dev->iobase + PCI171x_CLRFIFO);
443         outb(0, dev->iobase + PCI171x_CLRINT);
444
445         setup_channel_list(dev, s, &insn->chanspec, 1, 1);
446
447         for (i = 0; i < insn->n; i++) {
448                 unsigned int val;
449
450                 outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */
451
452                 ret = comedi_timeout(dev, s, insn, pci171x_ai_eoc, 0);
453                 if (ret)
454                         break;
455
456                 val = inw(dev->iobase + PCI171x_AD_DATA);
457                 ret = pci171x_ai_dropout(dev, s, chan, val);
458                 if (ret)
459                         break;
460
461                 data[i] = val & s->maxdata;
462         }
463
464         outb(0, dev->iobase + PCI171x_CLRFIFO);
465         outb(0, dev->iobase + PCI171x_CLRINT);
466
467         return ret ? ret : insn->n;
468 }
469
470 static int pci171x_ao_insn_write(struct comedi_device *dev,
471                                  struct comedi_subdevice *s,
472                                  struct comedi_insn *insn,
473                                  unsigned int *data)
474 {
475         struct pci1710_private *devpriv = dev->private;
476         unsigned int chan = CR_CHAN(insn->chanspec);
477         unsigned int range = CR_RANGE(insn->chanspec);
478         unsigned int reg = chan ? PCI171x_DA2 : PCI171x_DA1;
479         unsigned int val = s->readback[chan];
480         int i;
481
482         devpriv->da_ranges &= ~(1 << (chan << 1));
483         devpriv->da_ranges |= (range << (chan << 1));
484         outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
485
486         for (i = 0; i < insn->n; i++) {
487                 val = data[i];
488                 outw(val, dev->iobase + reg);
489         }
490
491         s->readback[chan] = val;
492
493         return insn->n;
494 }
495
496 static int pci171x_di_insn_bits(struct comedi_device *dev,
497                                 struct comedi_subdevice *s,
498                                 struct comedi_insn *insn,
499                                 unsigned int *data)
500 {
501         data[1] = inw(dev->iobase + PCI171x_DI);
502
503         return insn->n;
504 }
505
506 static int pci171x_do_insn_bits(struct comedi_device *dev,
507                                 struct comedi_subdevice *s,
508                                 struct comedi_insn *insn,
509                                 unsigned int *data)
510 {
511         if (comedi_dio_update_state(s, data))
512                 outw(s->state, dev->iobase + PCI171x_DO);
513
514         data[1] = s->state;
515
516         return insn->n;
517 }
518
519 static void pci171x_start_pacer(struct comedi_device *dev,
520                                 bool load_counters)
521 {
522         struct pci1710_private *devpriv = dev->private;
523         unsigned long timer_base = dev->iobase + PCI171X_TIMER_BASE;
524
525         i8254_set_mode(timer_base, 1, 2, I8254_MODE2 | I8254_BINARY);
526         i8254_set_mode(timer_base, 1, 1, I8254_MODE2 | I8254_BINARY);
527
528         if (load_counters) {
529                 i8254_write(timer_base, 1, 2, devpriv->divisor2);
530                 i8254_write(timer_base, 1, 1, devpriv->divisor1);
531         }
532 }
533
534 static int pci171x_counter_insn_read(struct comedi_device *dev,
535                                      struct comedi_subdevice *s,
536                                      struct comedi_insn *insn,
537                                      unsigned int *data)
538 {
539         unsigned int msb, lsb, ccntrl;
540         int i;
541
542         ccntrl = 0xD2;          /* count only */
543         for (i = 0; i < insn->n; i++) {
544                 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
545
546                 lsb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
547                 msb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
548
549                 data[0] = lsb | (msb << 8);
550         }
551
552         return insn->n;
553 }
554
555 static int pci171x_counter_insn_write(struct comedi_device *dev,
556                                       struct comedi_subdevice *s,
557                                       struct comedi_insn *insn,
558                                       unsigned int *data)
559 {
560         struct pci1710_private *devpriv = dev->private;
561         uint msb, lsb, ccntrl, status;
562
563         lsb = data[0] & 0x00FF;
564         msb = (data[0] & 0xFF00) >> 8;
565
566         /* write lsb, then msb */
567         outw(lsb, dev->iobase + PCI171x_CNT0);
568         outw(msb, dev->iobase + PCI171x_CNT0);
569
570         if (devpriv->cnt0_write_wait) {
571                 /* wait for the new count to be loaded */
572                 ccntrl = 0xE2;
573                 do {
574                         outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
575                         status = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
576                 } while (status & 0x40);
577         }
578
579         return insn->n;
580 }
581
582 static int pci171x_counter_insn_config(struct comedi_device *dev,
583                                        struct comedi_subdevice *s,
584                                        struct comedi_insn *insn,
585                                        unsigned int *data)
586 {
587 #ifdef unused
588         /* This doesn't work like a normal Comedi counter config */
589         struct pci1710_private *devpriv = dev->private;
590         uint ccntrl = 0;
591
592         devpriv->cnt0_write_wait = data[0] & 0x20;
593
594         /* internal or external clock? */
595         if (!(data[0] & 0x10)) {        /* internal */
596                 devpriv->CntrlReg &= ~Control_CNT0;
597         } else {
598                 devpriv->CntrlReg |= Control_CNT0;
599         }
600         outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
601
602         if (data[0] & 0x01)
603                 ccntrl |= Counter_M0;
604         if (data[0] & 0x02)
605                 ccntrl |= Counter_M1;
606         if (data[0] & 0x04)
607                 ccntrl |= Counter_M2;
608         if (data[0] & 0x08)
609                 ccntrl |= Counter_BCD;
610         ccntrl |= Counter_RW0;  /* set read/write mode */
611         ccntrl |= Counter_RW1;
612         outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
613 #endif
614
615         return 1;
616 }
617
618 static int pci1720_ao_insn_write(struct comedi_device *dev,
619                                  struct comedi_subdevice *s,
620                                  struct comedi_insn *insn,
621                                  unsigned int *data)
622 {
623         struct pci1710_private *devpriv = dev->private;
624         unsigned int chan = CR_CHAN(insn->chanspec);
625         unsigned int range = CR_RANGE(insn->chanspec);
626         unsigned int val;
627         int i;
628
629         val = devpriv->da_ranges & (~(0x03 << (chan << 1)));
630         val |= (range << (chan << 1));
631         if (val != devpriv->da_ranges) {
632                 outb(val, dev->iobase + PCI1720_RANGE);
633                 devpriv->da_ranges = val;
634         }
635
636         val = s->readback[chan];
637         for (i = 0; i < insn->n; i++) {
638                 val = data[i];
639                 outw(val, dev->iobase + PCI1720_DA0 + (chan << 1));
640                 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
641         }
642
643         s->readback[chan] = val;
644
645         return insn->n;
646 }
647
648 static int pci171x_ai_cancel(struct comedi_device *dev,
649                              struct comedi_subdevice *s)
650 {
651         const struct boardtype *board = dev->board_ptr;
652         struct pci1710_private *devpriv = dev->private;
653
654         switch (board->cardtype) {
655         default:
656                 devpriv->CntrlReg &= Control_CNT0;
657                 devpriv->CntrlReg |= Control_SW;
658                 /* reset any operations */
659                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
660                 pci171x_start_pacer(dev, false);
661                 outb(0, dev->iobase + PCI171x_CLRFIFO);
662                 outb(0, dev->iobase + PCI171x_CLRINT);
663                 break;
664         }
665
666         return 0;
667 }
668
669 static void pci1710_handle_every_sample(struct comedi_device *dev,
670                                         struct comedi_subdevice *s)
671 {
672         struct comedi_cmd *cmd = &s->async->cmd;
673         unsigned int status;
674         unsigned int val;
675         int ret;
676
677         status = inw(dev->iobase + PCI171x_STATUS);
678         if (status & Status_FE) {
679                 dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", status);
680                 s->async->events |= COMEDI_CB_ERROR;
681                 comedi_handle_events(dev, s);
682                 return;
683         }
684         if (status & Status_FF) {
685                 dev_dbg(dev->class_dev,
686                         "A/D FIFO Full status (Fatal Error!) (%4x)\n", status);
687                 s->async->events |= COMEDI_CB_ERROR;
688                 comedi_handle_events(dev, s);
689                 return;
690         }
691
692         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear our INT request */
693
694         for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
695                 val = inw(dev->iobase + PCI171x_AD_DATA);
696                 ret = pci171x_ai_dropout(dev, s, s->async->cur_chan, val);
697                 if (ret) {
698                         s->async->events |= COMEDI_CB_ERROR;
699                         break;
700                 }
701
702                 val &= s->maxdata;
703                 comedi_buf_write_samples(s, &val, 1);
704
705                 if (cmd->stop_src == TRIG_COUNT &&
706                     s->async->scans_done >= cmd->stop_arg) {
707                         s->async->events |= COMEDI_CB_EOA;
708                         break;
709                 }
710         }
711
712         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear our INT request */
713
714         comedi_handle_events(dev, s);
715 }
716
717 static int move_block_from_fifo(struct comedi_device *dev,
718                                 struct comedi_subdevice *s, int n, int turn)
719 {
720         unsigned int val;
721         int ret;
722         int i;
723
724         for (i = 0; i < n; i++) {
725                 val = inw(dev->iobase + PCI171x_AD_DATA);
726
727                 ret = pci171x_ai_dropout(dev, s, s->async->cur_chan, val);
728                 if (ret) {
729                         s->async->events |= COMEDI_CB_ERROR;
730                         return ret;
731                 }
732
733                 val &= s->maxdata;
734                 comedi_buf_write_samples(s, &val, 1);
735         }
736         return 0;
737 }
738
739 static void pci1710_handle_fifo(struct comedi_device *dev,
740                                 struct comedi_subdevice *s)
741 {
742         struct pci1710_private *devpriv = dev->private;
743         struct comedi_cmd *cmd = &s->async->cmd;
744         unsigned int nsamples;
745         unsigned int m;
746
747         m = inw(dev->iobase + PCI171x_STATUS);
748         if (!(m & Status_FH)) {
749                 dev_dbg(dev->class_dev, "A/D FIFO not half full! (%4x)\n", m);
750                 s->async->events |= COMEDI_CB_ERROR;
751                 comedi_handle_events(dev, s);
752                 return;
753         }
754         if (m & Status_FF) {
755                 dev_dbg(dev->class_dev,
756                         "A/D FIFO Full status (Fatal Error!) (%4x)\n", m);
757                 s->async->events |= COMEDI_CB_ERROR;
758                 comedi_handle_events(dev, s);
759                 return;
760         }
761
762         nsamples = devpriv->max_samples;
763         if (comedi_samples_to_bytes(s, nsamples) >= s->async->prealloc_bufsz) {
764                 m = comedi_bytes_to_samples(s, s->async->prealloc_bufsz);
765                 if (move_block_from_fifo(dev, s, m, 0))
766                         return;
767                 nsamples -= m;
768         }
769
770         if (nsamples) {
771                 if (move_block_from_fifo(dev, s, nsamples, 1))
772                         return;
773         }
774
775         if (cmd->stop_src == TRIG_COUNT &&
776             s->async->scans_done >= cmd->stop_arg) {
777                 s->async->events |= COMEDI_CB_EOA;
778                 comedi_handle_events(dev, s);
779                 return;
780         }
781         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear our INT request */
782
783         comedi_handle_events(dev, s);
784 }
785
786 static irqreturn_t interrupt_service_pci1710(int irq, void *d)
787 {
788         struct comedi_device *dev = d;
789         struct pci1710_private *devpriv = dev->private;
790         struct comedi_subdevice *s;
791         struct comedi_cmd *cmd;
792
793         if (!dev->attached)     /*  is device attached? */
794                 return IRQ_NONE;        /*  no, exit */
795
796         s = dev->read_subdev;
797         cmd = &s->async->cmd;
798
799         /*  is this interrupt from our board? */
800         if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))
801                 return IRQ_NONE;        /*  no, exit */
802
803         if (devpriv->ai_et) {   /*  Switch from initial TRIG_EXT to TRIG_xxx. */
804                 devpriv->ai_et = 0;
805                 devpriv->CntrlReg &= Control_CNT0;
806                 devpriv->CntrlReg |= Control_SW; /* set software trigger */
807                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
808                 devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
809                 outb(0, dev->iobase + PCI171x_CLRFIFO);
810                 outb(0, dev->iobase + PCI171x_CLRINT);
811                 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
812                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
813                 pci171x_start_pacer(dev, true);
814                 return IRQ_HANDLED;
815         }
816
817         if (cmd->flags & CMDF_WAKE_EOS)
818                 pci1710_handle_every_sample(dev, s);
819         else
820                 pci1710_handle_fifo(dev, s);
821
822         return IRQ_HANDLED;
823 }
824
825 static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
826 {
827         struct pci1710_private *devpriv = dev->private;
828         struct comedi_cmd *cmd = &s->async->cmd;
829
830         pci171x_start_pacer(dev, false);
831
832         setup_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len,
833                            devpriv->saved_seglen);
834
835         outb(0, dev->iobase + PCI171x_CLRFIFO);
836         outb(0, dev->iobase + PCI171x_CLRINT);
837
838         devpriv->CntrlReg &= Control_CNT0;
839         if ((cmd->flags & CMDF_WAKE_EOS) == 0)
840                 devpriv->CntrlReg |= Control_ONEFH;
841
842         devpriv->divisor1 = devpriv->next_divisor1;
843         devpriv->divisor2 = devpriv->next_divisor2;
844
845         if (cmd->convert_src == TRIG_TIMER) {
846                 devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
847                 if (cmd->start_src == TRIG_EXT) {
848                         devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
849                         devpriv->CntrlReg &=
850                             ~(Control_PACER | Control_ONEFH | Control_GATE);
851                         devpriv->CntrlReg |= Control_EXT;
852                         devpriv->ai_et = 1;
853                 } else {        /* TRIG_NOW */
854                         devpriv->ai_et = 0;
855                 }
856                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
857
858                 if (cmd->start_src == TRIG_NOW)
859                         pci171x_start_pacer(dev, true);
860         } else {        /* TRIG_EXT */
861                 devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
862                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
863         }
864
865         return 0;
866 }
867
868 static int pci171x_ai_cmdtest(struct comedi_device *dev,
869                               struct comedi_subdevice *s,
870                               struct comedi_cmd *cmd)
871 {
872         struct pci1710_private *devpriv = dev->private;
873         int err = 0;
874         unsigned int arg;
875
876         /* Step 1 : check if triggers are trivially valid */
877
878         err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
879         err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
880         err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
881         err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
882         err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
883
884         if (err)
885                 return 1;
886
887         /* step 2a: make sure trigger sources are unique */
888
889         err |= cfc_check_trigger_is_unique(cmd->start_src);
890         err |= cfc_check_trigger_is_unique(cmd->convert_src);
891         err |= cfc_check_trigger_is_unique(cmd->stop_src);
892
893         /* step 2b: and mutually compatible */
894
895         if (err)
896                 return 2;
897
898         /* Step 3: check if arguments are trivially valid */
899
900         err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
901         err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
902
903         if (cmd->convert_src == TRIG_TIMER)
904                 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000);
905         else    /* TRIG_FOLLOW */
906                 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
907
908         err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
909
910         if (cmd->stop_src == TRIG_COUNT)
911                 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
912         else    /* TRIG_NONE */
913                 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
914
915         if (err)
916                 return 3;
917
918         /* step 4: fix up any arguments */
919
920         if (cmd->convert_src == TRIG_TIMER) {
921                 arg = cmd->convert_arg;
922                 i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
923                                           &devpriv->next_divisor1,
924                                           &devpriv->next_divisor2,
925                                           &arg, cmd->flags);
926                 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
927         }
928
929         if (err)
930                 return 4;
931
932         /* Step 5: check channel list */
933
934         err |= pci171x_ai_check_chanlist(dev, s, cmd);
935
936         if (err)
937                 return 5;
938
939         return 0;
940 }
941
942 static int pci171x_reset(struct comedi_device *dev)
943 {
944         const struct boardtype *board = dev->board_ptr;
945         struct pci1710_private *devpriv = dev->private;
946
947         outw(0x30, dev->iobase + PCI171x_CNTCTRL);
948         /* Software trigger, CNT0=external */
949         devpriv->CntrlReg = Control_SW | Control_CNT0;
950         /* reset any operations */
951         outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
952         outb(0, dev->iobase + PCI171x_CLRFIFO); /*  clear FIFO */
953         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear INT request */
954         pci171x_start_pacer(dev, false);
955         devpriv->da_ranges = 0;
956         if (board->has_ao) {
957                 /* set DACs to 0..5V */
958                 outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
959                 outw(0, dev->iobase + PCI171x_DA1); /* set DA outputs to 0V */
960                 outw(0, dev->iobase + PCI171x_DA2);
961         }
962         outw(0, dev->iobase + PCI171x_DO);      /*  digital outputs to 0 */
963         outb(0, dev->iobase + PCI171x_CLRFIFO); /*  clear FIFO */
964         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear INT request */
965
966         return 0;
967 }
968
969 static int pci1720_reset(struct comedi_device *dev)
970 {
971         struct pci1710_private *devpriv = dev->private;
972         /* set synchronous output mode */
973         outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT);
974         devpriv->da_ranges = 0xAA;
975         /* set all ranges to +/-5V */
976         outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE);
977         outw(0x0800, dev->iobase + PCI1720_DA0);        /*  set outputs to 0V */
978         outw(0x0800, dev->iobase + PCI1720_DA1);
979         outw(0x0800, dev->iobase + PCI1720_DA2);
980         outw(0x0800, dev->iobase + PCI1720_DA3);
981         outb(0, dev->iobase + PCI1720_SYNCOUT); /*  update outputs */
982
983         return 0;
984 }
985
986 static int pci1710_reset(struct comedi_device *dev)
987 {
988         const struct boardtype *board = dev->board_ptr;
989
990         switch (board->cardtype) {
991         case TYPE_PCI1720:
992                 return pci1720_reset(dev);
993         default:
994                 return pci171x_reset(dev);
995         }
996 }
997
998 static int pci1710_auto_attach(struct comedi_device *dev,
999                                unsigned long context)
1000 {
1001         struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1002         const struct boardtype *board = NULL;
1003         struct pci1710_private *devpriv;
1004         struct comedi_subdevice *s;
1005         int ret, subdev, n_subdevices;
1006
1007         if (context < ARRAY_SIZE(boardtypes))
1008                 board = &boardtypes[context];
1009         if (!board)
1010                 return -ENODEV;
1011         dev->board_ptr = board;
1012         dev->board_name = board->name;
1013
1014         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1015         if (!devpriv)
1016                 return -ENOMEM;
1017
1018         ret = comedi_pci_enable(dev);
1019         if (ret)
1020                 return ret;
1021         dev->iobase = pci_resource_start(pcidev, 2);
1022
1023         n_subdevices = 0;
1024         if (board->n_aichan)
1025                 n_subdevices++;
1026         if (board->has_ao)
1027                 n_subdevices++;
1028         if (board->has_di_do)
1029                 n_subdevices += 2;
1030         if (board->has_counter)
1031                 n_subdevices++;
1032
1033         ret = comedi_alloc_subdevices(dev, n_subdevices);
1034         if (ret)
1035                 return ret;
1036
1037         pci1710_reset(dev);
1038
1039         if (board->has_irq && pcidev->irq) {
1040                 ret = request_irq(pcidev->irq, interrupt_service_pci1710,
1041                                   IRQF_SHARED, dev->board_name, dev);
1042                 if (ret == 0)
1043                         dev->irq = pcidev->irq;
1044         }
1045
1046         subdev = 0;
1047
1048         if (board->n_aichan) {
1049                 s = &dev->subdevices[subdev];
1050                 s->type         = COMEDI_SUBD_AI;
1051                 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
1052                 if (board->has_diff_ai)
1053                         s->subdev_flags |= SDF_DIFF;
1054                 s->n_chan       = board->n_aichan;
1055                 s->maxdata      = 0x0fff;
1056                 s->range_table  = board->rangelist_ai;
1057                 s->insn_read    = pci171x_ai_insn_read;
1058                 if (dev->irq) {
1059                         dev->read_subdev = s;
1060                         s->subdev_flags |= SDF_CMD_READ;
1061                         s->len_chanlist = s->n_chan;
1062                         s->do_cmdtest   = pci171x_ai_cmdtest;
1063                         s->do_cmd       = pci171x_ai_cmd;
1064                         s->cancel       = pci171x_ai_cancel;
1065                 }
1066                 subdev++;
1067         }
1068
1069         if (board->has_ao) {
1070                 s = &dev->subdevices[subdev];
1071                 s->type         = COMEDI_SUBD_AO;
1072                 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1073                 s->maxdata      = 0x0fff;
1074                 s->range_table  = board->rangelist_ao;
1075                 switch (board->cardtype) {
1076                 case TYPE_PCI1720:
1077                         s->n_chan       = 4;
1078                         s->insn_write   = pci1720_ao_insn_write;
1079                         break;
1080                 default:
1081                         s->n_chan       = 2;
1082                         s->insn_write   = pci171x_ao_insn_write;
1083                         break;
1084                 }
1085
1086                 ret = comedi_alloc_subdev_readback(s);
1087                 if (ret)
1088                         return ret;
1089
1090                 /* initialize the readback values to match the board reset */
1091                 if (board->cardtype == TYPE_PCI1720) {
1092                         int i;
1093
1094                         for (i = 0; i < s->n_chan; i++)
1095                                 s->readback[i] = 0x0800;
1096                 }
1097
1098                 subdev++;
1099         }
1100
1101         if (board->has_di_do) {
1102                 s = &dev->subdevices[subdev];
1103                 s->type         = COMEDI_SUBD_DI;
1104                 s->subdev_flags = SDF_READABLE;
1105                 s->n_chan       = 16;
1106                 s->maxdata      = 1;
1107                 s->range_table  = &range_digital;
1108                 s->insn_bits    = pci171x_di_insn_bits;
1109                 subdev++;
1110
1111                 s = &dev->subdevices[subdev];
1112                 s->type         = COMEDI_SUBD_DO;
1113                 s->subdev_flags = SDF_WRITABLE;
1114                 s->n_chan       = 16;
1115                 s->maxdata      = 1;
1116                 s->range_table  = &range_digital;
1117                 s->insn_bits    = pci171x_do_insn_bits;
1118                 subdev++;
1119         }
1120
1121         if (board->has_counter) {
1122                 s = &dev->subdevices[subdev];
1123                 s->type         = COMEDI_SUBD_COUNTER;
1124                 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1125                 s->n_chan       = 1;
1126                 s->maxdata      = 0xffff;
1127                 s->range_table  = &range_unknown;
1128                 s->insn_read    = pci171x_counter_insn_read;
1129                 s->insn_write   = pci171x_counter_insn_write;
1130                 s->insn_config  = pci171x_counter_insn_config;
1131                 subdev++;
1132         }
1133
1134         /* max_samples is half the FIFO size (2 bytes/sample) */
1135         devpriv->max_samples = (board->has_large_fifo) ? 2048 : 512;
1136
1137         return 0;
1138 }
1139
1140 static void pci1710_detach(struct comedi_device *dev)
1141 {
1142         if (dev->iobase)
1143                 pci1710_reset(dev);
1144         comedi_pci_detach(dev);
1145 }
1146
1147 static struct comedi_driver adv_pci1710_driver = {
1148         .driver_name    = "adv_pci1710",
1149         .module         = THIS_MODULE,
1150         .auto_attach    = pci1710_auto_attach,
1151         .detach         = pci1710_detach,
1152 };
1153
1154 static int adv_pci1710_pci_probe(struct pci_dev *dev,
1155                                  const struct pci_device_id *id)
1156 {
1157         return comedi_pci_auto_config(dev, &adv_pci1710_driver,
1158                                       id->driver_data);
1159 }
1160
1161 static const struct pci_device_id adv_pci1710_pci_table[] = {
1162         {
1163                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1164                                PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050),
1165                 .driver_data = BOARD_PCI1710,
1166         }, {
1167                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1168                                PCI_VENDOR_ID_ADVANTECH, 0x0000),
1169                 .driver_data = BOARD_PCI1710,
1170         }, {
1171                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1172                                PCI_VENDOR_ID_ADVANTECH, 0xb100),
1173                 .driver_data = BOARD_PCI1710,
1174         }, {
1175                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1176                                PCI_VENDOR_ID_ADVANTECH, 0xb200),
1177                 .driver_data = BOARD_PCI1710,
1178         }, {
1179                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1180                                PCI_VENDOR_ID_ADVANTECH, 0xc100),
1181                 .driver_data = BOARD_PCI1710,
1182         }, {
1183                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1184                                PCI_VENDOR_ID_ADVANTECH, 0xc200),
1185                 .driver_data = BOARD_PCI1710,
1186         }, {
1187                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd100),
1188                 .driver_data = BOARD_PCI1710,
1189         }, {
1190                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1191                                PCI_VENDOR_ID_ADVANTECH, 0x0002),
1192                 .driver_data = BOARD_PCI1710HG,
1193         }, {
1194                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1195                                PCI_VENDOR_ID_ADVANTECH, 0xb102),
1196                 .driver_data = BOARD_PCI1710HG,
1197         }, {
1198                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1199                                PCI_VENDOR_ID_ADVANTECH, 0xb202),
1200                 .driver_data = BOARD_PCI1710HG,
1201         }, {
1202                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1203                                PCI_VENDOR_ID_ADVANTECH, 0xc102),
1204                 .driver_data = BOARD_PCI1710HG,
1205         }, {
1206                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1207                                PCI_VENDOR_ID_ADVANTECH, 0xc202),
1208                 .driver_data = BOARD_PCI1710HG,
1209         }, {
1210                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd102),
1211                 .driver_data = BOARD_PCI1710HG,
1212         },
1213         { PCI_VDEVICE(ADVANTECH, 0x1711), BOARD_PCI1711 },
1214         { PCI_VDEVICE(ADVANTECH, 0x1713), BOARD_PCI1713 },
1215         { PCI_VDEVICE(ADVANTECH, 0x1720), BOARD_PCI1720 },
1216         { PCI_VDEVICE(ADVANTECH, 0x1731), BOARD_PCI1731 },
1217         { 0 }
1218 };
1219 MODULE_DEVICE_TABLE(pci, adv_pci1710_pci_table);
1220
1221 static struct pci_driver adv_pci1710_pci_driver = {
1222         .name           = "adv_pci1710",
1223         .id_table       = adv_pci1710_pci_table,
1224         .probe          = adv_pci1710_pci_probe,
1225         .remove         = comedi_pci_auto_unconfig,
1226 };
1227 module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver);
1228
1229 MODULE_AUTHOR("Comedi http://www.comedi.org");
1230 MODULE_DESCRIPTION("Comedi: Advantech PCI-1710 Series Multifunction DAS Cards");
1231 MODULE_LICENSE("GPL");