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