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