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