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