Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6
[pandora-kernel.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 occured */
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 #define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype))
268
269 static struct comedi_driver driver_pci1710 = {
270         .driver_name = DRV_NAME,
271         .module = THIS_MODULE,
272         .attach = pci1710_attach,
273         .detach = pci1710_detach,
274         .num_names = n_boardtypes,
275         .board_name = &boardtypes[0].name,
276         .offset = sizeof(struct boardtype),
277 };
278
279 struct pci1710_private {
280         struct pci_dev *pcidev; /*  ptr to PCI device */
281         char valid;             /*  card is usable */
282         char neverending_ai;    /*  we do unlimited AI */
283         unsigned int CntrlReg;  /*  Control register */
284         unsigned int i8254_osc_base;    /*  frequence of onboard oscilator */
285         unsigned int ai_do;     /*  what do AI? 0=nothing, 1 to 4 mode */
286         unsigned int ai_act_scan;       /*  how many scans we finished */
287         unsigned int ai_act_chan;       /*  actual position in actual scan */
288         unsigned int ai_buf_ptr;        /*  data buffer ptr in samples */
289         unsigned char ai_eos;   /*  1=EOS wake up */
290         unsigned char ai_et;
291         unsigned int ai_et_CntrlReg;
292         unsigned int ai_et_MuxVal;
293         unsigned int ai_et_div1, ai_et_div2;
294         unsigned int act_chanlist[32];  /*  list of scaned channel */
295         unsigned char act_chanlist_len; /*  len of scanlist */
296         unsigned char act_chanlist_pos; /*  actual position in MUX list */
297         unsigned char da_ranges;        /*  copy of D/A outpit range register */
298         unsigned int ai_scans;  /*  len of scanlist */
299         unsigned int ai_n_chan; /*  how many channels is measured */
300         unsigned int *ai_chanlist;      /*  actaul chanlist */
301         unsigned int ai_flags;  /*  flaglist */
302         unsigned int ai_data_len;       /*  len of data buffer */
303         short *ai_data;         /*  data buffer */
304         unsigned int ai_timer1; /*  timers */
305         unsigned int ai_timer2;
306         short ao_data[4];       /*  data output buffer */
307         unsigned int cnt0_write_wait;   /* after a write, wait for update of the
308                                          * internal state */
309 };
310
311 #define devpriv ((struct pci1710_private *)dev->private)
312 #define this_board ((const struct boardtype *)dev->board_ptr)
313
314 /*
315 ==============================================================================
316 */
317
318 static int check_channel_list(struct comedi_device *dev,
319                               struct comedi_subdevice *s,
320                               unsigned int *chanlist, unsigned int n_chan);
321 static void setup_channel_list(struct comedi_device *dev,
322                                struct comedi_subdevice *s,
323                                unsigned int *chanlist, unsigned int n_chan,
324                                unsigned int seglen);
325 static void start_pacer(struct comedi_device *dev, int mode,
326                         unsigned int divisor1, unsigned int divisor2);
327 static int pci1710_reset(struct comedi_device *dev);
328 static int pci171x_ai_cancel(struct comedi_device *dev,
329                              struct comedi_subdevice *s);
330
331 /*  used for gain list programming */
332 static const unsigned int muxonechan[] = {
333         0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707,
334         0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f,
335         0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717,
336         0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f
337 };
338
339 /*
340 ==============================================================================
341 */
342 static int pci171x_insn_read_ai(struct comedi_device *dev,
343                                 struct comedi_subdevice *s,
344                                 struct comedi_insn *insn, unsigned int *data)
345 {
346         int n, timeout;
347 #ifdef PCI171x_PARANOIDCHECK
348         unsigned int idata;
349 #endif
350
351         DPRINTK("adv_pci1710 EDBG: BGN: pci171x_insn_read_ai(...)\n");
352         devpriv->CntrlReg &= Control_CNT0;
353         devpriv->CntrlReg |= Control_SW;        /*  set software trigger */
354         outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
355         outb(0, dev->iobase + PCI171x_CLRFIFO);
356         outb(0, dev->iobase + PCI171x_CLRINT);
357
358         setup_channel_list(dev, s, &insn->chanspec, 1, 1);
359
360         DPRINTK("adv_pci1710 A ST=%4x IO=%x\n",
361                 inw(dev->iobase + PCI171x_STATUS),
362                 dev->iobase + PCI171x_STATUS);
363         for (n = 0; n < insn->n; n++) {
364                 outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */
365                 DPRINTK("adv_pci1710 B n=%d ST=%4x\n", n,
366                         inw(dev->iobase + PCI171x_STATUS));
367                 /* udelay(1); */
368                 DPRINTK("adv_pci1710 C n=%d ST=%4x\n", n,
369                         inw(dev->iobase + PCI171x_STATUS));
370                 timeout = 100;
371                 while (timeout--) {
372                         if (!(inw(dev->iobase + PCI171x_STATUS) & Status_FE))
373                                 goto conv_finish;
374                         if (!(timeout % 10))
375                                 DPRINTK("adv_pci1710 D n=%d tm=%d ST=%4x\n", n,
376                                         timeout,
377                                         inw(dev->iobase + PCI171x_STATUS));
378                 }
379                 comedi_error(dev, "A/D insn timeout");
380                 outb(0, dev->iobase + PCI171x_CLRFIFO);
381                 outb(0, dev->iobase + PCI171x_CLRINT);
382                 data[n] = 0;
383                 DPRINTK
384                     ("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n",
385                      n);
386                 return -ETIME;
387
388 conv_finish:
389 #ifdef PCI171x_PARANOIDCHECK
390                 idata = inw(dev->iobase + PCI171x_AD_DATA);
391                 if (this_board->cardtype != TYPE_PCI1713)
392                         if ((idata & 0xf000) != devpriv->act_chanlist[0]) {
393                                 comedi_error(dev, "A/D insn data droput!");
394                                 return -ETIME;
395                         }
396                 data[n] = idata & 0x0fff;
397 #else
398                 data[n] = inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff;
399 #endif
400
401         }
402
403         outb(0, dev->iobase + PCI171x_CLRFIFO);
404         outb(0, dev->iobase + PCI171x_CLRINT);
405
406         DPRINTK("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n", n);
407         return n;
408 }
409
410 /*
411 ==============================================================================
412 */
413 static int pci171x_insn_write_ao(struct comedi_device *dev,
414                                  struct comedi_subdevice *s,
415                                  struct comedi_insn *insn, unsigned int *data)
416 {
417         int n, chan, range, ofs;
418
419         chan = CR_CHAN(insn->chanspec);
420         range = CR_RANGE(insn->chanspec);
421         if (chan) {
422                 devpriv->da_ranges &= 0xfb;
423                 devpriv->da_ranges |= (range << 2);
424                 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
425                 ofs = PCI171x_DA2;
426         } else {
427                 devpriv->da_ranges &= 0xfe;
428                 devpriv->da_ranges |= range;
429                 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
430                 ofs = PCI171x_DA1;
431         }
432
433         for (n = 0; n < insn->n; n++)
434                 outw(data[n], dev->iobase + ofs);
435
436         devpriv->ao_data[chan] = data[n];
437
438         return n;
439
440 }
441
442 /*
443 ==============================================================================
444 */
445 static int pci171x_insn_read_ao(struct comedi_device *dev,
446                                 struct comedi_subdevice *s,
447                                 struct comedi_insn *insn, unsigned int *data)
448 {
449         int n, chan;
450
451         chan = CR_CHAN(insn->chanspec);
452         for (n = 0; n < insn->n; n++)
453                 data[n] = devpriv->ao_data[chan];
454
455         return n;
456 }
457
458 /*
459 ==============================================================================
460 */
461 static int pci171x_insn_bits_di(struct comedi_device *dev,
462                                 struct comedi_subdevice *s,
463                                 struct comedi_insn *insn, unsigned int *data)
464 {
465         data[1] = inw(dev->iobase + PCI171x_DI);
466
467         return 2;
468 }
469
470 /*
471 ==============================================================================
472 */
473 static int pci171x_insn_bits_do(struct comedi_device *dev,
474                                 struct comedi_subdevice *s,
475                                 struct comedi_insn *insn, unsigned int *data)
476 {
477         if (data[0]) {
478                 s->state &= ~data[0];
479                 s->state |= (data[0] & data[1]);
480                 outw(s->state, dev->iobase + PCI171x_DO);
481         }
482         data[1] = s->state;
483
484         return 2;
485 }
486
487 /*
488 ==============================================================================
489 */
490 static int pci171x_insn_counter_read(struct comedi_device *dev,
491                                      struct comedi_subdevice *s,
492                                      struct comedi_insn *insn,
493                                      unsigned int *data)
494 {
495         unsigned int msb, lsb, ccntrl;
496         int i;
497
498         ccntrl = 0xD2;          /* count only */
499         for (i = 0; i < insn->n; i++) {
500                 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
501
502                 lsb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
503                 msb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
504
505                 data[0] = lsb | (msb << 8);
506         }
507
508         return insn->n;
509 }
510
511 /*
512 ==============================================================================
513 */
514 static int pci171x_insn_counter_write(struct comedi_device *dev,
515                                       struct comedi_subdevice *s,
516                                       struct comedi_insn *insn,
517                                       unsigned int *data)
518 {
519         uint msb, lsb, ccntrl, status;
520
521         lsb = data[0] & 0x00FF;
522         msb = (data[0] & 0xFF00) >> 8;
523
524         /* write lsb, then msb */
525         outw(lsb, dev->iobase + PCI171x_CNT0);
526         outw(msb, dev->iobase + PCI171x_CNT0);
527
528         if (devpriv->cnt0_write_wait) {
529                 /* wait for the new count to be loaded */
530                 ccntrl = 0xE2;
531                 do {
532                         outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
533                         status = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
534                 } while (status & 0x40);
535         }
536
537         return insn->n;
538 }
539
540 /*
541 ==============================================================================
542 */
543 static int pci171x_insn_counter_config(struct comedi_device *dev,
544                                        struct comedi_subdevice *s,
545                                        struct comedi_insn *insn,
546                                        unsigned int *data)
547 {
548 #ifdef unused
549         /* This doesn't work like a normal Comedi counter config */
550         uint ccntrl = 0;
551
552         devpriv->cnt0_write_wait = data[0] & 0x20;
553
554         /* internal or external clock? */
555         if (!(data[0] & 0x10)) {        /* internal */
556                 devpriv->CntrlReg &= ~Control_CNT0;
557         } else {
558                 devpriv->CntrlReg |= Control_CNT0;
559         }
560         outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
561
562         if (data[0] & 0x01)
563                 ccntrl |= Counter_M0;
564         if (data[0] & 0x02)
565                 ccntrl |= Counter_M1;
566         if (data[0] & 0x04)
567                 ccntrl |= Counter_M2;
568         if (data[0] & 0x08)
569                 ccntrl |= Counter_BCD;
570         ccntrl |= Counter_RW0;  /* set read/write mode */
571         ccntrl |= Counter_RW1;
572         outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
573 #endif
574
575         return 1;
576 }
577
578 /*
579 ==============================================================================
580 */
581 static int pci1720_insn_write_ao(struct comedi_device *dev,
582                                  struct comedi_subdevice *s,
583                                  struct comedi_insn *insn, unsigned int *data)
584 {
585         int n, rangereg, chan;
586
587         chan = CR_CHAN(insn->chanspec);
588         rangereg = devpriv->da_ranges & (~(0x03 << (chan << 1)));
589         rangereg |= (CR_RANGE(insn->chanspec) << (chan << 1));
590         if (rangereg != devpriv->da_ranges) {
591                 outb(rangereg, dev->iobase + PCI1720_RANGE);
592                 devpriv->da_ranges = rangereg;
593         }
594
595         for (n = 0; n < insn->n; n++) {
596                 outw(data[n], dev->iobase + PCI1720_DA0 + (chan << 1));
597                 outb(0, dev->iobase + PCI1720_SYNCOUT); /*  update outputs */
598         }
599
600         devpriv->ao_data[chan] = data[n];
601
602         return n;
603 }
604
605 /*
606 ==============================================================================
607 */
608 static void interrupt_pci1710_every_sample(void *d)
609 {
610         struct comedi_device *dev = d;
611         struct comedi_subdevice *s = dev->subdevices + 0;
612         int m;
613 #ifdef PCI171x_PARANOIDCHECK
614         short sampl;
615 #endif
616
617         DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_every_sample(...)\n");
618         m = inw(dev->iobase + PCI171x_STATUS);
619         if (m & Status_FE) {
620                 printk("comedi%d: A/D FIFO empty (%4x)\n", dev->minor, m);
621                 pci171x_ai_cancel(dev, s);
622                 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
623                 comedi_event(dev, s);
624                 return;
625         }
626         if (m & Status_FF) {
627                 printk
628                     ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
629                      dev->minor, m);
630                 pci171x_ai_cancel(dev, s);
631                 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
632                 comedi_event(dev, s);
633                 return;
634         }
635
636         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear our INT request */
637
638         DPRINTK("FOR ");
639         for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
640 #ifdef PCI171x_PARANOIDCHECK
641                 sampl = inw(dev->iobase + PCI171x_AD_DATA);
642                 DPRINTK("%04x:", sampl);
643                 if (this_board->cardtype != TYPE_PCI1713)
644                         if ((sampl & 0xf000) !=
645                             devpriv->act_chanlist[s->async->cur_chan]) {
646                                 printk
647                                     ("comedi: A/D data dropout: received data from channel %d, expected %d!\n",
648                                      (sampl & 0xf000) >> 12,
649                                      (devpriv->
650                                       act_chanlist[s->
651                                                    async->cur_chan] & 0xf000) >>
652                                      12);
653                                 pci171x_ai_cancel(dev, s);
654                                 s->async->events |=
655                                     COMEDI_CB_EOA | COMEDI_CB_ERROR;
656                                 comedi_event(dev, s);
657                                 return;
658                         }
659                 DPRINTK("%8d %2d %8d~", s->async->buf_int_ptr,
660                         s->async->cur_chan, s->async->buf_int_count);
661                 comedi_buf_put(s->async, sampl & 0x0fff);
662 #else
663                 comedi_buf_put(s->async,
664                                inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
665 #endif
666                 ++s->async->cur_chan;
667
668                 if (s->async->cur_chan >= devpriv->ai_n_chan)
669                         s->async->cur_chan = 0;
670
671
672                 if (s->async->cur_chan == 0) {  /*  one scan done */
673                         devpriv->ai_act_scan++;
674                         DPRINTK
675                             ("adv_pci1710 EDBG: EOS1 bic %d bip %d buc %d bup %d\n",
676                              s->async->buf_int_count, s->async->buf_int_ptr,
677                              s->async->buf_user_count, s->async->buf_user_ptr);
678                         DPRINTK("adv_pci1710 EDBG: EOS2\n");
679                         if ((!devpriv->neverending_ai) && (devpriv->ai_act_scan >= devpriv->ai_scans)) {        /*  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
808         if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))  /*  is this interrupt from our board? */
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         if ((devpriv->ai_flags & TRIG_WAKE_EOS)) {      /*  don't we want wake up every scan?            devpriv->ai_eos=1; */
869                 devpriv->ai_eos = 1;
870         } else {
871                 devpriv->CntrlReg |= Control_ONEFH;
872                 devpriv->ai_eos = 0;
873         }
874
875         if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1))
876                 devpriv->neverending_ai = 1;
877         /* well, user want neverending */
878         else
879                 devpriv->neverending_ai = 0;
880
881         switch (mode) {
882         case 1:
883         case 2:
884                 if (devpriv->ai_timer1 < this_board->ai_ns_min)
885                         devpriv->ai_timer1 = this_board->ai_ns_min;
886                 devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
887                 if (mode == 2) {
888                         devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
889                         devpriv->CntrlReg &=
890                             ~(Control_PACER | Control_ONEFH | Control_GATE);
891                         devpriv->CntrlReg |= Control_EXT;
892                         devpriv->ai_et = 1;
893                 } else {
894                         devpriv->ai_et = 0;
895                 }
896                 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
897                                           &divisor2, &devpriv->ai_timer1,
898                                           devpriv->ai_flags & TRIG_ROUND_MASK);
899                 DPRINTK
900                     ("adv_pci1710 EDBG: OSC base=%u div1=%u div2=%u timer=%u\n",
901                      devpriv->i8254_osc_base, divisor1, divisor2,
902                      devpriv->ai_timer1);
903                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
904                 if (mode != 2) {
905                         /*  start pacer */
906                         start_pacer(dev, mode, divisor1, divisor2);
907                 } else {
908                         devpriv->ai_et_div1 = divisor1;
909                         devpriv->ai_et_div2 = divisor2;
910                 }
911                 break;
912         case 3:
913                 devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
914                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
915                 break;
916         }
917
918         DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_docmd_and_mode(...)\n");
919         return 0;
920 }
921
922 #ifdef PCI171X_EXTDEBUG
923 /*
924 ==============================================================================
925 */
926 static void pci171x_cmdtest_out(int e, struct comedi_cmd *cmd)
927 {
928         printk("adv_pci1710 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e,
929                cmd->start_src, cmd->scan_begin_src, cmd->convert_src);
930         printk("adv_pci1710 e=%d startarg=%d scanarg=%d convarg=%d\n", e,
931                cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg);
932         printk("adv_pci1710 e=%d stopsrc=%x scanend=%x\n", e, cmd->stop_src,
933                cmd->scan_end_src);
934         printk("adv_pci1710 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n",
935                e, cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len);
936 }
937 #endif
938
939 /*
940 ==============================================================================
941 */
942 static int pci171x_ai_cmdtest(struct comedi_device *dev,
943                               struct comedi_subdevice *s,
944                               struct comedi_cmd *cmd)
945 {
946         int err = 0;
947         int tmp;
948         unsigned int divisor1 = 0, divisor2 = 0;
949
950         DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...)\n");
951 #ifdef PCI171X_EXTDEBUG
952         pci171x_cmdtest_out(-1, cmd);
953 #endif
954         /* step 1: make sure trigger sources are trivially valid */
955
956         tmp = cmd->start_src;
957         cmd->start_src &= TRIG_NOW | TRIG_EXT;
958         if (!cmd->start_src || tmp != cmd->start_src)
959                 err++;
960
961         tmp = cmd->scan_begin_src;
962         cmd->scan_begin_src &= TRIG_FOLLOW;
963         if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
964                 err++;
965
966         tmp = cmd->convert_src;
967         cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
968         if (!cmd->convert_src || tmp != cmd->convert_src)
969                 err++;
970
971         tmp = cmd->scan_end_src;
972         cmd->scan_end_src &= TRIG_COUNT;
973         if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
974                 err++;
975
976         tmp = cmd->stop_src;
977         cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
978         if (!cmd->stop_src || tmp != cmd->stop_src)
979                 err++;
980
981         if (err) {
982 #ifdef PCI171X_EXTDEBUG
983                 pci171x_cmdtest_out(1, cmd);
984 #endif
985                 DPRINTK
986                     ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=1\n",
987                      err);
988                 return 1;
989         }
990
991         /* step 2: make sure trigger sources are unique and mutually compatible */
992
993         if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) {
994                 cmd->start_src = TRIG_NOW;
995                 err++;
996         }
997
998         if (cmd->scan_begin_src != TRIG_FOLLOW) {
999                 cmd->scan_begin_src = TRIG_FOLLOW;
1000                 err++;
1001         }
1002
1003         if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
1004                 err++;
1005
1006         if (cmd->scan_end_src != TRIG_COUNT) {
1007                 cmd->scan_end_src = TRIG_COUNT;
1008                 err++;
1009         }
1010
1011         if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
1012                 err++;
1013
1014         if (err) {
1015 #ifdef PCI171X_EXTDEBUG
1016                 pci171x_cmdtest_out(2, cmd);
1017 #endif
1018                 DPRINTK
1019                     ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=2\n",
1020                      err);
1021                 return 2;
1022         }
1023
1024         /* step 3: make sure arguments are trivially compatible */
1025
1026         if (cmd->start_arg != 0) {
1027                 cmd->start_arg = 0;
1028                 err++;
1029         }
1030
1031         if (cmd->scan_begin_arg != 0) {
1032                 cmd->scan_begin_arg = 0;
1033                 err++;
1034         }
1035
1036         if (cmd->convert_src == TRIG_TIMER) {
1037                 if (cmd->convert_arg < this_board->ai_ns_min) {
1038                         cmd->convert_arg = this_board->ai_ns_min;
1039                         err++;
1040                 }
1041         } else {                /* TRIG_FOLLOW */
1042                 if (cmd->convert_arg != 0) {
1043                         cmd->convert_arg = 0;
1044                         err++;
1045                 }
1046         }
1047
1048         if (cmd->scan_end_arg != cmd->chanlist_len) {
1049                 cmd->scan_end_arg = cmd->chanlist_len;
1050                 err++;
1051         }
1052         if (cmd->stop_src == TRIG_COUNT) {
1053                 if (!cmd->stop_arg) {
1054                         cmd->stop_arg = 1;
1055                         err++;
1056                 }
1057         } else {                /* TRIG_NONE */
1058                 if (cmd->stop_arg != 0) {
1059                         cmd->stop_arg = 0;
1060                         err++;
1061                 }
1062         }
1063
1064         if (err) {
1065 #ifdef PCI171X_EXTDEBUG
1066                 pci171x_cmdtest_out(3, cmd);
1067 #endif
1068                 DPRINTK
1069                     ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=3\n",
1070                      err);
1071                 return 3;
1072         }
1073
1074         /* step 4: fix up any arguments */
1075
1076         if (cmd->convert_src == TRIG_TIMER) {
1077                 tmp = cmd->convert_arg;
1078                 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
1079                                           &divisor2, &cmd->convert_arg,
1080                                           cmd->flags & TRIG_ROUND_MASK);
1081                 if (cmd->convert_arg < this_board->ai_ns_min)
1082                         cmd->convert_arg = this_board->ai_ns_min;
1083                 if (tmp != cmd->convert_arg)
1084                         err++;
1085         }
1086
1087         if (err) {
1088                 DPRINTK
1089                     ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=4\n",
1090                      err);
1091                 return 4;
1092         }
1093
1094         /* step 5: complain about special chanlist considerations */
1095
1096         if (cmd->chanlist) {
1097                 if (!check_channel_list(dev, s, cmd->chanlist,
1098                                         cmd->chanlist_len))
1099                         return 5;       /*  incorrect channels list */
1100         }
1101
1102         DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) ret=0\n");
1103         return 0;
1104 }
1105
1106 /*
1107 ==============================================================================
1108 */
1109 static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1110 {
1111         struct comedi_cmd *cmd = &s->async->cmd;
1112
1113         DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmd(...)\n");
1114         devpriv->ai_n_chan = cmd->chanlist_len;
1115         devpriv->ai_chanlist = cmd->chanlist;
1116         devpriv->ai_flags = cmd->flags;
1117         devpriv->ai_data_len = s->async->prealloc_bufsz;
1118         devpriv->ai_data = s->async->prealloc_buf;
1119         devpriv->ai_timer1 = 0;
1120         devpriv->ai_timer2 = 0;
1121
1122         if (cmd->stop_src == TRIG_COUNT)
1123                 devpriv->ai_scans = cmd->stop_arg;
1124         else
1125                 devpriv->ai_scans = 0;
1126
1127
1128         if (cmd->scan_begin_src == TRIG_FOLLOW) {       /*  mode 1, 2, 3 */
1129                 if (cmd->convert_src == TRIG_TIMER) {   /*  mode 1 and 2 */
1130                         devpriv->ai_timer1 = cmd->convert_arg;
1131                         return pci171x_ai_docmd_and_mode(cmd->start_src ==
1132                                                          TRIG_EXT ? 2 : 1, dev,
1133                                                          s);
1134                 }
1135                 if (cmd->convert_src == TRIG_EXT) {     /*  mode 3 */
1136                         return pci171x_ai_docmd_and_mode(3, dev, s);
1137                 }
1138         }
1139
1140         return -1;
1141 }
1142
1143 /*
1144 ==============================================================================
1145  Check if channel list from user is builded correctly
1146  If it's ok, then program scan/gain logic.
1147  This works for all cards.
1148 */
1149 static int check_channel_list(struct comedi_device *dev,
1150                               struct comedi_subdevice *s,
1151                               unsigned int *chanlist, unsigned int n_chan)
1152 {
1153         unsigned int chansegment[32];
1154         unsigned int i, nowmustbechan, seglen, segpos;
1155
1156         DPRINTK("adv_pci1710 EDBG:  check_channel_list(...,%d)\n", n_chan);
1157         /* correct channel and range number check itself comedi/range.c */
1158         if (n_chan < 1) {
1159                 comedi_error(dev, "range/channel list is empty!");
1160                 return 0;
1161         }
1162
1163         if (n_chan > 1) {
1164                 chansegment[0] = chanlist[0];   /*  first channel is everytime ok */
1165                 for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {    /*  build part of chanlist */
1166                         /*  printk("%d. %d %d\n",i,CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
1167                         if (chanlist[0] == chanlist[i])
1168                                 break;  /*  we detect loop, this must by finish */
1169                         if (CR_CHAN(chanlist[i]) & 1)   /*  odd channel cann't by differencial */
1170                                 if (CR_AREF(chanlist[i]) == AREF_DIFF) {
1171                                         comedi_error(dev,
1172                                                      "Odd channel can't be differential input!\n");
1173                                         return 0;
1174                                 }
1175                         nowmustbechan =
1176                             (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
1177                         if (CR_AREF(chansegment[i - 1]) == AREF_DIFF)
1178                                 nowmustbechan = (nowmustbechan + 1) % s->n_chan;
1179                         if (nowmustbechan != CR_CHAN(chanlist[i])) {    /*  channel list isn't continous :-( */
1180                                 printk
1181                                     ("channel list must be continous! chanlist[%i]=%d but must be %d or %d!\n",
1182                                      i, CR_CHAN(chanlist[i]), nowmustbechan,
1183                                      CR_CHAN(chanlist[0]));
1184                                 return 0;
1185                         }
1186                         chansegment[i] = chanlist[i];   /*  well, this is next correct channel in list */
1187                 }
1188
1189                 for (i = 0, segpos = 0; i < n_chan; i++) {      /*  check whole chanlist */
1190                         /* printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
1191                         if (chanlist[i] != chansegment[i % seglen]) {
1192                                 printk
1193                                     ("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
1194                                      i, CR_CHAN(chansegment[i]),
1195                                      CR_RANGE(chansegment[i]),
1196                                      CR_AREF(chansegment[i]),
1197                                      CR_CHAN(chanlist[i % seglen]),
1198                                      CR_RANGE(chanlist[i % seglen]),
1199                                      CR_AREF(chansegment[i % seglen]));
1200                                 return 0;       /*  chan/gain list is strange */
1201                         }
1202                 }
1203         } else {
1204                 seglen = 1;
1205         }
1206         return seglen;
1207 }
1208
1209 static void setup_channel_list(struct comedi_device *dev,
1210                                struct comedi_subdevice *s,
1211                                unsigned int *chanlist, unsigned int n_chan,
1212                                unsigned int seglen)
1213 {
1214         unsigned int i, range, chanprog;
1215
1216         DPRINTK("adv_pci1710 EDBG:  setup_channel_list(...,%d,%d)\n", n_chan,
1217                 seglen);
1218         devpriv->act_chanlist_len = seglen;
1219         devpriv->act_chanlist_pos = 0;
1220
1221         DPRINTK("SegLen: %d\n", seglen);
1222         for (i = 0; i < seglen; i++) {  /*  store range list to card */
1223                 chanprog = muxonechan[CR_CHAN(chanlist[i])];
1224                 outw(chanprog, dev->iobase + PCI171x_MUX);      /* select channel */
1225                 range = this_board->rangecode_ai[CR_RANGE(chanlist[i])];
1226                 if (CR_AREF(chanlist[i]) == AREF_DIFF)
1227                         range |= 0x0020;
1228                 outw(range, dev->iobase + PCI171x_RANGE);       /* select gain */
1229 #ifdef PCI171x_PARANOIDCHECK
1230                 devpriv->act_chanlist[i] =
1231                     (CR_CHAN(chanlist[i]) << 12) & 0xf000;
1232 #endif
1233                 DPRINTK("GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range,
1234                         devpriv->act_chanlist[i]);
1235         }
1236 #ifdef PCI171x_PARANOIDCHECK
1237         for ( ; i < n_chan; i++) { /* store remainder of channel list */
1238                 devpriv->act_chanlist[i] =
1239                     (CR_CHAN(chanlist[i]) << 12) & 0xf000;
1240         }
1241 #endif
1242
1243         devpriv->ai_et_MuxVal =
1244             CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
1245         outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX); /* select channel interval to scan */
1246         DPRINTK("MUX: %4x L%4x.H%4x\n",
1247                 CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8),
1248                 CR_CHAN(chanlist[0]), CR_CHAN(chanlist[seglen - 1]));
1249 }
1250
1251 /*
1252 ==============================================================================
1253 */
1254 static void start_pacer(struct comedi_device *dev, int mode,
1255                         unsigned int divisor1, unsigned int divisor2)
1256 {
1257         DPRINTK("adv_pci1710 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode,
1258                 divisor1, divisor2);
1259         outw(0xb4, dev->iobase + PCI171x_CNTCTRL);
1260         outw(0x74, dev->iobase + PCI171x_CNTCTRL);
1261
1262         if (mode == 1) {
1263                 outw(divisor2 & 0xff, dev->iobase + PCI171x_CNT2);
1264                 outw((divisor2 >> 8) & 0xff, dev->iobase + PCI171x_CNT2);
1265                 outw(divisor1 & 0xff, dev->iobase + PCI171x_CNT1);
1266                 outw((divisor1 >> 8) & 0xff, dev->iobase + PCI171x_CNT1);
1267         }
1268         DPRINTK("adv_pci1710 EDBG: END: start_pacer(...)\n");
1269 }
1270
1271 /*
1272 ==============================================================================
1273 */
1274 static int pci171x_ai_cancel(struct comedi_device *dev,
1275                              struct comedi_subdevice *s)
1276 {
1277         DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cancel(...)\n");
1278
1279         switch (this_board->cardtype) {
1280         default:
1281                 devpriv->CntrlReg &= Control_CNT0;
1282                 devpriv->CntrlReg |= Control_SW;
1283
1284                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /*  reset any operations */
1285                 start_pacer(dev, -1, 0, 0);
1286                 outb(0, dev->iobase + PCI171x_CLRFIFO);
1287                 outb(0, dev->iobase + PCI171x_CLRINT);
1288                 break;
1289         }
1290
1291         devpriv->ai_do = 0;
1292         devpriv->ai_act_scan = 0;
1293         s->async->cur_chan = 0;
1294         devpriv->ai_buf_ptr = 0;
1295         devpriv->neverending_ai = 0;
1296
1297         DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_cancel(...)\n");
1298         return 0;
1299 }
1300
1301 /*
1302 ==============================================================================
1303 */
1304 static int pci171x_reset(struct comedi_device *dev)
1305 {
1306         DPRINTK("adv_pci1710 EDBG: BGN: pci171x_reset(...)\n");
1307         outw(0x30, dev->iobase + PCI171x_CNTCTRL);
1308         devpriv->CntrlReg = Control_SW | Control_CNT0;  /*  Software trigger, CNT0=external */
1309         outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /*  reset any operations */
1310         outb(0, dev->iobase + PCI171x_CLRFIFO); /*  clear FIFO */
1311         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear INT request */
1312         start_pacer(dev, -1, 0, 0);     /*  stop 8254 */
1313         devpriv->da_ranges = 0;
1314         if (this_board->n_aochan) {
1315                 outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);  /*  set DACs to 0..5V */
1316                 outw(0, dev->iobase + PCI171x_DA1);     /*  set DA outputs to 0V */
1317                 devpriv->ao_data[0] = 0x0000;
1318                 if (this_board->n_aochan > 1) {
1319                         outw(0, dev->iobase + PCI171x_DA2);
1320                         devpriv->ao_data[1] = 0x0000;
1321                 }
1322         }
1323         outw(0, dev->iobase + PCI171x_DO);      /*  digital outputs to 0 */
1324         outb(0, dev->iobase + PCI171x_CLRFIFO); /*  clear FIFO */
1325         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear INT request */
1326
1327         DPRINTK("adv_pci1710 EDBG: END: pci171x_reset(...)\n");
1328         return 0;
1329 }
1330
1331 /*
1332 ==============================================================================
1333 */
1334 static int pci1720_reset(struct comedi_device *dev)
1335 {
1336         DPRINTK("adv_pci1710 EDBG: BGN: pci1720_reset(...)\n");
1337         outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT);       /*  set synchronous output mode */
1338         devpriv->da_ranges = 0xAA;
1339         outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE);  /*  set all ranges to +/-5V */
1340         outw(0x0800, dev->iobase + PCI1720_DA0);        /*  set outputs to 0V */
1341         outw(0x0800, dev->iobase + PCI1720_DA1);
1342         outw(0x0800, dev->iobase + PCI1720_DA2);
1343         outw(0x0800, dev->iobase + PCI1720_DA3);
1344         outb(0, dev->iobase + PCI1720_SYNCOUT); /*  update outputs */
1345         devpriv->ao_data[0] = 0x0800;
1346         devpriv->ao_data[1] = 0x0800;
1347         devpriv->ao_data[2] = 0x0800;
1348         devpriv->ao_data[3] = 0x0800;
1349         DPRINTK("adv_pci1710 EDBG: END: pci1720_reset(...)\n");
1350         return 0;
1351 }
1352
1353 /*
1354 ==============================================================================
1355 */
1356 static int pci1710_reset(struct comedi_device *dev)
1357 {
1358         DPRINTK("adv_pci1710 EDBG: BGN: pci1710_reset(...)\n");
1359         switch (this_board->cardtype) {
1360         case TYPE_PCI1720:
1361                 return pci1720_reset(dev);
1362         default:
1363                 return pci171x_reset(dev);
1364         }
1365         DPRINTK("adv_pci1710 EDBG: END: pci1710_reset(...)\n");
1366 }
1367
1368 /*
1369 ==============================================================================
1370 */
1371 static int pci1710_attach(struct comedi_device *dev,
1372                           struct comedi_devconfig *it)
1373 {
1374         struct comedi_subdevice *s;
1375         int ret, subdev, n_subdevices;
1376         unsigned int irq;
1377         unsigned long iobase;
1378         struct pci_dev *pcidev;
1379         int opt_bus, opt_slot;
1380         const char *errstr;
1381         unsigned char pci_bus, pci_slot, pci_func;
1382         int i;
1383         int board_index;
1384
1385         printk("comedi%d: adv_pci1710: ", dev->minor);
1386
1387         opt_bus = it->options[0];
1388         opt_slot = it->options[1];
1389
1390         ret = alloc_private(dev, sizeof(struct pci1710_private));
1391         if (ret < 0) {
1392                 printk(" - Allocation failed!\n");
1393                 return -ENOMEM;
1394         }
1395
1396         /* Look for matching PCI device */
1397         errstr = "not found!";
1398         pcidev = NULL;
1399         board_index = this_board - boardtypes;
1400         while (NULL != (pcidev = pci_get_device(PCI_VENDOR_ID_ADVANTECH,
1401                                                 PCI_ANY_ID, pcidev))) {
1402                 if (strcmp(this_board->name, DRV_NAME) == 0) {
1403                         for (i = 0; i < n_boardtypes; ++i) {
1404                                 if (pcidev->device == boardtypes[i].device_id) {
1405                                         board_index = i;
1406                                         break;
1407                                 }
1408                         }
1409                         if (i == n_boardtypes)
1410                                 continue;
1411                 } else {
1412                         if (pcidev->device != boardtypes[board_index].device_id)
1413                                 continue;
1414                 }
1415
1416                 /* Found matching vendor/device. */
1417                 if (opt_bus || opt_slot) {
1418                         /* Check bus/slot. */
1419                         if (opt_bus != pcidev->bus->number
1420                             || opt_slot != PCI_SLOT(pcidev->devfn))
1421                                 continue;       /* no match */
1422                 }
1423                 /*
1424                  * Look for device that isn't in use.
1425                  * Enable PCI device and request regions.
1426                  */
1427                 if (comedi_pci_enable(pcidev, DRV_NAME)) {
1428                         errstr =
1429                             "failed to enable PCI device and request regions!";
1430                         continue;
1431                 }
1432                 /*  fixup board_ptr in case we were using the dummy entry with the driver name */
1433                 dev->board_ptr = &boardtypes[board_index];
1434                 break;
1435         }
1436
1437         if (!pcidev) {
1438                 if (opt_bus || opt_slot) {
1439                         printk(" - Card at b:s %d:%d %s\n",
1440                                opt_bus, opt_slot, errstr);
1441                 } else {
1442                         printk(" - Card %s\n", errstr);
1443                 }
1444                 return -EIO;
1445         }
1446
1447         pci_bus = pcidev->bus->number;
1448         pci_slot = PCI_SLOT(pcidev->devfn);
1449         pci_func = PCI_FUNC(pcidev->devfn);
1450         irq = pcidev->irq;
1451         iobase = pci_resource_start(pcidev, 2);
1452
1453         printk(", b:s:f=%d:%d:%d, io=0x%4lx", pci_bus, pci_slot, pci_func,
1454                iobase);
1455
1456         dev->iobase = iobase;
1457
1458         dev->board_name = this_board->name;
1459         devpriv->pcidev = pcidev;
1460
1461         n_subdevices = 0;
1462         if (this_board->n_aichan)
1463                 n_subdevices++;
1464         if (this_board->n_aochan)
1465                 n_subdevices++;
1466         if (this_board->n_dichan)
1467                 n_subdevices++;
1468         if (this_board->n_dochan)
1469                 n_subdevices++;
1470         if (this_board->n_counter)
1471                 n_subdevices++;
1472
1473         ret = alloc_subdevices(dev, n_subdevices);
1474         if (ret < 0) {
1475                 printk(" - Allocation failed!\n");
1476                 return ret;
1477         }
1478
1479         pci1710_reset(dev);
1480
1481         if (this_board->have_irq) {
1482                 if (irq) {
1483                         if (request_irq(irq, interrupt_service_pci1710,
1484                                         IRQF_SHARED, "Advantech PCI-1710",
1485                                         dev)) {
1486                                 printk
1487                                     (", unable to allocate IRQ %d, DISABLING IT",
1488                                      irq);
1489                                 irq = 0;        /* Can't use IRQ */
1490                         } else {
1491                                 printk(", irq=%u", irq);
1492                         }
1493                 } else {
1494                         printk(", IRQ disabled");
1495                 }
1496         } else {
1497                 irq = 0;
1498         }
1499
1500         dev->irq = irq;
1501
1502         printk(".\n");
1503
1504         subdev = 0;
1505
1506         if (this_board->n_aichan) {
1507                 s = dev->subdevices + subdev;
1508                 dev->read_subdev = s;
1509                 s->type = COMEDI_SUBD_AI;
1510                 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
1511                 if (this_board->n_aichand)
1512                         s->subdev_flags |= SDF_DIFF;
1513                 s->n_chan = this_board->n_aichan;
1514                 s->maxdata = this_board->ai_maxdata;
1515                 s->len_chanlist = this_board->n_aichan;
1516                 s->range_table = this_board->rangelist_ai;
1517                 s->cancel = pci171x_ai_cancel;
1518                 s->insn_read = pci171x_insn_read_ai;
1519                 if (irq) {
1520                         s->subdev_flags |= SDF_CMD_READ;
1521                         s->do_cmdtest = pci171x_ai_cmdtest;
1522                         s->do_cmd = pci171x_ai_cmd;
1523                 }
1524                 devpriv->i8254_osc_base = 100;  /*  100ns=10MHz */
1525                 subdev++;
1526         }
1527
1528         if (this_board->n_aochan) {
1529                 s = dev->subdevices + subdev;
1530                 s->type = COMEDI_SUBD_AO;
1531                 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1532                 s->n_chan = this_board->n_aochan;
1533                 s->maxdata = this_board->ao_maxdata;
1534                 s->len_chanlist = this_board->n_aochan;
1535                 s->range_table = this_board->rangelist_ao;
1536                 switch (this_board->cardtype) {
1537                 case TYPE_PCI1720:
1538                         s->insn_write = pci1720_insn_write_ao;
1539                         break;
1540                 default:
1541                         s->insn_write = pci171x_insn_write_ao;
1542                         break;
1543                 }
1544                 s->insn_read = pci171x_insn_read_ao;
1545                 subdev++;
1546         }
1547
1548         if (this_board->n_dichan) {
1549                 s = dev->subdevices + subdev;
1550                 s->type = COMEDI_SUBD_DI;
1551                 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
1552                 s->n_chan = this_board->n_dichan;
1553                 s->maxdata = 1;
1554                 s->len_chanlist = this_board->n_dichan;
1555                 s->range_table = &range_digital;
1556                 s->io_bits = 0; /* all bits input */
1557                 s->insn_bits = pci171x_insn_bits_di;
1558                 subdev++;
1559         }
1560
1561         if (this_board->n_dochan) {
1562                 s = dev->subdevices + subdev;
1563                 s->type = COMEDI_SUBD_DO;
1564                 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1565                 s->n_chan = this_board->n_dochan;
1566                 s->maxdata = 1;
1567                 s->len_chanlist = this_board->n_dochan;
1568                 s->range_table = &range_digital;
1569                 /* all bits output */
1570                 s->io_bits = (1 << this_board->n_dochan) - 1;
1571                 s->state = 0;
1572                 s->insn_bits = pci171x_insn_bits_do;
1573                 subdev++;
1574         }
1575
1576         if (this_board->n_counter) {
1577                 s = dev->subdevices + subdev;
1578                 s->type = COMEDI_SUBD_COUNTER;
1579                 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1580                 s->n_chan = this_board->n_counter;
1581                 s->len_chanlist = this_board->n_counter;
1582                 s->maxdata = 0xffff;
1583                 s->range_table = &range_unknown;
1584                 s->insn_read = pci171x_insn_counter_read;
1585                 s->insn_write = pci171x_insn_counter_write;
1586                 s->insn_config = pci171x_insn_counter_config;
1587                 subdev++;
1588         }
1589
1590         devpriv->valid = 1;
1591
1592         return 0;
1593 }
1594
1595 /*
1596 ==============================================================================
1597 */
1598 static int pci1710_detach(struct comedi_device *dev)
1599 {
1600
1601         if (dev->private) {
1602                 if (devpriv->valid)
1603                         pci1710_reset(dev);
1604                 if (dev->irq)
1605                         free_irq(dev->irq, dev);
1606                 if (devpriv->pcidev) {
1607                         if (dev->iobase)
1608                                 comedi_pci_disable(devpriv->pcidev);
1609
1610                         pci_dev_put(devpriv->pcidev);
1611                 }
1612         }
1613
1614         return 0;
1615 }
1616
1617 /*
1618 ==============================================================================
1619 */
1620 static int __devinit driver_pci1710_pci_probe(struct pci_dev *dev,
1621                                               const struct pci_device_id *ent)
1622 {
1623         return comedi_pci_auto_config(dev, driver_pci1710.driver_name);
1624 }
1625
1626 static void __devexit driver_pci1710_pci_remove(struct pci_dev *dev)
1627 {
1628         comedi_pci_auto_unconfig(dev);
1629 }
1630
1631 static struct pci_driver driver_pci1710_pci_driver = {
1632         .id_table = pci1710_pci_table,
1633         .probe = &driver_pci1710_pci_probe,
1634         .remove = __devexit_p(&driver_pci1710_pci_remove)
1635 };
1636
1637 static int __init driver_pci1710_init_module(void)
1638 {
1639         int retval;
1640
1641         retval = comedi_driver_register(&driver_pci1710);
1642         if (retval < 0)
1643                 return retval;
1644
1645         driver_pci1710_pci_driver.name = (char *)driver_pci1710.driver_name;
1646         return pci_register_driver(&driver_pci1710_pci_driver);
1647 }
1648
1649 static void __exit driver_pci1710_cleanup_module(void)
1650 {
1651         pci_unregister_driver(&driver_pci1710_pci_driver);
1652         comedi_driver_unregister(&driver_pci1710);
1653 }
1654
1655 module_init(driver_pci1710_init_module);
1656 module_exit(driver_pci1710_cleanup_module);
1657 /*
1658 ==============================================================================
1659 */
1660
1661 MODULE_AUTHOR("Comedi http://www.comedi.org");
1662 MODULE_DESCRIPTION("Comedi low-level driver");
1663 MODULE_LICENSE("GPL");