Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[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         int n, chan, range, ofs;
493
494         chan = CR_CHAN(insn->chanspec);
495         range = CR_RANGE(insn->chanspec);
496         if (chan) {
497                 devpriv->da_ranges &= 0xfb;
498                 devpriv->da_ranges |= (range << 2);
499                 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
500                 ofs = PCI171x_DA2;
501         } else {
502                 devpriv->da_ranges &= 0xfe;
503                 devpriv->da_ranges |= range;
504                 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
505                 ofs = PCI171x_DA1;
506         }
507
508         for (n = 0; n < insn->n; n++)
509                 outw(data[n], dev->iobase + ofs);
510
511         devpriv->ao_data[chan] = data[n];
512
513         return n;
514
515 }
516
517 /*
518 ==============================================================================
519 */
520 static int pci171x_insn_read_ao(struct comedi_device *dev,
521                                 struct comedi_subdevice *s,
522                                 struct comedi_insn *insn, unsigned int *data)
523 {
524         struct pci1710_private *devpriv = dev->private;
525         int n, chan;
526
527         chan = CR_CHAN(insn->chanspec);
528         for (n = 0; n < insn->n; n++)
529                 data[n] = devpriv->ao_data[chan];
530
531         return n;
532 }
533
534 /*
535 ==============================================================================
536 */
537 static int pci171x_insn_bits_di(struct comedi_device *dev,
538                                 struct comedi_subdevice *s,
539                                 struct comedi_insn *insn, unsigned int *data)
540 {
541         data[1] = inw(dev->iobase + PCI171x_DI);
542
543         return insn->n;
544 }
545
546 /*
547 ==============================================================================
548 */
549 static int pci171x_insn_bits_do(struct comedi_device *dev,
550                                 struct comedi_subdevice *s,
551                                 struct comedi_insn *insn, unsigned int *data)
552 {
553         if (data[0]) {
554                 s->state &= ~data[0];
555                 s->state |= (data[0] & data[1]);
556                 outw(s->state, dev->iobase + PCI171x_DO);
557         }
558         data[1] = s->state;
559
560         return insn->n;
561 }
562
563 /*
564 ==============================================================================
565 */
566 static void start_pacer(struct comedi_device *dev, int mode,
567                         unsigned int divisor1, unsigned int divisor2)
568 {
569         outw(0xb4, dev->iobase + PCI171x_CNTCTRL);
570         outw(0x74, dev->iobase + PCI171x_CNTCTRL);
571
572         if (mode == 1) {
573                 outw(divisor2 & 0xff, dev->iobase + PCI171x_CNT2);
574                 outw((divisor2 >> 8) & 0xff, dev->iobase + PCI171x_CNT2);
575                 outw(divisor1 & 0xff, dev->iobase + PCI171x_CNT1);
576                 outw((divisor1 >> 8) & 0xff, dev->iobase + PCI171x_CNT1);
577         }
578 }
579
580 /*
581 ==============================================================================
582 */
583 static int pci171x_insn_counter_read(struct comedi_device *dev,
584                                      struct comedi_subdevice *s,
585                                      struct comedi_insn *insn,
586                                      unsigned int *data)
587 {
588         unsigned int msb, lsb, ccntrl;
589         int i;
590
591         ccntrl = 0xD2;          /* count only */
592         for (i = 0; i < insn->n; i++) {
593                 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
594
595                 lsb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
596                 msb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
597
598                 data[0] = lsb | (msb << 8);
599         }
600
601         return insn->n;
602 }
603
604 /*
605 ==============================================================================
606 */
607 static int pci171x_insn_counter_write(struct comedi_device *dev,
608                                       struct comedi_subdevice *s,
609                                       struct comedi_insn *insn,
610                                       unsigned int *data)
611 {
612         struct pci1710_private *devpriv = dev->private;
613         uint msb, lsb, ccntrl, status;
614
615         lsb = data[0] & 0x00FF;
616         msb = (data[0] & 0xFF00) >> 8;
617
618         /* write lsb, then msb */
619         outw(lsb, dev->iobase + PCI171x_CNT0);
620         outw(msb, dev->iobase + PCI171x_CNT0);
621
622         if (devpriv->cnt0_write_wait) {
623                 /* wait for the new count to be loaded */
624                 ccntrl = 0xE2;
625                 do {
626                         outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
627                         status = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
628                 } while (status & 0x40);
629         }
630
631         return insn->n;
632 }
633
634 /*
635 ==============================================================================
636 */
637 static int pci171x_insn_counter_config(struct comedi_device *dev,
638                                        struct comedi_subdevice *s,
639                                        struct comedi_insn *insn,
640                                        unsigned int *data)
641 {
642 #ifdef unused
643         /* This doesn't work like a normal Comedi counter config */
644         struct pci1710_private *devpriv = dev->private;
645         uint ccntrl = 0;
646
647         devpriv->cnt0_write_wait = data[0] & 0x20;
648
649         /* internal or external clock? */
650         if (!(data[0] & 0x10)) {        /* internal */
651                 devpriv->CntrlReg &= ~Control_CNT0;
652         } else {
653                 devpriv->CntrlReg |= Control_CNT0;
654         }
655         outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
656
657         if (data[0] & 0x01)
658                 ccntrl |= Counter_M0;
659         if (data[0] & 0x02)
660                 ccntrl |= Counter_M1;
661         if (data[0] & 0x04)
662                 ccntrl |= Counter_M2;
663         if (data[0] & 0x08)
664                 ccntrl |= Counter_BCD;
665         ccntrl |= Counter_RW0;  /* set read/write mode */
666         ccntrl |= Counter_RW1;
667         outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
668 #endif
669
670         return 1;
671 }
672
673 /*
674 ==============================================================================
675 */
676 static int pci1720_insn_write_ao(struct comedi_device *dev,
677                                  struct comedi_subdevice *s,
678                                  struct comedi_insn *insn, unsigned int *data)
679 {
680         struct pci1710_private *devpriv = dev->private;
681         int n, rangereg, chan;
682
683         chan = CR_CHAN(insn->chanspec);
684         rangereg = devpriv->da_ranges & (~(0x03 << (chan << 1)));
685         rangereg |= (CR_RANGE(insn->chanspec) << (chan << 1));
686         if (rangereg != devpriv->da_ranges) {
687                 outb(rangereg, dev->iobase + PCI1720_RANGE);
688                 devpriv->da_ranges = rangereg;
689         }
690
691         for (n = 0; n < insn->n; n++) {
692                 outw(data[n], dev->iobase + PCI1720_DA0 + (chan << 1));
693                 outb(0, dev->iobase + PCI1720_SYNCOUT); /*  update outputs */
694         }
695
696         devpriv->ao_data[chan] = data[n];
697
698         return n;
699 }
700
701 /*
702 ==============================================================================
703 */
704 static int pci171x_ai_cancel(struct comedi_device *dev,
705                              struct comedi_subdevice *s)
706 {
707         const struct boardtype *this_board = comedi_board(dev);
708         struct pci1710_private *devpriv = dev->private;
709
710         switch (this_board->cardtype) {
711         default:
712                 devpriv->CntrlReg &= Control_CNT0;
713                 devpriv->CntrlReg |= Control_SW;
714
715                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /*  reset any operations */
716                 start_pacer(dev, -1, 0, 0);
717                 outb(0, dev->iobase + PCI171x_CLRFIFO);
718                 outb(0, dev->iobase + PCI171x_CLRINT);
719                 break;
720         }
721
722         devpriv->ai_do = 0;
723         devpriv->ai_act_scan = 0;
724         s->async->cur_chan = 0;
725         devpriv->ai_buf_ptr = 0;
726         devpriv->neverending_ai = 0;
727
728         return 0;
729 }
730
731 /*
732 ==============================================================================
733 */
734 static void interrupt_pci1710_every_sample(void *d)
735 {
736         struct comedi_device *dev = d;
737         struct pci1710_private *devpriv = dev->private;
738         struct comedi_subdevice *s = &dev->subdevices[0];
739         int m;
740 #ifdef PCI171x_PARANOIDCHECK
741         const struct boardtype *this_board = comedi_board(dev);
742         short sampl;
743 #endif
744
745         m = inw(dev->iobase + PCI171x_STATUS);
746         if (m & Status_FE) {
747                 printk("comedi%d: A/D FIFO empty (%4x)\n", dev->minor, m);
748                 pci171x_ai_cancel(dev, s);
749                 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
750                 comedi_event(dev, s);
751                 return;
752         }
753         if (m & Status_FF) {
754                 printk
755                     ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
756                      dev->minor, m);
757                 pci171x_ai_cancel(dev, s);
758                 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
759                 comedi_event(dev, s);
760                 return;
761         }
762
763         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear our INT request */
764
765         for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
766 #ifdef PCI171x_PARANOIDCHECK
767                 sampl = inw(dev->iobase + PCI171x_AD_DATA);
768                 if (this_board->cardtype != TYPE_PCI1713)
769                         if ((sampl & 0xf000) !=
770                             devpriv->act_chanlist[s->async->cur_chan]) {
771                                 printk
772                                     ("comedi: A/D data dropout: received data from channel %d, expected %d!\n",
773                                      (sampl & 0xf000) >> 12,
774                                      (devpriv->
775                                       act_chanlist[s->
776                                                    async->cur_chan] & 0xf000) >>
777                                      12);
778                                 pci171x_ai_cancel(dev, s);
779                                 s->async->events |=
780                                     COMEDI_CB_EOA | COMEDI_CB_ERROR;
781                                 comedi_event(dev, s);
782                                 return;
783                         }
784                 comedi_buf_put(s->async, sampl & 0x0fff);
785 #else
786                 comedi_buf_put(s->async,
787                                inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
788 #endif
789                 ++s->async->cur_chan;
790
791                 if (s->async->cur_chan >= devpriv->ai_n_chan)
792                         s->async->cur_chan = 0;
793
794
795                 if (s->async->cur_chan == 0) {  /*  one scan done */
796                         devpriv->ai_act_scan++;
797                         if ((!devpriv->neverending_ai) &&
798                             (devpriv->ai_act_scan >= devpriv->ai_scans)) {
799                                 /*  all data sampled */
800                                 pci171x_ai_cancel(dev, s);
801                                 s->async->events |= COMEDI_CB_EOA;
802                                 comedi_event(dev, s);
803                                 return;
804                         }
805                 }
806         }
807
808         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear our INT request */
809
810         comedi_event(dev, s);
811 }
812
813 /*
814 ==============================================================================
815 */
816 static int move_block_from_fifo(struct comedi_device *dev,
817                                 struct comedi_subdevice *s, int n, int turn)
818 {
819         struct pci1710_private *devpriv = dev->private;
820         int i, j;
821 #ifdef PCI171x_PARANOIDCHECK
822         const struct boardtype *this_board = comedi_board(dev);
823         int sampl;
824 #endif
825
826         j = s->async->cur_chan;
827         for (i = 0; i < n; i++) {
828 #ifdef PCI171x_PARANOIDCHECK
829                 sampl = inw(dev->iobase + PCI171x_AD_DATA);
830                 if (this_board->cardtype != TYPE_PCI1713)
831                         if ((sampl & 0xf000) != devpriv->act_chanlist[j]) {
832                                 printk
833                                     ("comedi%d: A/D  FIFO data dropout: received data from channel %d, expected %d! (%d/%d/%d/%d/%d/%4x)\n",
834                                      dev->minor, (sampl & 0xf000) >> 12,
835                                      (devpriv->act_chanlist[j] & 0xf000) >> 12,
836                                      i, j, devpriv->ai_act_scan, n, turn,
837                                      sampl);
838                                 pci171x_ai_cancel(dev, s);
839                                 s->async->events |=
840                                     COMEDI_CB_EOA | COMEDI_CB_ERROR;
841                                 comedi_event(dev, s);
842                                 return 1;
843                         }
844                 comedi_buf_put(s->async, sampl & 0x0fff);
845 #else
846                 comedi_buf_put(s->async,
847                                inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
848 #endif
849                 j++;
850                 if (j >= devpriv->ai_n_chan) {
851                         j = 0;
852                         devpriv->ai_act_scan++;
853                 }
854         }
855         s->async->cur_chan = j;
856         return 0;
857 }
858
859 /*
860 ==============================================================================
861 */
862 static void interrupt_pci1710_half_fifo(void *d)
863 {
864         struct comedi_device *dev = d;
865         const struct boardtype *this_board = comedi_board(dev);
866         struct pci1710_private *devpriv = dev->private;
867         struct comedi_subdevice *s = &dev->subdevices[0];
868         int m, samplesinbuf;
869
870         m = inw(dev->iobase + PCI171x_STATUS);
871         if (!(m & Status_FH)) {
872                 printk("comedi%d: A/D FIFO not half full! (%4x)\n",
873                        dev->minor, m);
874                 pci171x_ai_cancel(dev, s);
875                 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
876                 comedi_event(dev, s);
877                 return;
878         }
879         if (m & Status_FF) {
880                 printk
881                     ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
882                      dev->minor, m);
883                 pci171x_ai_cancel(dev, s);
884                 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
885                 comedi_event(dev, s);
886                 return;
887         }
888
889         samplesinbuf = this_board->fifo_half_size;
890         if (samplesinbuf * sizeof(short) >= devpriv->ai_data_len) {
891                 m = devpriv->ai_data_len / sizeof(short);
892                 if (move_block_from_fifo(dev, s, m, 0))
893                         return;
894                 samplesinbuf -= m;
895         }
896
897         if (samplesinbuf) {
898                 if (move_block_from_fifo(dev, s, samplesinbuf, 1))
899                         return;
900         }
901
902         if (!devpriv->neverending_ai)
903                 if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data
904                                                                     sampled */
905                         pci171x_ai_cancel(dev, s);
906                         s->async->events |= COMEDI_CB_EOA;
907                         comedi_event(dev, s);
908                         return;
909                 }
910         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear our INT request */
911
912         comedi_event(dev, s);
913 }
914
915 /*
916 ==============================================================================
917 */
918 static irqreturn_t interrupt_service_pci1710(int irq, void *d)
919 {
920         struct comedi_device *dev = d;
921         struct pci1710_private *devpriv = dev->private;
922
923         if (!dev->attached)     /*  is device attached? */
924                 return IRQ_NONE;        /*  no, exit */
925         /*  is this interrupt from our board? */
926         if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))
927                 return IRQ_NONE;        /*  no, exit */
928
929         if (devpriv->ai_et) {   /*  Switch from initial TRIG_EXT to TRIG_xxx. */
930                 devpriv->ai_et = 0;
931                 devpriv->CntrlReg &= Control_CNT0;
932                 devpriv->CntrlReg |= Control_SW; /* set software trigger */
933                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
934                 devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
935                 outb(0, dev->iobase + PCI171x_CLRFIFO);
936                 outb(0, dev->iobase + PCI171x_CLRINT);
937                 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
938                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
939                 /*  start pacer */
940                 start_pacer(dev, 1, devpriv->ai_et_div1, devpriv->ai_et_div2);
941                 return IRQ_HANDLED;
942         }
943         if (devpriv->ai_eos) {  /*  We use FIFO half full INT or not? */
944                 interrupt_pci1710_every_sample(d);
945         } else {
946                 interrupt_pci1710_half_fifo(d);
947         }
948         return IRQ_HANDLED;
949 }
950
951 /*
952 ==============================================================================
953 */
954 static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev,
955                                      struct comedi_subdevice *s)
956 {
957         const struct boardtype *this_board = comedi_board(dev);
958         struct pci1710_private *devpriv = dev->private;
959         unsigned int divisor1 = 0, divisor2 = 0;
960         unsigned int seglen;
961
962         start_pacer(dev, -1, 0, 0);     /*  stop pacer */
963
964         seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
965                                     devpriv->ai_n_chan);
966         if (seglen < 1)
967                 return -EINVAL;
968         setup_channel_list(dev, s, devpriv->ai_chanlist,
969                            devpriv->ai_n_chan, seglen);
970
971         outb(0, dev->iobase + PCI171x_CLRFIFO);
972         outb(0, dev->iobase + PCI171x_CLRINT);
973
974         devpriv->ai_do = mode;
975
976         devpriv->ai_act_scan = 0;
977         s->async->cur_chan = 0;
978         devpriv->ai_buf_ptr = 0;
979         devpriv->neverending_ai = 0;
980
981         devpriv->CntrlReg &= Control_CNT0;
982         /*  don't we want wake up every scan?  devpriv->ai_eos=1; */
983         if ((devpriv->ai_flags & TRIG_WAKE_EOS)) {
984                 devpriv->ai_eos = 1;
985         } else {
986                 devpriv->CntrlReg |= Control_ONEFH;
987                 devpriv->ai_eos = 0;
988         }
989
990         if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1))
991                 devpriv->neverending_ai = 1;
992         /* well, user want neverending */
993         else
994                 devpriv->neverending_ai = 0;
995
996         switch (mode) {
997         case 1:
998         case 2:
999                 if (devpriv->ai_timer1 < this_board->ai_ns_min)
1000                         devpriv->ai_timer1 = this_board->ai_ns_min;
1001                 devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
1002                 if (mode == 2) {
1003                         devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
1004                         devpriv->CntrlReg &=
1005                             ~(Control_PACER | Control_ONEFH | Control_GATE);
1006                         devpriv->CntrlReg |= Control_EXT;
1007                         devpriv->ai_et = 1;
1008                 } else {
1009                         devpriv->ai_et = 0;
1010                 }
1011                 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
1012                                           &divisor2, &devpriv->ai_timer1,
1013                                           devpriv->ai_flags & TRIG_ROUND_MASK);
1014                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
1015                 if (mode != 2) {
1016                         /*  start pacer */
1017                         start_pacer(dev, mode, divisor1, divisor2);
1018                 } else {
1019                         devpriv->ai_et_div1 = divisor1;
1020                         devpriv->ai_et_div2 = divisor2;
1021                 }
1022                 break;
1023         case 3:
1024                 devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
1025                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
1026                 break;
1027         }
1028
1029         return 0;
1030 }
1031
1032 /*
1033 ==============================================================================
1034 */
1035 static int pci171x_ai_cmdtest(struct comedi_device *dev,
1036                               struct comedi_subdevice *s,
1037                               struct comedi_cmd *cmd)
1038 {
1039         const struct boardtype *this_board = comedi_board(dev);
1040         struct pci1710_private *devpriv = dev->private;
1041         int err = 0;
1042         int tmp;
1043         unsigned int divisor1 = 0, divisor2 = 0;
1044
1045         /* Step 1 : check if triggers are trivially valid */
1046
1047         err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
1048         err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
1049         err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
1050         err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
1051         err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
1052
1053         if (err)
1054                 return 1;
1055
1056         /* step 2a: make sure trigger sources are unique */
1057
1058         err |= cfc_check_trigger_is_unique(cmd->start_src);
1059         err |= cfc_check_trigger_is_unique(cmd->convert_src);
1060         err |= cfc_check_trigger_is_unique(cmd->stop_src);
1061
1062         /* step 2b: and mutually compatible */
1063
1064         if (err)
1065                 return 2;
1066
1067         /* Step 3: check if arguments are trivially valid */
1068
1069         err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
1070         err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
1071
1072         if (cmd->convert_src == TRIG_TIMER)
1073                 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
1074                                                  this_board->ai_ns_min);
1075         else    /* TRIG_FOLLOW */
1076                 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
1077
1078         err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
1079
1080         if (cmd->stop_src == TRIG_COUNT)
1081                 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
1082         else    /* TRIG_NONE */
1083                 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
1084
1085         if (err)
1086                 return 3;
1087
1088         /* step 4: fix up any arguments */
1089
1090         if (cmd->convert_src == TRIG_TIMER) {
1091                 tmp = cmd->convert_arg;
1092                 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
1093                                           &divisor2, &cmd->convert_arg,
1094                                           cmd->flags & TRIG_ROUND_MASK);
1095                 if (cmd->convert_arg < this_board->ai_ns_min)
1096                         cmd->convert_arg = this_board->ai_ns_min;
1097                 if (tmp != cmd->convert_arg)
1098                         err++;
1099         }
1100
1101         if (err)
1102                 return 4;
1103
1104         /* step 5: complain about special chanlist considerations */
1105
1106         if (cmd->chanlist) {
1107                 if (!check_channel_list(dev, s, cmd->chanlist,
1108                                         cmd->chanlist_len))
1109                         return 5;       /*  incorrect channels list */
1110         }
1111
1112         return 0;
1113 }
1114
1115 /*
1116 ==============================================================================
1117 */
1118 static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1119 {
1120         struct pci1710_private *devpriv = dev->private;
1121         struct comedi_cmd *cmd = &s->async->cmd;
1122
1123         devpriv->ai_n_chan = cmd->chanlist_len;
1124         devpriv->ai_chanlist = cmd->chanlist;
1125         devpriv->ai_flags = cmd->flags;
1126         devpriv->ai_data_len = s->async->prealloc_bufsz;
1127         devpriv->ai_data = s->async->prealloc_buf;
1128         devpriv->ai_timer1 = 0;
1129         devpriv->ai_timer2 = 0;
1130
1131         if (cmd->stop_src == TRIG_COUNT)
1132                 devpriv->ai_scans = cmd->stop_arg;
1133         else
1134                 devpriv->ai_scans = 0;
1135
1136
1137         if (cmd->scan_begin_src == TRIG_FOLLOW) {       /*  mode 1, 2, 3 */
1138                 if (cmd->convert_src == TRIG_TIMER) {   /*  mode 1 and 2 */
1139                         devpriv->ai_timer1 = cmd->convert_arg;
1140                         return pci171x_ai_docmd_and_mode(cmd->start_src ==
1141                                                          TRIG_EXT ? 2 : 1, dev,
1142                                                          s);
1143                 }
1144                 if (cmd->convert_src == TRIG_EXT) {     /*  mode 3 */
1145                         return pci171x_ai_docmd_and_mode(3, dev, s);
1146                 }
1147         }
1148
1149         return -1;
1150 }
1151
1152 /*
1153 ==============================================================================
1154 */
1155 static int pci171x_reset(struct comedi_device *dev)
1156 {
1157         const struct boardtype *this_board = comedi_board(dev);
1158         struct pci1710_private *devpriv = dev->private;
1159
1160         outw(0x30, dev->iobase + PCI171x_CNTCTRL);
1161         devpriv->CntrlReg = Control_SW | Control_CNT0;  /*  Software trigger, CNT0=external */
1162         outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /*  reset any operations */
1163         outb(0, dev->iobase + PCI171x_CLRFIFO); /*  clear FIFO */
1164         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear INT request */
1165         start_pacer(dev, -1, 0, 0);     /*  stop 8254 */
1166         devpriv->da_ranges = 0;
1167         if (this_board->n_aochan) {
1168                 outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);  /*  set DACs to 0..5V */
1169                 outw(0, dev->iobase + PCI171x_DA1);     /*  set DA outputs to 0V */
1170                 devpriv->ao_data[0] = 0x0000;
1171                 if (this_board->n_aochan > 1) {
1172                         outw(0, dev->iobase + PCI171x_DA2);
1173                         devpriv->ao_data[1] = 0x0000;
1174                 }
1175         }
1176         outw(0, dev->iobase + PCI171x_DO);      /*  digital outputs to 0 */
1177         outb(0, dev->iobase + PCI171x_CLRFIFO); /*  clear FIFO */
1178         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear INT request */
1179
1180         return 0;
1181 }
1182
1183 /*
1184 ==============================================================================
1185 */
1186 static int pci1720_reset(struct comedi_device *dev)
1187 {
1188         struct pci1710_private *devpriv = dev->private;
1189
1190         outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT);       /*  set synchronous output mode */
1191         devpriv->da_ranges = 0xAA;
1192         outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE);  /*  set all ranges to +/-5V */
1193         outw(0x0800, dev->iobase + PCI1720_DA0);        /*  set outputs to 0V */
1194         outw(0x0800, dev->iobase + PCI1720_DA1);
1195         outw(0x0800, dev->iobase + PCI1720_DA2);
1196         outw(0x0800, dev->iobase + PCI1720_DA3);
1197         outb(0, dev->iobase + PCI1720_SYNCOUT); /*  update outputs */
1198         devpriv->ao_data[0] = 0x0800;
1199         devpriv->ao_data[1] = 0x0800;
1200         devpriv->ao_data[2] = 0x0800;
1201         devpriv->ao_data[3] = 0x0800;
1202         return 0;
1203 }
1204
1205 /*
1206 ==============================================================================
1207 */
1208 static int pci1710_reset(struct comedi_device *dev)
1209 {
1210         const struct boardtype *this_board = comedi_board(dev);
1211
1212         switch (this_board->cardtype) {
1213         case TYPE_PCI1720:
1214                 return pci1720_reset(dev);
1215         default:
1216                 return pci171x_reset(dev);
1217         }
1218 }
1219
1220 static int pci1710_auto_attach(struct comedi_device *dev,
1221                                unsigned long context)
1222 {
1223         struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1224         const struct boardtype *this_board = NULL;
1225         struct pci1710_private *devpriv;
1226         struct comedi_subdevice *s;
1227         int ret, subdev, n_subdevices;
1228
1229         if (context < ARRAY_SIZE(boardtypes))
1230                 this_board = &boardtypes[context];
1231         if (!this_board)
1232                 return -ENODEV;
1233         dev->board_ptr = this_board;
1234         dev->board_name = this_board->name;
1235
1236         devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
1237         if (!devpriv)
1238                 return -ENOMEM;
1239         dev->private = devpriv;
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");