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