]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/comedi/drivers/adv_pci1710.c
Merge branch 'core-locking-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[karo-tx-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         short *ai_data;         /*  data buffer */
318         unsigned int ai_timer1; /*  timers */
319         unsigned int ai_timer2;
320         short ao_data[4];       /*  data output buffer */
321         unsigned int cnt0_write_wait;   /* after a write, wait for update of the
322                                          * internal state */
323 };
324
325 /*  used for gain list programming */
326 static const unsigned int muxonechan[] = {
327         0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707,
328         0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f,
329         0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717,
330         0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f
331 };
332
333 /*
334 ==============================================================================
335  Check if channel list from user is built correctly
336  If it's ok, then program scan/gain logic.
337  This works for all cards.
338 */
339 static int check_channel_list(struct comedi_device *dev,
340                               struct comedi_subdevice *s,
341                               unsigned int *chanlist, unsigned int n_chan)
342 {
343         unsigned int chansegment[32];
344         unsigned int i, nowmustbechan, seglen, segpos;
345
346         /* correct channel and range number check itself comedi/range.c */
347         if (n_chan < 1) {
348                 comedi_error(dev, "range/channel list is empty!");
349                 return 0;
350         }
351
352         if (n_chan == 1)
353                 return 1; /* seglen=1 */
354
355         chansegment[0] = chanlist[0]; /*  first channel is every time ok */
356         for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {
357                 if (chanlist[0] == chanlist[i])
358                         break;  /*  we detected a loop, stop */
359                 if ((CR_CHAN(chanlist[i]) & 1) &&
360                     (CR_AREF(chanlist[i]) == AREF_DIFF)) {
361                         comedi_error(dev, "Odd channel cannot be differential input!\n");
362                         return 0;
363                 }
364                 nowmustbechan = (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
365                 if (CR_AREF(chansegment[i - 1]) == AREF_DIFF)
366                         nowmustbechan = (nowmustbechan + 1) % s->n_chan;
367                 if (nowmustbechan != CR_CHAN(chanlist[i])) {
368                         printk("channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
369                                i, CR_CHAN(chanlist[i]), nowmustbechan,
370                                CR_CHAN(chanlist[0]));
371                         return 0;
372                 }
373                 chansegment[i] = chanlist[i]; /* next correct channel in list */
374         }
375
376         for (i = 0, segpos = 0; i < n_chan; i++) {
377                 if (chanlist[i] != chansegment[i % seglen]) {
378                         printk("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
379                                i, CR_CHAN(chansegment[i]),
380                                CR_RANGE(chansegment[i]),
381                                CR_AREF(chansegment[i]),
382                                CR_CHAN(chanlist[i % seglen]),
383                                CR_RANGE(chanlist[i % seglen]),
384                                CR_AREF(chansegment[i % seglen]));
385                         return 0;
386                 }
387         }
388         return seglen;
389 }
390
391 static void setup_channel_list(struct comedi_device *dev,
392                                struct comedi_subdevice *s,
393                                unsigned int *chanlist, unsigned int n_chan,
394                                unsigned int seglen)
395 {
396         const struct boardtype *this_board = comedi_board(dev);
397         struct pci1710_private *devpriv = dev->private;
398         unsigned int i, range, chanprog;
399
400         devpriv->act_chanlist_len = seglen;
401         devpriv->act_chanlist_pos = 0;
402
403         for (i = 0; i < seglen; i++) {  /*  store range list to card */
404                 chanprog = muxonechan[CR_CHAN(chanlist[i])];
405                 outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */
406                 range = this_board->rangecode_ai[CR_RANGE(chanlist[i])];
407                 if (CR_AREF(chanlist[i]) == AREF_DIFF)
408                         range |= 0x0020;
409                 outw(range, dev->iobase + PCI171x_RANGE); /* select gain */
410 #ifdef PCI171x_PARANOIDCHECK
411                 devpriv->act_chanlist[i] =
412                         (CR_CHAN(chanlist[i]) << 12) & 0xf000;
413 #endif
414         }
415 #ifdef PCI171x_PARANOIDCHECK
416         for ( ; i < n_chan; i++) { /* store remainder of channel list */
417                 devpriv->act_chanlist[i] =
418                         (CR_CHAN(chanlist[i]) << 12) & 0xf000;
419         }
420 #endif
421
422         devpriv->ai_et_MuxVal =
423                 CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
424         /* select channel interval to scan */
425         outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
426 }
427
428 /*
429 ==============================================================================
430 */
431 static int pci171x_insn_read_ai(struct comedi_device *dev,
432                                 struct comedi_subdevice *s,
433                                 struct comedi_insn *insn, unsigned int *data)
434 {
435         struct pci1710_private *devpriv = dev->private;
436         int n, timeout;
437 #ifdef PCI171x_PARANOIDCHECK
438         const struct boardtype *this_board = comedi_board(dev);
439         unsigned int idata;
440 #endif
441
442         devpriv->CntrlReg &= Control_CNT0;
443         devpriv->CntrlReg |= Control_SW;        /*  set software trigger */
444         outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
445         outb(0, dev->iobase + PCI171x_CLRFIFO);
446         outb(0, dev->iobase + PCI171x_CLRINT);
447
448         setup_channel_list(dev, s, &insn->chanspec, 1, 1);
449
450         for (n = 0; n < insn->n; n++) {
451                 outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */
452                 /* udelay(1); */
453                 timeout = 100;
454                 while (timeout--) {
455                         if (!(inw(dev->iobase + PCI171x_STATUS) & Status_FE))
456                                 goto conv_finish;
457                 }
458                 comedi_error(dev, "A/D insn timeout");
459                 outb(0, dev->iobase + PCI171x_CLRFIFO);
460                 outb(0, dev->iobase + PCI171x_CLRINT);
461                 data[n] = 0;
462                 return -ETIME;
463
464 conv_finish:
465 #ifdef PCI171x_PARANOIDCHECK
466                 idata = inw(dev->iobase + PCI171x_AD_DATA);
467                 if (this_board->cardtype != TYPE_PCI1713)
468                         if ((idata & 0xf000) != devpriv->act_chanlist[0]) {
469                                 comedi_error(dev, "A/D insn data droput!");
470                                 return -ETIME;
471                         }
472                 data[n] = idata & 0x0fff;
473 #else
474                 data[n] = inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff;
475 #endif
476
477         }
478
479         outb(0, dev->iobase + PCI171x_CLRFIFO);
480         outb(0, dev->iobase + PCI171x_CLRINT);
481
482         return n;
483 }
484
485 /*
486 ==============================================================================
487 */
488 static int pci171x_insn_write_ao(struct comedi_device *dev,
489                                  struct comedi_subdevice *s,
490                                  struct comedi_insn *insn, unsigned int *data)
491 {
492         struct pci1710_private *devpriv = dev->private;
493         int n, chan, range, ofs;
494
495         chan = CR_CHAN(insn->chanspec);
496         range = CR_RANGE(insn->chanspec);
497         if (chan) {
498                 devpriv->da_ranges &= 0xfb;
499                 devpriv->da_ranges |= (range << 2);
500                 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
501                 ofs = PCI171x_DA2;
502         } else {
503                 devpriv->da_ranges &= 0xfe;
504                 devpriv->da_ranges |= range;
505                 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
506                 ofs = PCI171x_DA1;
507         }
508
509         for (n = 0; n < insn->n; n++)
510                 outw(data[n], dev->iobase + ofs);
511
512         devpriv->ao_data[chan] = data[n];
513
514         return n;
515
516 }
517
518 /*
519 ==============================================================================
520 */
521 static int pci171x_insn_read_ao(struct comedi_device *dev,
522                                 struct comedi_subdevice *s,
523                                 struct comedi_insn *insn, unsigned int *data)
524 {
525         struct pci1710_private *devpriv = dev->private;
526         int n, chan;
527
528         chan = CR_CHAN(insn->chanspec);
529         for (n = 0; n < insn->n; n++)
530                 data[n] = devpriv->ao_data[chan];
531
532         return n;
533 }
534
535 /*
536 ==============================================================================
537 */
538 static int pci171x_insn_bits_di(struct comedi_device *dev,
539                                 struct comedi_subdevice *s,
540                                 struct comedi_insn *insn, unsigned int *data)
541 {
542         data[1] = inw(dev->iobase + PCI171x_DI);
543
544         return insn->n;
545 }
546
547 /*
548 ==============================================================================
549 */
550 static int pci171x_insn_bits_do(struct comedi_device *dev,
551                                 struct comedi_subdevice *s,
552                                 struct comedi_insn *insn, unsigned int *data)
553 {
554         if (data[0]) {
555                 s->state &= ~data[0];
556                 s->state |= (data[0] & data[1]);
557                 outw(s->state, dev->iobase + PCI171x_DO);
558         }
559         data[1] = s->state;
560
561         return insn->n;
562 }
563
564 /*
565 ==============================================================================
566 */
567 static void start_pacer(struct comedi_device *dev, int mode,
568                         unsigned int divisor1, unsigned int divisor2)
569 {
570         outw(0xb4, dev->iobase + PCI171x_CNTCTRL);
571         outw(0x74, dev->iobase + PCI171x_CNTCTRL);
572
573         if (mode == 1) {
574                 outw(divisor2 & 0xff, dev->iobase + PCI171x_CNT2);
575                 outw((divisor2 >> 8) & 0xff, dev->iobase + PCI171x_CNT2);
576                 outw(divisor1 & 0xff, dev->iobase + PCI171x_CNT1);
577                 outw((divisor1 >> 8) & 0xff, dev->iobase + PCI171x_CNT1);
578         }
579 }
580
581 /*
582 ==============================================================================
583 */
584 static int pci171x_insn_counter_read(struct comedi_device *dev,
585                                      struct comedi_subdevice *s,
586                                      struct comedi_insn *insn,
587                                      unsigned int *data)
588 {
589         unsigned int msb, lsb, ccntrl;
590         int i;
591
592         ccntrl = 0xD2;          /* count only */
593         for (i = 0; i < insn->n; i++) {
594                 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
595
596                 lsb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
597                 msb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
598
599                 data[0] = lsb | (msb << 8);
600         }
601
602         return insn->n;
603 }
604
605 /*
606 ==============================================================================
607 */
608 static int pci171x_insn_counter_write(struct comedi_device *dev,
609                                       struct comedi_subdevice *s,
610                                       struct comedi_insn *insn,
611                                       unsigned int *data)
612 {
613         struct pci1710_private *devpriv = dev->private;
614         uint msb, lsb, ccntrl, status;
615
616         lsb = data[0] & 0x00FF;
617         msb = (data[0] & 0xFF00) >> 8;
618
619         /* write lsb, then msb */
620         outw(lsb, dev->iobase + PCI171x_CNT0);
621         outw(msb, dev->iobase + PCI171x_CNT0);
622
623         if (devpriv->cnt0_write_wait) {
624                 /* wait for the new count to be loaded */
625                 ccntrl = 0xE2;
626                 do {
627                         outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
628                         status = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
629                 } while (status & 0x40);
630         }
631
632         return insn->n;
633 }
634
635 /*
636 ==============================================================================
637 */
638 static int pci171x_insn_counter_config(struct comedi_device *dev,
639                                        struct comedi_subdevice *s,
640                                        struct comedi_insn *insn,
641                                        unsigned int *data)
642 {
643 #ifdef unused
644         /* This doesn't work like a normal Comedi counter config */
645         struct pci1710_private *devpriv = dev->private;
646         uint ccntrl = 0;
647
648         devpriv->cnt0_write_wait = data[0] & 0x20;
649
650         /* internal or external clock? */
651         if (!(data[0] & 0x10)) {        /* internal */
652                 devpriv->CntrlReg &= ~Control_CNT0;
653         } else {
654                 devpriv->CntrlReg |= Control_CNT0;
655         }
656         outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
657
658         if (data[0] & 0x01)
659                 ccntrl |= Counter_M0;
660         if (data[0] & 0x02)
661                 ccntrl |= Counter_M1;
662         if (data[0] & 0x04)
663                 ccntrl |= Counter_M2;
664         if (data[0] & 0x08)
665                 ccntrl |= Counter_BCD;
666         ccntrl |= Counter_RW0;  /* set read/write mode */
667         ccntrl |= Counter_RW1;
668         outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
669 #endif
670
671         return 1;
672 }
673
674 /*
675 ==============================================================================
676 */
677 static int pci1720_insn_write_ao(struct comedi_device *dev,
678                                  struct comedi_subdevice *s,
679                                  struct comedi_insn *insn, unsigned int *data)
680 {
681         struct pci1710_private *devpriv = dev->private;
682         int n, rangereg, chan;
683
684         chan = CR_CHAN(insn->chanspec);
685         rangereg = devpriv->da_ranges & (~(0x03 << (chan << 1)));
686         rangereg |= (CR_RANGE(insn->chanspec) << (chan << 1));
687         if (rangereg != devpriv->da_ranges) {
688                 outb(rangereg, dev->iobase + PCI1720_RANGE);
689                 devpriv->da_ranges = rangereg;
690         }
691
692         for (n = 0; n < insn->n; n++) {
693                 outw(data[n], dev->iobase + PCI1720_DA0 + (chan << 1));
694                 outb(0, dev->iobase + PCI1720_SYNCOUT); /*  update outputs */
695         }
696
697         devpriv->ao_data[chan] = data[n];
698
699         return n;
700 }
701
702 /*
703 ==============================================================================
704 */
705 static int pci171x_ai_cancel(struct comedi_device *dev,
706                              struct comedi_subdevice *s)
707 {
708         const struct boardtype *this_board = comedi_board(dev);
709         struct pci1710_private *devpriv = dev->private;
710
711         switch (this_board->cardtype) {
712         default:
713                 devpriv->CntrlReg &= Control_CNT0;
714                 devpriv->CntrlReg |= Control_SW;
715
716                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /*  reset any operations */
717                 start_pacer(dev, -1, 0, 0);
718                 outb(0, dev->iobase + PCI171x_CLRFIFO);
719                 outb(0, dev->iobase + PCI171x_CLRINT);
720                 break;
721         }
722
723         devpriv->ai_do = 0;
724         devpriv->ai_act_scan = 0;
725         s->async->cur_chan = 0;
726         devpriv->ai_buf_ptr = 0;
727         devpriv->neverending_ai = 0;
728
729         return 0;
730 }
731
732 /*
733 ==============================================================================
734 */
735 static void interrupt_pci1710_every_sample(void *d)
736 {
737         struct comedi_device *dev = d;
738         struct pci1710_private *devpriv = dev->private;
739         struct comedi_subdevice *s = &dev->subdevices[0];
740         int m;
741 #ifdef PCI171x_PARANOIDCHECK
742         const struct boardtype *this_board = comedi_board(dev);
743         short sampl;
744 #endif
745
746         m = inw(dev->iobase + PCI171x_STATUS);
747         if (m & Status_FE) {
748                 printk("comedi%d: A/D FIFO empty (%4x)\n", dev->minor, m);
749                 pci171x_ai_cancel(dev, s);
750                 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
751                 comedi_event(dev, s);
752                 return;
753         }
754         if (m & Status_FF) {
755                 printk
756                     ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
757                      dev->minor, m);
758                 pci171x_ai_cancel(dev, s);
759                 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
760                 comedi_event(dev, s);
761                 return;
762         }
763
764         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear our INT request */
765
766         for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
767 #ifdef PCI171x_PARANOIDCHECK
768                 sampl = inw(dev->iobase + PCI171x_AD_DATA);
769                 if (this_board->cardtype != TYPE_PCI1713)
770                         if ((sampl & 0xf000) !=
771                             devpriv->act_chanlist[s->async->cur_chan]) {
772                                 printk
773                                     ("comedi: A/D data dropout: received data from channel %d, expected %d!\n",
774                                      (sampl & 0xf000) >> 12,
775                                      (devpriv->
776                                       act_chanlist[s->
777                                                    async->cur_chan] & 0xf000) >>
778                                      12);
779                                 pci171x_ai_cancel(dev, s);
780                                 s->async->events |=
781                                     COMEDI_CB_EOA | COMEDI_CB_ERROR;
782                                 comedi_event(dev, s);
783                                 return;
784                         }
785                 comedi_buf_put(s->async, sampl & 0x0fff);
786 #else
787                 comedi_buf_put(s->async,
788                                inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
789 #endif
790                 ++s->async->cur_chan;
791
792                 if (s->async->cur_chan >= devpriv->ai_n_chan)
793                         s->async->cur_chan = 0;
794
795
796                 if (s->async->cur_chan == 0) {  /*  one scan done */
797                         devpriv->ai_act_scan++;
798                         if ((!devpriv->neverending_ai) &&
799                             (devpriv->ai_act_scan >= devpriv->ai_scans)) {
800                                 /*  all data sampled */
801                                 pci171x_ai_cancel(dev, s);
802                                 s->async->events |= COMEDI_CB_EOA;
803                                 comedi_event(dev, s);
804                                 return;
805                         }
806                 }
807         }
808
809         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear our INT request */
810
811         comedi_event(dev, s);
812 }
813
814 /*
815 ==============================================================================
816 */
817 static int move_block_from_fifo(struct comedi_device *dev,
818                                 struct comedi_subdevice *s, int n, int turn)
819 {
820         struct pci1710_private *devpriv = dev->private;
821         int i, j;
822 #ifdef PCI171x_PARANOIDCHECK
823         const struct boardtype *this_board = comedi_board(dev);
824         int sampl;
825 #endif
826
827         j = s->async->cur_chan;
828         for (i = 0; i < n; i++) {
829 #ifdef PCI171x_PARANOIDCHECK
830                 sampl = inw(dev->iobase + PCI171x_AD_DATA);
831                 if (this_board->cardtype != TYPE_PCI1713)
832                         if ((sampl & 0xf000) != devpriv->act_chanlist[j]) {
833                                 printk
834                                     ("comedi%d: A/D  FIFO data dropout: received data from channel %d, expected %d! (%d/%d/%d/%d/%d/%4x)\n",
835                                      dev->minor, (sampl & 0xf000) >> 12,
836                                      (devpriv->act_chanlist[j] & 0xf000) >> 12,
837                                      i, j, devpriv->ai_act_scan, n, turn,
838                                      sampl);
839                                 pci171x_ai_cancel(dev, s);
840                                 s->async->events |=
841                                     COMEDI_CB_EOA | COMEDI_CB_ERROR;
842                                 comedi_event(dev, s);
843                                 return 1;
844                         }
845                 comedi_buf_put(s->async, sampl & 0x0fff);
846 #else
847                 comedi_buf_put(s->async,
848                                inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
849 #endif
850                 j++;
851                 if (j >= devpriv->ai_n_chan) {
852                         j = 0;
853                         devpriv->ai_act_scan++;
854                 }
855         }
856         s->async->cur_chan = j;
857         return 0;
858 }
859
860 /*
861 ==============================================================================
862 */
863 static void interrupt_pci1710_half_fifo(void *d)
864 {
865         struct comedi_device *dev = d;
866         const struct boardtype *this_board = comedi_board(dev);
867         struct pci1710_private *devpriv = dev->private;
868         struct comedi_subdevice *s = &dev->subdevices[0];
869         int m, samplesinbuf;
870
871         m = inw(dev->iobase + PCI171x_STATUS);
872         if (!(m & Status_FH)) {
873                 printk("comedi%d: A/D FIFO not half full! (%4x)\n",
874                        dev->minor, m);
875                 pci171x_ai_cancel(dev, s);
876                 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
877                 comedi_event(dev, s);
878                 return;
879         }
880         if (m & Status_FF) {
881                 printk
882                     ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
883                      dev->minor, m);
884                 pci171x_ai_cancel(dev, s);
885                 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
886                 comedi_event(dev, s);
887                 return;
888         }
889
890         samplesinbuf = this_board->fifo_half_size;
891         if (samplesinbuf * sizeof(short) >= devpriv->ai_data_len) {
892                 m = devpriv->ai_data_len / sizeof(short);
893                 if (move_block_from_fifo(dev, s, m, 0))
894                         return;
895                 samplesinbuf -= m;
896         }
897
898         if (samplesinbuf) {
899                 if (move_block_from_fifo(dev, s, samplesinbuf, 1))
900                         return;
901         }
902
903         if (!devpriv->neverending_ai)
904                 if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data
905                                                                     sampled */
906                         pci171x_ai_cancel(dev, s);
907                         s->async->events |= COMEDI_CB_EOA;
908                         comedi_event(dev, s);
909                         return;
910                 }
911         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear our INT request */
912
913         comedi_event(dev, s);
914 }
915
916 /*
917 ==============================================================================
918 */
919 static irqreturn_t interrupt_service_pci1710(int irq, void *d)
920 {
921         struct comedi_device *dev = d;
922         struct pci1710_private *devpriv = dev->private;
923
924         if (!dev->attached)     /*  is device attached? */
925                 return IRQ_NONE;        /*  no, exit */
926         /*  is this interrupt from our board? */
927         if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))
928                 return IRQ_NONE;        /*  no, exit */
929
930         if (devpriv->ai_et) {   /*  Switch from initial TRIG_EXT to TRIG_xxx. */
931                 devpriv->ai_et = 0;
932                 devpriv->CntrlReg &= Control_CNT0;
933                 devpriv->CntrlReg |= Control_SW; /* set software trigger */
934                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
935                 devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
936                 outb(0, dev->iobase + PCI171x_CLRFIFO);
937                 outb(0, dev->iobase + PCI171x_CLRINT);
938                 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
939                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
940                 /*  start pacer */
941                 start_pacer(dev, 1, devpriv->ai_et_div1, devpriv->ai_et_div2);
942                 return IRQ_HANDLED;
943         }
944         if (devpriv->ai_eos) {  /*  We use FIFO half full INT or not? */
945                 interrupt_pci1710_every_sample(d);
946         } else {
947                 interrupt_pci1710_half_fifo(d);
948         }
949         return IRQ_HANDLED;
950 }
951
952 /*
953 ==============================================================================
954 */
955 static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev,
956                                      struct comedi_subdevice *s)
957 {
958         const struct boardtype *this_board = comedi_board(dev);
959         struct pci1710_private *devpriv = dev->private;
960         unsigned int divisor1 = 0, divisor2 = 0;
961         unsigned int seglen;
962
963         start_pacer(dev, -1, 0, 0);     /*  stop pacer */
964
965         seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
966                                     devpriv->ai_n_chan);
967         if (seglen < 1)
968                 return -EINVAL;
969         setup_channel_list(dev, s, devpriv->ai_chanlist,
970                            devpriv->ai_n_chan, seglen);
971
972         outb(0, dev->iobase + PCI171x_CLRFIFO);
973         outb(0, dev->iobase + PCI171x_CLRINT);
974
975         devpriv->ai_do = mode;
976
977         devpriv->ai_act_scan = 0;
978         s->async->cur_chan = 0;
979         devpriv->ai_buf_ptr = 0;
980         devpriv->neverending_ai = 0;
981
982         devpriv->CntrlReg &= Control_CNT0;
983         /*  don't we want wake up every scan?  devpriv->ai_eos=1; */
984         if ((devpriv->ai_flags & TRIG_WAKE_EOS)) {
985                 devpriv->ai_eos = 1;
986         } else {
987                 devpriv->CntrlReg |= Control_ONEFH;
988                 devpriv->ai_eos = 0;
989         }
990
991         if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1))
992                 devpriv->neverending_ai = 1;
993         /* well, user want neverending */
994         else
995                 devpriv->neverending_ai = 0;
996
997         switch (mode) {
998         case 1:
999         case 2:
1000                 if (devpriv->ai_timer1 < this_board->ai_ns_min)
1001                         devpriv->ai_timer1 = this_board->ai_ns_min;
1002                 devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
1003                 if (mode == 2) {
1004                         devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
1005                         devpriv->CntrlReg &=
1006                             ~(Control_PACER | Control_ONEFH | Control_GATE);
1007                         devpriv->CntrlReg |= Control_EXT;
1008                         devpriv->ai_et = 1;
1009                 } else {
1010                         devpriv->ai_et = 0;
1011                 }
1012                 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
1013                                           &divisor2, &devpriv->ai_timer1,
1014                                           devpriv->ai_flags & TRIG_ROUND_MASK);
1015                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
1016                 if (mode != 2) {
1017                         /*  start pacer */
1018                         start_pacer(dev, mode, divisor1, divisor2);
1019                 } else {
1020                         devpriv->ai_et_div1 = divisor1;
1021                         devpriv->ai_et_div2 = divisor2;
1022                 }
1023                 break;
1024         case 3:
1025                 devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
1026                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
1027                 break;
1028         }
1029
1030         return 0;
1031 }
1032
1033 /*
1034 ==============================================================================
1035 */
1036 static int pci171x_ai_cmdtest(struct comedi_device *dev,
1037                               struct comedi_subdevice *s,
1038                               struct comedi_cmd *cmd)
1039 {
1040         const struct boardtype *this_board = comedi_board(dev);
1041         struct pci1710_private *devpriv = dev->private;
1042         int err = 0;
1043         int tmp;
1044         unsigned int divisor1 = 0, divisor2 = 0;
1045
1046         /* Step 1 : check if triggers are trivially valid */
1047
1048         err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
1049         err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
1050         err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
1051         err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
1052         err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
1053
1054         if (err)
1055                 return 1;
1056
1057         /* step 2a: make sure trigger sources are unique */
1058
1059         err |= cfc_check_trigger_is_unique(cmd->start_src);
1060         err |= cfc_check_trigger_is_unique(cmd->convert_src);
1061         err |= cfc_check_trigger_is_unique(cmd->stop_src);
1062
1063         /* step 2b: and mutually compatible */
1064
1065         if (err)
1066                 return 2;
1067
1068         /* Step 3: check if arguments are trivially valid */
1069
1070         err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
1071         err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
1072
1073         if (cmd->convert_src == TRIG_TIMER)
1074                 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
1075                                                  this_board->ai_ns_min);
1076         else    /* TRIG_FOLLOW */
1077                 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
1078
1079         err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
1080
1081         if (cmd->stop_src == TRIG_COUNT)
1082                 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
1083         else    /* TRIG_NONE */
1084                 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
1085
1086         if (err)
1087                 return 3;
1088
1089         /* step 4: fix up any arguments */
1090
1091         if (cmd->convert_src == TRIG_TIMER) {
1092                 tmp = cmd->convert_arg;
1093                 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
1094                                           &divisor2, &cmd->convert_arg,
1095                                           cmd->flags & TRIG_ROUND_MASK);
1096                 if (cmd->convert_arg < this_board->ai_ns_min)
1097                         cmd->convert_arg = this_board->ai_ns_min;
1098                 if (tmp != cmd->convert_arg)
1099                         err++;
1100         }
1101
1102         if (err)
1103                 return 4;
1104
1105         /* step 5: complain about special chanlist considerations */
1106
1107         if (cmd->chanlist) {
1108                 if (!check_channel_list(dev, s, cmd->chanlist,
1109                                         cmd->chanlist_len))
1110                         return 5;       /*  incorrect channels list */
1111         }
1112
1113         return 0;
1114 }
1115
1116 /*
1117 ==============================================================================
1118 */
1119 static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1120 {
1121         struct pci1710_private *devpriv = dev->private;
1122         struct comedi_cmd *cmd = &s->async->cmd;
1123
1124         devpriv->ai_n_chan = cmd->chanlist_len;
1125         devpriv->ai_chanlist = cmd->chanlist;
1126         devpriv->ai_flags = cmd->flags;
1127         devpriv->ai_data_len = s->async->prealloc_bufsz;
1128         devpriv->ai_data = s->async->prealloc_buf;
1129         devpriv->ai_timer1 = 0;
1130         devpriv->ai_timer2 = 0;
1131
1132         if (cmd->stop_src == TRIG_COUNT)
1133                 devpriv->ai_scans = cmd->stop_arg;
1134         else
1135                 devpriv->ai_scans = 0;
1136
1137
1138         if (cmd->scan_begin_src == TRIG_FOLLOW) {       /*  mode 1, 2, 3 */
1139                 if (cmd->convert_src == TRIG_TIMER) {   /*  mode 1 and 2 */
1140                         devpriv->ai_timer1 = cmd->convert_arg;
1141                         return pci171x_ai_docmd_and_mode(cmd->start_src ==
1142                                                          TRIG_EXT ? 2 : 1, dev,
1143                                                          s);
1144                 }
1145                 if (cmd->convert_src == TRIG_EXT) {     /*  mode 3 */
1146                         return pci171x_ai_docmd_and_mode(3, dev, s);
1147                 }
1148         }
1149
1150         return -1;
1151 }
1152
1153 /*
1154 ==============================================================================
1155 */
1156 static int pci171x_reset(struct comedi_device *dev)
1157 {
1158         const struct boardtype *this_board = comedi_board(dev);
1159         struct pci1710_private *devpriv = dev->private;
1160
1161         outw(0x30, dev->iobase + PCI171x_CNTCTRL);
1162         devpriv->CntrlReg = Control_SW | Control_CNT0;  /*  Software trigger, CNT0=external */
1163         outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /*  reset any operations */
1164         outb(0, dev->iobase + PCI171x_CLRFIFO); /*  clear FIFO */
1165         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear INT request */
1166         start_pacer(dev, -1, 0, 0);     /*  stop 8254 */
1167         devpriv->da_ranges = 0;
1168         if (this_board->n_aochan) {
1169                 outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);  /*  set DACs to 0..5V */
1170                 outw(0, dev->iobase + PCI171x_DA1);     /*  set DA outputs to 0V */
1171                 devpriv->ao_data[0] = 0x0000;
1172                 if (this_board->n_aochan > 1) {
1173                         outw(0, dev->iobase + PCI171x_DA2);
1174                         devpriv->ao_data[1] = 0x0000;
1175                 }
1176         }
1177         outw(0, dev->iobase + PCI171x_DO);      /*  digital outputs to 0 */
1178         outb(0, dev->iobase + PCI171x_CLRFIFO); /*  clear FIFO */
1179         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear INT request */
1180
1181         return 0;
1182 }
1183
1184 /*
1185 ==============================================================================
1186 */
1187 static int pci1720_reset(struct comedi_device *dev)
1188 {
1189         struct pci1710_private *devpriv = dev->private;
1190
1191         outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT);       /*  set synchronous output mode */
1192         devpriv->da_ranges = 0xAA;
1193         outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE);  /*  set all ranges to +/-5V */
1194         outw(0x0800, dev->iobase + PCI1720_DA0);        /*  set outputs to 0V */
1195         outw(0x0800, dev->iobase + PCI1720_DA1);
1196         outw(0x0800, dev->iobase + PCI1720_DA2);
1197         outw(0x0800, dev->iobase + PCI1720_DA3);
1198         outb(0, dev->iobase + PCI1720_SYNCOUT); /*  update outputs */
1199         devpriv->ao_data[0] = 0x0800;
1200         devpriv->ao_data[1] = 0x0800;
1201         devpriv->ao_data[2] = 0x0800;
1202         devpriv->ao_data[3] = 0x0800;
1203         return 0;
1204 }
1205
1206 /*
1207 ==============================================================================
1208 */
1209 static int pci1710_reset(struct comedi_device *dev)
1210 {
1211         const struct boardtype *this_board = comedi_board(dev);
1212
1213         switch (this_board->cardtype) {
1214         case TYPE_PCI1720:
1215                 return pci1720_reset(dev);
1216         default:
1217                 return pci171x_reset(dev);
1218         }
1219 }
1220
1221 static int pci1710_auto_attach(struct comedi_device *dev,
1222                                unsigned long context)
1223 {
1224         struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1225         const struct boardtype *this_board = NULL;
1226         struct pci1710_private *devpriv;
1227         struct comedi_subdevice *s;
1228         int ret, subdev, n_subdevices;
1229
1230         if (context < ARRAY_SIZE(boardtypes))
1231                 this_board = &boardtypes[context];
1232         if (!this_board)
1233                 return -ENODEV;
1234         dev->board_ptr = this_board;
1235         dev->board_name = this_board->name;
1236
1237         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1238         if (!devpriv)
1239                 return -ENOMEM;
1240
1241         ret = comedi_pci_enable(dev);
1242         if (ret)
1243                 return ret;
1244         dev->iobase = pci_resource_start(pcidev, 2);
1245
1246         n_subdevices = 0;
1247         if (this_board->n_aichan)
1248                 n_subdevices++;
1249         if (this_board->n_aochan)
1250                 n_subdevices++;
1251         if (this_board->n_dichan)
1252                 n_subdevices++;
1253         if (this_board->n_dochan)
1254                 n_subdevices++;
1255         if (this_board->n_counter)
1256                 n_subdevices++;
1257
1258         ret = comedi_alloc_subdevices(dev, n_subdevices);
1259         if (ret)
1260                 return ret;
1261
1262         pci1710_reset(dev);
1263
1264         if (this_board->have_irq && pcidev->irq) {
1265                 ret = request_irq(pcidev->irq, interrupt_service_pci1710,
1266                                   IRQF_SHARED, dev->board_name, dev);
1267                 if (ret == 0)
1268                         dev->irq = pcidev->irq;
1269         }
1270
1271         subdev = 0;
1272
1273         if (this_board->n_aichan) {
1274                 s = &dev->subdevices[subdev];
1275                 dev->read_subdev = s;
1276                 s->type = COMEDI_SUBD_AI;
1277                 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
1278                 if (this_board->n_aichand)
1279                         s->subdev_flags |= SDF_DIFF;
1280                 s->n_chan = this_board->n_aichan;
1281                 s->maxdata = this_board->ai_maxdata;
1282                 s->len_chanlist = this_board->n_aichan;
1283                 s->range_table = this_board->rangelist_ai;
1284                 s->cancel = pci171x_ai_cancel;
1285                 s->insn_read = pci171x_insn_read_ai;
1286                 if (dev->irq) {
1287                         s->subdev_flags |= SDF_CMD_READ;
1288                         s->do_cmdtest = pci171x_ai_cmdtest;
1289                         s->do_cmd = pci171x_ai_cmd;
1290                 }
1291                 devpriv->i8254_osc_base = 100;  /*  100ns=10MHz */
1292                 subdev++;
1293         }
1294
1295         if (this_board->n_aochan) {
1296                 s = &dev->subdevices[subdev];
1297                 s->type = COMEDI_SUBD_AO;
1298                 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1299                 s->n_chan = this_board->n_aochan;
1300                 s->maxdata = this_board->ao_maxdata;
1301                 s->len_chanlist = this_board->n_aochan;
1302                 s->range_table = this_board->rangelist_ao;
1303                 switch (this_board->cardtype) {
1304                 case TYPE_PCI1720:
1305                         s->insn_write = pci1720_insn_write_ao;
1306                         break;
1307                 default:
1308                         s->insn_write = pci171x_insn_write_ao;
1309                         break;
1310                 }
1311                 s->insn_read = pci171x_insn_read_ao;
1312                 subdev++;
1313         }
1314
1315         if (this_board->n_dichan) {
1316                 s = &dev->subdevices[subdev];
1317                 s->type = COMEDI_SUBD_DI;
1318                 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
1319                 s->n_chan = this_board->n_dichan;
1320                 s->maxdata = 1;
1321                 s->len_chanlist = this_board->n_dichan;
1322                 s->range_table = &range_digital;
1323                 s->io_bits = 0; /* all bits input */
1324                 s->insn_bits = pci171x_insn_bits_di;
1325                 subdev++;
1326         }
1327
1328         if (this_board->n_dochan) {
1329                 s = &dev->subdevices[subdev];
1330                 s->type = COMEDI_SUBD_DO;
1331                 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1332                 s->n_chan = this_board->n_dochan;
1333                 s->maxdata = 1;
1334                 s->len_chanlist = this_board->n_dochan;
1335                 s->range_table = &range_digital;
1336                 /* all bits output */
1337                 s->io_bits = (1 << this_board->n_dochan) - 1;
1338                 s->state = 0;
1339                 s->insn_bits = pci171x_insn_bits_do;
1340                 subdev++;
1341         }
1342
1343         if (this_board->n_counter) {
1344                 s = &dev->subdevices[subdev];
1345                 s->type = COMEDI_SUBD_COUNTER;
1346                 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1347                 s->n_chan = this_board->n_counter;
1348                 s->len_chanlist = this_board->n_counter;
1349                 s->maxdata = 0xffff;
1350                 s->range_table = &range_unknown;
1351                 s->insn_read = pci171x_insn_counter_read;
1352                 s->insn_write = pci171x_insn_counter_write;
1353                 s->insn_config = pci171x_insn_counter_config;
1354                 subdev++;
1355         }
1356
1357         dev_info(dev->class_dev, "%s attached, irq %sabled\n",
1358                 dev->board_name, dev->irq ? "en" : "dis");
1359
1360         return 0;
1361 }
1362
1363 static void pci1710_detach(struct comedi_device *dev)
1364 {
1365         if (dev->iobase)
1366                 pci1710_reset(dev);
1367         if (dev->irq)
1368                 free_irq(dev->irq, dev);
1369         comedi_pci_disable(dev);
1370 }
1371
1372 static struct comedi_driver adv_pci1710_driver = {
1373         .driver_name    = "adv_pci1710",
1374         .module         = THIS_MODULE,
1375         .auto_attach    = pci1710_auto_attach,
1376         .detach         = pci1710_detach,
1377 };
1378
1379 static int adv_pci1710_pci_probe(struct pci_dev *dev,
1380                                  const struct pci_device_id *id)
1381 {
1382         return comedi_pci_auto_config(dev, &adv_pci1710_driver,
1383                                       id->driver_data);
1384 }
1385
1386 static DEFINE_PCI_DEVICE_TABLE(adv_pci1710_pci_table) = {
1387         {
1388                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1389                                PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050),
1390                 .driver_data = BOARD_PCI1710,
1391         }, {
1392                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1393                                PCI_VENDOR_ID_ADVANTECH, 0x0000),
1394                 .driver_data = BOARD_PCI1710,
1395         }, {
1396                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1397                                PCI_VENDOR_ID_ADVANTECH, 0xb100),
1398                 .driver_data = BOARD_PCI1710,
1399         }, {
1400                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1401                                PCI_VENDOR_ID_ADVANTECH, 0xb200),
1402                 .driver_data = BOARD_PCI1710,
1403         }, {
1404                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1405                                PCI_VENDOR_ID_ADVANTECH, 0xc100),
1406                 .driver_data = BOARD_PCI1710,
1407         }, {
1408                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1409                                PCI_VENDOR_ID_ADVANTECH, 0xc200),
1410                 .driver_data = BOARD_PCI1710,
1411         }, {
1412                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd100),
1413                 .driver_data = BOARD_PCI1710,
1414         }, {
1415                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1416                                PCI_VENDOR_ID_ADVANTECH, 0x0002),
1417                 .driver_data = BOARD_PCI1710HG,
1418         }, {
1419                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1420                                PCI_VENDOR_ID_ADVANTECH, 0xb102),
1421                 .driver_data = BOARD_PCI1710HG,
1422         }, {
1423                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1424                                PCI_VENDOR_ID_ADVANTECH, 0xb202),
1425                 .driver_data = BOARD_PCI1710HG,
1426         }, {
1427                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1428                                PCI_VENDOR_ID_ADVANTECH, 0xc102),
1429                 .driver_data = BOARD_PCI1710HG,
1430         }, {
1431                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1432                                PCI_VENDOR_ID_ADVANTECH, 0xc202),
1433                 .driver_data = BOARD_PCI1710HG,
1434         }, {
1435                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd102),
1436                 .driver_data = BOARD_PCI1710HG,
1437         },
1438         { PCI_VDEVICE(ADVANTECH, 0x1711), BOARD_PCI1711 },
1439         { PCI_VDEVICE(ADVANTECH, 0x1713), BOARD_PCI1713 },
1440         { PCI_VDEVICE(ADVANTECH, 0x1720), BOARD_PCI1720 },
1441         { PCI_VDEVICE(ADVANTECH, 0x1731), BOARD_PCI1731 },
1442         { 0 }
1443 };
1444 MODULE_DEVICE_TABLE(pci, adv_pci1710_pci_table);
1445
1446 static struct pci_driver adv_pci1710_pci_driver = {
1447         .name           = "adv_pci1710",
1448         .id_table       = adv_pci1710_pci_table,
1449         .probe          = adv_pci1710_pci_probe,
1450         .remove         = comedi_pci_auto_unconfig,
1451 };
1452 module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver);
1453
1454 MODULE_AUTHOR("Comedi http://www.comedi.org");
1455 MODULE_DESCRIPTION("Comedi low-level driver");
1456 MODULE_LICENSE("GPL");