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