staging: comedi_pci: pass comedi_device to comedi_pci_enable()
[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/pci.h>
45 #include <linux/interrupt.h>
46
47 #include "../comedidev.h"
48
49 #include "comedi_fc.h"
50 #include "8253.h"
51 #include "amcc_s5933.h"
52
53 #define PCI171x_PARANOIDCHECK   /* if defined, then is used code which control
54                                  * correct channel number on every 12 bit
55                                  * sample */
56
57 /* hardware types of the cards */
58 #define TYPE_PCI171X    0
59 #define TYPE_PCI1713    2
60 #define TYPE_PCI1720    3
61
62 #define IORANGE_171x    32
63 #define IORANGE_1720    16
64
65 #define PCI171x_AD_DATA  0      /* R:   A/D data */
66 #define PCI171x_SOFTTRG  0      /* W:   soft trigger for A/D */
67 #define PCI171x_RANGE    2      /* W:   A/D gain/range register */
68 #define PCI171x_MUX      4      /* W:   A/D multiplexor control */
69 #define PCI171x_STATUS   6      /* R:   status register */
70 #define PCI171x_CONTROL  6      /* W:   control register */
71 #define PCI171x_CLRINT   8      /* W:   clear interrupts request */
72 #define PCI171x_CLRFIFO  9      /* W:   clear FIFO */
73 #define PCI171x_DA1     10      /* W:   D/A register */
74 #define PCI171x_DA2     12      /* W:   D/A register */
75 #define PCI171x_DAREF   14      /* W:   D/A reference control */
76 #define PCI171x_DI      16      /* R:   digi inputs */
77 #define PCI171x_DO      16      /* R:   digi inputs */
78 #define PCI171x_CNT0    24      /* R/W: 8254 counter 0 */
79 #define PCI171x_CNT1    26      /* R/W: 8254 counter 1 */
80 #define PCI171x_CNT2    28      /* R/W: 8254 counter 2 */
81 #define PCI171x_CNTCTRL 30      /* W:   8254 counter control */
82
83 /* upper bits from status register (PCI171x_STATUS) (lower is same with control
84  * reg) */
85 #define Status_FE       0x0100  /* 1=FIFO is empty */
86 #define Status_FH       0x0200  /* 1=FIFO is half full */
87 #define Status_FF       0x0400  /* 1=FIFO is full, fatal error */
88 #define Status_IRQ      0x0800  /* 1=IRQ occurred */
89 /* bits from control register (PCI171x_CONTROL) */
90 #define Control_CNT0    0x0040  /* 1=CNT0 have external source,
91                                  * 0=have internal 100kHz source */
92 #define Control_ONEFH   0x0020  /* 1=IRQ on FIFO is half full, 0=every sample */
93 #define Control_IRQEN   0x0010  /* 1=enable IRQ */
94 #define Control_GATE    0x0008  /* 1=enable external trigger GATE (8254?) */
95 #define Control_EXT     0x0004  /* 1=external trigger source */
96 #define Control_PACER   0x0002  /* 1=enable internal 8254 trigger source */
97 #define Control_SW      0x0001  /* 1=enable software trigger source */
98 /* bits from counter control register (PCI171x_CNTCTRL) */
99 #define Counter_BCD     0x0001  /* 0 = binary counter, 1 = BCD counter */
100 #define Counter_M0      0x0002  /* M0-M2 select modes 0-5 */
101 #define Counter_M1      0x0004  /* 000 = mode 0, 010 = mode 2 ... */
102 #define Counter_M2      0x0008
103 #define Counter_RW0     0x0010  /* RW0/RW1 select read/write mode */
104 #define Counter_RW1     0x0020
105 #define Counter_SC0     0x0040  /* Select Counter. Only 00 or 11 may */
106 #define Counter_SC1     0x0080  /* be used, 00 for CNT0,
107                                  * 11 for read-back command */
108
109 #define PCI1720_DA0      0      /* W:   D/A register 0 */
110 #define PCI1720_DA1      2      /* W:   D/A register 1 */
111 #define PCI1720_DA2      4      /* W:   D/A register 2 */
112 #define PCI1720_DA3      6      /* W:   D/A register 3 */
113 #define PCI1720_RANGE    8      /* R/W: D/A range register */
114 #define PCI1720_SYNCOUT  9      /* W:   D/A synchronized output register */
115 #define PCI1720_SYNCONT 15      /* R/W: D/A synchronized control */
116
117 /* D/A synchronized control (PCI1720_SYNCONT) */
118 #define Syncont_SC0      1      /* set synchronous output mode */
119
120 static const struct comedi_lrange range_pci1710_3 = { 9, {
121                                                           BIP_RANGE(5),
122                                                           BIP_RANGE(2.5),
123                                                           BIP_RANGE(1.25),
124                                                           BIP_RANGE(0.625),
125                                                           BIP_RANGE(10),
126                                                           UNI_RANGE(10),
127                                                           UNI_RANGE(5),
128                                                           UNI_RANGE(2.5),
129                                                           UNI_RANGE(1.25)
130                                                           }
131 };
132
133 static const char range_codes_pci1710_3[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
134                                               0x10, 0x11, 0x12, 0x13 };
135
136 static const struct comedi_lrange range_pci1710hg = { 12, {
137                                                            BIP_RANGE(5),
138                                                            BIP_RANGE(0.5),
139                                                            BIP_RANGE(0.05),
140                                                            BIP_RANGE(0.005),
141                                                            BIP_RANGE(10),
142                                                            BIP_RANGE(1),
143                                                            BIP_RANGE(0.1),
144                                                            BIP_RANGE(0.01),
145                                                            UNI_RANGE(10),
146                                                            UNI_RANGE(1),
147                                                            UNI_RANGE(0.1),
148                                                            UNI_RANGE(0.01)
149                                                            }
150 };
151
152 static const char range_codes_pci1710hg[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
153                                               0x05, 0x06, 0x07, 0x10, 0x11,
154                                               0x12, 0x13 };
155
156 static const struct comedi_lrange range_pci17x1 = { 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 = { 4, {
168                                                         UNI_RANGE(5),
169                                                         UNI_RANGE(10),
170                                                         BIP_RANGE(5),
171                                                         BIP_RANGE(10)
172                                                         }
173 };
174
175 static const struct comedi_lrange range_pci171x_da = { 2, {
176                                                            UNI_RANGE(5),
177                                                            UNI_RANGE(10),
178                                                            }
179 };
180
181 enum pci1710_boardid {
182         BOARD_PCI1710,
183         BOARD_PCI1710HG,
184         BOARD_PCI1711,
185         BOARD_PCI1713,
186         BOARD_PCI1720,
187         BOARD_PCI1731,
188 };
189
190 struct boardtype {
191         const char *name;       /*  board name */
192         int iorange;            /*  I/O range len */
193         char have_irq;          /*  1=card support IRQ */
194         char cardtype;          /*  0=1710& co. 2=1713, ... */
195         int n_aichan;           /*  num of A/D chans */
196         int n_aichand;          /*  num of A/D chans in diff mode */
197         int n_aochan;           /*  num of D/A chans */
198         int n_dichan;           /*  num of DI chans */
199         int n_dochan;           /*  num of DO chans */
200         int n_counter;          /*  num of counters */
201         int ai_maxdata;         /*  resolution of A/D */
202         int ao_maxdata;         /*  resolution of D/A */
203         const struct comedi_lrange *rangelist_ai;       /*  rangelist for A/D */
204         const char *rangecode_ai;       /*  range codes for programming */
205         const struct comedi_lrange *rangelist_ao;       /*  rangelist for D/A */
206         unsigned int ai_ns_min; /*  max sample speed of card v ns */
207         unsigned int fifo_half_size;    /*  size of FIFO/2 */
208 };
209
210 static const struct boardtype boardtypes[] = {
211         [BOARD_PCI1710] = {
212                 .name           = "pci1710",
213                 .iorange        = IORANGE_171x,
214                 .have_irq       = 1,
215                 .cardtype       = TYPE_PCI171X,
216                 .n_aichan       = 16,
217                 .n_aichand      = 8,
218                 .n_aochan       = 2,
219                 .n_dichan       = 16,
220                 .n_dochan       = 16,
221                 .n_counter      = 1,
222                 .ai_maxdata     = 0x0fff,
223                 .ao_maxdata     = 0x0fff,
224                 .rangelist_ai   = &range_pci1710_3,
225                 .rangecode_ai   = range_codes_pci1710_3,
226                 .rangelist_ao   = &range_pci171x_da,
227                 .ai_ns_min      = 10000,
228                 .fifo_half_size = 2048,
229         },
230         [BOARD_PCI1710HG] = {
231                 .name           = "pci1710hg",
232                 .iorange        = IORANGE_171x,
233                 .have_irq       = 1,
234                 .cardtype       = TYPE_PCI171X,
235                 .n_aichan       = 16,
236                 .n_aichand      = 8,
237                 .n_aochan       = 2,
238                 .n_dichan       = 16,
239                 .n_dochan       = 16,
240                 .n_counter      = 1,
241                 .ai_maxdata     = 0x0fff,
242                 .ao_maxdata     = 0x0fff,
243                 .rangelist_ai   = &range_pci1710hg,
244                 .rangecode_ai   = range_codes_pci1710hg,
245                 .rangelist_ao   = &range_pci171x_da,
246                 .ai_ns_min      = 10000,
247                 .fifo_half_size = 2048,
248         },
249         [BOARD_PCI1711] = {
250                 .name           = "pci1711",
251                 .iorange        = IORANGE_171x,
252                 .have_irq       = 1,
253                 .cardtype       = TYPE_PCI171X,
254                 .n_aichan       = 16,
255                 .n_aochan       = 2,
256                 .n_dichan       = 16,
257                 .n_dochan       = 16,
258                 .n_counter      = 1,
259                 .ai_maxdata     = 0x0fff,
260                 .ao_maxdata     = 0x0fff,
261                 .rangelist_ai   = &range_pci17x1,
262                 .rangecode_ai   = range_codes_pci17x1,
263                 .rangelist_ao   = &range_pci171x_da,
264                 .ai_ns_min      = 10000,
265                 .fifo_half_size = 512,
266         },
267         [BOARD_PCI1713] = {
268                 .name           = "pci1713",
269                 .iorange        = IORANGE_171x,
270                 .have_irq       = 1,
271                 .cardtype       = TYPE_PCI1713,
272                 .n_aichan       = 32,
273                 .n_aichand      = 16,
274                 .ai_maxdata     = 0x0fff,
275                 .rangelist_ai   = &range_pci1710_3,
276                 .rangecode_ai   = range_codes_pci1710_3,
277                 .ai_ns_min      = 10000,
278                 .fifo_half_size = 2048,
279         },
280         [BOARD_PCI1720] = {
281                 .name           = "pci1720",
282                 .iorange        = IORANGE_1720,
283                 .cardtype       = TYPE_PCI1720,
284                 .n_aochan       = 4,
285                 .ao_maxdata     = 0x0fff,
286                 .rangelist_ao   = &range_pci1720,
287         },
288         [BOARD_PCI1731] = {
289                 .name           = "pci1731",
290                 .iorange        = IORANGE_171x,
291                 .have_irq       = 1,
292                 .cardtype       = TYPE_PCI171X,
293                 .n_aichan       = 16,
294                 .n_dichan       = 16,
295                 .n_dochan       = 16,
296                 .ai_maxdata     = 0x0fff,
297                 .rangelist_ai   = &range_pci17x1,
298                 .rangecode_ai   = range_codes_pci17x1,
299                 .ai_ns_min      = 10000,
300                 .fifo_half_size = 512,
301         },
302 };
303
304 struct pci1710_private {
305         char neverending_ai;    /*  we do unlimited AI */
306         unsigned int CntrlReg;  /*  Control register */
307         unsigned int i8254_osc_base;    /*  frequence of onboard oscilator */
308         unsigned int ai_do;     /*  what do AI? 0=nothing, 1 to 4 mode */
309         unsigned int ai_act_scan;       /*  how many scans we finished */
310         unsigned int ai_act_chan;       /*  actual position in actual scan */
311         unsigned int ai_buf_ptr;        /*  data buffer ptr in samples */
312         unsigned char ai_eos;   /*  1=EOS wake up */
313         unsigned char ai_et;
314         unsigned int ai_et_CntrlReg;
315         unsigned int ai_et_MuxVal;
316         unsigned int ai_et_div1, ai_et_div2;
317         unsigned int act_chanlist[32];  /*  list of scanned channel */
318         unsigned char act_chanlist_len; /*  len of scanlist */
319         unsigned char act_chanlist_pos; /*  actual position in MUX list */
320         unsigned char da_ranges;        /*  copy of D/A outpit range register */
321         unsigned int ai_scans;  /*  len of scanlist */
322         unsigned int ai_n_chan; /*  how many channels is measured */
323         unsigned int *ai_chanlist;      /*  actaul chanlist */
324         unsigned int ai_flags;  /*  flaglist */
325         unsigned int ai_data_len;       /*  len of data buffer */
326         short *ai_data;         /*  data buffer */
327         unsigned int ai_timer1; /*  timers */
328         unsigned int ai_timer2;
329         short ao_data[4];       /*  data output buffer */
330         unsigned int cnt0_write_wait;   /* after a write, wait for update of the
331                                          * internal state */
332 };
333
334 /*  used for gain list programming */
335 static const unsigned int muxonechan[] = {
336         0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707,
337         0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f,
338         0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717,
339         0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f
340 };
341
342 /*
343 ==============================================================================
344  Check if channel list from user is built correctly
345  If it's ok, then program scan/gain logic.
346  This works for all cards.
347 */
348 static int check_channel_list(struct comedi_device *dev,
349                               struct comedi_subdevice *s,
350                               unsigned int *chanlist, unsigned int n_chan)
351 {
352         unsigned int chansegment[32];
353         unsigned int i, nowmustbechan, seglen, segpos;
354
355         /* correct channel and range number check itself comedi/range.c */
356         if (n_chan < 1) {
357                 comedi_error(dev, "range/channel list is empty!");
358                 return 0;
359         }
360
361         if (n_chan == 1)
362                 return 1; /* seglen=1 */
363
364         chansegment[0] = chanlist[0]; /*  first channel is every time ok */
365         for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {
366                 if (chanlist[0] == chanlist[i])
367                         break;  /*  we detected a loop, stop */
368                 if ((CR_CHAN(chanlist[i]) & 1) &&
369                     (CR_AREF(chanlist[i]) == AREF_DIFF)) {
370                         comedi_error(dev, "Odd channel cannot be differential input!\n");
371                         return 0;
372                 }
373                 nowmustbechan = (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
374                 if (CR_AREF(chansegment[i - 1]) == AREF_DIFF)
375                         nowmustbechan = (nowmustbechan + 1) % s->n_chan;
376                 if (nowmustbechan != CR_CHAN(chanlist[i])) {
377                         printk("channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
378                                i, CR_CHAN(chanlist[i]), nowmustbechan,
379                                CR_CHAN(chanlist[0]));
380                         return 0;
381                 }
382                 chansegment[i] = chanlist[i]; /* next correct channel in list */
383         }
384
385         for (i = 0, segpos = 0; i < n_chan; i++) {
386                 if (chanlist[i] != chansegment[i % seglen]) {
387                         printk("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
388                                i, CR_CHAN(chansegment[i]),
389                                CR_RANGE(chansegment[i]),
390                                CR_AREF(chansegment[i]),
391                                CR_CHAN(chanlist[i % seglen]),
392                                CR_RANGE(chanlist[i % seglen]),
393                                CR_AREF(chansegment[i % seglen]));
394                         return 0;
395                 }
396         }
397         return seglen;
398 }
399
400 static void setup_channel_list(struct comedi_device *dev,
401                                struct comedi_subdevice *s,
402                                unsigned int *chanlist, unsigned int n_chan,
403                                unsigned int seglen)
404 {
405         const struct boardtype *this_board = comedi_board(dev);
406         struct pci1710_private *devpriv = dev->private;
407         unsigned int i, range, chanprog;
408
409         devpriv->act_chanlist_len = seglen;
410         devpriv->act_chanlist_pos = 0;
411
412         for (i = 0; i < seglen; i++) {  /*  store range list to card */
413                 chanprog = muxonechan[CR_CHAN(chanlist[i])];
414                 outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */
415                 range = this_board->rangecode_ai[CR_RANGE(chanlist[i])];
416                 if (CR_AREF(chanlist[i]) == AREF_DIFF)
417                         range |= 0x0020;
418                 outw(range, dev->iobase + PCI171x_RANGE); /* select gain */
419 #ifdef PCI171x_PARANOIDCHECK
420                 devpriv->act_chanlist[i] =
421                         (CR_CHAN(chanlist[i]) << 12) & 0xf000;
422 #endif
423         }
424 #ifdef PCI171x_PARANOIDCHECK
425         for ( ; i < n_chan; i++) { /* store remainder of channel list */
426                 devpriv->act_chanlist[i] =
427                         (CR_CHAN(chanlist[i]) << 12) & 0xf000;
428         }
429 #endif
430
431         devpriv->ai_et_MuxVal =
432                 CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
433         /* select channel interval to scan */
434         outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
435 }
436
437 /*
438 ==============================================================================
439 */
440 static int pci171x_insn_read_ai(struct comedi_device *dev,
441                                 struct comedi_subdevice *s,
442                                 struct comedi_insn *insn, unsigned int *data)
443 {
444         struct pci1710_private *devpriv = dev->private;
445         int n, timeout;
446 #ifdef PCI171x_PARANOIDCHECK
447         const struct boardtype *this_board = comedi_board(dev);
448         unsigned int idata;
449 #endif
450
451         devpriv->CntrlReg &= Control_CNT0;
452         devpriv->CntrlReg |= Control_SW;        /*  set software trigger */
453         outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
454         outb(0, dev->iobase + PCI171x_CLRFIFO);
455         outb(0, dev->iobase + PCI171x_CLRINT);
456
457         setup_channel_list(dev, s, &insn->chanspec, 1, 1);
458
459         for (n = 0; n < insn->n; n++) {
460                 outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */
461                 /* udelay(1); */
462                 timeout = 100;
463                 while (timeout--) {
464                         if (!(inw(dev->iobase + PCI171x_STATUS) & Status_FE))
465                                 goto conv_finish;
466                 }
467                 comedi_error(dev, "A/D insn timeout");
468                 outb(0, dev->iobase + PCI171x_CLRFIFO);
469                 outb(0, dev->iobase + PCI171x_CLRINT);
470                 data[n] = 0;
471                 return -ETIME;
472
473 conv_finish:
474 #ifdef PCI171x_PARANOIDCHECK
475                 idata = inw(dev->iobase + PCI171x_AD_DATA);
476                 if (this_board->cardtype != TYPE_PCI1713)
477                         if ((idata & 0xf000) != devpriv->act_chanlist[0]) {
478                                 comedi_error(dev, "A/D insn data droput!");
479                                 return -ETIME;
480                         }
481                 data[n] = idata & 0x0fff;
482 #else
483                 data[n] = inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff;
484 #endif
485
486         }
487
488         outb(0, dev->iobase + PCI171x_CLRFIFO);
489         outb(0, dev->iobase + PCI171x_CLRINT);
490
491         return n;
492 }
493
494 /*
495 ==============================================================================
496 */
497 static int pci171x_insn_write_ao(struct comedi_device *dev,
498                                  struct comedi_subdevice *s,
499                                  struct comedi_insn *insn, unsigned int *data)
500 {
501         struct pci1710_private *devpriv = dev->private;
502         int n, chan, range, ofs;
503
504         chan = CR_CHAN(insn->chanspec);
505         range = CR_RANGE(insn->chanspec);
506         if (chan) {
507                 devpriv->da_ranges &= 0xfb;
508                 devpriv->da_ranges |= (range << 2);
509                 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
510                 ofs = PCI171x_DA2;
511         } else {
512                 devpriv->da_ranges &= 0xfe;
513                 devpriv->da_ranges |= range;
514                 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
515                 ofs = PCI171x_DA1;
516         }
517
518         for (n = 0; n < insn->n; n++)
519                 outw(data[n], dev->iobase + ofs);
520
521         devpriv->ao_data[chan] = data[n];
522
523         return n;
524
525 }
526
527 /*
528 ==============================================================================
529 */
530 static int pci171x_insn_read_ao(struct comedi_device *dev,
531                                 struct comedi_subdevice *s,
532                                 struct comedi_insn *insn, unsigned int *data)
533 {
534         struct pci1710_private *devpriv = dev->private;
535         int n, chan;
536
537         chan = CR_CHAN(insn->chanspec);
538         for (n = 0; n < insn->n; n++)
539                 data[n] = devpriv->ao_data[chan];
540
541         return n;
542 }
543
544 /*
545 ==============================================================================
546 */
547 static int pci171x_insn_bits_di(struct comedi_device *dev,
548                                 struct comedi_subdevice *s,
549                                 struct comedi_insn *insn, unsigned int *data)
550 {
551         data[1] = inw(dev->iobase + PCI171x_DI);
552
553         return insn->n;
554 }
555
556 /*
557 ==============================================================================
558 */
559 static int pci171x_insn_bits_do(struct comedi_device *dev,
560                                 struct comedi_subdevice *s,
561                                 struct comedi_insn *insn, unsigned int *data)
562 {
563         if (data[0]) {
564                 s->state &= ~data[0];
565                 s->state |= (data[0] & data[1]);
566                 outw(s->state, dev->iobase + PCI171x_DO);
567         }
568         data[1] = s->state;
569
570         return insn->n;
571 }
572
573 /*
574 ==============================================================================
575 */
576 static void start_pacer(struct comedi_device *dev, int mode,
577                         unsigned int divisor1, unsigned int divisor2)
578 {
579         outw(0xb4, dev->iobase + PCI171x_CNTCTRL);
580         outw(0x74, dev->iobase + PCI171x_CNTCTRL);
581
582         if (mode == 1) {
583                 outw(divisor2 & 0xff, dev->iobase + PCI171x_CNT2);
584                 outw((divisor2 >> 8) & 0xff, dev->iobase + PCI171x_CNT2);
585                 outw(divisor1 & 0xff, dev->iobase + PCI171x_CNT1);
586                 outw((divisor1 >> 8) & 0xff, dev->iobase + PCI171x_CNT1);
587         }
588 }
589
590 /*
591 ==============================================================================
592 */
593 static int pci171x_insn_counter_read(struct comedi_device *dev,
594                                      struct comedi_subdevice *s,
595                                      struct comedi_insn *insn,
596                                      unsigned int *data)
597 {
598         unsigned int msb, lsb, ccntrl;
599         int i;
600
601         ccntrl = 0xD2;          /* count only */
602         for (i = 0; i < insn->n; i++) {
603                 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
604
605                 lsb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
606                 msb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
607
608                 data[0] = lsb | (msb << 8);
609         }
610
611         return insn->n;
612 }
613
614 /*
615 ==============================================================================
616 */
617 static int pci171x_insn_counter_write(struct comedi_device *dev,
618                                       struct comedi_subdevice *s,
619                                       struct comedi_insn *insn,
620                                       unsigned int *data)
621 {
622         struct pci1710_private *devpriv = dev->private;
623         uint msb, lsb, ccntrl, status;
624
625         lsb = data[0] & 0x00FF;
626         msb = (data[0] & 0xFF00) >> 8;
627
628         /* write lsb, then msb */
629         outw(lsb, dev->iobase + PCI171x_CNT0);
630         outw(msb, dev->iobase + PCI171x_CNT0);
631
632         if (devpriv->cnt0_write_wait) {
633                 /* wait for the new count to be loaded */
634                 ccntrl = 0xE2;
635                 do {
636                         outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
637                         status = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
638                 } while (status & 0x40);
639         }
640
641         return insn->n;
642 }
643
644 /*
645 ==============================================================================
646 */
647 static int pci171x_insn_counter_config(struct comedi_device *dev,
648                                        struct comedi_subdevice *s,
649                                        struct comedi_insn *insn,
650                                        unsigned int *data)
651 {
652 #ifdef unused
653         /* This doesn't work like a normal Comedi counter config */
654         struct pci1710_private *devpriv = dev->private;
655         uint ccntrl = 0;
656
657         devpriv->cnt0_write_wait = data[0] & 0x20;
658
659         /* internal or external clock? */
660         if (!(data[0] & 0x10)) {        /* internal */
661                 devpriv->CntrlReg &= ~Control_CNT0;
662         } else {
663                 devpriv->CntrlReg |= Control_CNT0;
664         }
665         outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
666
667         if (data[0] & 0x01)
668                 ccntrl |= Counter_M0;
669         if (data[0] & 0x02)
670                 ccntrl |= Counter_M1;
671         if (data[0] & 0x04)
672                 ccntrl |= Counter_M2;
673         if (data[0] & 0x08)
674                 ccntrl |= Counter_BCD;
675         ccntrl |= Counter_RW0;  /* set read/write mode */
676         ccntrl |= Counter_RW1;
677         outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
678 #endif
679
680         return 1;
681 }
682
683 /*
684 ==============================================================================
685 */
686 static int pci1720_insn_write_ao(struct comedi_device *dev,
687                                  struct comedi_subdevice *s,
688                                  struct comedi_insn *insn, unsigned int *data)
689 {
690         struct pci1710_private *devpriv = dev->private;
691         int n, rangereg, chan;
692
693         chan = CR_CHAN(insn->chanspec);
694         rangereg = devpriv->da_ranges & (~(0x03 << (chan << 1)));
695         rangereg |= (CR_RANGE(insn->chanspec) << (chan << 1));
696         if (rangereg != devpriv->da_ranges) {
697                 outb(rangereg, dev->iobase + PCI1720_RANGE);
698                 devpriv->da_ranges = rangereg;
699         }
700
701         for (n = 0; n < insn->n; n++) {
702                 outw(data[n], dev->iobase + PCI1720_DA0 + (chan << 1));
703                 outb(0, dev->iobase + PCI1720_SYNCOUT); /*  update outputs */
704         }
705
706         devpriv->ao_data[chan] = data[n];
707
708         return n;
709 }
710
711 /*
712 ==============================================================================
713 */
714 static int pci171x_ai_cancel(struct comedi_device *dev,
715                              struct comedi_subdevice *s)
716 {
717         const struct boardtype *this_board = comedi_board(dev);
718         struct pci1710_private *devpriv = dev->private;
719
720         switch (this_board->cardtype) {
721         default:
722                 devpriv->CntrlReg &= Control_CNT0;
723                 devpriv->CntrlReg |= Control_SW;
724
725                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /*  reset any operations */
726                 start_pacer(dev, -1, 0, 0);
727                 outb(0, dev->iobase + PCI171x_CLRFIFO);
728                 outb(0, dev->iobase + PCI171x_CLRINT);
729                 break;
730         }
731
732         devpriv->ai_do = 0;
733         devpriv->ai_act_scan = 0;
734         s->async->cur_chan = 0;
735         devpriv->ai_buf_ptr = 0;
736         devpriv->neverending_ai = 0;
737
738         return 0;
739 }
740
741 /*
742 ==============================================================================
743 */
744 static void interrupt_pci1710_every_sample(void *d)
745 {
746         struct comedi_device *dev = d;
747         struct pci1710_private *devpriv = dev->private;
748         struct comedi_subdevice *s = &dev->subdevices[0];
749         int m;
750 #ifdef PCI171x_PARANOIDCHECK
751         const struct boardtype *this_board = comedi_board(dev);
752         short sampl;
753 #endif
754
755         m = inw(dev->iobase + PCI171x_STATUS);
756         if (m & Status_FE) {
757                 printk("comedi%d: A/D FIFO empty (%4x)\n", dev->minor, m);
758                 pci171x_ai_cancel(dev, s);
759                 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
760                 comedi_event(dev, s);
761                 return;
762         }
763         if (m & Status_FF) {
764                 printk
765                     ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
766                      dev->minor, m);
767                 pci171x_ai_cancel(dev, s);
768                 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
769                 comedi_event(dev, s);
770                 return;
771         }
772
773         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear our INT request */
774
775         for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
776 #ifdef PCI171x_PARANOIDCHECK
777                 sampl = inw(dev->iobase + PCI171x_AD_DATA);
778                 if (this_board->cardtype != TYPE_PCI1713)
779                         if ((sampl & 0xf000) !=
780                             devpriv->act_chanlist[s->async->cur_chan]) {
781                                 printk
782                                     ("comedi: A/D data dropout: received data from channel %d, expected %d!\n",
783                                      (sampl & 0xf000) >> 12,
784                                      (devpriv->
785                                       act_chanlist[s->
786                                                    async->cur_chan] & 0xf000) >>
787                                      12);
788                                 pci171x_ai_cancel(dev, s);
789                                 s->async->events |=
790                                     COMEDI_CB_EOA | COMEDI_CB_ERROR;
791                                 comedi_event(dev, s);
792                                 return;
793                         }
794                 comedi_buf_put(s->async, sampl & 0x0fff);
795 #else
796                 comedi_buf_put(s->async,
797                                inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
798 #endif
799                 ++s->async->cur_chan;
800
801                 if (s->async->cur_chan >= devpriv->ai_n_chan)
802                         s->async->cur_chan = 0;
803
804
805                 if (s->async->cur_chan == 0) {  /*  one scan done */
806                         devpriv->ai_act_scan++;
807                         if ((!devpriv->neverending_ai) &&
808                             (devpriv->ai_act_scan >= devpriv->ai_scans)) {
809                                 /*  all data sampled */
810                                 pci171x_ai_cancel(dev, s);
811                                 s->async->events |= COMEDI_CB_EOA;
812                                 comedi_event(dev, s);
813                                 return;
814                         }
815                 }
816         }
817
818         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear our INT request */
819
820         comedi_event(dev, s);
821 }
822
823 /*
824 ==============================================================================
825 */
826 static int move_block_from_fifo(struct comedi_device *dev,
827                                 struct comedi_subdevice *s, int n, int turn)
828 {
829         struct pci1710_private *devpriv = dev->private;
830         int i, j;
831 #ifdef PCI171x_PARANOIDCHECK
832         const struct boardtype *this_board = comedi_board(dev);
833         int sampl;
834 #endif
835
836         j = s->async->cur_chan;
837         for (i = 0; i < n; i++) {
838 #ifdef PCI171x_PARANOIDCHECK
839                 sampl = inw(dev->iobase + PCI171x_AD_DATA);
840                 if (this_board->cardtype != TYPE_PCI1713)
841                         if ((sampl & 0xf000) != devpriv->act_chanlist[j]) {
842                                 printk
843                                     ("comedi%d: A/D  FIFO data dropout: received data from channel %d, expected %d! (%d/%d/%d/%d/%d/%4x)\n",
844                                      dev->minor, (sampl & 0xf000) >> 12,
845                                      (devpriv->act_chanlist[j] & 0xf000) >> 12,
846                                      i, j, devpriv->ai_act_scan, n, turn,
847                                      sampl);
848                                 pci171x_ai_cancel(dev, s);
849                                 s->async->events |=
850                                     COMEDI_CB_EOA | COMEDI_CB_ERROR;
851                                 comedi_event(dev, s);
852                                 return 1;
853                         }
854                 comedi_buf_put(s->async, sampl & 0x0fff);
855 #else
856                 comedi_buf_put(s->async,
857                                inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
858 #endif
859                 j++;
860                 if (j >= devpriv->ai_n_chan) {
861                         j = 0;
862                         devpriv->ai_act_scan++;
863                 }
864         }
865         s->async->cur_chan = j;
866         return 0;
867 }
868
869 /*
870 ==============================================================================
871 */
872 static void interrupt_pci1710_half_fifo(void *d)
873 {
874         struct comedi_device *dev = d;
875         const struct boardtype *this_board = comedi_board(dev);
876         struct pci1710_private *devpriv = dev->private;
877         struct comedi_subdevice *s = &dev->subdevices[0];
878         int m, samplesinbuf;
879
880         m = inw(dev->iobase + PCI171x_STATUS);
881         if (!(m & Status_FH)) {
882                 printk("comedi%d: A/D FIFO not half full! (%4x)\n",
883                        dev->minor, m);
884                 pci171x_ai_cancel(dev, s);
885                 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
886                 comedi_event(dev, s);
887                 return;
888         }
889         if (m & Status_FF) {
890                 printk
891                     ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
892                      dev->minor, m);
893                 pci171x_ai_cancel(dev, s);
894                 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
895                 comedi_event(dev, s);
896                 return;
897         }
898
899         samplesinbuf = this_board->fifo_half_size;
900         if (samplesinbuf * sizeof(short) >= devpriv->ai_data_len) {
901                 m = devpriv->ai_data_len / sizeof(short);
902                 if (move_block_from_fifo(dev, s, m, 0))
903                         return;
904                 samplesinbuf -= m;
905         }
906
907         if (samplesinbuf) {
908                 if (move_block_from_fifo(dev, s, samplesinbuf, 1))
909                         return;
910         }
911
912         if (!devpriv->neverending_ai)
913                 if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data
914                                                                     sampled */
915                         pci171x_ai_cancel(dev, s);
916                         s->async->events |= COMEDI_CB_EOA;
917                         comedi_event(dev, s);
918                         return;
919                 }
920         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear our INT request */
921
922         comedi_event(dev, s);
923 }
924
925 /*
926 ==============================================================================
927 */
928 static irqreturn_t interrupt_service_pci1710(int irq, void *d)
929 {
930         struct comedi_device *dev = d;
931         struct pci1710_private *devpriv = dev->private;
932
933         if (!dev->attached)     /*  is device attached? */
934                 return IRQ_NONE;        /*  no, exit */
935         /*  is this interrupt from our board? */
936         if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))
937                 return IRQ_NONE;        /*  no, exit */
938
939         if (devpriv->ai_et) {   /*  Switch from initial TRIG_EXT to TRIG_xxx. */
940                 devpriv->ai_et = 0;
941                 devpriv->CntrlReg &= Control_CNT0;
942                 devpriv->CntrlReg |= Control_SW; /* set software trigger */
943                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
944                 devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
945                 outb(0, dev->iobase + PCI171x_CLRFIFO);
946                 outb(0, dev->iobase + PCI171x_CLRINT);
947                 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
948                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
949                 /*  start pacer */
950                 start_pacer(dev, 1, devpriv->ai_et_div1, devpriv->ai_et_div2);
951                 return IRQ_HANDLED;
952         }
953         if (devpriv->ai_eos) {  /*  We use FIFO half full INT or not? */
954                 interrupt_pci1710_every_sample(d);
955         } else {
956                 interrupt_pci1710_half_fifo(d);
957         }
958         return IRQ_HANDLED;
959 }
960
961 /*
962 ==============================================================================
963 */
964 static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev,
965                                      struct comedi_subdevice *s)
966 {
967         const struct boardtype *this_board = comedi_board(dev);
968         struct pci1710_private *devpriv = dev->private;
969         unsigned int divisor1 = 0, divisor2 = 0;
970         unsigned int seglen;
971
972         start_pacer(dev, -1, 0, 0);     /*  stop pacer */
973
974         seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
975                                     devpriv->ai_n_chan);
976         if (seglen < 1)
977                 return -EINVAL;
978         setup_channel_list(dev, s, devpriv->ai_chanlist,
979                            devpriv->ai_n_chan, seglen);
980
981         outb(0, dev->iobase + PCI171x_CLRFIFO);
982         outb(0, dev->iobase + PCI171x_CLRINT);
983
984         devpriv->ai_do = mode;
985
986         devpriv->ai_act_scan = 0;
987         s->async->cur_chan = 0;
988         devpriv->ai_buf_ptr = 0;
989         devpriv->neverending_ai = 0;
990
991         devpriv->CntrlReg &= Control_CNT0;
992         /*  don't we want wake up every scan?  devpriv->ai_eos=1; */
993         if ((devpriv->ai_flags & TRIG_WAKE_EOS)) {
994                 devpriv->ai_eos = 1;
995         } else {
996                 devpriv->CntrlReg |= Control_ONEFH;
997                 devpriv->ai_eos = 0;
998         }
999
1000         if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1))
1001                 devpriv->neverending_ai = 1;
1002         /* well, user want neverending */
1003         else
1004                 devpriv->neverending_ai = 0;
1005
1006         switch (mode) {
1007         case 1:
1008         case 2:
1009                 if (devpriv->ai_timer1 < this_board->ai_ns_min)
1010                         devpriv->ai_timer1 = this_board->ai_ns_min;
1011                 devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
1012                 if (mode == 2) {
1013                         devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
1014                         devpriv->CntrlReg &=
1015                             ~(Control_PACER | Control_ONEFH | Control_GATE);
1016                         devpriv->CntrlReg |= Control_EXT;
1017                         devpriv->ai_et = 1;
1018                 } else {
1019                         devpriv->ai_et = 0;
1020                 }
1021                 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
1022                                           &divisor2, &devpriv->ai_timer1,
1023                                           devpriv->ai_flags & TRIG_ROUND_MASK);
1024                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
1025                 if (mode != 2) {
1026                         /*  start pacer */
1027                         start_pacer(dev, mode, divisor1, divisor2);
1028                 } else {
1029                         devpriv->ai_et_div1 = divisor1;
1030                         devpriv->ai_et_div2 = divisor2;
1031                 }
1032                 break;
1033         case 3:
1034                 devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
1035                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
1036                 break;
1037         }
1038
1039         return 0;
1040 }
1041
1042 /*
1043 ==============================================================================
1044 */
1045 static int pci171x_ai_cmdtest(struct comedi_device *dev,
1046                               struct comedi_subdevice *s,
1047                               struct comedi_cmd *cmd)
1048 {
1049         const struct boardtype *this_board = comedi_board(dev);
1050         struct pci1710_private *devpriv = dev->private;
1051         int err = 0;
1052         int tmp;
1053         unsigned int divisor1 = 0, divisor2 = 0;
1054
1055         /* Step 1 : check if triggers are trivially valid */
1056
1057         err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
1058         err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
1059         err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
1060         err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
1061         err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
1062
1063         if (err)
1064                 return 1;
1065
1066         /* step 2a: make sure trigger sources are unique */
1067
1068         err |= cfc_check_trigger_is_unique(cmd->start_src);
1069         err |= cfc_check_trigger_is_unique(cmd->convert_src);
1070         err |= cfc_check_trigger_is_unique(cmd->stop_src);
1071
1072         /* step 2b: and mutually compatible */
1073
1074         if (err)
1075                 return 2;
1076
1077         /* Step 3: check if arguments are trivially valid */
1078
1079         err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
1080         err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
1081
1082         if (cmd->convert_src == TRIG_TIMER)
1083                 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
1084                                                  this_board->ai_ns_min);
1085         else    /* TRIG_FOLLOW */
1086                 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
1087
1088         err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
1089
1090         if (cmd->stop_src == TRIG_COUNT)
1091                 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
1092         else    /* TRIG_NONE */
1093                 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
1094
1095         if (err)
1096                 return 3;
1097
1098         /* step 4: fix up any arguments */
1099
1100         if (cmd->convert_src == TRIG_TIMER) {
1101                 tmp = cmd->convert_arg;
1102                 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
1103                                           &divisor2, &cmd->convert_arg,
1104                                           cmd->flags & TRIG_ROUND_MASK);
1105                 if (cmd->convert_arg < this_board->ai_ns_min)
1106                         cmd->convert_arg = this_board->ai_ns_min;
1107                 if (tmp != cmd->convert_arg)
1108                         err++;
1109         }
1110
1111         if (err)
1112                 return 4;
1113
1114         /* step 5: complain about special chanlist considerations */
1115
1116         if (cmd->chanlist) {
1117                 if (!check_channel_list(dev, s, cmd->chanlist,
1118                                         cmd->chanlist_len))
1119                         return 5;       /*  incorrect channels list */
1120         }
1121
1122         return 0;
1123 }
1124
1125 /*
1126 ==============================================================================
1127 */
1128 static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1129 {
1130         struct pci1710_private *devpriv = dev->private;
1131         struct comedi_cmd *cmd = &s->async->cmd;
1132
1133         devpriv->ai_n_chan = cmd->chanlist_len;
1134         devpriv->ai_chanlist = cmd->chanlist;
1135         devpriv->ai_flags = cmd->flags;
1136         devpriv->ai_data_len = s->async->prealloc_bufsz;
1137         devpriv->ai_data = s->async->prealloc_buf;
1138         devpriv->ai_timer1 = 0;
1139         devpriv->ai_timer2 = 0;
1140
1141         if (cmd->stop_src == TRIG_COUNT)
1142                 devpriv->ai_scans = cmd->stop_arg;
1143         else
1144                 devpriv->ai_scans = 0;
1145
1146
1147         if (cmd->scan_begin_src == TRIG_FOLLOW) {       /*  mode 1, 2, 3 */
1148                 if (cmd->convert_src == TRIG_TIMER) {   /*  mode 1 and 2 */
1149                         devpriv->ai_timer1 = cmd->convert_arg;
1150                         return pci171x_ai_docmd_and_mode(cmd->start_src ==
1151                                                          TRIG_EXT ? 2 : 1, dev,
1152                                                          s);
1153                 }
1154                 if (cmd->convert_src == TRIG_EXT) {     /*  mode 3 */
1155                         return pci171x_ai_docmd_and_mode(3, dev, s);
1156                 }
1157         }
1158
1159         return -1;
1160 }
1161
1162 /*
1163 ==============================================================================
1164 */
1165 static int pci171x_reset(struct comedi_device *dev)
1166 {
1167         const struct boardtype *this_board = comedi_board(dev);
1168         struct pci1710_private *devpriv = dev->private;
1169
1170         outw(0x30, dev->iobase + PCI171x_CNTCTRL);
1171         devpriv->CntrlReg = Control_SW | Control_CNT0;  /*  Software trigger, CNT0=external */
1172         outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /*  reset any operations */
1173         outb(0, dev->iobase + PCI171x_CLRFIFO); /*  clear FIFO */
1174         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear INT request */
1175         start_pacer(dev, -1, 0, 0);     /*  stop 8254 */
1176         devpriv->da_ranges = 0;
1177         if (this_board->n_aochan) {
1178                 outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);  /*  set DACs to 0..5V */
1179                 outw(0, dev->iobase + PCI171x_DA1);     /*  set DA outputs to 0V */
1180                 devpriv->ao_data[0] = 0x0000;
1181                 if (this_board->n_aochan > 1) {
1182                         outw(0, dev->iobase + PCI171x_DA2);
1183                         devpriv->ao_data[1] = 0x0000;
1184                 }
1185         }
1186         outw(0, dev->iobase + PCI171x_DO);      /*  digital outputs to 0 */
1187         outb(0, dev->iobase + PCI171x_CLRFIFO); /*  clear FIFO */
1188         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear INT request */
1189
1190         return 0;
1191 }
1192
1193 /*
1194 ==============================================================================
1195 */
1196 static int pci1720_reset(struct comedi_device *dev)
1197 {
1198         struct pci1710_private *devpriv = dev->private;
1199
1200         outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT);       /*  set synchronous output mode */
1201         devpriv->da_ranges = 0xAA;
1202         outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE);  /*  set all ranges to +/-5V */
1203         outw(0x0800, dev->iobase + PCI1720_DA0);        /*  set outputs to 0V */
1204         outw(0x0800, dev->iobase + PCI1720_DA1);
1205         outw(0x0800, dev->iobase + PCI1720_DA2);
1206         outw(0x0800, dev->iobase + PCI1720_DA3);
1207         outb(0, dev->iobase + PCI1720_SYNCOUT); /*  update outputs */
1208         devpriv->ao_data[0] = 0x0800;
1209         devpriv->ao_data[1] = 0x0800;
1210         devpriv->ao_data[2] = 0x0800;
1211         devpriv->ao_data[3] = 0x0800;
1212         return 0;
1213 }
1214
1215 /*
1216 ==============================================================================
1217 */
1218 static int pci1710_reset(struct comedi_device *dev)
1219 {
1220         const struct boardtype *this_board = comedi_board(dev);
1221
1222         switch (this_board->cardtype) {
1223         case TYPE_PCI1720:
1224                 return pci1720_reset(dev);
1225         default:
1226                 return pci171x_reset(dev);
1227         }
1228 }
1229
1230 static int pci1710_auto_attach(struct comedi_device *dev,
1231                                unsigned long context)
1232 {
1233         struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1234         const struct boardtype *this_board = NULL;
1235         struct pci1710_private *devpriv;
1236         struct comedi_subdevice *s;
1237         int ret, subdev, n_subdevices;
1238
1239         if (context < ARRAY_SIZE(boardtypes))
1240                 this_board = &boardtypes[context];
1241         if (!this_board)
1242                 return -ENODEV;
1243         dev->board_ptr = this_board;
1244         dev->board_name = this_board->name;
1245
1246         devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
1247         if (!devpriv)
1248                 return -ENOMEM;
1249         dev->private = devpriv;
1250
1251         ret = comedi_pci_enable(dev);
1252         if (ret)
1253                 return ret;
1254         dev->iobase = pci_resource_start(pcidev, 2);
1255
1256         n_subdevices = 0;
1257         if (this_board->n_aichan)
1258                 n_subdevices++;
1259         if (this_board->n_aochan)
1260                 n_subdevices++;
1261         if (this_board->n_dichan)
1262                 n_subdevices++;
1263         if (this_board->n_dochan)
1264                 n_subdevices++;
1265         if (this_board->n_counter)
1266                 n_subdevices++;
1267
1268         ret = comedi_alloc_subdevices(dev, n_subdevices);
1269         if (ret)
1270                 return ret;
1271
1272         pci1710_reset(dev);
1273
1274         if (this_board->have_irq && pcidev->irq) {
1275                 ret = request_irq(pcidev->irq, interrupt_service_pci1710,
1276                                   IRQF_SHARED, dev->board_name, dev);
1277                 if (ret == 0)
1278                         dev->irq = pcidev->irq;
1279         }
1280
1281         subdev = 0;
1282
1283         if (this_board->n_aichan) {
1284                 s = &dev->subdevices[subdev];
1285                 dev->read_subdev = s;
1286                 s->type = COMEDI_SUBD_AI;
1287                 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
1288                 if (this_board->n_aichand)
1289                         s->subdev_flags |= SDF_DIFF;
1290                 s->n_chan = this_board->n_aichan;
1291                 s->maxdata = this_board->ai_maxdata;
1292                 s->len_chanlist = this_board->n_aichan;
1293                 s->range_table = this_board->rangelist_ai;
1294                 s->cancel = pci171x_ai_cancel;
1295                 s->insn_read = pci171x_insn_read_ai;
1296                 if (dev->irq) {
1297                         s->subdev_flags |= SDF_CMD_READ;
1298                         s->do_cmdtest = pci171x_ai_cmdtest;
1299                         s->do_cmd = pci171x_ai_cmd;
1300                 }
1301                 devpriv->i8254_osc_base = 100;  /*  100ns=10MHz */
1302                 subdev++;
1303         }
1304
1305         if (this_board->n_aochan) {
1306                 s = &dev->subdevices[subdev];
1307                 s->type = COMEDI_SUBD_AO;
1308                 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1309                 s->n_chan = this_board->n_aochan;
1310                 s->maxdata = this_board->ao_maxdata;
1311                 s->len_chanlist = this_board->n_aochan;
1312                 s->range_table = this_board->rangelist_ao;
1313                 switch (this_board->cardtype) {
1314                 case TYPE_PCI1720:
1315                         s->insn_write = pci1720_insn_write_ao;
1316                         break;
1317                 default:
1318                         s->insn_write = pci171x_insn_write_ao;
1319                         break;
1320                 }
1321                 s->insn_read = pci171x_insn_read_ao;
1322                 subdev++;
1323         }
1324
1325         if (this_board->n_dichan) {
1326                 s = &dev->subdevices[subdev];
1327                 s->type = COMEDI_SUBD_DI;
1328                 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
1329                 s->n_chan = this_board->n_dichan;
1330                 s->maxdata = 1;
1331                 s->len_chanlist = this_board->n_dichan;
1332                 s->range_table = &range_digital;
1333                 s->io_bits = 0; /* all bits input */
1334                 s->insn_bits = pci171x_insn_bits_di;
1335                 subdev++;
1336         }
1337
1338         if (this_board->n_dochan) {
1339                 s = &dev->subdevices[subdev];
1340                 s->type = COMEDI_SUBD_DO;
1341                 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1342                 s->n_chan = this_board->n_dochan;
1343                 s->maxdata = 1;
1344                 s->len_chanlist = this_board->n_dochan;
1345                 s->range_table = &range_digital;
1346                 /* all bits output */
1347                 s->io_bits = (1 << this_board->n_dochan) - 1;
1348                 s->state = 0;
1349                 s->insn_bits = pci171x_insn_bits_do;
1350                 subdev++;
1351         }
1352
1353         if (this_board->n_counter) {
1354                 s = &dev->subdevices[subdev];
1355                 s->type = COMEDI_SUBD_COUNTER;
1356                 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1357                 s->n_chan = this_board->n_counter;
1358                 s->len_chanlist = this_board->n_counter;
1359                 s->maxdata = 0xffff;
1360                 s->range_table = &range_unknown;
1361                 s->insn_read = pci171x_insn_counter_read;
1362                 s->insn_write = pci171x_insn_counter_write;
1363                 s->insn_config = pci171x_insn_counter_config;
1364                 subdev++;
1365         }
1366
1367         dev_info(dev->class_dev, "%s attached, irq %sabled\n",
1368                 dev->board_name, dev->irq ? "en" : "dis");
1369
1370         return 0;
1371 }
1372
1373 static void pci1710_detach(struct comedi_device *dev)
1374 {
1375         if (dev->iobase)
1376                 pci1710_reset(dev);
1377         if (dev->irq)
1378                 free_irq(dev->irq, dev);
1379         comedi_pci_disable(dev);
1380 }
1381
1382 static struct comedi_driver adv_pci1710_driver = {
1383         .driver_name    = "adv_pci1710",
1384         .module         = THIS_MODULE,
1385         .auto_attach    = pci1710_auto_attach,
1386         .detach         = pci1710_detach,
1387 };
1388
1389 static int adv_pci1710_pci_probe(struct pci_dev *dev,
1390                                  const struct pci_device_id *id)
1391 {
1392         return comedi_pci_auto_config(dev, &adv_pci1710_driver,
1393                                       id->driver_data);
1394 }
1395
1396 static DEFINE_PCI_DEVICE_TABLE(adv_pci1710_pci_table) = {
1397         {
1398                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1399                                PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050),
1400                 .driver_data = BOARD_PCI1710,
1401         }, {
1402                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1403                                PCI_VENDOR_ID_ADVANTECH, 0x0000),
1404                 .driver_data = BOARD_PCI1710,
1405         }, {
1406                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1407                                PCI_VENDOR_ID_ADVANTECH, 0xb100),
1408                 .driver_data = BOARD_PCI1710,
1409         }, {
1410                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1411                                PCI_VENDOR_ID_ADVANTECH, 0xb200),
1412                 .driver_data = BOARD_PCI1710,
1413         }, {
1414                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1415                                PCI_VENDOR_ID_ADVANTECH, 0xc100),
1416                 .driver_data = BOARD_PCI1710,
1417         }, {
1418                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1419                                PCI_VENDOR_ID_ADVANTECH, 0xc200),
1420                 .driver_data = BOARD_PCI1710,
1421         }, {
1422                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd100),
1423                 .driver_data = BOARD_PCI1710,
1424         }, {
1425                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1426                                PCI_VENDOR_ID_ADVANTECH, 0x0002),
1427                 .driver_data = BOARD_PCI1710HG,
1428         }, {
1429                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1430                                PCI_VENDOR_ID_ADVANTECH, 0xb102),
1431                 .driver_data = BOARD_PCI1710HG,
1432         }, {
1433                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1434                                PCI_VENDOR_ID_ADVANTECH, 0xb202),
1435                 .driver_data = BOARD_PCI1710HG,
1436         }, {
1437                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1438                                PCI_VENDOR_ID_ADVANTECH, 0xc102),
1439                 .driver_data = BOARD_PCI1710HG,
1440         }, {
1441                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1442                                PCI_VENDOR_ID_ADVANTECH, 0xc202),
1443                 .driver_data = BOARD_PCI1710HG,
1444         }, {
1445                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd102),
1446                 .driver_data = BOARD_PCI1710HG,
1447         },
1448         { PCI_VDEVICE(ADVANTECH, 0x1711), BOARD_PCI1711 },
1449         { PCI_VDEVICE(ADVANTECH, 0x1713), BOARD_PCI1713 },
1450         { PCI_VDEVICE(ADVANTECH, 0x1720), BOARD_PCI1720 },
1451         { PCI_VDEVICE(ADVANTECH, 0x1731), BOARD_PCI1731 },
1452         { 0 }
1453 };
1454 MODULE_DEVICE_TABLE(pci, adv_pci1710_pci_table);
1455
1456 static struct pci_driver adv_pci1710_pci_driver = {
1457         .name           = "adv_pci1710",
1458         .id_table       = adv_pci1710_pci_table,
1459         .probe          = adv_pci1710_pci_probe,
1460         .remove         = comedi_pci_auto_unconfig,
1461 };
1462 module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver);
1463
1464 MODULE_AUTHOR("Comedi http://www.comedi.org");
1465 MODULE_DESCRIPTION("Comedi low-level driver");
1466 MODULE_LICENSE("GPL");