staging: comedi: adv_pci1710: change boardinfo 'fifo_half_size' to 'has_large_fifo'
[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         int n_aochan;           /*  num of D/A chans */
197         const struct comedi_lrange *rangelist_ai;       /*  rangelist for A/D */
198         const char *rangecode_ai;       /*  range codes for programming */
199         const struct comedi_lrange *rangelist_ao;       /*  rangelist for D/A */
200         unsigned int has_irq:1;
201         unsigned int has_large_fifo:1;  /* 4K or 1K FIFO */
202         unsigned int has_diff_ai: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                 .n_aochan       = 2,
213                 .rangelist_ai   = &range_pci1710_3,
214                 .rangecode_ai   = range_codes_pci1710_3,
215                 .rangelist_ao   = &range_pci171x_da,
216                 .has_irq        = 1,
217                 .has_large_fifo = 1,
218                 .has_diff_ai    = 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                 .n_aochan       = 2,
227                 .rangelist_ai   = &range_pci1710hg,
228                 .rangecode_ai   = range_codes_pci1710hg,
229                 .rangelist_ao   = &range_pci171x_da,
230                 .has_irq        = 1,
231                 .has_large_fifo = 1,
232                 .has_diff_ai    = 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                 .n_aochan       = 2,
241                 .rangelist_ai   = &range_pci17x1,
242                 .rangecode_ai   = range_codes_pci17x1,
243                 .rangelist_ao   = &range_pci171x_da,
244                 .has_irq        = 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                 .n_aochan       = 4,
262                 .rangelist_ao   = &range_pci1720,
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 short ao_data[4];      /*  data output buffer */
289         unsigned int cnt0_write_wait;   /* after a write, wait for update of the
290                                          * internal state */
291 };
292
293 /*  used for gain list programming */
294 static const unsigned int muxonechan[] = {
295         0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707,
296         0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f,
297         0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717,
298         0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f
299 };
300
301 static int pci171x_ai_dropout(struct comedi_device *dev,
302                               struct comedi_subdevice *s,
303                               unsigned int chan,
304                               unsigned int val)
305 {
306         const struct boardtype *board = dev->board_ptr;
307         struct pci1710_private *devpriv = dev->private;
308
309         if (board->cardtype != TYPE_PCI1713) {
310                 if ((val & 0xf000) != devpriv->act_chanlist[chan]) {
311                         dev_err(dev->class_dev,
312                                 "A/D data droput: received from channel %d, expected %d\n",
313                                 (val >> 12) & 0xf,
314                                 (devpriv->act_chanlist[chan] >> 12) & 0xf);
315                         return -ENODATA;
316                 }
317         }
318         return 0;
319 }
320
321 static int pci171x_ai_check_chanlist(struct comedi_device *dev,
322                                      struct comedi_subdevice *s,
323                                      struct comedi_cmd *cmd)
324 {
325         struct pci1710_private *devpriv = dev->private;
326         unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
327         unsigned int last_aref = CR_AREF(cmd->chanlist[0]);
328         unsigned int next_chan = (chan0 + 1) % s->n_chan;
329         unsigned int chansegment[32];
330         unsigned int seglen;
331         int i;
332
333         if (cmd->chanlist_len == 1) {
334                 devpriv->saved_seglen = cmd->chanlist_len;
335                 return 0;
336         }
337
338         /* first channel is always ok */
339         chansegment[0] = cmd->chanlist[0];
340
341         for (i = 1; i < cmd->chanlist_len; i++) {
342                 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
343                 unsigned int aref = CR_AREF(cmd->chanlist[i]);
344
345                 if (cmd->chanlist[0] == cmd->chanlist[i])
346                         break;  /*  we detected a loop, stop */
347
348                 if (aref == AREF_DIFF && (chan & 1)) {
349                         dev_err(dev->class_dev,
350                                 "Odd channel cannot be differential input!\n");
351                         return -EINVAL;
352                 }
353
354                 if (last_aref == AREF_DIFF)
355                         next_chan = (next_chan + 1) % s->n_chan;
356                 if (chan != next_chan) {
357                         dev_err(dev->class_dev,
358                                 "channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
359                                 i, chan, next_chan, chan0);
360                         return -EINVAL;
361                 }
362
363                 /* next correct channel in list */
364                 chansegment[i] = cmd->chanlist[i];
365                 last_aref = aref;
366         }
367         seglen = i;
368
369         for (i = 0; i < cmd->chanlist_len; i++) {
370                 if (cmd->chanlist[i] != chansegment[i % seglen]) {
371                         dev_err(dev->class_dev,
372                                 "bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
373                                 i, CR_CHAN(chansegment[i]),
374                                 CR_RANGE(chansegment[i]),
375                                 CR_AREF(chansegment[i]),
376                                 CR_CHAN(cmd->chanlist[i % seglen]),
377                                 CR_RANGE(cmd->chanlist[i % seglen]),
378                                 CR_AREF(chansegment[i % seglen]));
379                         return -EINVAL;
380                 }
381         }
382         devpriv->saved_seglen = seglen;
383
384         return 0;
385 }
386
387 static void setup_channel_list(struct comedi_device *dev,
388                                struct comedi_subdevice *s,
389                                unsigned int *chanlist, unsigned int n_chan,
390                                unsigned int seglen)
391 {
392         const struct boardtype *this_board = dev->board_ptr;
393         struct pci1710_private *devpriv = dev->private;
394         unsigned int i, range, chanprog;
395
396         for (i = 0; i < seglen; i++) {  /*  store range list to card */
397                 chanprog = muxonechan[CR_CHAN(chanlist[i])];
398                 outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */
399                 range = this_board->rangecode_ai[CR_RANGE(chanlist[i])];
400                 if (CR_AREF(chanlist[i]) == AREF_DIFF)
401                         range |= 0x0020;
402                 outw(range, dev->iobase + PCI171x_RANGE); /* select gain */
403                 devpriv->act_chanlist[i] =
404                         (CR_CHAN(chanlist[i]) << 12) & 0xf000;
405         }
406         for ( ; i < n_chan; i++) { /* store remainder of channel list */
407                 devpriv->act_chanlist[i] =
408                         (CR_CHAN(chanlist[i]) << 12) & 0xf000;
409         }
410
411         devpriv->ai_et_MuxVal =
412                 CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
413         /* select channel interval to scan */
414         outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
415 }
416
417 static int pci171x_ai_eoc(struct comedi_device *dev,
418                           struct comedi_subdevice *s,
419                           struct comedi_insn *insn,
420                           unsigned long context)
421 {
422         unsigned int status;
423
424         status = inw(dev->iobase + PCI171x_STATUS);
425         if ((status & Status_FE) == 0)
426                 return 0;
427         return -EBUSY;
428 }
429
430 static int pci171x_insn_read_ai(struct comedi_device *dev,
431                                 struct comedi_subdevice *s,
432                                 struct comedi_insn *insn, 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 /*
471 ==============================================================================
472 */
473 static int pci171x_insn_write_ao(struct comedi_device *dev,
474                                  struct comedi_subdevice *s,
475                                  struct comedi_insn *insn, unsigned int *data)
476 {
477         struct pci1710_private *devpriv = dev->private;
478         unsigned int val;
479         int n, chan, range, ofs;
480
481         chan = CR_CHAN(insn->chanspec);
482         range = CR_RANGE(insn->chanspec);
483         if (chan) {
484                 devpriv->da_ranges &= 0xfb;
485                 devpriv->da_ranges |= (range << 2);
486                 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
487                 ofs = PCI171x_DA2;
488         } else {
489                 devpriv->da_ranges &= 0xfe;
490                 devpriv->da_ranges |= range;
491                 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
492                 ofs = PCI171x_DA1;
493         }
494         val = devpriv->ao_data[chan];
495
496         for (n = 0; n < insn->n; n++) {
497                 val = data[n];
498                 outw(val, dev->iobase + ofs);
499         }
500
501         devpriv->ao_data[chan] = val;
502
503         return n;
504
505 }
506
507 /*
508 ==============================================================================
509 */
510 static int pci171x_insn_read_ao(struct comedi_device *dev,
511                                 struct comedi_subdevice *s,
512                                 struct comedi_insn *insn, unsigned int *data)
513 {
514         struct pci1710_private *devpriv = dev->private;
515         int n, chan;
516
517         chan = CR_CHAN(insn->chanspec);
518         for (n = 0; n < insn->n; n++)
519                 data[n] = devpriv->ao_data[chan];
520
521         return n;
522 }
523
524 /*
525 ==============================================================================
526 */
527 static int pci171x_insn_bits_di(struct comedi_device *dev,
528                                 struct comedi_subdevice *s,
529                                 struct comedi_insn *insn, unsigned int *data)
530 {
531         data[1] = inw(dev->iobase + PCI171x_DI);
532
533         return insn->n;
534 }
535
536 static int pci171x_insn_bits_do(struct comedi_device *dev,
537                                 struct comedi_subdevice *s,
538                                 struct comedi_insn *insn,
539                                 unsigned int *data)
540 {
541         if (comedi_dio_update_state(s, data))
542                 outw(s->state, dev->iobase + PCI171x_DO);
543
544         data[1] = s->state;
545
546         return insn->n;
547 }
548
549 static void pci171x_start_pacer(struct comedi_device *dev,
550                                 bool load_counters)
551 {
552         struct pci1710_private *devpriv = dev->private;
553         unsigned long timer_base = dev->iobase + PCI171X_TIMER_BASE;
554
555         i8254_set_mode(timer_base, 1, 2, I8254_MODE2 | I8254_BINARY);
556         i8254_set_mode(timer_base, 1, 1, I8254_MODE2 | I8254_BINARY);
557
558         if (load_counters) {
559                 i8254_write(timer_base, 1, 2, devpriv->divisor2);
560                 i8254_write(timer_base, 1, 1, devpriv->divisor1);
561         }
562 }
563
564 /*
565 ==============================================================================
566 */
567 static int pci171x_insn_counter_read(struct comedi_device *dev,
568                                      struct comedi_subdevice *s,
569                                      struct comedi_insn *insn,
570                                      unsigned int *data)
571 {
572         unsigned int msb, lsb, ccntrl;
573         int i;
574
575         ccntrl = 0xD2;          /* count only */
576         for (i = 0; i < insn->n; i++) {
577                 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
578
579                 lsb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
580                 msb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
581
582                 data[0] = lsb | (msb << 8);
583         }
584
585         return insn->n;
586 }
587
588 /*
589 ==============================================================================
590 */
591 static int pci171x_insn_counter_write(struct comedi_device *dev,
592                                       struct comedi_subdevice *s,
593                                       struct comedi_insn *insn,
594                                       unsigned int *data)
595 {
596         struct pci1710_private *devpriv = dev->private;
597         uint msb, lsb, ccntrl, status;
598
599         lsb = data[0] & 0x00FF;
600         msb = (data[0] & 0xFF00) >> 8;
601
602         /* write lsb, then msb */
603         outw(lsb, dev->iobase + PCI171x_CNT0);
604         outw(msb, dev->iobase + PCI171x_CNT0);
605
606         if (devpriv->cnt0_write_wait) {
607                 /* wait for the new count to be loaded */
608                 ccntrl = 0xE2;
609                 do {
610                         outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
611                         status = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
612                 } while (status & 0x40);
613         }
614
615         return insn->n;
616 }
617
618 /*
619 ==============================================================================
620 */
621 static int pci171x_insn_counter_config(struct comedi_device *dev,
622                                        struct comedi_subdevice *s,
623                                        struct comedi_insn *insn,
624                                        unsigned int *data)
625 {
626 #ifdef unused
627         /* This doesn't work like a normal Comedi counter config */
628         struct pci1710_private *devpriv = dev->private;
629         uint ccntrl = 0;
630
631         devpriv->cnt0_write_wait = data[0] & 0x20;
632
633         /* internal or external clock? */
634         if (!(data[0] & 0x10)) {        /* internal */
635                 devpriv->CntrlReg &= ~Control_CNT0;
636         } else {
637                 devpriv->CntrlReg |= Control_CNT0;
638         }
639         outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
640
641         if (data[0] & 0x01)
642                 ccntrl |= Counter_M0;
643         if (data[0] & 0x02)
644                 ccntrl |= Counter_M1;
645         if (data[0] & 0x04)
646                 ccntrl |= Counter_M2;
647         if (data[0] & 0x08)
648                 ccntrl |= Counter_BCD;
649         ccntrl |= Counter_RW0;  /* set read/write mode */
650         ccntrl |= Counter_RW1;
651         outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
652 #endif
653
654         return 1;
655 }
656
657 /*
658 ==============================================================================
659 */
660 static int pci1720_insn_write_ao(struct comedi_device *dev,
661                                  struct comedi_subdevice *s,
662                                  struct comedi_insn *insn, unsigned int *data)
663 {
664         struct pci1710_private *devpriv = dev->private;
665         unsigned int val;
666         int n, rangereg, chan;
667
668         chan = CR_CHAN(insn->chanspec);
669         rangereg = devpriv->da_ranges & (~(0x03 << (chan << 1)));
670         rangereg |= (CR_RANGE(insn->chanspec) << (chan << 1));
671         if (rangereg != devpriv->da_ranges) {
672                 outb(rangereg, dev->iobase + PCI1720_RANGE);
673                 devpriv->da_ranges = rangereg;
674         }
675         val = devpriv->ao_data[chan];
676
677         for (n = 0; n < insn->n; n++) {
678                 val = data[n];
679                 outw(val, dev->iobase + PCI1720_DA0 + (chan << 1));
680                 outb(0, dev->iobase + PCI1720_SYNCOUT); /*  update outputs */
681         }
682
683         devpriv->ao_data[chan] = val;
684
685         return n;
686 }
687
688 /*
689 ==============================================================================
690 */
691 static int pci171x_ai_cancel(struct comedi_device *dev,
692                              struct comedi_subdevice *s)
693 {
694         const struct boardtype *this_board = dev->board_ptr;
695         struct pci1710_private *devpriv = dev->private;
696
697         switch (this_board->cardtype) {
698         default:
699                 devpriv->CntrlReg &= Control_CNT0;
700                 devpriv->CntrlReg |= Control_SW;
701                 /* reset any operations */
702                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
703                 pci171x_start_pacer(dev, false);
704                 outb(0, dev->iobase + PCI171x_CLRFIFO);
705                 outb(0, dev->iobase + PCI171x_CLRINT);
706                 break;
707         }
708
709         return 0;
710 }
711
712 static void pci1710_handle_every_sample(struct comedi_device *dev,
713                                         struct comedi_subdevice *s)
714 {
715         struct comedi_cmd *cmd = &s->async->cmd;
716         unsigned int status;
717         unsigned int val;
718         int ret;
719
720         status = inw(dev->iobase + PCI171x_STATUS);
721         if (status & Status_FE) {
722                 dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", status);
723                 s->async->events |= COMEDI_CB_ERROR;
724                 comedi_handle_events(dev, s);
725                 return;
726         }
727         if (status & Status_FF) {
728                 dev_dbg(dev->class_dev,
729                         "A/D FIFO Full status (Fatal Error!) (%4x)\n", status);
730                 s->async->events |= COMEDI_CB_ERROR;
731                 comedi_handle_events(dev, s);
732                 return;
733         }
734
735         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear our INT request */
736
737         for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
738                 val = inw(dev->iobase + PCI171x_AD_DATA);
739                 ret = pci171x_ai_dropout(dev, s, s->async->cur_chan, val);
740                 if (ret) {
741                         s->async->events |= COMEDI_CB_ERROR;
742                         break;
743                 }
744
745                 val &= s->maxdata;
746                 comedi_buf_write_samples(s, &val, 1);
747
748                 if (cmd->stop_src == TRIG_COUNT &&
749                     s->async->scans_done >= cmd->stop_arg) {
750                         s->async->events |= COMEDI_CB_EOA;
751                         break;
752                 }
753         }
754
755         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear our INT request */
756
757         comedi_handle_events(dev, s);
758 }
759
760 /*
761 ==============================================================================
762 */
763 static int move_block_from_fifo(struct comedi_device *dev,
764                                 struct comedi_subdevice *s, int n, int turn)
765 {
766         unsigned int val;
767         int ret;
768         int i;
769
770         for (i = 0; i < n; i++) {
771                 val = inw(dev->iobase + PCI171x_AD_DATA);
772
773                 ret = pci171x_ai_dropout(dev, s, s->async->cur_chan, val);
774                 if (ret) {
775                         s->async->events |= COMEDI_CB_ERROR;
776                         return ret;
777                 }
778
779                 val &= s->maxdata;
780                 comedi_buf_write_samples(s, &val, 1);
781         }
782         return 0;
783 }
784
785 static void pci1710_handle_fifo(struct comedi_device *dev,
786                                 struct comedi_subdevice *s)
787 {
788         struct pci1710_private *devpriv = dev->private;
789         struct comedi_cmd *cmd = &s->async->cmd;
790         unsigned int nsamples;
791         unsigned int m;
792
793         m = inw(dev->iobase + PCI171x_STATUS);
794         if (!(m & Status_FH)) {
795                 dev_dbg(dev->class_dev, "A/D FIFO not half full! (%4x)\n", m);
796                 s->async->events |= COMEDI_CB_ERROR;
797                 comedi_handle_events(dev, s);
798                 return;
799         }
800         if (m & Status_FF) {
801                 dev_dbg(dev->class_dev,
802                         "A/D FIFO Full status (Fatal Error!) (%4x)\n", m);
803                 s->async->events |= COMEDI_CB_ERROR;
804                 comedi_handle_events(dev, s);
805                 return;
806         }
807
808         nsamples = devpriv->max_samples;
809         if (comedi_samples_to_bytes(s, nsamples) >= s->async->prealloc_bufsz) {
810                 m = comedi_bytes_to_samples(s, s->async->prealloc_bufsz);
811                 if (move_block_from_fifo(dev, s, m, 0))
812                         return;
813                 nsamples -= m;
814         }
815
816         if (nsamples) {
817                 if (move_block_from_fifo(dev, s, nsamples, 1))
818                         return;
819         }
820
821         if (cmd->stop_src == TRIG_COUNT &&
822             s->async->scans_done >= cmd->stop_arg) {
823                 s->async->events |= COMEDI_CB_EOA;
824                 comedi_handle_events(dev, s);
825                 return;
826         }
827         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear our INT request */
828
829         comedi_handle_events(dev, s);
830 }
831
832 /*
833 ==============================================================================
834 */
835 static irqreturn_t interrupt_service_pci1710(int irq, void *d)
836 {
837         struct comedi_device *dev = d;
838         struct pci1710_private *devpriv = dev->private;
839         struct comedi_subdevice *s;
840         struct comedi_cmd *cmd;
841
842         if (!dev->attached)     /*  is device attached? */
843                 return IRQ_NONE;        /*  no, exit */
844
845         s = dev->read_subdev;
846         cmd = &s->async->cmd;
847
848         /*  is this interrupt from our board? */
849         if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))
850                 return IRQ_NONE;        /*  no, exit */
851
852         if (devpriv->ai_et) {   /*  Switch from initial TRIG_EXT to TRIG_xxx. */
853                 devpriv->ai_et = 0;
854                 devpriv->CntrlReg &= Control_CNT0;
855                 devpriv->CntrlReg |= Control_SW; /* set software trigger */
856                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
857                 devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
858                 outb(0, dev->iobase + PCI171x_CLRFIFO);
859                 outb(0, dev->iobase + PCI171x_CLRINT);
860                 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
861                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
862                 pci171x_start_pacer(dev, true);
863                 return IRQ_HANDLED;
864         }
865
866         if (cmd->flags & CMDF_WAKE_EOS)
867                 pci1710_handle_every_sample(dev, s);
868         else
869                 pci1710_handle_fifo(dev, s);
870
871         return IRQ_HANDLED;
872 }
873
874 static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
875 {
876         struct pci1710_private *devpriv = dev->private;
877         struct comedi_cmd *cmd = &s->async->cmd;
878
879         pci171x_start_pacer(dev, false);
880
881         setup_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len,
882                            devpriv->saved_seglen);
883
884         outb(0, dev->iobase + PCI171x_CLRFIFO);
885         outb(0, dev->iobase + PCI171x_CLRINT);
886
887         devpriv->CntrlReg &= Control_CNT0;
888         if ((cmd->flags & CMDF_WAKE_EOS) == 0)
889                 devpriv->CntrlReg |= Control_ONEFH;
890
891         devpriv->divisor1 = devpriv->next_divisor1;
892         devpriv->divisor2 = devpriv->next_divisor2;
893
894         if (cmd->convert_src == TRIG_TIMER) {
895                 devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
896                 if (cmd->start_src == TRIG_EXT) {
897                         devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
898                         devpriv->CntrlReg &=
899                             ~(Control_PACER | Control_ONEFH | Control_GATE);
900                         devpriv->CntrlReg |= Control_EXT;
901                         devpriv->ai_et = 1;
902                 } else {        /* TRIG_NOW */
903                         devpriv->ai_et = 0;
904                 }
905                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
906
907                 if (cmd->start_src == TRIG_NOW)
908                         pci171x_start_pacer(dev, true);
909         } else {        /* TRIG_EXT */
910                 devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
911                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
912         }
913
914         return 0;
915 }
916
917 /*
918 ==============================================================================
919 */
920 static int pci171x_ai_cmdtest(struct comedi_device *dev,
921                               struct comedi_subdevice *s,
922                               struct comedi_cmd *cmd)
923 {
924         struct pci1710_private *devpriv = dev->private;
925         int err = 0;
926         unsigned int arg;
927
928         /* Step 1 : check if triggers are trivially valid */
929
930         err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
931         err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
932         err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
933         err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
934         err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
935
936         if (err)
937                 return 1;
938
939         /* step 2a: make sure trigger sources are unique */
940
941         err |= cfc_check_trigger_is_unique(cmd->start_src);
942         err |= cfc_check_trigger_is_unique(cmd->convert_src);
943         err |= cfc_check_trigger_is_unique(cmd->stop_src);
944
945         /* step 2b: and mutually compatible */
946
947         if (err)
948                 return 2;
949
950         /* Step 3: check if arguments are trivially valid */
951
952         err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
953         err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
954
955         if (cmd->convert_src == TRIG_TIMER)
956                 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000);
957         else    /* TRIG_FOLLOW */
958                 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
959
960         err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
961
962         if (cmd->stop_src == TRIG_COUNT)
963                 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
964         else    /* TRIG_NONE */
965                 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
966
967         if (err)
968                 return 3;
969
970         /* step 4: fix up any arguments */
971
972         if (cmd->convert_src == TRIG_TIMER) {
973                 arg = cmd->convert_arg;
974                 i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
975                                           &devpriv->next_divisor1,
976                                           &devpriv->next_divisor2,
977                                           &arg, cmd->flags);
978                 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
979         }
980
981         if (err)
982                 return 4;
983
984         /* Step 5: check channel list */
985
986         err |= pci171x_ai_check_chanlist(dev, s, cmd);
987
988         if (err)
989                 return 5;
990
991         return 0;
992 }
993
994 /*
995 ==============================================================================
996 */
997 static int pci171x_reset(struct comedi_device *dev)
998 {
999         const struct boardtype *this_board = dev->board_ptr;
1000         struct pci1710_private *devpriv = dev->private;
1001
1002         outw(0x30, dev->iobase + PCI171x_CNTCTRL);
1003         /* Software trigger, CNT0=external */
1004         devpriv->CntrlReg = Control_SW | Control_CNT0;
1005         /* reset any operations */
1006         outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
1007         outb(0, dev->iobase + PCI171x_CLRFIFO); /*  clear FIFO */
1008         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear INT request */
1009         pci171x_start_pacer(dev, false);
1010         devpriv->da_ranges = 0;
1011         if (this_board->n_aochan) {
1012                 /* set DACs to 0..5V */
1013                 outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
1014                 outw(0, dev->iobase + PCI171x_DA1); /* set DA outputs to 0V */
1015                 devpriv->ao_data[0] = 0x0000;
1016                 if (this_board->n_aochan > 1) {
1017                         outw(0, dev->iobase + PCI171x_DA2);
1018                         devpriv->ao_data[1] = 0x0000;
1019                 }
1020         }
1021         outw(0, dev->iobase + PCI171x_DO);      /*  digital outputs to 0 */
1022         outb(0, dev->iobase + PCI171x_CLRFIFO); /*  clear FIFO */
1023         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear INT request */
1024
1025         return 0;
1026 }
1027
1028 /*
1029 ==============================================================================
1030 */
1031 static int pci1720_reset(struct comedi_device *dev)
1032 {
1033         struct pci1710_private *devpriv = dev->private;
1034         /* set synchronous output mode */
1035         outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT);
1036         devpriv->da_ranges = 0xAA;
1037         /* set all ranges to +/-5V */
1038         outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE);
1039         outw(0x0800, dev->iobase + PCI1720_DA0);        /*  set outputs to 0V */
1040         outw(0x0800, dev->iobase + PCI1720_DA1);
1041         outw(0x0800, dev->iobase + PCI1720_DA2);
1042         outw(0x0800, dev->iobase + PCI1720_DA3);
1043         outb(0, dev->iobase + PCI1720_SYNCOUT); /*  update outputs */
1044         devpriv->ao_data[0] = 0x0800;
1045         devpriv->ao_data[1] = 0x0800;
1046         devpriv->ao_data[2] = 0x0800;
1047         devpriv->ao_data[3] = 0x0800;
1048         return 0;
1049 }
1050
1051 /*
1052 ==============================================================================
1053 */
1054 static int pci1710_reset(struct comedi_device *dev)
1055 {
1056         const struct boardtype *this_board = dev->board_ptr;
1057
1058         switch (this_board->cardtype) {
1059         case TYPE_PCI1720:
1060                 return pci1720_reset(dev);
1061         default:
1062                 return pci171x_reset(dev);
1063         }
1064 }
1065
1066 static int pci1710_auto_attach(struct comedi_device *dev,
1067                                unsigned long context)
1068 {
1069         struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1070         const struct boardtype *this_board = NULL;
1071         struct pci1710_private *devpriv;
1072         struct comedi_subdevice *s;
1073         int ret, subdev, n_subdevices;
1074
1075         if (context < ARRAY_SIZE(boardtypes))
1076                 this_board = &boardtypes[context];
1077         if (!this_board)
1078                 return -ENODEV;
1079         dev->board_ptr = this_board;
1080         dev->board_name = this_board->name;
1081
1082         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1083         if (!devpriv)
1084                 return -ENOMEM;
1085
1086         ret = comedi_pci_enable(dev);
1087         if (ret)
1088                 return ret;
1089         dev->iobase = pci_resource_start(pcidev, 2);
1090
1091         n_subdevices = 0;
1092         if (this_board->n_aichan)
1093                 n_subdevices++;
1094         if (this_board->n_aochan)
1095                 n_subdevices++;
1096         if (this_board->has_di_do)
1097                 n_subdevices += 2;
1098         if (this_board->has_counter)
1099                 n_subdevices++;
1100
1101         ret = comedi_alloc_subdevices(dev, n_subdevices);
1102         if (ret)
1103                 return ret;
1104
1105         pci1710_reset(dev);
1106
1107         if (this_board->has_irq && pcidev->irq) {
1108                 ret = request_irq(pcidev->irq, interrupt_service_pci1710,
1109                                   IRQF_SHARED, dev->board_name, dev);
1110                 if (ret == 0)
1111                         dev->irq = pcidev->irq;
1112         }
1113
1114         subdev = 0;
1115
1116         if (this_board->n_aichan) {
1117                 s = &dev->subdevices[subdev];
1118                 s->type = COMEDI_SUBD_AI;
1119                 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
1120                 if (this_board->has_diff_ai)
1121                         s->subdev_flags |= SDF_DIFF;
1122                 s->n_chan = this_board->n_aichan;
1123                 s->maxdata = 0x0fff;
1124                 s->range_table = this_board->rangelist_ai;
1125                 s->insn_read = pci171x_insn_read_ai;
1126                 if (dev->irq) {
1127                         dev->read_subdev = s;
1128                         s->subdev_flags |= SDF_CMD_READ;
1129                         s->len_chanlist = s->n_chan;
1130                         s->do_cmdtest = pci171x_ai_cmdtest;
1131                         s->do_cmd = pci171x_ai_cmd;
1132                         s->cancel = pci171x_ai_cancel;
1133                 }
1134                 subdev++;
1135         }
1136
1137         if (this_board->n_aochan) {
1138                 s = &dev->subdevices[subdev];
1139                 s->type = COMEDI_SUBD_AO;
1140                 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1141                 s->n_chan = this_board->n_aochan;
1142                 s->maxdata = 0x0fff;
1143                 s->len_chanlist = this_board->n_aochan;
1144                 s->range_table = this_board->rangelist_ao;
1145                 switch (this_board->cardtype) {
1146                 case TYPE_PCI1720:
1147                         s->insn_write = pci1720_insn_write_ao;
1148                         break;
1149                 default:
1150                         s->insn_write = pci171x_insn_write_ao;
1151                         break;
1152                 }
1153                 s->insn_read = pci171x_insn_read_ao;
1154                 subdev++;
1155         }
1156
1157         if (this_board->has_di_do) {
1158                 s = &dev->subdevices[subdev];
1159                 s->type = COMEDI_SUBD_DI;
1160                 s->subdev_flags = SDF_READABLE;
1161                 s->n_chan = 16;
1162                 s->maxdata = 1;
1163                 s->range_table = &range_digital;
1164                 s->insn_bits = pci171x_insn_bits_di;
1165                 subdev++;
1166
1167                 s = &dev->subdevices[subdev];
1168                 s->type = COMEDI_SUBD_DO;
1169                 s->subdev_flags = SDF_WRITABLE;
1170                 s->n_chan = 16;
1171                 s->maxdata = 1;
1172                 s->range_table = &range_digital;
1173                 s->insn_bits = pci171x_insn_bits_do;
1174                 subdev++;
1175         }
1176
1177         if (this_board->has_counter) {
1178                 s = &dev->subdevices[subdev];
1179                 s->type = COMEDI_SUBD_COUNTER;
1180                 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1181                 s->n_chan = 1;
1182                 s->maxdata = 0xffff;
1183                 s->range_table = &range_unknown;
1184                 s->insn_read = pci171x_insn_counter_read;
1185                 s->insn_write = pci171x_insn_counter_write;
1186                 s->insn_config = pci171x_insn_counter_config;
1187                 subdev++;
1188         }
1189
1190         /* max_samples is half the FIFO size (2 bytes/sample) */
1191         devpriv->max_samples = (this_board->has_large_fifo) ? 2048 : 512;
1192
1193         return 0;
1194 }
1195
1196 static void pci1710_detach(struct comedi_device *dev)
1197 {
1198         if (dev->iobase)
1199                 pci1710_reset(dev);
1200         comedi_pci_detach(dev);
1201 }
1202
1203 static struct comedi_driver adv_pci1710_driver = {
1204         .driver_name    = "adv_pci1710",
1205         .module         = THIS_MODULE,
1206         .auto_attach    = pci1710_auto_attach,
1207         .detach         = pci1710_detach,
1208 };
1209
1210 static int adv_pci1710_pci_probe(struct pci_dev *dev,
1211                                  const struct pci_device_id *id)
1212 {
1213         return comedi_pci_auto_config(dev, &adv_pci1710_driver,
1214                                       id->driver_data);
1215 }
1216
1217 static const struct pci_device_id adv_pci1710_pci_table[] = {
1218         {
1219                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1220                                PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050),
1221                 .driver_data = BOARD_PCI1710,
1222         }, {
1223                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1224                                PCI_VENDOR_ID_ADVANTECH, 0x0000),
1225                 .driver_data = BOARD_PCI1710,
1226         }, {
1227                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1228                                PCI_VENDOR_ID_ADVANTECH, 0xb100),
1229                 .driver_data = BOARD_PCI1710,
1230         }, {
1231                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1232                                PCI_VENDOR_ID_ADVANTECH, 0xb200),
1233                 .driver_data = BOARD_PCI1710,
1234         }, {
1235                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1236                                PCI_VENDOR_ID_ADVANTECH, 0xc100),
1237                 .driver_data = BOARD_PCI1710,
1238         }, {
1239                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1240                                PCI_VENDOR_ID_ADVANTECH, 0xc200),
1241                 .driver_data = BOARD_PCI1710,
1242         }, {
1243                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd100),
1244                 .driver_data = BOARD_PCI1710,
1245         }, {
1246                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1247                                PCI_VENDOR_ID_ADVANTECH, 0x0002),
1248                 .driver_data = BOARD_PCI1710HG,
1249         }, {
1250                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1251                                PCI_VENDOR_ID_ADVANTECH, 0xb102),
1252                 .driver_data = BOARD_PCI1710HG,
1253         }, {
1254                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1255                                PCI_VENDOR_ID_ADVANTECH, 0xb202),
1256                 .driver_data = BOARD_PCI1710HG,
1257         }, {
1258                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1259                                PCI_VENDOR_ID_ADVANTECH, 0xc102),
1260                 .driver_data = BOARD_PCI1710HG,
1261         }, {
1262                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1263                                PCI_VENDOR_ID_ADVANTECH, 0xc202),
1264                 .driver_data = BOARD_PCI1710HG,
1265         }, {
1266                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd102),
1267                 .driver_data = BOARD_PCI1710HG,
1268         },
1269         { PCI_VDEVICE(ADVANTECH, 0x1711), BOARD_PCI1711 },
1270         { PCI_VDEVICE(ADVANTECH, 0x1713), BOARD_PCI1713 },
1271         { PCI_VDEVICE(ADVANTECH, 0x1720), BOARD_PCI1720 },
1272         { PCI_VDEVICE(ADVANTECH, 0x1731), BOARD_PCI1731 },
1273         { 0 }
1274 };
1275 MODULE_DEVICE_TABLE(pci, adv_pci1710_pci_table);
1276
1277 static struct pci_driver adv_pci1710_pci_driver = {
1278         .name           = "adv_pci1710",
1279         .id_table       = adv_pci1710_pci_table,
1280         .probe          = adv_pci1710_pci_probe,
1281         .remove         = comedi_pci_auto_unconfig,
1282 };
1283 module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver);
1284
1285 MODULE_AUTHOR("Comedi http://www.comedi.org");
1286 MODULE_DESCRIPTION("Comedi low-level driver");
1287 MODULE_LICENSE("GPL");