]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/comedi/drivers/adv_pci1710.c
9eaae0d18d1fd7b18706ae897c839eb5f2f400f6
[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/interrupt.h>
45
46 #include "../comedidev.h"
47
48 #include "comedi_pci.h"
49
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 #undef PCI171X_EXTDEBUG
58
59 #define DRV_NAME "adv_pci1710"
60
61 #undef DPRINTK
62 #ifdef PCI171X_EXTDEBUG
63 #define DPRINTK(fmt, args...) printk(fmt, ## args)
64 #else
65 #define DPRINTK(fmt, args...)
66 #endif
67
68 #define PCI_VENDOR_ID_ADVANTECH         0x13fe
69
70 /* hardware types of the cards */
71 #define TYPE_PCI171X    0
72 #define TYPE_PCI1713    2
73 #define TYPE_PCI1720    3
74
75 #define IORANGE_171x    32
76 #define IORANGE_1720    16
77
78 #define PCI171x_AD_DATA  0      /* R:   A/D data */
79 #define PCI171x_SOFTTRG  0      /* W:   soft trigger for A/D */
80 #define PCI171x_RANGE    2      /* W:   A/D gain/range register */
81 #define PCI171x_MUX      4      /* W:   A/D multiplexor control */
82 #define PCI171x_STATUS   6      /* R:   status register */
83 #define PCI171x_CONTROL  6      /* W:   control register */
84 #define PCI171x_CLRINT   8      /* W:   clear interrupts request */
85 #define PCI171x_CLRFIFO  9      /* W:   clear FIFO */
86 #define PCI171x_DA1     10      /* W:   D/A register */
87 #define PCI171x_DA2     12      /* W:   D/A register */
88 #define PCI171x_DAREF   14      /* W:   D/A reference control */
89 #define PCI171x_DI      16      /* R:   digi inputs */
90 #define PCI171x_DO      16      /* R:   digi inputs */
91 #define PCI171x_CNT0    24      /* R/W: 8254 counter 0 */
92 #define PCI171x_CNT1    26      /* R/W: 8254 counter 1 */
93 #define PCI171x_CNT2    28      /* R/W: 8254 counter 2 */
94 #define PCI171x_CNTCTRL 30      /* W:   8254 counter control */
95
96 /* upper bits from status register (PCI171x_STATUS) (lower is same with control
97  * reg) */
98 #define Status_FE       0x0100  /* 1=FIFO is empty */
99 #define Status_FH       0x0200  /* 1=FIFO is half full */
100 #define Status_FF       0x0400  /* 1=FIFO is full, fatal error */
101 #define Status_IRQ      0x0800  /* 1=IRQ occurred */
102 /* bits from control register (PCI171x_CONTROL) */
103 #define Control_CNT0    0x0040  /* 1=CNT0 have external source,
104                                  * 0=have internal 100kHz source */
105 #define Control_ONEFH   0x0020  /* 1=IRQ on FIFO is half full, 0=every sample */
106 #define Control_IRQEN   0x0010  /* 1=enable IRQ */
107 #define Control_GATE    0x0008  /* 1=enable external trigger GATE (8254?) */
108 #define Control_EXT     0x0004  /* 1=external trigger source */
109 #define Control_PACER   0x0002  /* 1=enable internal 8254 trigger source */
110 #define Control_SW      0x0001  /* 1=enable software trigger source */
111 /* bits from counter control register (PCI171x_CNTCTRL) */
112 #define Counter_BCD     0x0001  /* 0 = binary counter, 1 = BCD counter */
113 #define Counter_M0      0x0002  /* M0-M2 select modes 0-5 */
114 #define Counter_M1      0x0004  /* 000 = mode 0, 010 = mode 2 ... */
115 #define Counter_M2      0x0008
116 #define Counter_RW0     0x0010  /* RW0/RW1 select read/write mode */
117 #define Counter_RW1     0x0020
118 #define Counter_SC0     0x0040  /* Select Counter. Only 00 or 11 may */
119 #define Counter_SC1     0x0080  /* be used, 00 for CNT0,
120                                  * 11 for read-back command */
121
122 #define PCI1720_DA0      0      /* W:   D/A register 0 */
123 #define PCI1720_DA1      2      /* W:   D/A register 1 */
124 #define PCI1720_DA2      4      /* W:   D/A register 2 */
125 #define PCI1720_DA3      6      /* W:   D/A register 3 */
126 #define PCI1720_RANGE    8      /* R/W: D/A range register */
127 #define PCI1720_SYNCOUT  9      /* W:   D/A synchronized output register */
128 #define PCI1720_SYNCONT 15      /* R/W: D/A synchronized control */
129
130 /* D/A synchronized control (PCI1720_SYNCONT) */
131 #define Syncont_SC0      1      /* set synchronous output mode */
132
133 static const struct comedi_lrange range_pci1710_3 = { 9, {
134                                                           BIP_RANGE(5),
135                                                           BIP_RANGE(2.5),
136                                                           BIP_RANGE(1.25),
137                                                           BIP_RANGE(0.625),
138                                                           BIP_RANGE(10),
139                                                           UNI_RANGE(10),
140                                                           UNI_RANGE(5),
141                                                           UNI_RANGE(2.5),
142                                                           UNI_RANGE(1.25)
143                                                           }
144 };
145
146 static const char range_codes_pci1710_3[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
147                                               0x10, 0x11, 0x12, 0x13 };
148
149 static const struct comedi_lrange range_pci1710hg = { 12, {
150                                                            BIP_RANGE(5),
151                                                            BIP_RANGE(0.5),
152                                                            BIP_RANGE(0.05),
153                                                            BIP_RANGE(0.005),
154                                                            BIP_RANGE(10),
155                                                            BIP_RANGE(1),
156                                                            BIP_RANGE(0.1),
157                                                            BIP_RANGE(0.01),
158                                                            UNI_RANGE(10),
159                                                            UNI_RANGE(1),
160                                                            UNI_RANGE(0.1),
161                                                            UNI_RANGE(0.01)
162                                                            }
163 };
164
165 static const char range_codes_pci1710hg[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
166                                               0x05, 0x06, 0x07, 0x10, 0x11,
167                                               0x12, 0x13 };
168
169 static const struct comedi_lrange range_pci17x1 = { 5, {
170                                                         BIP_RANGE(10),
171                                                         BIP_RANGE(5),
172                                                         BIP_RANGE(2.5),
173                                                         BIP_RANGE(1.25),
174                                                         BIP_RANGE(0.625)
175                                                         }
176 };
177
178 static const char range_codes_pci17x1[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
179
180 static const struct comedi_lrange range_pci1720 = { 4, {
181                                                         UNI_RANGE(5),
182                                                         UNI_RANGE(10),
183                                                         BIP_RANGE(5),
184                                                         BIP_RANGE(10)
185                                                         }
186 };
187
188 static const struct comedi_lrange range_pci171x_da = { 2, {
189                                                            UNI_RANGE(5),
190                                                            UNI_RANGE(10),
191                                                            }
192 };
193
194 static int pci1710_attach(struct comedi_device *dev,
195                           struct comedi_devconfig *it);
196 static int pci1710_detach(struct comedi_device *dev);
197
198 struct boardtype {
199         const char *name;       /*  board name */
200         int device_id;
201         int iorange;            /*  I/O range len */
202         char have_irq;          /*  1=card support IRQ */
203         char cardtype;          /*  0=1710& co. 2=1713, ... */
204         int n_aichan;           /*  num of A/D chans */
205         int n_aichand;          /*  num of A/D chans in diff mode */
206         int n_aochan;           /*  num of D/A chans */
207         int n_dichan;           /*  num of DI chans */
208         int n_dochan;           /*  num of DO chans */
209         int n_counter;          /*  num of counters */
210         int ai_maxdata;         /*  resolution of A/D */
211         int ao_maxdata;         /*  resolution of D/A */
212         const struct comedi_lrange *rangelist_ai;       /*  rangelist for A/D */
213         const char *rangecode_ai;       /*  range codes for programming */
214         const struct comedi_lrange *rangelist_ao;       /*  rangelist for D/A */
215         unsigned int ai_ns_min; /*  max sample speed of card v ns */
216         unsigned int fifo_half_size;    /*  size of FIFO/2 */
217 };
218
219 static DEFINE_PCI_DEVICE_TABLE(pci1710_pci_table) = {
220         { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1710) },
221         { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1711) },
222         { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1713) },
223         { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1720) },
224         { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1731) },
225         { 0 }
226 };
227
228 MODULE_DEVICE_TABLE(pci, pci1710_pci_table);
229
230 static const struct boardtype boardtypes[] = {
231         {"pci1710", 0x1710,
232          IORANGE_171x, 1, TYPE_PCI171X,
233          16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff,
234          &range_pci1710_3, range_codes_pci1710_3,
235          &range_pci171x_da,
236          10000, 2048},
237         {"pci1710hg", 0x1710,
238          IORANGE_171x, 1, TYPE_PCI171X,
239          16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff,
240          &range_pci1710hg, range_codes_pci1710hg,
241          &range_pci171x_da,
242          10000, 2048},
243         {"pci1711", 0x1711,
244          IORANGE_171x, 1, TYPE_PCI171X,
245          16, 0, 2, 16, 16, 1, 0x0fff, 0x0fff,
246          &range_pci17x1, range_codes_pci17x1, &range_pci171x_da,
247          10000, 512},
248         {"pci1713", 0x1713,
249          IORANGE_171x, 1, TYPE_PCI1713,
250          32, 16, 0, 0, 0, 0, 0x0fff, 0x0000,
251          &range_pci1710_3, range_codes_pci1710_3, NULL,
252          10000, 2048},
253         {"pci1720", 0x1720,
254          IORANGE_1720, 0, TYPE_PCI1720,
255          0, 0, 4, 0, 0, 0, 0x0000, 0x0fff,
256          NULL, NULL, &range_pci1720,
257          0, 0},
258         {"pci1731", 0x1731,
259          IORANGE_171x, 1, TYPE_PCI171X,
260          16, 0, 0, 16, 16, 0, 0x0fff, 0x0000,
261          &range_pci17x1, range_codes_pci17x1, NULL,
262          10000, 512},
263         /*  dummy entry corresponding to driver name */
264         {.name = DRV_NAME},
265 };
266
267 static struct comedi_driver driver_pci1710 = {
268         .driver_name = DRV_NAME,
269         .module = THIS_MODULE,
270         .attach = pci1710_attach,
271         .detach = pci1710_detach,
272         .num_names = ARRAY_SIZE(boardtypes),
273         .board_name = &boardtypes[0].name,
274         .offset = sizeof(struct boardtype),
275 };
276
277 struct pci1710_private {
278         struct pci_dev *pcidev; /*  ptr to PCI device */
279         char valid;             /*  card is usable */
280         char neverending_ai;    /*  we do unlimited AI */
281         unsigned int CntrlReg;  /*  Control register */
282         unsigned int i8254_osc_base;    /*  frequence of onboard oscilator */
283         unsigned int ai_do;     /*  what do AI? 0=nothing, 1 to 4 mode */
284         unsigned int ai_act_scan;       /*  how many scans we finished */
285         unsigned int ai_act_chan;       /*  actual position in actual scan */
286         unsigned int ai_buf_ptr;        /*  data buffer ptr in samples */
287         unsigned char ai_eos;   /*  1=EOS wake up */
288         unsigned char ai_et;
289         unsigned int ai_et_CntrlReg;
290         unsigned int ai_et_MuxVal;
291         unsigned int ai_et_div1, ai_et_div2;
292         unsigned int act_chanlist[32];  /*  list of scaned channel */
293         unsigned char act_chanlist_len; /*  len of scanlist */
294         unsigned char act_chanlist_pos; /*  actual position in MUX list */
295         unsigned char da_ranges;        /*  copy of D/A outpit range register */
296         unsigned int ai_scans;  /*  len of scanlist */
297         unsigned int ai_n_chan; /*  how many channels is measured */
298         unsigned int *ai_chanlist;      /*  actaul chanlist */
299         unsigned int ai_flags;  /*  flaglist */
300         unsigned int ai_data_len;       /*  len of data buffer */
301         short *ai_data;         /*  data buffer */
302         unsigned int ai_timer1; /*  timers */
303         unsigned int ai_timer2;
304         short ao_data[4];       /*  data output buffer */
305         unsigned int cnt0_write_wait;   /* after a write, wait for update of the
306                                          * internal state */
307 };
308
309 #define devpriv ((struct pci1710_private *)dev->private)
310 #define this_board ((const struct boardtype *)dev->board_ptr)
311
312 /*
313 ==============================================================================
314 */
315
316 static int check_channel_list(struct comedi_device *dev,
317                               struct comedi_subdevice *s,
318                               unsigned int *chanlist, unsigned int n_chan);
319 static void setup_channel_list(struct comedi_device *dev,
320                                struct comedi_subdevice *s,
321                                unsigned int *chanlist, unsigned int n_chan,
322                                unsigned int seglen);
323 static void start_pacer(struct comedi_device *dev, int mode,
324                         unsigned int divisor1, unsigned int divisor2);
325 static int pci1710_reset(struct comedi_device *dev);
326 static int pci171x_ai_cancel(struct comedi_device *dev,
327                              struct comedi_subdevice *s);
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 */
340 static int pci171x_insn_read_ai(struct comedi_device *dev,
341                                 struct comedi_subdevice *s,
342                                 struct comedi_insn *insn, unsigned int *data)
343 {
344         int n, timeout;
345 #ifdef PCI171x_PARANOIDCHECK
346         unsigned int idata;
347 #endif
348
349         DPRINTK("adv_pci1710 EDBG: BGN: pci171x_insn_read_ai(...)\n");
350         devpriv->CntrlReg &= Control_CNT0;
351         devpriv->CntrlReg |= Control_SW;        /*  set software trigger */
352         outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
353         outb(0, dev->iobase + PCI171x_CLRFIFO);
354         outb(0, dev->iobase + PCI171x_CLRINT);
355
356         setup_channel_list(dev, s, &insn->chanspec, 1, 1);
357
358         DPRINTK("adv_pci1710 A ST=%4x IO=%x\n",
359                 inw(dev->iobase + PCI171x_STATUS),
360                 dev->iobase + PCI171x_STATUS);
361         for (n = 0; n < insn->n; n++) {
362                 outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */
363                 DPRINTK("adv_pci1710 B n=%d ST=%4x\n", n,
364                         inw(dev->iobase + PCI171x_STATUS));
365                 /* udelay(1); */
366                 DPRINTK("adv_pci1710 C n=%d ST=%4x\n", n,
367                         inw(dev->iobase + PCI171x_STATUS));
368                 timeout = 100;
369                 while (timeout--) {
370                         if (!(inw(dev->iobase + PCI171x_STATUS) & Status_FE))
371                                 goto conv_finish;
372                         if (!(timeout % 10))
373                                 DPRINTK("adv_pci1710 D n=%d tm=%d ST=%4x\n", n,
374                                         timeout,
375                                         inw(dev->iobase + PCI171x_STATUS));
376                 }
377                 comedi_error(dev, "A/D insn timeout");
378                 outb(0, dev->iobase + PCI171x_CLRFIFO);
379                 outb(0, dev->iobase + PCI171x_CLRINT);
380                 data[n] = 0;
381                 DPRINTK
382                     ("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n",
383                      n);
384                 return -ETIME;
385
386 conv_finish:
387 #ifdef PCI171x_PARANOIDCHECK
388                 idata = inw(dev->iobase + PCI171x_AD_DATA);
389                 if (this_board->cardtype != TYPE_PCI1713)
390                         if ((idata & 0xf000) != devpriv->act_chanlist[0]) {
391                                 comedi_error(dev, "A/D insn data droput!");
392                                 return -ETIME;
393                         }
394                 data[n] = idata & 0x0fff;
395 #else
396                 data[n] = inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff;
397 #endif
398
399         }
400
401         outb(0, dev->iobase + PCI171x_CLRFIFO);
402         outb(0, dev->iobase + PCI171x_CLRINT);
403
404         DPRINTK("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n", n);
405         return n;
406 }
407
408 /*
409 ==============================================================================
410 */
411 static int pci171x_insn_write_ao(struct comedi_device *dev,
412                                  struct comedi_subdevice *s,
413                                  struct comedi_insn *insn, unsigned int *data)
414 {
415         int n, chan, range, ofs;
416
417         chan = CR_CHAN(insn->chanspec);
418         range = CR_RANGE(insn->chanspec);
419         if (chan) {
420                 devpriv->da_ranges &= 0xfb;
421                 devpriv->da_ranges |= (range << 2);
422                 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
423                 ofs = PCI171x_DA2;
424         } else {
425                 devpriv->da_ranges &= 0xfe;
426                 devpriv->da_ranges |= range;
427                 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
428                 ofs = PCI171x_DA1;
429         }
430
431         for (n = 0; n < insn->n; n++)
432                 outw(data[n], dev->iobase + ofs);
433
434         devpriv->ao_data[chan] = data[n];
435
436         return n;
437
438 }
439
440 /*
441 ==============================================================================
442 */
443 static int pci171x_insn_read_ao(struct comedi_device *dev,
444                                 struct comedi_subdevice *s,
445                                 struct comedi_insn *insn, unsigned int *data)
446 {
447         int n, chan;
448
449         chan = CR_CHAN(insn->chanspec);
450         for (n = 0; n < insn->n; n++)
451                 data[n] = devpriv->ao_data[chan];
452
453         return n;
454 }
455
456 /*
457 ==============================================================================
458 */
459 static int pci171x_insn_bits_di(struct comedi_device *dev,
460                                 struct comedi_subdevice *s,
461                                 struct comedi_insn *insn, unsigned int *data)
462 {
463         data[1] = inw(dev->iobase + PCI171x_DI);
464
465         return 2;
466 }
467
468 /*
469 ==============================================================================
470 */
471 static int pci171x_insn_bits_do(struct comedi_device *dev,
472                                 struct comedi_subdevice *s,
473                                 struct comedi_insn *insn, unsigned int *data)
474 {
475         if (data[0]) {
476                 s->state &= ~data[0];
477                 s->state |= (data[0] & data[1]);
478                 outw(s->state, dev->iobase + PCI171x_DO);
479         }
480         data[1] = s->state;
481
482         return 2;
483 }
484
485 /*
486 ==============================================================================
487 */
488 static int pci171x_insn_counter_read(struct comedi_device *dev,
489                                      struct comedi_subdevice *s,
490                                      struct comedi_insn *insn,
491                                      unsigned int *data)
492 {
493         unsigned int msb, lsb, ccntrl;
494         int i;
495
496         ccntrl = 0xD2;          /* count only */
497         for (i = 0; i < insn->n; i++) {
498                 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
499
500                 lsb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
501                 msb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
502
503                 data[0] = lsb | (msb << 8);
504         }
505
506         return insn->n;
507 }
508
509 /*
510 ==============================================================================
511 */
512 static int pci171x_insn_counter_write(struct comedi_device *dev,
513                                       struct comedi_subdevice *s,
514                                       struct comedi_insn *insn,
515                                       unsigned int *data)
516 {
517         uint msb, lsb, ccntrl, status;
518
519         lsb = data[0] & 0x00FF;
520         msb = (data[0] & 0xFF00) >> 8;
521
522         /* write lsb, then msb */
523         outw(lsb, dev->iobase + PCI171x_CNT0);
524         outw(msb, dev->iobase + PCI171x_CNT0);
525
526         if (devpriv->cnt0_write_wait) {
527                 /* wait for the new count to be loaded */
528                 ccntrl = 0xE2;
529                 do {
530                         outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
531                         status = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
532                 } while (status & 0x40);
533         }
534
535         return insn->n;
536 }
537
538 /*
539 ==============================================================================
540 */
541 static int pci171x_insn_counter_config(struct comedi_device *dev,
542                                        struct comedi_subdevice *s,
543                                        struct comedi_insn *insn,
544                                        unsigned int *data)
545 {
546 #ifdef unused
547         /* This doesn't work like a normal Comedi counter config */
548         uint ccntrl = 0;
549
550         devpriv->cnt0_write_wait = data[0] & 0x20;
551
552         /* internal or external clock? */
553         if (!(data[0] & 0x10)) {        /* internal */
554                 devpriv->CntrlReg &= ~Control_CNT0;
555         } else {
556                 devpriv->CntrlReg |= Control_CNT0;
557         }
558         outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
559
560         if (data[0] & 0x01)
561                 ccntrl |= Counter_M0;
562         if (data[0] & 0x02)
563                 ccntrl |= Counter_M1;
564         if (data[0] & 0x04)
565                 ccntrl |= Counter_M2;
566         if (data[0] & 0x08)
567                 ccntrl |= Counter_BCD;
568         ccntrl |= Counter_RW0;  /* set read/write mode */
569         ccntrl |= Counter_RW1;
570         outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
571 #endif
572
573         return 1;
574 }
575
576 /*
577 ==============================================================================
578 */
579 static int pci1720_insn_write_ao(struct comedi_device *dev,
580                                  struct comedi_subdevice *s,
581                                  struct comedi_insn *insn, unsigned int *data)
582 {
583         int n, rangereg, chan;
584
585         chan = CR_CHAN(insn->chanspec);
586         rangereg = devpriv->da_ranges & (~(0x03 << (chan << 1)));
587         rangereg |= (CR_RANGE(insn->chanspec) << (chan << 1));
588         if (rangereg != devpriv->da_ranges) {
589                 outb(rangereg, dev->iobase + PCI1720_RANGE);
590                 devpriv->da_ranges = rangereg;
591         }
592
593         for (n = 0; n < insn->n; n++) {
594                 outw(data[n], dev->iobase + PCI1720_DA0 + (chan << 1));
595                 outb(0, dev->iobase + PCI1720_SYNCOUT); /*  update outputs */
596         }
597
598         devpriv->ao_data[chan] = data[n];
599
600         return n;
601 }
602
603 /*
604 ==============================================================================
605 */
606 static void interrupt_pci1710_every_sample(void *d)
607 {
608         struct comedi_device *dev = d;
609         struct comedi_subdevice *s = dev->subdevices + 0;
610         int m;
611 #ifdef PCI171x_PARANOIDCHECK
612         short sampl;
613 #endif
614
615         DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_every_sample(...)\n");
616         m = inw(dev->iobase + PCI171x_STATUS);
617         if (m & Status_FE) {
618                 printk("comedi%d: A/D FIFO empty (%4x)\n", dev->minor, m);
619                 pci171x_ai_cancel(dev, s);
620                 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
621                 comedi_event(dev, s);
622                 return;
623         }
624         if (m & Status_FF) {
625                 printk
626                     ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
627                      dev->minor, m);
628                 pci171x_ai_cancel(dev, s);
629                 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
630                 comedi_event(dev, s);
631                 return;
632         }
633
634         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear our INT request */
635
636         DPRINTK("FOR ");
637         for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
638 #ifdef PCI171x_PARANOIDCHECK
639                 sampl = inw(dev->iobase + PCI171x_AD_DATA);
640                 DPRINTK("%04x:", sampl);
641                 if (this_board->cardtype != TYPE_PCI1713)
642                         if ((sampl & 0xf000) !=
643                             devpriv->act_chanlist[s->async->cur_chan]) {
644                                 printk
645                                     ("comedi: A/D data dropout: received data from channel %d, expected %d!\n",
646                                      (sampl & 0xf000) >> 12,
647                                      (devpriv->
648                                       act_chanlist[s->
649                                                    async->cur_chan] & 0xf000) >>
650                                      12);
651                                 pci171x_ai_cancel(dev, s);
652                                 s->async->events |=
653                                     COMEDI_CB_EOA | COMEDI_CB_ERROR;
654                                 comedi_event(dev, s);
655                                 return;
656                         }
657                 DPRINTK("%8d %2d %8d~", s->async->buf_int_ptr,
658                         s->async->cur_chan, s->async->buf_int_count);
659                 comedi_buf_put(s->async, sampl & 0x0fff);
660 #else
661                 comedi_buf_put(s->async,
662                                inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
663 #endif
664                 ++s->async->cur_chan;
665
666                 if (s->async->cur_chan >= devpriv->ai_n_chan)
667                         s->async->cur_chan = 0;
668
669
670                 if (s->async->cur_chan == 0) {  /*  one scan done */
671                         devpriv->ai_act_scan++;
672                         DPRINTK
673                             ("adv_pci1710 EDBG: EOS1 bic %d bip %d buc %d bup %d\n",
674                              s->async->buf_int_count, s->async->buf_int_ptr,
675                              s->async->buf_user_count, s->async->buf_user_ptr);
676                         DPRINTK("adv_pci1710 EDBG: EOS2\n");
677                         if ((!devpriv->neverending_ai) &&
678                             (devpriv->ai_act_scan >= devpriv->ai_scans)) {
679                                 /*  all data sampled */
680                                 pci171x_ai_cancel(dev, s);
681                                 s->async->events |= COMEDI_CB_EOA;
682                                 comedi_event(dev, s);
683                                 return;
684                         }
685                 }
686         }
687
688         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear our INT request */
689         DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_every_sample(...)\n");
690
691         comedi_event(dev, s);
692 }
693
694 /*
695 ==============================================================================
696 */
697 static int move_block_from_fifo(struct comedi_device *dev,
698                                 struct comedi_subdevice *s, int n, int turn)
699 {
700         int i, j;
701 #ifdef PCI171x_PARANOIDCHECK
702         int sampl;
703 #endif
704         DPRINTK("adv_pci1710 EDBG: BGN: move_block_from_fifo(...,%d,%d)\n", n,
705                 turn);
706         j = s->async->cur_chan;
707         for (i = 0; i < n; i++) {
708 #ifdef PCI171x_PARANOIDCHECK
709                 sampl = inw(dev->iobase + PCI171x_AD_DATA);
710                 if (this_board->cardtype != TYPE_PCI1713)
711                         if ((sampl & 0xf000) != devpriv->act_chanlist[j]) {
712                                 printk
713                                     ("comedi%d: A/D  FIFO data dropout: received data from channel %d, expected %d! (%d/%d/%d/%d/%d/%4x)\n",
714                                      dev->minor, (sampl & 0xf000) >> 12,
715                                      (devpriv->act_chanlist[j] & 0xf000) >> 12,
716                                      i, j, devpriv->ai_act_scan, n, turn,
717                                      sampl);
718                                 pci171x_ai_cancel(dev, s);
719                                 s->async->events |=
720                                     COMEDI_CB_EOA | COMEDI_CB_ERROR;
721                                 comedi_event(dev, s);
722                                 return 1;
723                         }
724                 comedi_buf_put(s->async, sampl & 0x0fff);
725 #else
726                 comedi_buf_put(s->async,
727                                inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
728 #endif
729                 j++;
730                 if (j >= devpriv->ai_n_chan) {
731                         j = 0;
732                         devpriv->ai_act_scan++;
733                 }
734         }
735         s->async->cur_chan = j;
736         DPRINTK("adv_pci1710 EDBG: END: move_block_from_fifo(...)\n");
737         return 0;
738 }
739
740 /*
741 ==============================================================================
742 */
743 static void interrupt_pci1710_half_fifo(void *d)
744 {
745         struct comedi_device *dev = d;
746         struct comedi_subdevice *s = dev->subdevices + 0;
747         int m, samplesinbuf;
748
749         DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_half_fifo(...)\n");
750         m = inw(dev->iobase + PCI171x_STATUS);
751         if (!(m & Status_FH)) {
752                 printk("comedi%d: A/D FIFO not half full! (%4x)\n",
753                        dev->minor, m);
754                 pci171x_ai_cancel(dev, s);
755                 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
756                 comedi_event(dev, s);
757                 return;
758         }
759         if (m & Status_FF) {
760                 printk
761                     ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
762                      dev->minor, m);
763                 pci171x_ai_cancel(dev, s);
764                 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
765                 comedi_event(dev, s);
766                 return;
767         }
768
769         samplesinbuf = this_board->fifo_half_size;
770         if (samplesinbuf * sizeof(short) >= devpriv->ai_data_len) {
771                 m = devpriv->ai_data_len / sizeof(short);
772                 if (move_block_from_fifo(dev, s, m, 0))
773                         return;
774                 samplesinbuf -= m;
775         }
776
777         if (samplesinbuf) {
778                 if (move_block_from_fifo(dev, s, samplesinbuf, 1))
779                         return;
780         }
781
782         if (!devpriv->neverending_ai)
783                 if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data
784                                                                     sampled */
785                         pci171x_ai_cancel(dev, s);
786                         s->async->events |= COMEDI_CB_EOA;
787                         comedi_event(dev, s);
788                         return;
789                 }
790         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear our INT request */
791         DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_half_fifo(...)\n");
792
793         comedi_event(dev, s);
794 }
795
796 /*
797 ==============================================================================
798 */
799 static irqreturn_t interrupt_service_pci1710(int irq, void *d)
800 {
801         struct comedi_device *dev = d;
802
803         DPRINTK("adv_pci1710 EDBG: BGN: interrupt_service_pci1710(%d,...)\n",
804                 irq);
805         if (!dev->attached)     /*  is device attached? */
806                 return IRQ_NONE;        /*  no, exit */
807         /*  is this interrupt from our board? */
808         if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))
809                 return IRQ_NONE;        /*  no, exit */
810
811         DPRINTK("adv_pci1710 EDBG: interrupt_service_pci1710() ST: %4x\n",
812                 inw(dev->iobase + PCI171x_STATUS));
813
814         if (devpriv->ai_et) {   /*  Switch from initial TRIG_EXT to TRIG_xxx. */
815                 devpriv->ai_et = 0;
816                 devpriv->CntrlReg &= Control_CNT0;
817                 devpriv->CntrlReg |= Control_SW; /* set software trigger */
818                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
819                 devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
820                 outb(0, dev->iobase + PCI171x_CLRFIFO);
821                 outb(0, dev->iobase + PCI171x_CLRINT);
822                 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
823                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
824                 /*  start pacer */
825                 start_pacer(dev, 1, devpriv->ai_et_div1, devpriv->ai_et_div2);
826                 return IRQ_HANDLED;
827         }
828         if (devpriv->ai_eos) {  /*  We use FIFO half full INT or not? */
829                 interrupt_pci1710_every_sample(d);
830         } else {
831                 interrupt_pci1710_half_fifo(d);
832         }
833         DPRINTK("adv_pci1710 EDBG: END: interrupt_service_pci1710(...)\n");
834         return IRQ_HANDLED;
835 }
836
837 /*
838 ==============================================================================
839 */
840 static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev,
841                                      struct comedi_subdevice *s)
842 {
843         unsigned int divisor1 = 0, divisor2 = 0;
844         unsigned int seglen;
845
846         DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_docmd_and_mode(%d,...)\n",
847                 mode);
848         start_pacer(dev, -1, 0, 0);     /*  stop pacer */
849
850         seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
851                                     devpriv->ai_n_chan);
852         if (seglen < 1)
853                 return -EINVAL;
854         setup_channel_list(dev, s, devpriv->ai_chanlist,
855                            devpriv->ai_n_chan, seglen);
856
857         outb(0, dev->iobase + PCI171x_CLRFIFO);
858         outb(0, dev->iobase + PCI171x_CLRINT);
859
860         devpriv->ai_do = mode;
861
862         devpriv->ai_act_scan = 0;
863         s->async->cur_chan = 0;
864         devpriv->ai_buf_ptr = 0;
865         devpriv->neverending_ai = 0;
866
867         devpriv->CntrlReg &= Control_CNT0;
868         /*  don't we want wake up every scan?  devpriv->ai_eos=1; */
869         if ((devpriv->ai_flags & TRIG_WAKE_EOS)) {
870                 devpriv->ai_eos = 1;
871         } else {
872                 devpriv->CntrlReg |= Control_ONEFH;
873                 devpriv->ai_eos = 0;
874         }
875
876         if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1))
877                 devpriv->neverending_ai = 1;
878         /* well, user want neverending */
879         else
880                 devpriv->neverending_ai = 0;
881
882         switch (mode) {
883         case 1:
884         case 2:
885                 if (devpriv->ai_timer1 < this_board->ai_ns_min)
886                         devpriv->ai_timer1 = this_board->ai_ns_min;
887                 devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
888                 if (mode == 2) {
889                         devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
890                         devpriv->CntrlReg &=
891                             ~(Control_PACER | Control_ONEFH | Control_GATE);
892                         devpriv->CntrlReg |= Control_EXT;
893                         devpriv->ai_et = 1;
894                 } else {
895                         devpriv->ai_et = 0;
896                 }
897                 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
898                                           &divisor2, &devpriv->ai_timer1,
899                                           devpriv->ai_flags & TRIG_ROUND_MASK);
900                 DPRINTK
901                     ("adv_pci1710 EDBG: OSC base=%u div1=%u div2=%u timer=%u\n",
902                      devpriv->i8254_osc_base, divisor1, divisor2,
903                      devpriv->ai_timer1);
904                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
905                 if (mode != 2) {
906                         /*  start pacer */
907                         start_pacer(dev, mode, divisor1, divisor2);
908                 } else {
909                         devpriv->ai_et_div1 = divisor1;
910                         devpriv->ai_et_div2 = divisor2;
911                 }
912                 break;
913         case 3:
914                 devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
915                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
916                 break;
917         }
918
919         DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_docmd_and_mode(...)\n");
920         return 0;
921 }
922
923 #ifdef PCI171X_EXTDEBUG
924 /*
925 ==============================================================================
926 */
927 static void pci171x_cmdtest_out(int e, struct comedi_cmd *cmd)
928 {
929         printk("adv_pci1710 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e,
930                cmd->start_src, cmd->scan_begin_src, cmd->convert_src);
931         printk("adv_pci1710 e=%d startarg=%d scanarg=%d convarg=%d\n", e,
932                cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg);
933         printk("adv_pci1710 e=%d stopsrc=%x scanend=%x\n", e, cmd->stop_src,
934                cmd->scan_end_src);
935         printk("adv_pci1710 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n",
936                e, cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len);
937 }
938 #endif
939
940 /*
941 ==============================================================================
942 */
943 static int pci171x_ai_cmdtest(struct comedi_device *dev,
944                               struct comedi_subdevice *s,
945                               struct comedi_cmd *cmd)
946 {
947         int err = 0;
948         int tmp;
949         unsigned int divisor1 = 0, divisor2 = 0;
950
951         DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...)\n");
952 #ifdef PCI171X_EXTDEBUG
953         pci171x_cmdtest_out(-1, cmd);
954 #endif
955         /* step 1: make sure trigger sources are trivially valid */
956
957         tmp = cmd->start_src;
958         cmd->start_src &= TRIG_NOW | TRIG_EXT;
959         if (!cmd->start_src || tmp != cmd->start_src)
960                 err++;
961
962         tmp = cmd->scan_begin_src;
963         cmd->scan_begin_src &= TRIG_FOLLOW;
964         if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
965                 err++;
966
967         tmp = cmd->convert_src;
968         cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
969         if (!cmd->convert_src || tmp != cmd->convert_src)
970                 err++;
971
972         tmp = cmd->scan_end_src;
973         cmd->scan_end_src &= TRIG_COUNT;
974         if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
975                 err++;
976
977         tmp = cmd->stop_src;
978         cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
979         if (!cmd->stop_src || tmp != cmd->stop_src)
980                 err++;
981
982         if (err) {
983 #ifdef PCI171X_EXTDEBUG
984                 pci171x_cmdtest_out(1, cmd);
985 #endif
986                 DPRINTK(
987                 "adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=1\n",
988                 err);
989                 return 1;
990         }
991
992         /* step2: make sure trigger srcs are unique and mutually compatible */
993
994         if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) {
995                 cmd->start_src = TRIG_NOW;
996                 err++;
997         }
998
999         if (cmd->scan_begin_src != TRIG_FOLLOW) {
1000                 cmd->scan_begin_src = TRIG_FOLLOW;
1001                 err++;
1002         }
1003
1004         if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
1005                 err++;
1006
1007         if (cmd->scan_end_src != TRIG_COUNT) {
1008                 cmd->scan_end_src = TRIG_COUNT;
1009                 err++;
1010         }
1011
1012         if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
1013                 err++;
1014
1015         if (err) {
1016 #ifdef PCI171X_EXTDEBUG
1017                 pci171x_cmdtest_out(2, cmd);
1018 #endif
1019                 DPRINTK(
1020                 "adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=2\n",
1021                 err);
1022                 return 2;
1023         }
1024
1025         /* step 3: make sure arguments are trivially compatible */
1026
1027         if (cmd->start_arg != 0) {
1028                 cmd->start_arg = 0;
1029                 err++;
1030         }
1031
1032         if (cmd->scan_begin_arg != 0) {
1033                 cmd->scan_begin_arg = 0;
1034                 err++;
1035         }
1036
1037         if (cmd->convert_src == TRIG_TIMER) {
1038                 if (cmd->convert_arg < this_board->ai_ns_min) {
1039                         cmd->convert_arg = this_board->ai_ns_min;
1040                         err++;
1041                 }
1042         } else {                /* TRIG_FOLLOW */
1043                 if (cmd->convert_arg != 0) {
1044                         cmd->convert_arg = 0;
1045                         err++;
1046                 }
1047         }
1048
1049         if (cmd->scan_end_arg != cmd->chanlist_len) {
1050                 cmd->scan_end_arg = cmd->chanlist_len;
1051                 err++;
1052         }
1053         if (cmd->stop_src == TRIG_COUNT) {
1054                 if (!cmd->stop_arg) {
1055                         cmd->stop_arg = 1;
1056                         err++;
1057                 }
1058         } else {                /* TRIG_NONE */
1059                 if (cmd->stop_arg != 0) {
1060                         cmd->stop_arg = 0;
1061                         err++;
1062                 }
1063         }
1064
1065         if (err) {
1066 #ifdef PCI171X_EXTDEBUG
1067                 pci171x_cmdtest_out(3, cmd);
1068 #endif
1069                 DPRINTK(
1070                 "adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=3\n",
1071                 err);
1072                 return 3;
1073         }
1074
1075         /* step 4: fix up any arguments */
1076
1077         if (cmd->convert_src == TRIG_TIMER) {
1078                 tmp = cmd->convert_arg;
1079                 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
1080                                           &divisor2, &cmd->convert_arg,
1081                                           cmd->flags & TRIG_ROUND_MASK);
1082                 if (cmd->convert_arg < this_board->ai_ns_min)
1083                         cmd->convert_arg = this_board->ai_ns_min;
1084                 if (tmp != cmd->convert_arg)
1085                         err++;
1086         }
1087
1088         if (err) {
1089                 DPRINTK
1090                     ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=4\n",
1091                      err);
1092                 return 4;
1093         }
1094
1095         /* step 5: complain about special chanlist considerations */
1096
1097         if (cmd->chanlist) {
1098                 if (!check_channel_list(dev, s, cmd->chanlist,
1099                                         cmd->chanlist_len))
1100                         return 5;       /*  incorrect channels list */
1101         }
1102
1103         DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) ret=0\n");
1104         return 0;
1105 }
1106
1107 /*
1108 ==============================================================================
1109 */
1110 static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1111 {
1112         struct comedi_cmd *cmd = &s->async->cmd;
1113
1114         DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmd(...)\n");
1115         devpriv->ai_n_chan = cmd->chanlist_len;
1116         devpriv->ai_chanlist = cmd->chanlist;
1117         devpriv->ai_flags = cmd->flags;
1118         devpriv->ai_data_len = s->async->prealloc_bufsz;
1119         devpriv->ai_data = s->async->prealloc_buf;
1120         devpriv->ai_timer1 = 0;
1121         devpriv->ai_timer2 = 0;
1122
1123         if (cmd->stop_src == TRIG_COUNT)
1124                 devpriv->ai_scans = cmd->stop_arg;
1125         else
1126                 devpriv->ai_scans = 0;
1127
1128
1129         if (cmd->scan_begin_src == TRIG_FOLLOW) {       /*  mode 1, 2, 3 */
1130                 if (cmd->convert_src == TRIG_TIMER) {   /*  mode 1 and 2 */
1131                         devpriv->ai_timer1 = cmd->convert_arg;
1132                         return pci171x_ai_docmd_and_mode(cmd->start_src ==
1133                                                          TRIG_EXT ? 2 : 1, dev,
1134                                                          s);
1135                 }
1136                 if (cmd->convert_src == TRIG_EXT) {     /*  mode 3 */
1137                         return pci171x_ai_docmd_and_mode(3, dev, s);
1138                 }
1139         }
1140
1141         return -1;
1142 }
1143
1144 /*
1145 ==============================================================================
1146  Check if channel list from user is builded correctly
1147  If it's ok, then program scan/gain logic.
1148  This works for all cards.
1149 */
1150 static int check_channel_list(struct comedi_device *dev,
1151                               struct comedi_subdevice *s,
1152                               unsigned int *chanlist, unsigned int n_chan)
1153 {
1154         unsigned int chansegment[32];
1155         unsigned int i, nowmustbechan, seglen, segpos;
1156
1157         DPRINTK("adv_pci1710 EDBG:  check_channel_list(...,%d)\n", n_chan);
1158         /* correct channel and range number check itself comedi/range.c */
1159         if (n_chan < 1) {
1160                 comedi_error(dev, "range/channel list is empty!");
1161                 return 0;
1162         }
1163
1164         if (n_chan > 1) {
1165                 chansegment[0] = chanlist[0];   /*  first channel is every time ok */
1166                 for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {    /*  build part of chanlist */
1167                         /*  printk("%d. %d %d\n",i,CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
1168                         if (chanlist[0] == chanlist[i])
1169                                 break;  /*  we detect loop, this must by finish */
1170                         if (CR_CHAN(chanlist[i]) & 1)   /*  odd channel cann't by differencial */
1171                                 if (CR_AREF(chanlist[i]) == AREF_DIFF) {
1172                                         comedi_error(dev,
1173                                                      "Odd channel can't be differential input!\n");
1174                                         return 0;
1175                                 }
1176                         nowmustbechan =
1177                             (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
1178                         if (CR_AREF(chansegment[i - 1]) == AREF_DIFF)
1179                                 nowmustbechan = (nowmustbechan + 1) % s->n_chan;
1180                         if (nowmustbechan != CR_CHAN(chanlist[i])) {    /*  channel list isn't continuous :-( */
1181                                 printk
1182                                     ("channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
1183                                      i, CR_CHAN(chanlist[i]), nowmustbechan,
1184                                      CR_CHAN(chanlist[0]));
1185                                 return 0;
1186                         }
1187                         chansegment[i] = chanlist[i];   /*  well, this is next correct channel in list */
1188                 }
1189
1190                 for (i = 0, segpos = 0; i < n_chan; i++) {      /*  check whole chanlist */
1191                         /* printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
1192                         if (chanlist[i] != chansegment[i % seglen]) {
1193                                 printk
1194                                     ("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
1195                                      i, CR_CHAN(chansegment[i]),
1196                                      CR_RANGE(chansegment[i]),
1197                                      CR_AREF(chansegment[i]),
1198                                      CR_CHAN(chanlist[i % seglen]),
1199                                      CR_RANGE(chanlist[i % seglen]),
1200                                      CR_AREF(chansegment[i % seglen]));
1201                                 return 0;       /*  chan/gain list is strange */
1202                         }
1203                 }
1204         } else {
1205                 seglen = 1;
1206         }
1207         return seglen;
1208 }
1209
1210 static void setup_channel_list(struct comedi_device *dev,
1211                                struct comedi_subdevice *s,
1212                                unsigned int *chanlist, unsigned int n_chan,
1213                                unsigned int seglen)
1214 {
1215         unsigned int i, range, chanprog;
1216
1217         DPRINTK("adv_pci1710 EDBG:  setup_channel_list(...,%d,%d)\n", n_chan,
1218                 seglen);
1219         devpriv->act_chanlist_len = seglen;
1220         devpriv->act_chanlist_pos = 0;
1221
1222         DPRINTK("SegLen: %d\n", seglen);
1223         for (i = 0; i < seglen; i++) {  /*  store range list to card */
1224                 chanprog = muxonechan[CR_CHAN(chanlist[i])];
1225                 outw(chanprog, dev->iobase + PCI171x_MUX);      /* select channel */
1226                 range = this_board->rangecode_ai[CR_RANGE(chanlist[i])];
1227                 if (CR_AREF(chanlist[i]) == AREF_DIFF)
1228                         range |= 0x0020;
1229                 outw(range, dev->iobase + PCI171x_RANGE);       /* select gain */
1230 #ifdef PCI171x_PARANOIDCHECK
1231                 devpriv->act_chanlist[i] =
1232                     (CR_CHAN(chanlist[i]) << 12) & 0xf000;
1233 #endif
1234                 DPRINTK("GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range,
1235                         devpriv->act_chanlist[i]);
1236         }
1237 #ifdef PCI171x_PARANOIDCHECK
1238         for ( ; i < n_chan; i++) { /* store remainder of channel list */
1239                 devpriv->act_chanlist[i] =
1240                     (CR_CHAN(chanlist[i]) << 12) & 0xf000;
1241         }
1242 #endif
1243
1244         devpriv->ai_et_MuxVal =
1245             CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
1246         outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX); /* select channel interval to scan */
1247         DPRINTK("MUX: %4x L%4x.H%4x\n",
1248                 CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8),
1249                 CR_CHAN(chanlist[0]), CR_CHAN(chanlist[seglen - 1]));
1250 }
1251
1252 /*
1253 ==============================================================================
1254 */
1255 static void start_pacer(struct comedi_device *dev, int mode,
1256                         unsigned int divisor1, unsigned int divisor2)
1257 {
1258         DPRINTK("adv_pci1710 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode,
1259                 divisor1, divisor2);
1260         outw(0xb4, dev->iobase + PCI171x_CNTCTRL);
1261         outw(0x74, dev->iobase + PCI171x_CNTCTRL);
1262
1263         if (mode == 1) {
1264                 outw(divisor2 & 0xff, dev->iobase + PCI171x_CNT2);
1265                 outw((divisor2 >> 8) & 0xff, dev->iobase + PCI171x_CNT2);
1266                 outw(divisor1 & 0xff, dev->iobase + PCI171x_CNT1);
1267                 outw((divisor1 >> 8) & 0xff, dev->iobase + PCI171x_CNT1);
1268         }
1269         DPRINTK("adv_pci1710 EDBG: END: start_pacer(...)\n");
1270 }
1271
1272 /*
1273 ==============================================================================
1274 */
1275 static int pci171x_ai_cancel(struct comedi_device *dev,
1276                              struct comedi_subdevice *s)
1277 {
1278         DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cancel(...)\n");
1279
1280         switch (this_board->cardtype) {
1281         default:
1282                 devpriv->CntrlReg &= Control_CNT0;
1283                 devpriv->CntrlReg |= Control_SW;
1284
1285                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /*  reset any operations */
1286                 start_pacer(dev, -1, 0, 0);
1287                 outb(0, dev->iobase + PCI171x_CLRFIFO);
1288                 outb(0, dev->iobase + PCI171x_CLRINT);
1289                 break;
1290         }
1291
1292         devpriv->ai_do = 0;
1293         devpriv->ai_act_scan = 0;
1294         s->async->cur_chan = 0;
1295         devpriv->ai_buf_ptr = 0;
1296         devpriv->neverending_ai = 0;
1297
1298         DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_cancel(...)\n");
1299         return 0;
1300 }
1301
1302 /*
1303 ==============================================================================
1304 */
1305 static int pci171x_reset(struct comedi_device *dev)
1306 {
1307         DPRINTK("adv_pci1710 EDBG: BGN: pci171x_reset(...)\n");
1308         outw(0x30, dev->iobase + PCI171x_CNTCTRL);
1309         devpriv->CntrlReg = Control_SW | Control_CNT0;  /*  Software trigger, CNT0=external */
1310         outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /*  reset any operations */
1311         outb(0, dev->iobase + PCI171x_CLRFIFO); /*  clear FIFO */
1312         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear INT request */
1313         start_pacer(dev, -1, 0, 0);     /*  stop 8254 */
1314         devpriv->da_ranges = 0;
1315         if (this_board->n_aochan) {
1316                 outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);  /*  set DACs to 0..5V */
1317                 outw(0, dev->iobase + PCI171x_DA1);     /*  set DA outputs to 0V */
1318                 devpriv->ao_data[0] = 0x0000;
1319                 if (this_board->n_aochan > 1) {
1320                         outw(0, dev->iobase + PCI171x_DA2);
1321                         devpriv->ao_data[1] = 0x0000;
1322                 }
1323         }
1324         outw(0, dev->iobase + PCI171x_DO);      /*  digital outputs to 0 */
1325         outb(0, dev->iobase + PCI171x_CLRFIFO); /*  clear FIFO */
1326         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear INT request */
1327
1328         DPRINTK("adv_pci1710 EDBG: END: pci171x_reset(...)\n");
1329         return 0;
1330 }
1331
1332 /*
1333 ==============================================================================
1334 */
1335 static int pci1720_reset(struct comedi_device *dev)
1336 {
1337         DPRINTK("adv_pci1710 EDBG: BGN: pci1720_reset(...)\n");
1338         outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT);       /*  set synchronous output mode */
1339         devpriv->da_ranges = 0xAA;
1340         outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE);  /*  set all ranges to +/-5V */
1341         outw(0x0800, dev->iobase + PCI1720_DA0);        /*  set outputs to 0V */
1342         outw(0x0800, dev->iobase + PCI1720_DA1);
1343         outw(0x0800, dev->iobase + PCI1720_DA2);
1344         outw(0x0800, dev->iobase + PCI1720_DA3);
1345         outb(0, dev->iobase + PCI1720_SYNCOUT); /*  update outputs */
1346         devpriv->ao_data[0] = 0x0800;
1347         devpriv->ao_data[1] = 0x0800;
1348         devpriv->ao_data[2] = 0x0800;
1349         devpriv->ao_data[3] = 0x0800;
1350         DPRINTK("adv_pci1710 EDBG: END: pci1720_reset(...)\n");
1351         return 0;
1352 }
1353
1354 /*
1355 ==============================================================================
1356 */
1357 static int pci1710_reset(struct comedi_device *dev)
1358 {
1359         DPRINTK("adv_pci1710 EDBG: BGN: pci1710_reset(...)\n");
1360         switch (this_board->cardtype) {
1361         case TYPE_PCI1720:
1362                 return pci1720_reset(dev);
1363         default:
1364                 return pci171x_reset(dev);
1365         }
1366         DPRINTK("adv_pci1710 EDBG: END: pci1710_reset(...)\n");
1367 }
1368
1369 /*
1370 ==============================================================================
1371 */
1372 static int pci1710_attach(struct comedi_device *dev,
1373                           struct comedi_devconfig *it)
1374 {
1375         struct comedi_subdevice *s;
1376         int ret, subdev, n_subdevices;
1377         unsigned int irq;
1378         unsigned long iobase;
1379         struct pci_dev *pcidev;
1380         int opt_bus, opt_slot;
1381         const char *errstr;
1382         unsigned char pci_bus, pci_slot, pci_func;
1383         int i;
1384         int board_index;
1385
1386         dev_info(dev->hw_dev, "comedi%d: adv_pci1710:\n", dev->minor);
1387
1388         opt_bus = it->options[0];
1389         opt_slot = it->options[1];
1390
1391         ret = alloc_private(dev, sizeof(struct pci1710_private));
1392         if (ret < 0)
1393                 return -ENOMEM;
1394
1395         /* Look for matching PCI device */
1396         errstr = "not found!";
1397         pcidev = NULL;
1398         board_index = this_board - boardtypes;
1399         while (NULL != (pcidev = pci_get_device(PCI_VENDOR_ID_ADVANTECH,
1400                                                 PCI_ANY_ID, pcidev))) {
1401                 if (strcmp(this_board->name, DRV_NAME) == 0) {
1402                         for (i = 0; i < ARRAY_SIZE(boardtypes); ++i) {
1403                                 if (pcidev->device == boardtypes[i].device_id) {
1404                                         board_index = i;
1405                                         break;
1406                                 }
1407                         }
1408                         if (i == ARRAY_SIZE(boardtypes))
1409                                 continue;
1410                 } else {
1411                         if (pcidev->device != boardtypes[board_index].device_id)
1412                                 continue;
1413                 }
1414
1415                 /* Found matching vendor/device. */
1416                 if (opt_bus || opt_slot) {
1417                         /* Check bus/slot. */
1418                         if (opt_bus != pcidev->bus->number
1419                             || opt_slot != PCI_SLOT(pcidev->devfn))
1420                                 continue;       /* no match */
1421                 }
1422                 /*
1423                  * Look for device that isn't in use.
1424                  * Enable PCI device and request regions.
1425                  */
1426                 if (comedi_pci_enable(pcidev, DRV_NAME)) {
1427                         errstr =
1428                             "failed to enable PCI device and request regions!";
1429                         continue;
1430                 }
1431                 /*  fixup board_ptr in case we were using the dummy entry with the driver name */
1432                 dev->board_ptr = &boardtypes[board_index];
1433                 break;
1434         }
1435
1436         if (!pcidev) {
1437                 if (opt_bus || opt_slot) {
1438                         dev_err(dev->hw_dev, "- Card at b:s %d:%d %s\n",
1439                                 opt_bus, opt_slot, errstr);
1440                 } else {
1441                         dev_err(dev->hw_dev, "- Card %s\n", errstr);
1442                 }
1443                 return -EIO;
1444         }
1445
1446         pci_bus = pcidev->bus->number;
1447         pci_slot = PCI_SLOT(pcidev->devfn);
1448         pci_func = PCI_FUNC(pcidev->devfn);
1449         irq = pcidev->irq;
1450         iobase = pci_resource_start(pcidev, 2);
1451
1452         dev_dbg(dev->hw_dev, "b:s:f=%d:%d:%d, io=0x%4lx\n", pci_bus, pci_slot,
1453                 pci_func, iobase);
1454
1455         dev->iobase = iobase;
1456
1457         dev->board_name = this_board->name;
1458         devpriv->pcidev = pcidev;
1459
1460         n_subdevices = 0;
1461         if (this_board->n_aichan)
1462                 n_subdevices++;
1463         if (this_board->n_aochan)
1464                 n_subdevices++;
1465         if (this_board->n_dichan)
1466                 n_subdevices++;
1467         if (this_board->n_dochan)
1468                 n_subdevices++;
1469         if (this_board->n_counter)
1470                 n_subdevices++;
1471
1472         ret = alloc_subdevices(dev, n_subdevices);
1473         if (ret < 0)
1474                 return ret;
1475
1476         pci1710_reset(dev);
1477
1478         if (this_board->have_irq) {
1479                 if (irq) {
1480                         if (request_irq(irq, interrupt_service_pci1710,
1481                                         IRQF_SHARED, "Advantech PCI-1710",
1482                                         dev)) {
1483                                 dev_dbg(dev->hw_dev, "unable to allocate IRQ %d, DISABLING IT",
1484                                         irq);
1485                                 irq = 0;        /* Can't use IRQ */
1486                         } else {
1487                                 dev_dbg(dev->hw_dev, "irq=%u", irq);
1488                         }
1489                 } else {
1490                         dev_dbg(dev->hw_dev, "IRQ disabled");
1491                 }
1492         } else {
1493                 irq = 0;
1494         }
1495
1496         dev->irq = irq;
1497         subdev = 0;
1498
1499         if (this_board->n_aichan) {
1500                 s = dev->subdevices + subdev;
1501                 dev->read_subdev = s;
1502                 s->type = COMEDI_SUBD_AI;
1503                 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
1504                 if (this_board->n_aichand)
1505                         s->subdev_flags |= SDF_DIFF;
1506                 s->n_chan = this_board->n_aichan;
1507                 s->maxdata = this_board->ai_maxdata;
1508                 s->len_chanlist = this_board->n_aichan;
1509                 s->range_table = this_board->rangelist_ai;
1510                 s->cancel = pci171x_ai_cancel;
1511                 s->insn_read = pci171x_insn_read_ai;
1512                 if (irq) {
1513                         s->subdev_flags |= SDF_CMD_READ;
1514                         s->do_cmdtest = pci171x_ai_cmdtest;
1515                         s->do_cmd = pci171x_ai_cmd;
1516                 }
1517                 devpriv->i8254_osc_base = 100;  /*  100ns=10MHz */
1518                 subdev++;
1519         }
1520
1521         if (this_board->n_aochan) {
1522                 s = dev->subdevices + subdev;
1523                 s->type = COMEDI_SUBD_AO;
1524                 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1525                 s->n_chan = this_board->n_aochan;
1526                 s->maxdata = this_board->ao_maxdata;
1527                 s->len_chanlist = this_board->n_aochan;
1528                 s->range_table = this_board->rangelist_ao;
1529                 switch (this_board->cardtype) {
1530                 case TYPE_PCI1720:
1531                         s->insn_write = pci1720_insn_write_ao;
1532                         break;
1533                 default:
1534                         s->insn_write = pci171x_insn_write_ao;
1535                         break;
1536                 }
1537                 s->insn_read = pci171x_insn_read_ao;
1538                 subdev++;
1539         }
1540
1541         if (this_board->n_dichan) {
1542                 s = dev->subdevices + subdev;
1543                 s->type = COMEDI_SUBD_DI;
1544                 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
1545                 s->n_chan = this_board->n_dichan;
1546                 s->maxdata = 1;
1547                 s->len_chanlist = this_board->n_dichan;
1548                 s->range_table = &range_digital;
1549                 s->io_bits = 0; /* all bits input */
1550                 s->insn_bits = pci171x_insn_bits_di;
1551                 subdev++;
1552         }
1553
1554         if (this_board->n_dochan) {
1555                 s = dev->subdevices + subdev;
1556                 s->type = COMEDI_SUBD_DO;
1557                 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1558                 s->n_chan = this_board->n_dochan;
1559                 s->maxdata = 1;
1560                 s->len_chanlist = this_board->n_dochan;
1561                 s->range_table = &range_digital;
1562                 /* all bits output */
1563                 s->io_bits = (1 << this_board->n_dochan) - 1;
1564                 s->state = 0;
1565                 s->insn_bits = pci171x_insn_bits_do;
1566                 subdev++;
1567         }
1568
1569         if (this_board->n_counter) {
1570                 s = dev->subdevices + subdev;
1571                 s->type = COMEDI_SUBD_COUNTER;
1572                 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1573                 s->n_chan = this_board->n_counter;
1574                 s->len_chanlist = this_board->n_counter;
1575                 s->maxdata = 0xffff;
1576                 s->range_table = &range_unknown;
1577                 s->insn_read = pci171x_insn_counter_read;
1578                 s->insn_write = pci171x_insn_counter_write;
1579                 s->insn_config = pci171x_insn_counter_config;
1580                 subdev++;
1581         }
1582
1583         devpriv->valid = 1;
1584
1585         return 0;
1586 }
1587
1588 /*
1589 ==============================================================================
1590 */
1591 static int pci1710_detach(struct comedi_device *dev)
1592 {
1593
1594         if (dev->private) {
1595                 if (devpriv->valid)
1596                         pci1710_reset(dev);
1597                 if (dev->irq)
1598                         free_irq(dev->irq, dev);
1599                 if (devpriv->pcidev) {
1600                         if (dev->iobase)
1601                                 comedi_pci_disable(devpriv->pcidev);
1602
1603                         pci_dev_put(devpriv->pcidev);
1604                 }
1605         }
1606
1607         return 0;
1608 }
1609
1610 /*
1611 ==============================================================================
1612 */
1613 static int __devinit driver_pci1710_pci_probe(struct pci_dev *dev,
1614                                               const struct pci_device_id *ent)
1615 {
1616         return comedi_pci_auto_config(dev, &driver_pci1710);
1617 }
1618
1619 static void __devexit driver_pci1710_pci_remove(struct pci_dev *dev)
1620 {
1621         comedi_pci_auto_unconfig(dev);
1622 }
1623
1624 static struct pci_driver driver_pci1710_pci_driver = {
1625         .id_table = pci1710_pci_table,
1626         .probe = &driver_pci1710_pci_probe,
1627         .remove = __devexit_p(&driver_pci1710_pci_remove)
1628 };
1629
1630 static int __init driver_pci1710_init_module(void)
1631 {
1632         int retval;
1633
1634         retval = comedi_driver_register(&driver_pci1710);
1635         if (retval < 0)
1636                 return retval;
1637
1638         driver_pci1710_pci_driver.name = (char *)driver_pci1710.driver_name;
1639         return pci_register_driver(&driver_pci1710_pci_driver);
1640 }
1641
1642 static void __exit driver_pci1710_cleanup_module(void)
1643 {
1644         pci_unregister_driver(&driver_pci1710_pci_driver);
1645         comedi_driver_unregister(&driver_pci1710);
1646 }
1647
1648 module_init(driver_pci1710_init_module);
1649 module_exit(driver_pci1710_cleanup_module);
1650 /*
1651 ==============================================================================
1652 */
1653
1654 MODULE_AUTHOR("Comedi http://www.comedi.org");
1655 MODULE_DESCRIPTION("Comedi low-level driver");
1656 MODULE_LICENSE("GPL");