Linux-libre 2.6.34.11-gnu1
[librecmc/linux-libre.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 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 counter 0 */
88 #define PCI171x_CNT1    26      /* R/W: 8254 counter 1 */
89 #define PCI171x_CNT2    28      /* R/W: 8254 counter 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         s->async->cur_chan = j;
728         DPRINTK("adv_pci1710 EDBG: END: move_block_from_fifo(...)\n");
729         return 0;
730 }
731
732 /*
733 ==============================================================================
734 */
735 static void interrupt_pci1710_half_fifo(void *d)
736 {
737         struct comedi_device *dev = d;
738         struct comedi_subdevice *s = dev->subdevices + 0;
739         int m, samplesinbuf;
740
741         DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_half_fifo(...)\n");
742         m = inw(dev->iobase + PCI171x_STATUS);
743         if (!(m & Status_FH)) {
744                 printk("comedi%d: A/D FIFO not half full! (%4x)\n",
745                        dev->minor, m);
746                 pci171x_ai_cancel(dev, s);
747                 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
748                 comedi_event(dev, s);
749                 return;
750         }
751         if (m & Status_FF) {
752                 printk
753                     ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
754                      dev->minor, m);
755                 pci171x_ai_cancel(dev, s);
756                 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
757                 comedi_event(dev, s);
758                 return;
759         }
760
761         samplesinbuf = this_board->fifo_half_size;
762         if (samplesinbuf * sizeof(short) >= devpriv->ai_data_len) {
763                 m = devpriv->ai_data_len / sizeof(short);
764                 if (move_block_from_fifo(dev, s, m, 0))
765                         return;
766                 samplesinbuf -= m;
767         }
768
769         if (samplesinbuf) {
770                 if (move_block_from_fifo(dev, s, samplesinbuf, 1))
771                         return;
772         }
773
774         if (!devpriv->neverending_ai)
775                 if (devpriv->ai_act_scan >= devpriv->ai_scans) {        /* all data sampled */
776                         pci171x_ai_cancel(dev, s);
777                         s->async->events |= COMEDI_CB_EOA;
778                         comedi_event(dev, s);
779                         return;
780                 }
781         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear our INT request */
782         DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_half_fifo(...)\n");
783
784         comedi_event(dev, s);
785 }
786
787 /*
788 ==============================================================================
789 */
790 static irqreturn_t interrupt_service_pci1710(int irq, void *d)
791 {
792         struct comedi_device *dev = d;
793
794         DPRINTK("adv_pci1710 EDBG: BGN: interrupt_service_pci1710(%d,...)\n",
795                 irq);
796         if (!dev->attached)     /*  is device attached? */
797                 return IRQ_NONE;        /*  no, exit */
798
799         if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))  /*  is this interrupt from our board? */
800                 return IRQ_NONE;        /*  no, exit */
801
802         DPRINTK("adv_pci1710 EDBG: interrupt_service_pci1710() ST: %4x\n",
803                 inw(dev->iobase + PCI171x_STATUS));
804
805         if (devpriv->ai_et) {   /*  Switch from initial TRIG_EXT to TRIG_xxx. */
806                 devpriv->ai_et = 0;
807                 devpriv->CntrlReg &= Control_CNT0;
808                 devpriv->CntrlReg |= Control_SW;        /*  set software trigger */
809                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
810                 devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
811                 outb(0, dev->iobase + PCI171x_CLRFIFO);
812                 outb(0, dev->iobase + PCI171x_CLRINT);
813                 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
814                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
815                 /*  start pacer */
816                 start_pacer(dev, 1, devpriv->ai_et_div1, devpriv->ai_et_div2);
817                 return IRQ_HANDLED;
818         }
819         if (devpriv->ai_eos) {  /*  We use FIFO half full INT or not? */
820                 interrupt_pci1710_every_sample(d);
821         } else {
822                 interrupt_pci1710_half_fifo(d);
823         }
824         DPRINTK("adv_pci1710 EDBG: END: interrupt_service_pci1710(...)\n");
825         return IRQ_HANDLED;
826 }
827
828 /*
829 ==============================================================================
830 */
831 static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev,
832                                      struct comedi_subdevice *s)
833 {
834         unsigned int divisor1 = 0, divisor2 = 0;
835         unsigned int seglen;
836
837         DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_docmd_and_mode(%d,...)\n",
838                 mode);
839         start_pacer(dev, -1, 0, 0);     /*  stop pacer */
840
841         seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
842                                     devpriv->ai_n_chan);
843         if (seglen < 1)
844                 return -EINVAL;
845         setup_channel_list(dev, s, devpriv->ai_chanlist,
846                            devpriv->ai_n_chan, seglen);
847
848         outb(0, dev->iobase + PCI171x_CLRFIFO);
849         outb(0, dev->iobase + PCI171x_CLRINT);
850
851         devpriv->ai_do = mode;
852
853         devpriv->ai_act_scan = 0;
854         s->async->cur_chan = 0;
855         devpriv->ai_buf_ptr = 0;
856         devpriv->neverending_ai = 0;
857
858         devpriv->CntrlReg &= Control_CNT0;
859         if ((devpriv->ai_flags & TRIG_WAKE_EOS)) {      /*  don't we want wake up every scan?            devpriv->ai_eos=1; */
860                 devpriv->ai_eos = 1;
861         } else {
862                 devpriv->CntrlReg |= Control_ONEFH;
863                 devpriv->ai_eos = 0;
864         }
865
866         if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1)) {
867                 devpriv->neverending_ai = 1;
868         } /* well, user want neverending */
869         else {
870                 devpriv->neverending_ai = 0;
871         }
872         switch (mode) {
873         case 1:
874         case 2:
875                 if (devpriv->ai_timer1 < this_board->ai_ns_min)
876                         devpriv->ai_timer1 = this_board->ai_ns_min;
877                 devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
878                 if (mode == 2) {
879                         devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
880                         devpriv->CntrlReg &=
881                             ~(Control_PACER | Control_ONEFH | Control_GATE);
882                         devpriv->CntrlReg |= Control_EXT;
883                         devpriv->ai_et = 1;
884                 } else {
885                         devpriv->ai_et = 0;
886                 }
887                 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
888                                           &divisor2, &devpriv->ai_timer1,
889                                           devpriv->ai_flags & TRIG_ROUND_MASK);
890                 DPRINTK
891                     ("adv_pci1710 EDBG: OSC base=%u div1=%u div2=%u timer=%u\n",
892                      devpriv->i8254_osc_base, divisor1, divisor2,
893                      devpriv->ai_timer1);
894                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
895                 if (mode != 2) {
896                         /*  start pacer */
897                         start_pacer(dev, mode, divisor1, divisor2);
898                 } else {
899                         devpriv->ai_et_div1 = divisor1;
900                         devpriv->ai_et_div2 = divisor2;
901                 }
902                 break;
903         case 3:
904                 devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
905                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
906                 break;
907         }
908
909         DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_docmd_and_mode(...)\n");
910         return 0;
911 }
912
913 #ifdef PCI171X_EXTDEBUG
914 /*
915 ==============================================================================
916 */
917 static void pci171x_cmdtest_out(int e, struct comedi_cmd *cmd)
918 {
919         printk("adv_pci1710 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e,
920                cmd->start_src, cmd->scan_begin_src, cmd->convert_src);
921         printk("adv_pci1710 e=%d startarg=%d scanarg=%d convarg=%d\n", e,
922                cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg);
923         printk("adv_pci1710 e=%d stopsrc=%x scanend=%x\n", e, cmd->stop_src,
924                cmd->scan_end_src);
925         printk("adv_pci1710 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n",
926                e, cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len);
927 }
928 #endif
929
930 /*
931 ==============================================================================
932 */
933 static int pci171x_ai_cmdtest(struct comedi_device *dev,
934                               struct comedi_subdevice *s,
935                               struct comedi_cmd *cmd)
936 {
937         int err = 0;
938         int tmp, divisor1 = 0, divisor2 = 0;
939
940         DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...)\n");
941 #ifdef PCI171X_EXTDEBUG
942         pci171x_cmdtest_out(-1, cmd);
943 #endif
944         /* step 1: make sure trigger sources are trivially valid */
945
946         tmp = cmd->start_src;
947         cmd->start_src &= TRIG_NOW | TRIG_EXT;
948         if (!cmd->start_src || tmp != cmd->start_src)
949                 err++;
950
951         tmp = cmd->scan_begin_src;
952         cmd->scan_begin_src &= TRIG_FOLLOW;
953         if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
954                 err++;
955
956         tmp = cmd->convert_src;
957         cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
958         if (!cmd->convert_src || tmp != cmd->convert_src)
959                 err++;
960
961         tmp = cmd->scan_end_src;
962         cmd->scan_end_src &= TRIG_COUNT;
963         if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
964                 err++;
965
966         tmp = cmd->stop_src;
967         cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
968         if (!cmd->stop_src || tmp != cmd->stop_src)
969                 err++;
970
971         if (err) {
972 #ifdef PCI171X_EXTDEBUG
973                 pci171x_cmdtest_out(1, cmd);
974 #endif
975                 DPRINTK
976                     ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=1\n",
977                      err);
978                 return 1;
979         }
980
981         /* step 2: make sure trigger sources are unique and mutually compatible */
982
983         if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) {
984                 cmd->start_src = TRIG_NOW;
985                 err++;
986         }
987
988         if (cmd->scan_begin_src != TRIG_FOLLOW) {
989                 cmd->scan_begin_src = TRIG_FOLLOW;
990                 err++;
991         }
992
993         if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
994                 err++;
995
996         if (cmd->scan_end_src != TRIG_COUNT) {
997                 cmd->scan_end_src = TRIG_COUNT;
998                 err++;
999         }
1000
1001         if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
1002                 err++;
1003
1004         if (err) {
1005 #ifdef PCI171X_EXTDEBUG
1006                 pci171x_cmdtest_out(2, cmd);
1007 #endif
1008                 DPRINTK
1009                     ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=2\n",
1010                      err);
1011                 return 2;
1012         }
1013
1014         /* step 3: make sure arguments are trivially compatible */
1015
1016         if (cmd->start_arg != 0) {
1017                 cmd->start_arg = 0;
1018                 err++;
1019         }
1020
1021         if (cmd->scan_begin_arg != 0) {
1022                 cmd->scan_begin_arg = 0;
1023                 err++;
1024         }
1025
1026         if (cmd->convert_src == TRIG_TIMER) {
1027                 if (cmd->convert_arg < this_board->ai_ns_min) {
1028                         cmd->convert_arg = this_board->ai_ns_min;
1029                         err++;
1030                 }
1031         } else {                /* TRIG_FOLLOW */
1032                 if (cmd->convert_arg != 0) {
1033                         cmd->convert_arg = 0;
1034                         err++;
1035                 }
1036         }
1037
1038         if (cmd->scan_end_arg != cmd->chanlist_len) {
1039                 cmd->scan_end_arg = cmd->chanlist_len;
1040                 err++;
1041         }
1042         if (cmd->stop_src == TRIG_COUNT) {
1043                 if (!cmd->stop_arg) {
1044                         cmd->stop_arg = 1;
1045                         err++;
1046                 }
1047         } else {                /* TRIG_NONE */
1048                 if (cmd->stop_arg != 0) {
1049                         cmd->stop_arg = 0;
1050                         err++;
1051                 }
1052         }
1053
1054         if (err) {
1055 #ifdef PCI171X_EXTDEBUG
1056                 pci171x_cmdtest_out(3, cmd);
1057 #endif
1058                 DPRINTK
1059                     ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=3\n",
1060                      err);
1061                 return 3;
1062         }
1063
1064         /* step 4: fix up any arguments */
1065
1066         if (cmd->convert_src == TRIG_TIMER) {
1067                 tmp = cmd->convert_arg;
1068                 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
1069                                           &divisor2, &cmd->convert_arg,
1070                                           cmd->flags & TRIG_ROUND_MASK);
1071                 if (cmd->convert_arg < this_board->ai_ns_min)
1072                         cmd->convert_arg = this_board->ai_ns_min;
1073                 if (tmp != cmd->convert_arg)
1074                         err++;
1075         }
1076
1077         if (err) {
1078                 DPRINTK
1079                     ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=4\n",
1080                      err);
1081                 return 4;
1082         }
1083
1084         /* step 5: complain about special chanlist considerations */
1085
1086         if (cmd->chanlist) {
1087                 if (!check_channel_list(dev, s, cmd->chanlist,
1088                                         cmd->chanlist_len))
1089                         return 5;       /*  incorrect channels list */
1090         }
1091
1092         DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) ret=0\n");
1093         return 0;
1094 }
1095
1096 /*
1097 ==============================================================================
1098 */
1099 static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1100 {
1101         struct comedi_cmd *cmd = &s->async->cmd;
1102
1103         DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmd(...)\n");
1104         devpriv->ai_n_chan = cmd->chanlist_len;
1105         devpriv->ai_chanlist = cmd->chanlist;
1106         devpriv->ai_flags = cmd->flags;
1107         devpriv->ai_data_len = s->async->prealloc_bufsz;
1108         devpriv->ai_data = s->async->prealloc_buf;
1109         devpriv->ai_timer1 = 0;
1110         devpriv->ai_timer2 = 0;
1111
1112         if (cmd->stop_src == TRIG_COUNT) {
1113                 devpriv->ai_scans = cmd->stop_arg;
1114         } else {
1115                 devpriv->ai_scans = 0;
1116         }
1117
1118         if (cmd->scan_begin_src == TRIG_FOLLOW) {       /*  mode 1, 2, 3 */
1119                 if (cmd->convert_src == TRIG_TIMER) {   /*  mode 1 and 2 */
1120                         devpriv->ai_timer1 = cmd->convert_arg;
1121                         return pci171x_ai_docmd_and_mode(cmd->start_src ==
1122                                                          TRIG_EXT ? 2 : 1, dev,
1123                                                          s);
1124                 }
1125                 if (cmd->convert_src == TRIG_EXT) {     /*  mode 3 */
1126                         return pci171x_ai_docmd_and_mode(3, dev, s);
1127                 }
1128         }
1129
1130         return -1;
1131 }
1132
1133 /*
1134 ==============================================================================
1135  Check if channel list from user is builded correctly
1136  If it's ok, then program scan/gain logic.
1137  This works for all cards.
1138 */
1139 static int check_channel_list(struct comedi_device *dev,
1140                               struct comedi_subdevice *s,
1141                               unsigned int *chanlist, unsigned int n_chan)
1142 {
1143         unsigned int chansegment[32];
1144         unsigned int i, nowmustbechan, seglen, segpos;
1145
1146         DPRINTK("adv_pci1710 EDBG:  check_channel_list(...,%d)\n", n_chan);
1147         /* correct channel and range number check itself comedi/range.c */
1148         if (n_chan < 1) {
1149                 comedi_error(dev, "range/channel list is empty!");
1150                 return 0;
1151         }
1152
1153         if (n_chan > 1) {
1154                 chansegment[0] = chanlist[0];   /*  first channel is everytime ok */
1155                 for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {    /*  build part of chanlist */
1156                         /*  printk("%d. %d %d\n",i,CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
1157                         if (chanlist[0] == chanlist[i])
1158                                 break;  /*  we detect loop, this must by finish */
1159                         if (CR_CHAN(chanlist[i]) & 1)   /*  odd channel cann't by differencial */
1160                                 if (CR_AREF(chanlist[i]) == AREF_DIFF) {
1161                                         comedi_error(dev,
1162                                                      "Odd channel can't be differential input!\n");
1163                                         return 0;
1164                                 }
1165                         nowmustbechan =
1166                             (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
1167                         if (CR_AREF(chansegment[i - 1]) == AREF_DIFF)
1168                                 nowmustbechan = (nowmustbechan + 1) % s->n_chan;
1169                         if (nowmustbechan != CR_CHAN(chanlist[i])) {    /*  channel list isn't continous :-( */
1170                                 printk
1171                                     ("channel list must be continous! chanlist[%i]=%d but must be %d or %d!\n",
1172                                      i, CR_CHAN(chanlist[i]), nowmustbechan,
1173                                      CR_CHAN(chanlist[0]));
1174                                 return 0;
1175                         }
1176                         chansegment[i] = chanlist[i];   /*  well, this is next correct channel in list */
1177                 }
1178
1179                 for (i = 0, segpos = 0; i < n_chan; i++) {      /*  check whole chanlist */
1180                         /* printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
1181                         if (chanlist[i] != chansegment[i % seglen]) {
1182                                 printk
1183                                     ("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
1184                                      i, CR_CHAN(chansegment[i]),
1185                                      CR_RANGE(chansegment[i]),
1186                                      CR_AREF(chansegment[i]),
1187                                      CR_CHAN(chanlist[i % seglen]),
1188                                      CR_RANGE(chanlist[i % seglen]),
1189                                      CR_AREF(chansegment[i % seglen]));
1190                                 return 0;       /*  chan/gain list is strange */
1191                         }
1192                 }
1193         } else {
1194                 seglen = 1;
1195         }
1196         return seglen;
1197 }
1198
1199 static void setup_channel_list(struct comedi_device *dev,
1200                                struct comedi_subdevice *s,
1201                                unsigned int *chanlist, unsigned int n_chan,
1202                                unsigned int seglen)
1203 {
1204         unsigned int i, range, chanprog;
1205
1206         DPRINTK("adv_pci1710 EDBG:  setup_channel_list(...,%d,%d)\n", n_chan,
1207                 seglen);
1208         devpriv->act_chanlist_len = seglen;
1209         devpriv->act_chanlist_pos = 0;
1210
1211         DPRINTK("SegLen: %d\n", seglen);
1212         for (i = 0; i < seglen; i++) {  /*  store range list to card */
1213                 chanprog = muxonechan[CR_CHAN(chanlist[i])];
1214                 outw(chanprog, dev->iobase + PCI171x_MUX);      /* select channel */
1215                 range = this_board->rangecode_ai[CR_RANGE(chanlist[i])];
1216                 if (CR_AREF(chanlist[i]) == AREF_DIFF)
1217                         range |= 0x0020;
1218                 outw(range, dev->iobase + PCI171x_RANGE);       /* select gain */
1219 #ifdef PCI171x_PARANOIDCHECK
1220                 devpriv->act_chanlist[i] =
1221                     (CR_CHAN(chanlist[i]) << 12) & 0xf000;
1222 #endif
1223                 DPRINTK("GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range,
1224                         devpriv->act_chanlist[i]);
1225         }
1226 #ifdef PCI171x_PARANOIDCHECK
1227         for ( ; i < n_chan; i++) { /* store remainder of channel list */
1228                 devpriv->act_chanlist[i] =
1229                     (CR_CHAN(chanlist[i]) << 12) & 0xf000;
1230         }
1231 #endif
1232
1233         devpriv->ai_et_MuxVal =
1234             CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
1235         outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX); /* select channel interval to scan */
1236         DPRINTK("MUX: %4x L%4x.H%4x\n",
1237                 CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8),
1238                 CR_CHAN(chanlist[0]), CR_CHAN(chanlist[seglen - 1]));
1239 }
1240
1241 /*
1242 ==============================================================================
1243 */
1244 static void start_pacer(struct comedi_device *dev, int mode,
1245                         unsigned int divisor1, unsigned int divisor2)
1246 {
1247         DPRINTK("adv_pci1710 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode,
1248                 divisor1, divisor2);
1249         outw(0xb4, dev->iobase + PCI171x_CNTCTRL);
1250         outw(0x74, dev->iobase + PCI171x_CNTCTRL);
1251
1252         if (mode == 1) {
1253                 outw(divisor2 & 0xff, dev->iobase + PCI171x_CNT2);
1254                 outw((divisor2 >> 8) & 0xff, dev->iobase + PCI171x_CNT2);
1255                 outw(divisor1 & 0xff, dev->iobase + PCI171x_CNT1);
1256                 outw((divisor1 >> 8) & 0xff, dev->iobase + PCI171x_CNT1);
1257         }
1258         DPRINTK("adv_pci1710 EDBG: END: start_pacer(...)\n");
1259 }
1260
1261 /*
1262 ==============================================================================
1263 */
1264 static int pci171x_ai_cancel(struct comedi_device *dev,
1265                              struct comedi_subdevice *s)
1266 {
1267         DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cancel(...)\n");
1268
1269         switch (this_board->cardtype) {
1270         default:
1271                 devpriv->CntrlReg &= Control_CNT0;
1272                 devpriv->CntrlReg |= Control_SW;
1273
1274                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /*  reset any operations */
1275                 start_pacer(dev, -1, 0, 0);
1276                 outb(0, dev->iobase + PCI171x_CLRFIFO);
1277                 outb(0, dev->iobase + PCI171x_CLRINT);
1278                 break;
1279         }
1280
1281         devpriv->ai_do = 0;
1282         devpriv->ai_act_scan = 0;
1283         s->async->cur_chan = 0;
1284         devpriv->ai_buf_ptr = 0;
1285         devpriv->neverending_ai = 0;
1286
1287         DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_cancel(...)\n");
1288         return 0;
1289 }
1290
1291 /*
1292 ==============================================================================
1293 */
1294 static int pci171x_reset(struct comedi_device *dev)
1295 {
1296         DPRINTK("adv_pci1710 EDBG: BGN: pci171x_reset(...)\n");
1297         outw(0x30, dev->iobase + PCI171x_CNTCTRL);
1298         devpriv->CntrlReg = Control_SW | Control_CNT0;  /*  Software trigger, CNT0=external */
1299         outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /*  reset any operations */
1300         outb(0, dev->iobase + PCI171x_CLRFIFO); /*  clear FIFO */
1301         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear INT request */
1302         start_pacer(dev, -1, 0, 0);     /*  stop 8254 */
1303         devpriv->da_ranges = 0;
1304         if (this_board->n_aochan) {
1305                 outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);  /*  set DACs to 0..5V */
1306                 outw(0, dev->iobase + PCI171x_DA1);     /*  set DA outputs to 0V */
1307                 devpriv->ao_data[0] = 0x0000;
1308                 if (this_board->n_aochan > 1) {
1309                         outw(0, dev->iobase + PCI171x_DA2);
1310                         devpriv->ao_data[1] = 0x0000;
1311                 }
1312         }
1313         outw(0, dev->iobase + PCI171x_DO);      /*  digital outputs to 0 */
1314         outb(0, dev->iobase + PCI171x_CLRFIFO); /*  clear FIFO */
1315         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear INT request */
1316
1317         DPRINTK("adv_pci1710 EDBG: END: pci171x_reset(...)\n");
1318         return 0;
1319 }
1320
1321 /*
1322 ==============================================================================
1323 */
1324 static int pci1720_reset(struct comedi_device *dev)
1325 {
1326         DPRINTK("adv_pci1710 EDBG: BGN: pci1720_reset(...)\n");
1327         outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT);       /*  set synchronous output mode */
1328         devpriv->da_ranges = 0xAA;
1329         outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE);  /*  set all ranges to +/-5V */
1330         outw(0x0800, dev->iobase + PCI1720_DA0);        /*  set outputs to 0V */
1331         outw(0x0800, dev->iobase + PCI1720_DA1);
1332         outw(0x0800, dev->iobase + PCI1720_DA2);
1333         outw(0x0800, dev->iobase + PCI1720_DA3);
1334         outb(0, dev->iobase + PCI1720_SYNCOUT); /*  update outputs */
1335         devpriv->ao_data[0] = 0x0800;
1336         devpriv->ao_data[1] = 0x0800;
1337         devpriv->ao_data[2] = 0x0800;
1338         devpriv->ao_data[3] = 0x0800;
1339         DPRINTK("adv_pci1710 EDBG: END: pci1720_reset(...)\n");
1340         return 0;
1341 }
1342
1343 /*
1344 ==============================================================================
1345 */
1346 static int pci1710_reset(struct comedi_device *dev)
1347 {
1348         DPRINTK("adv_pci1710 EDBG: BGN: pci1710_reset(...)\n");
1349         switch (this_board->cardtype) {
1350         case TYPE_PCI1720:
1351                 return pci1720_reset(dev);
1352         default:
1353                 return pci171x_reset(dev);
1354         }
1355         DPRINTK("adv_pci1710 EDBG: END: pci1710_reset(...)\n");
1356 }
1357
1358 /*
1359 ==============================================================================
1360 */
1361 static int pci1710_attach(struct comedi_device *dev,
1362                           struct comedi_devconfig *it)
1363 {
1364         struct comedi_subdevice *s;
1365         int ret, subdev, n_subdevices;
1366         unsigned int irq;
1367         unsigned long iobase;
1368         struct pci_dev *pcidev;
1369         int opt_bus, opt_slot;
1370         const char *errstr;
1371         unsigned char pci_bus, pci_slot, pci_func;
1372         int i;
1373         int board_index;
1374
1375         printk("comedi%d: adv_pci1710: ", dev->minor);
1376
1377         opt_bus = it->options[0];
1378         opt_slot = it->options[1];
1379
1380         ret = alloc_private(dev, sizeof(struct pci1710_private));
1381         if (ret < 0) {
1382                 printk(" - Allocation failed!\n");
1383                 return -ENOMEM;
1384         }
1385
1386         /* Look for matching PCI device */
1387         errstr = "not found!";
1388         pcidev = NULL;
1389         board_index = this_board - boardtypes;
1390         while (NULL != (pcidev = pci_get_device(PCI_VENDOR_ID_ADVANTECH,
1391                                                 PCI_ANY_ID, pcidev))) {
1392                 if (strcmp(this_board->name, DRV_NAME) == 0) {
1393                         for (i = 0; i < n_boardtypes; ++i) {
1394                                 if (pcidev->device == boardtypes[i].device_id) {
1395                                         board_index = i;
1396                                         break;
1397                                 }
1398                         }
1399                         if (i == n_boardtypes)
1400                                 continue;
1401                 } else {
1402                         if (pcidev->device != boardtypes[board_index].device_id)
1403                                 continue;
1404                 }
1405
1406                 /* Found matching vendor/device. */
1407                 if (opt_bus || opt_slot) {
1408                         /* Check bus/slot. */
1409                         if (opt_bus != pcidev->bus->number
1410                             || opt_slot != PCI_SLOT(pcidev->devfn))
1411                                 continue;       /* no match */
1412                 }
1413                 /*
1414                  * Look for device that isn't in use.
1415                  * Enable PCI device and request regions.
1416                  */
1417                 if (comedi_pci_enable(pcidev, DRV_NAME)) {
1418                         errstr =
1419                             "failed to enable PCI device and request regions!";
1420                         continue;
1421                 }
1422                 /*  fixup board_ptr in case we were using the dummy entry with the driver name */
1423                 dev->board_ptr = &boardtypes[board_index];
1424                 break;
1425         }
1426
1427         if (!pcidev) {
1428                 if (opt_bus || opt_slot) {
1429                         printk(" - Card at b:s %d:%d %s\n",
1430                                opt_bus, opt_slot, errstr);
1431                 } else {
1432                         printk(" - Card %s\n", errstr);
1433                 }
1434                 return -EIO;
1435         }
1436
1437         pci_bus = pcidev->bus->number;
1438         pci_slot = PCI_SLOT(pcidev->devfn);
1439         pci_func = PCI_FUNC(pcidev->devfn);
1440         irq = pcidev->irq;
1441         iobase = pci_resource_start(pcidev, 2);
1442
1443         printk(", b:s:f=%d:%d:%d, io=0x%4lx", pci_bus, pci_slot, pci_func,
1444                iobase);
1445
1446         dev->iobase = iobase;
1447
1448         dev->board_name = this_board->name;
1449         devpriv->pcidev = pcidev;
1450
1451         n_subdevices = 0;
1452         if (this_board->n_aichan)
1453                 n_subdevices++;
1454         if (this_board->n_aochan)
1455                 n_subdevices++;
1456         if (this_board->n_dichan)
1457                 n_subdevices++;
1458         if (this_board->n_dochan)
1459                 n_subdevices++;
1460         if (this_board->n_counter)
1461                 n_subdevices++;
1462
1463         ret = alloc_subdevices(dev, n_subdevices);
1464         if (ret < 0) {
1465                 printk(" - Allocation failed!\n");
1466                 return ret;
1467         }
1468
1469         pci1710_reset(dev);
1470
1471         if (this_board->have_irq) {
1472                 if (irq) {
1473                         if (request_irq(irq, interrupt_service_pci1710,
1474                                         IRQF_SHARED, "Advantech PCI-1710",
1475                                         dev)) {
1476                                 printk
1477                                     (", unable to allocate IRQ %d, DISABLING IT",
1478                                      irq);
1479                                 irq = 0;        /* Can't use IRQ */
1480                         } else {
1481                                 printk(", irq=%u", irq);
1482                         }
1483                 } else {
1484                         printk(", IRQ disabled");
1485                 }
1486         } else {
1487                 irq = 0;
1488         }
1489
1490         dev->irq = irq;
1491
1492         printk(".\n");
1493
1494         subdev = 0;
1495
1496         if (this_board->n_aichan) {
1497                 s = dev->subdevices + subdev;
1498                 dev->read_subdev = s;
1499                 s->type = COMEDI_SUBD_AI;
1500                 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
1501                 if (this_board->n_aichand)
1502                         s->subdev_flags |= SDF_DIFF;
1503                 s->n_chan = this_board->n_aichan;
1504                 s->maxdata = this_board->ai_maxdata;
1505                 s->len_chanlist = this_board->n_aichan;
1506                 s->range_table = this_board->rangelist_ai;
1507                 s->cancel = pci171x_ai_cancel;
1508                 s->insn_read = pci171x_insn_read_ai;
1509                 if (irq) {
1510                         s->subdev_flags |= SDF_CMD_READ;
1511                         s->do_cmdtest = pci171x_ai_cmdtest;
1512                         s->do_cmd = pci171x_ai_cmd;
1513                 }
1514                 devpriv->i8254_osc_base = 100;  /*  100ns=10MHz */
1515                 subdev++;
1516         }
1517
1518         if (this_board->n_aochan) {
1519                 s = dev->subdevices + subdev;
1520                 s->type = COMEDI_SUBD_AO;
1521                 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1522                 s->n_chan = this_board->n_aochan;
1523                 s->maxdata = this_board->ao_maxdata;
1524                 s->len_chanlist = this_board->n_aochan;
1525                 s->range_table = this_board->rangelist_ao;
1526                 switch (this_board->cardtype) {
1527                 case TYPE_PCI1720:
1528                         s->insn_write = pci1720_insn_write_ao;
1529                         break;
1530                 default:
1531                         s->insn_write = pci171x_insn_write_ao;
1532                         break;
1533                 }
1534                 s->insn_read = pci171x_insn_read_ao;
1535                 subdev++;
1536         }
1537
1538         if (this_board->n_dichan) {
1539                 s = dev->subdevices + subdev;
1540                 s->type = COMEDI_SUBD_DI;
1541                 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
1542                 s->n_chan = this_board->n_dichan;
1543                 s->maxdata = 1;
1544                 s->len_chanlist = this_board->n_dichan;
1545                 s->range_table = &range_digital;
1546                 s->io_bits = 0; /* all bits input */
1547                 s->insn_bits = pci171x_insn_bits_di;
1548                 subdev++;
1549         }
1550
1551         if (this_board->n_dochan) {
1552                 s = dev->subdevices + subdev;
1553                 s->type = COMEDI_SUBD_DO;
1554                 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1555                 s->n_chan = this_board->n_dochan;
1556                 s->maxdata = 1;
1557                 s->len_chanlist = this_board->n_dochan;
1558                 s->range_table = &range_digital;
1559                 s->io_bits = (1 << this_board->n_dochan) - 1;   /* all bits output */
1560                 s->state = 0;
1561                 s->insn_bits = pci171x_insn_bits_do;
1562                 subdev++;
1563         }
1564
1565         if (this_board->n_counter) {
1566                 s = dev->subdevices + subdev;
1567                 s->type = COMEDI_SUBD_COUNTER;
1568                 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1569                 s->n_chan = this_board->n_counter;
1570                 s->len_chanlist = this_board->n_counter;
1571                 s->maxdata = 0xffff;
1572                 s->range_table = &range_unknown;
1573                 s->insn_read = pci171x_insn_counter_read;
1574                 s->insn_write = pci171x_insn_counter_write;
1575                 s->insn_config = pci171x_insn_counter_config;
1576                 subdev++;
1577         }
1578
1579         devpriv->valid = 1;
1580
1581         return 0;
1582 }
1583
1584 /*
1585 ==============================================================================
1586 */
1587 static int pci1710_detach(struct comedi_device *dev)
1588 {
1589
1590         if (dev->private) {
1591                 if (devpriv->valid)
1592                         pci1710_reset(dev);
1593                 if (dev->irq)
1594                         free_irq(dev->irq, dev);
1595                 if (devpriv->pcidev) {
1596                         if (dev->iobase) {
1597                                 comedi_pci_disable(devpriv->pcidev);
1598                         }
1599                         pci_dev_put(devpriv->pcidev);
1600                 }
1601         }
1602
1603         return 0;
1604 }
1605
1606 /*
1607 ==============================================================================
1608 */
1609 COMEDI_PCI_INITCLEANUP(driver_pci1710, pci1710_pci_table);
1610 /*
1611 ==============================================================================
1612 */