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