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